source: codes/icosagcm/devel/Python/test/py/Baroclinic_3D_ullrich.py @ 795

Last change on this file since 795 was 795, checked in by jisesh, 5 years ago

unstructured/Python : bugfix logging + more diagnostics

File size: 11.7 KB
Line 
1from __future__ import print_function
2from __future__ import division
3
4from dynamico import getargs
5
6getargs.add("--T", type=float, default=3600.,
7                    help="Length of time slice in seconds")
8getargs.add("--perturb", type=float, default=1.,
9                    help="Amplitude of wind perturbation in m/s")
10getargs.add("--N", type=int, default=48,
11                    help="Number of time slices")
12getargs.add("--Davies_N1", type=int, default=3)
13getargs.add("--Davies_N2", type=int, default=3)
14getargs.add("--nx", type=int, default=200)
15getargs.add("--ny", type=int, default=30)
16getargs.add("--betaplane", action='store_true')
17
18getargs.add("--kappa_divgrad",  type=float, default=3.0e15)
19getargs.add("--kappa_curlcurl", type=float, default=3.0e15)
20
21getargs.defaults(dt=360., llm=50)
22
23getargs.config_log(filename='out.log',filemode='w') # must be done before calling Logger()
24#    getargs.config_log(filename='out.log',filemode='w',
25#                    format='%(processName)s:%(name)s:%(filename)s:%(module)s:%(funcName)s:%(lineno)d:%(levelname)s:%(message)s' )
26
27logging = getargs.Logger('main')
28args = getargs.parse()
29
30from dynamico import unstructured as unst
31from dynamico import dyn
32from dynamico import time_step
33from dynamico import DCMIP
34from dynamico import meshes
35from dynamico import xios
36from dynamico import precision as prec
37from dynamico.meshes import Cartesian_mesh as Mesh
38from dynamico.kernels import grad, curl, div, KE
39from dynamico.LAM import Davies
40
41import math as math
42import numpy as np
43import time
44from numpy import pi, log, exp, sin, cos
45
46# Baroclinic instability test based on Ullrich et al. 2015, QJRMS
47
48def create_pmesh(nx,ny):
49    filename = 'cart_%03d_%03d.nc'%(nx,ny)
50    logging.info('Reading Cartesian mesh ...')
51    meshfile = meshes.DYNAMICO_Format(filename)
52    pmesh = meshes.Unstructured_PMesh(comm,meshfile)
53    pmesh.partition_curvilinear(args.mpi_ni,args.mpi_nj)
54    return pmesh
55
56def baroclinic_3D(pmesh, Lx,Ly,llm,ztop=25000.):
57    Rd    = 287.0      # Gas constant for dryy air (j kg^-1 K^-1)
58    T0    = 288.0      # Reference temperature (K)
59    lap   = 0.005      # Lapse rate (K m^-1)
60    b     = 2.         # Non dimensional vertical width parameter
61    u0    = 35.        # Reference zonal wind speed (m s^-1)
62    a     = 6.371229e6 # Radius of the Earth (m)
63    ptop  = 2000.
64    y0    = .5*Ly
65    Cpd   = 1004.5
66    p0    = 1e5
67    up    = args.perturb # amplitude (m/s)
68    xc,yc,lp = 0.,Ly/2.,600000.
69
70    omega  = 7.292e-5  # Angular velocity of the Earth (s^-1)   
71    phi0   = 45.*pi/180.0 # Reference latitude North pi/4 (deg)
72    f0     = 2*omega*sin(phi0) 
73    beta0  = 2*omega*cos(phi0)/a if args.betaplane else 0.
74    fb     = f0 - beta0*y0
75
76    def Phi_xy(y):
77        fc = y*y - (Ly*y/pi)*sin(2*pi*y/Ly)
78        fd = Ly*Ly/(2*pi*pi)*cos(2*pi*y/Ly)
79        return .5*u0*( fb*(y-y0-Ly/(2*pi)*sin(2*pi*y/Ly)) + .5*beta0*(fc-fd-(Ly*Ly/3.)- Ly*Ly/(2*pi*pi)) )
80
81    def Phi_xyeta(y,eta): return T0*g/lap*(1-eta**(Rd*lap/g)) + Phi_xy(y)*log(eta)*exp(-((log(eta)/b)**2))
82    def ulon(x,y,eta):
83        u = -u0*(sin(pi*y/Ly)**2)*log(eta)*(eta**(-log(eta)/(b*b))) 
84        u = u + up*exp(-(((x-xc)**2+(y-yc)**2)/lp**2))
85        return  u
86
87    def tmean(eta) : return T0*eta**(Rd*lap/g)
88    def T(y,eta) : return tmean(eta)+(Phi_xy(y)/Rd)*(((2/(b*b))*(log(eta))**2)-1)*exp(-((0.5*log(eta))**2)) 
89    def p(eta): return p0*eta     # eta  = p/p_s
90
91    def eta(alpha) : return (1.-(lap*ztop*alpha/T0))**(g/(Rd*lap)) # roughly equispaced levels
92    def coriolis(x,y): return f0+beta0*y # here y is 0 at domain center
93
94    nqdyn, radius = 1, None
95    mesh = meshes.Local_Mesh(pmesh, llm, nqdyn, radius, coriolis)
96
97    alpha_k = (np.arange(llm)  +.5)/llm
98    alpha_l = (np.arange(llm+1)+ 0.)/llm
99    x_ik, alpha_ik = np.meshgrid(mesh.lon_i,       alpha_k, indexing='ij')
100    y_ik, alpha_ik = np.meshgrid(mesh.lat_i+y0, alpha_k, indexing='ij')
101    x_il, alpha_il = np.meshgrid(mesh.lon_i,       alpha_l, indexing='ij')
102    y_il, alpha_il = np.meshgrid(mesh.lat_i+y0, alpha_l, indexing='ij')
103    x_ek, alpha_ek = np.meshgrid(mesh.lon_e,       alpha_k, indexing='ij')
104    y_ek, alpha_ek = np.meshgrid(mesh.lat_e+y0, alpha_k, indexing='ij')
105
106    print('ztop(ptop) according to Eq. 7:', T0/lap*(1.-(ptop/p0)**(Rd*lap/g))) 
107    print(np.shape(alpha_k),np.shape(alpha_l))
108    thermo = dyn.Ideal_perfect(Cpd, Rd, p0, T0)
109
110    eta_il = eta(alpha_il)
111    eta_ik = eta(alpha_ik)
112    eta_ek = eta(alpha_ek)
113#    print('min max eta_il', np.min(eta_il),np.max(eta_il))
114
115    Phi_il = Phi_xyeta(y_il, eta_il)
116    Phi_ik = Phi_xyeta(y_ik, eta_ik)
117    p_ik, p_il = p(eta_ik), p(eta_il)
118    T_ik = T(y_ik, eta_ik)  #ik full level(40), il(41)
119
120    gas = thermo.set_pT(p_ik,T_ik)
121    mass_ik = mesh.field_mass()
122    for l in range(llm): 
123        mass_ik[:,l]=(Phi_il[:,l+1]-Phi_il[:,l])/(g*gas.v[:,l])
124#        mass_ik[:,l]=(p_il[:,l]-p_il[:,l+1])/g
125    Sik, Wil  = gas.s*mass_ik, mesh.field_w()
126   
127    u_ek = mesh.ucov3D(ulon(x_ek, y_ek, eta_ek), 0.*eta_ek)
128
129    print('ztop (m) = ', Phi_il[0,-1]/g, ztop)
130    ptop = p(eta(1.))
131    print( 'ptop (Pa) = ', gas.p[0,-1], ptop)
132
133    params=dyn.Struct()
134    params.ptop=ptop
135    params.dx=dx
136    params.dx_g0=dx/g
137    params.g = g
138
139    # define parameters for lower BC
140    pbot = p(eta_il[:,0])
141    print( 'min p, T :', pbot.min(), tmean(pbot/p0))
142    gas_bot = thermo.set_pT(pbot, tmean(pbot/p0))
143    params.pbot = gas_bot.p
144    params.rho_bot = 1e6/gas_bot.v
145   
146    return thermo, mesh, params, prec.asnum([mass_ik,Sik,u_ek,Phi_il,Wil]), gas
147
148def diagnose(Phi,S,m,W,u):
149    s=S/m
150    curl_vk = curl(mesh, u)
151    abs_vort_vk = mesh.field_z() # absolute vorticity
152    un = mesh.field_u()
153    v = mesh.field_mass() # specific volume
154    w = mesh.field_mass()
155    z = mesh.field_mass()
156    for l in range(llm):
157        v[:,l]=(Phi[:,l+1]-Phi[:,l])/(g*m[:,l])
158        w[:,l]=.5*params.g*(W[:,l+1]+W[:,l])/m[:,l]
159        z[:,l]=.5*(Phi[:,l+1]+Phi[:,l])/params.g
160        un[:,l]=u[:,l]/mesh.de
161        abs_vort_vk[:,l]=curl_vk[:,l] + mesh.fv
162    gas = thermo.set_vs(v,s)
163    ps = gas.p[:,0]+ .5*g*m[:,0]
164    return gas, w, z, ps, un, curl_vk, abs_vort_vk
165
166class myDavies(Davies):
167    def mask(self,x,y):
168        logging.debug('davies dy = %f'% dy)
169        return self.mask0(y,.5*Ly,dy)*self.mask0(-y,.5*Ly,dy)
170       
171with xios.Client() as client: # setup XIOS which creates the DYNAMICO communicator
172    comm = client.comm
173    mpi_rank, mpi_size = comm.Get_rank(), comm.Get_size()
174
175    logging.info('%d/%d starting'%(mpi_rank,mpi_size))
176
177    g, Lx, Ly = 9.80616, 4e7, 6e6
178    nx, ny, llm = args.nx, args.ny, args.llm
179    dx = Lx/nx
180    dy = dx
181   
182    if True: # physical domain excludes relaxation zone
183        Dy = Ly + dy*2*(args.Davies_N1+args.Davies_N2)
184        print('Dy=%f, Ly = %f'%(Dy,Ly))
185    else: # physical domain includes relaxation zone
186        Dy=Ly
187    #    print('WARNING: Davies_N1 not equal to Davies_N2; average value will be used')
188
189    unst.setvar('g',g)
190   
191    pmesh = create_pmesh(nx,ny)
192    thermo, mesh, params, flow0, gas0 = baroclinic_3D(pmesh, Lx,Ly,llm)
193
194    mass_bl,mass_dak,mass_dbk = meshes.compute_hybrid_coefs(flow0[0])
195    unst.ker.dynamico_init_hybrid(mass_bl,mass_dak,mass_dbk)
196
197    T  = args.T
198    dt = args.dt
199    dz = flow0[3].max()/(params.g*llm)
200    nt = int(math.ceil(T/dt))
201    dt = T/nt
202    logging.info( 'Time step : %d x %g = %g s' % (nt,dt,nt*dt))
203
204   
205    caldyn_thermo, caldyn_eta = unst.thermo_entropy, unst.eta_mass
206
207    if False: # time stepping in Python
208        caldyn = unst.Caldyn_NH(caldyn_thermo,caldyn_eta, mesh,thermo,params,params.g)
209        scheme = time_step.ARK2(caldyn.bwd_fast_slow, dt)
210        def next_flow(m,S,u,Phi,W):
211            return scheme.advance((m,S,u,Phi,W),nt)
212
213    else: # time stepping in Fortran
214        scheme = time_step.ARK2(None, dt)
215        if args.hydrostatic:
216            caldyn_step = unst.caldyn_step_HPE(mesh,scheme,1, caldyn_thermo,caldyn_eta,
217                                               thermo,params,params.g)
218        else:
219            caldyn_step = unst.caldyn_step_NH(mesh,scheme,1, caldyn_thermo,caldyn_eta,
220                                              thermo,params,params.g)
221        davies = myDavies(args.Davies_N1, args.Davies_N2, 
222                          mesh.lon_i, mesh.lat_i, mesh.lon_e,mesh.lat_e)
223#        print('mask min/max :', davies.beta_i.min(), davies.beta_i.max() )
224        logging.debug('mask min/max :')
225        logging.debug('%f'% davies.beta_i.min())
226        logging.debug('%f'% davies.beta_i.max())
227
228        def next_flow(m,S,u,Phi,W):
229            # junk,fast,slow = caldyn.bwd_fast_slow(flow, 0.)
230            caldyn_step.mass[:,:], caldyn_step.theta_rhodz[:,:], caldyn_step.u[:,:] = m,S,u
231            caldyn_step.geopot[:,:], caldyn_step.W[:,:] = Phi,W
232            for i in range(nt):
233                caldyn_step.next()
234                davies.relax(llm, caldyn_step, flow0)
235                m,S,u = caldyn_step.mass, caldyn_step.theta_rhodz, caldyn_step.u
236                s = S/m
237                laps, bilaps = mesh.field_mass(), mesh.field_mass()
238                lapu, bilapu = mesh.field_u(), mesh.field_u()
239                unst.ker.dynamico_scalar_laplacian(s,laps)
240                unst.ker.dynamico_scalar_laplacian(laps,bilaps)
241                unst.ker.dynamico_curl_laplacian(u,lapu)
242                unst.ker.dynamico_curl_laplacian(lapu,bilapu)
243                caldyn_step.theta_rhodz[:] = S - dt*args.kappa_divgrad*bilaps*m # Euler step
244                caldyn_step.u[:] = u - dt*args.kappa_curlcurl*bilapu # Euler step
245
246            return (caldyn_step.mass.copy(), caldyn_step.theta_rhodz.copy(), caldyn_step.u.copy(),
247                    caldyn_step.geopot.copy(), caldyn_step.W.copy())
248
249    m,S,u,Phi,W = flow0
250    if caldyn_thermo == unst.thermo_theta:
251        s=S/m
252        theta = thermo.T0*exp(s/thermo.Cpd)
253        S=m*theta
254        title_format = 'Potential temperature at t=%g s (K)'
255    else:
256        title_format = 'Specific entropy at t=%g s (J/K/kg)'
257
258    #T, nslice, dt = 3600., 1, 3600.
259    Nslice = args.N
260
261    temp_v = mesh.field_z(),     
262
263    with xios.Context_Curvilinear(mesh,1, 24*3600) as context:
264        # now XIOS knows about the mesh and we can write to disk
265        for i in range(Nslice+1):
266            context.update_calendar(i+1)
267
268            # Diagnose quantities of interest from prognostic variables m,S,u,Phi,W
269            gas, w, z, ps, un, zeta_vk, zeta_abs_vk = diagnose(Phi,S,m,W,u)
270            KE_ik = KE(mesh,u)
271            du_fast, du_slow = caldyn_step.du_fast[0,:,:], caldyn_step.du_slow[0,:,:] 
272            div_fast, div_slow = div(mesh,du_fast), div(mesh,du_slow)
273            drhodz, hflux = caldyn_step.drhodz[0,:,:], caldyn_step.hflux[:,:]
274
275            # write to disk
276            context.send_field_primal('ps', ps)
277            context.send_field_primal('temp', gas.T)
278
279            context.send_field_primal('p', gas.p)
280#            context.send_field_primal('p', KE_ik)
281#            context.send_field_primal('p', drhodz)
282
283            context.send_field_primal('theta', gas.s)
284            context.send_field_primal('uz', w)
285            context.send_field_primal('z', z)
286            context.send_field_primal('div_fast', div_fast)
287
288            context.send_field_primal('div_slow', div_slow)
289
290            context.send_field_dual('curl', zeta_vk)
291            context.send_field_dual('curl_abs', zeta_abs_vk)
292
293            print( 'ptop, model top (m) :', unst.getvar('ptop'), Phi.max()/unst.getvar('g'))
294
295            time1, elapsed1 =time.time(), unst.getvar('elapsed')
296            m,S,u,Phi,W = next_flow(m,S,u,Phi,W)
297            time2, elapsed2 =time.time(), unst.getvar('elapsed')
298            factor = 1000./nt
299            print( 'ms per full time step : ', factor*(time2-time1), factor*(elapsed2-elapsed1))
300            factor = 1e9/(4*nt*nx*ny*llm)
301            print( 'nanosec per gridpoint per full time step : ', factor*(time2-time1), factor*(elapsed2-elapsed1))
302
303logging.info('************DONE************')
Note: See TracBrowser for help on using the repository browser.