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
RevLine 
[790]1from __future__ import print_function
[795]2from __future__ import division
3
[790]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')
[795]17
18getargs.add("--kappa_divgrad",  type=float, default=3.0e15)
19getargs.add("--kappa_curlcurl", type=float, default=3.0e15)
20
[790]21getargs.defaults(dt=360., llm=50)
22
[795]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
[790]27logging = getargs.Logger('main')
28args = getargs.parse()
29
[761]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
[791]38from dynamico.kernels import grad, curl, div, KE
39from dynamico.LAM import Davies
[761]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
[794]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
[764]55
[794]56def baroclinic_3D(pmesh, Lx,Ly,llm,ztop=25000.):
[761]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.
[787]64    y0    = .5*Ly
[761]65    Cpd   = 1004.5
66    p0    = 1e5
[790]67    up    = args.perturb # amplitude (m/s)
[774]68    xc,yc,lp = 0.,Ly/2.,600000.
[761]69
70    omega  = 7.292e-5  # Angular velocity of the Earth (s^-1)   
[790]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.
[787]74    fb     = f0 - beta0*y0
[761]75
[769]76    def Phi_xy(y):
[761]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
[769]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))
[774]82    def ulon(x,y,eta):
83        u = -u0*(sin(pi*y/Ly)**2)*log(eta)*(eta**(-log(eta)/(b*b))) 
[790]84        u = u + up*exp(-(((x-xc)**2+(y-yc)**2)/lp**2))
[774]85        return  u
86
[761]87    def tmean(eta) : return T0*eta**(Rd*lap/g)
[769]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)) 
[761]89    def p(eta): return p0*eta     # eta  = p/p_s
90
[787]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
[761]93
[769]94    nqdyn, radius = 1, None
[794]95    mesh = meshes.Local_Mesh(pmesh, llm, nqdyn, radius, coriolis)
[761]96
97    alpha_k = (np.arange(llm)  +.5)/llm
98    alpha_l = (np.arange(llm+1)+ 0.)/llm
[774]99    x_ik, alpha_ik = np.meshgrid(mesh.lon_i,       alpha_k, indexing='ij')
[787]100    y_ik, alpha_ik = np.meshgrid(mesh.lat_i+y0, alpha_k, indexing='ij')
[774]101    x_il, alpha_il = np.meshgrid(mesh.lon_i,       alpha_l, indexing='ij')
[787]102    y_il, alpha_il = np.meshgrid(mesh.lat_i+y0, alpha_l, indexing='ij')
[774]103    x_ek, alpha_ek = np.meshgrid(mesh.lon_e,       alpha_k, indexing='ij')
[787]104    y_ek, alpha_ek = np.meshgrid(mesh.lat_e+y0, alpha_k, indexing='ij')
[761]105
[774]106    print('ztop(ptop) according to Eq. 7:', T0/lap*(1.-(ptop/p0)**(Rd*lap/g))) 
[761]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)
[790]113#    print('min max eta_il', np.min(eta_il),np.max(eta_il))
[761]114
[769]115    Phi_il = Phi_xyeta(y_il, eta_il)
116    Phi_ik = Phi_xyeta(y_ik, eta_ik)
[787]117    p_ik, p_il = p(eta_ik), p(eta_il)
[769]118    T_ik = T(y_ik, eta_ik)  #ik full level(40), il(41)
[761]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])
[787]124#        mass_ik[:,l]=(p_il[:,l]-p_il[:,l+1])/g
[774]125    Sik, Wil  = gas.s*mass_ik, mesh.field_w()
[761]126   
127    u_ek = mesh.ucov3D(ulon(x_ek, y_ek, eta_ek), 0.*eta_ek)
128
[774]129    print('ztop (m) = ', Phi_il[0,-1]/g, ztop)
[761]130    ptop = p(eta(1.))
[774]131    print( 'ptop (Pa) = ', gas.p[0,-1], ptop)
[761]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])
[774]141    print( 'min p, T :', pbot.min(), tmean(pbot/p0))
[761]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   
[774]146    return thermo, mesh, params, prec.asnum([mass_ik,Sik,u_ek,Phi_il,Wil]), gas
[761]147
[795]148def diagnose(Phi,S,m,W,u):
[780]149    s=S/m
[795]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()
[769]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
[795]160        un[:,l]=u[:,l]/mesh.de
161        abs_vort_vk[:,l]=curl_vk[:,l] + mesh.fv
[769]162    gas = thermo.set_vs(v,s)
[795]163    ps = gas.p[:,0]+ .5*g*m[:,0]
164    return gas, w, z, ps, un, curl_vk, abs_vort_vk
[769]165
[771]166class myDavies(Davies):
167    def mask(self,x,y):
[790]168        logging.debug('davies dy = %f'% dy)
[774]169        return self.mask0(y,.5*Ly,dy)*self.mask0(-y,.5*Ly,dy)
[771]170       
[763]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()
[761]174
[790]175    logging.info('%d/%d starting'%(mpi_rank,mpi_size))
[774]176
[795]177    g, Lx, Ly = 9.80616, 4e7, 6e6
[787]178    nx, ny, llm = args.nx, args.ny, args.llm
[794]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')
[761]188
[763]189    unst.setvar('g',g)
[794]190   
191    pmesh = create_pmesh(nx,ny)
192    thermo, mesh, params, flow0, gas0 = baroclinic_3D(pmesh, Lx,Ly,llm)
[761]193
[769]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)
[761]196
[774]197    T  = args.T
[787]198    dt = args.dt
[769]199    dz = flow0[3].max()/(params.g*llm)
200    nt = int(math.ceil(T/dt))
201    dt = T/nt
[774]202    logging.info( 'Time step : %d x %g = %g s' % (nt,dt,nt*dt))
[794]203
[769]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)
[787]215        if args.hydrostatic:
[795]216            caldyn_step = unst.caldyn_step_HPE(mesh,scheme,1, caldyn_thermo,caldyn_eta,
217                                               thermo,params,params.g)
[787]218        else:
[795]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)
[790]223#        print('mask min/max :', davies.beta_i.min(), davies.beta_i.max() )
[774]224        logging.debug('mask min/max :')
[790]225        logging.debug('%f'% davies.beta_i.min())
226        logging.debug('%f'% davies.beta_i.max())
[795]227
[769]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
[771]232            for i in range(nt):
233                caldyn_step.next()
234                davies.relax(llm, caldyn_step, flow0)
[792]235                m,S,u = caldyn_step.mass, caldyn_step.theta_rhodz, caldyn_step.u
[785]236                s = S/m
[792]237                laps, bilaps = mesh.field_mass(), mesh.field_mass()
238                lapu, bilapu = mesh.field_u(), mesh.field_u()
[785]239                unst.ker.dynamico_scalar_laplacian(s,laps)
240                unst.ker.dynamico_scalar_laplacian(laps,bilaps)
[792]241                unst.ker.dynamico_curl_laplacian(u,lapu)
242                unst.ker.dynamico_curl_laplacian(lapu,bilapu)
[795]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
[792]245
[769]246            return (caldyn_step.mass.copy(), caldyn_step.theta_rhodz.copy(), caldyn_step.u.copy(),
[771]247                    caldyn_step.geopot.copy(), caldyn_step.W.copy())
[769]248
[774]249    m,S,u,Phi,W = flow0
[769]250    if caldyn_thermo == unst.thermo_theta:
251        s=S/m
[790]252        theta = thermo.T0*exp(s/thermo.Cpd)
[769]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.
[774]259    Nslice = args.N
[769]260
[795]261    temp_v = mesh.field_z(),     
262
[769]263    with xios.Context_Curvilinear(mesh,1, 24*3600) as context:
[763]264        # now XIOS knows about the mesh and we can write to disk
[792]265        for i in range(Nslice+1):
[785]266            context.update_calendar(i+1)
[769]267
268            # Diagnose quantities of interest from prognostic variables m,S,u,Phi,W
[795]269            gas, w, z, ps, un, zeta_vk, zeta_abs_vk = diagnose(Phi,S,m,W,u)
[790]270            KE_ik = KE(mesh,u)
[787]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)
[790]273            drhodz, hflux = caldyn_step.drhodz[0,:,:], caldyn_step.hflux[:,:]
274
[769]275            # write to disk
[787]276            context.send_field_primal('ps', ps)
[785]277            context.send_field_primal('temp', gas.T)
[790]278
[769]279            context.send_field_primal('p', gas.p)
[790]280#            context.send_field_primal('p', KE_ik)
281#            context.send_field_primal('p', drhodz)
282
[769]283            context.send_field_primal('theta', gas.s)
284            context.send_field_primal('uz', w)
[780]285            context.send_field_primal('z', z)
[787]286            context.send_field_primal('div_fast', div_fast)
[790]287
[787]288            context.send_field_primal('div_slow', div_slow)
[790]289
[795]290            context.send_field_dual('curl', zeta_vk)
291            context.send_field_dual('curl_abs', zeta_abs_vk)
[769]292
[774]293            print( 'ptop, model top (m) :', unst.getvar('ptop'), Phi.max()/unst.getvar('g'))
[769]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
[774]299            print( 'ms per full time step : ', factor*(time2-time1), factor*(elapsed2-elapsed1))
[769]300            factor = 1e9/(4*nt*nx*ny*llm)
[774]301            print( 'nanosec per gridpoint per full time step : ', factor*(time2-time1), factor*(elapsed2-elapsed1))
[769]302
[774]303logging.info('************DONE************')
Note: See TracBrowser for help on using the repository browser.