diff --git a/Cases.pxd b/Cases.pxd index 67461ad0..1752afc5 100644 --- a/Cases.pxd +++ b/Cases.pxd @@ -107,3 +107,14 @@ cdef class DYCOMS_RF01(CasesBase): cpdef io(self, NetCDFIO_Stats Stats) cpdef update_surface(self, GridMeanVariables GMV, TimeStepping TS) cpdef update_forcing(self, GridMeanVariables GMV, TimeStepping TS) + + +cdef class GABLS(CasesBase): + cpdef initialize_reference(self, Grid Gr, ReferenceState Ref, NetCDFIO_Stats Stats) + cpdef initialize_profiles(self, Grid Gr, GridMeanVariables GMV, ReferenceState Ref ) + cpdef initialize_surface(self, Grid Gr, ReferenceState Ref ) + cpdef initialize_forcing(self, Grid Gr, ReferenceState Ref, GridMeanVariables GMV ) + cpdef initialize_io(self, NetCDFIO_Stats Stats) + cpdef io(self, NetCDFIO_Stats Stats) + cpdef update_surface(self, GridMeanVariables GMV, TimeStepping TS) + cpdef update_forcing(self, GridMeanVariables GMV, TimeStepping TS) \ No newline at end of file diff --git a/Cases.pyx b/Cases.pyx index fde4cf75..79e4e18a 100644 --- a/Cases.pyx +++ b/Cases.pyx @@ -12,6 +12,7 @@ from NetCDFIO cimport NetCDFIO_Stats from thermodynamic_functions cimport * import math as mt from libc.math cimport sqrt, log, fabs,atan, exp, fmax +import pylab as plt def CasesFactory(namelist, paramlist): if namelist['meta']['casename'] == 'Soares': @@ -30,6 +31,8 @@ def CasesFactory(namelist, paramlist): return GATE_III(paramlist) elif namelist['meta']['casename'] == 'DYCOMS_RF01': return DYCOMS_RF01(paramlist) + elif namelist['meta']['casename'] == 'GABLS': + return GABLS(paramlist) else: print('case not recognized') @@ -87,13 +90,13 @@ cdef class Soares(CasesBase): Py_ssize_t k for k in xrange(Gr.gw, Gr.nzg-Gr.gw): - if Gr.z_half[k] <= 1350.0: - GMV.QT.values[k] = 5.0e-3 - 3.7e-4* Gr.z_half[k]/1000.0 + if Gr.z_c[k] <= 1350.0: + GMV.QT.values[k] = 5.0e-3 - 3.7e-4* Gr.z_c[k]/1000.0 theta[k] = 300.0 else: - GMV.QT.values[k] = 5.0e-3 - 3.7e-4 * 1.35 - 9.4e-4 * (Gr.z_half[k]-1350.0)/1000.0 - theta[k] = 300.0 + 2.0 * (Gr.z_half[k]-1350.0)/1000.0 + GMV.QT.values[k] = 5.0e-3 - 3.7e-4 * 1.35 - 9.4e-4 * (Gr.z_c[k]-1350.0)/1000.0 + theta[k] = 300.0 + 2.0 * (Gr.z_c[k]-1350.0)/1000.0 GMV.U.values[k] = 0.01 GMV.U.set_bcs(Gr) @@ -102,14 +105,14 @@ cdef class Soares(CasesBase): if GMV.H.name == 'thetal': for k in xrange(Gr.gw,Gr.nzg-Gr.gw): GMV.H.values[k] = theta[k] - GMV.T.values[k] = theta[k] * exner_c(Ref.p0_half[k]) + GMV.T.values[k] = theta[k] * exner_c(Ref.p0_c[k]) GMV.THL.values[k] = theta[k] elif GMV.H.name == 's': for k in xrange(Gr.gw,Gr.nzg-Gr.gw): - GMV.T.values[k] = theta[k] * exner_c(Ref.p0_half[k]) - GMV.H.values[k] = t_to_entropy_c(Ref.p0_half[k],GMV.T.values[k], + GMV.T.values[k] = theta[k] * exner_c(Ref.p0_c[k]) + GMV.H.values[k] = t_to_entropy_c(Ref.p0_c[k],GMV.T.values[k], GMV.QT.values[k], ql, qi) - GMV.THL.values[k] = thetali_c(Ref.p0_half[k],GMV.T.values[k], + GMV.THL.values[k] = thetali_c(Ref.p0_c[k],GMV.T.values[k], GMV.QT.values[k], ql, qi, latent_heat(GMV.T.values[k])) GMV.H.set_bcs(Gr) @@ -122,8 +125,8 @@ cdef class Soares(CasesBase): self.Sur.zrough = 1.0e-4 self.Sur.Tsurface = 300.0 self.Sur.qsurface = 5e-3 - self.Sur.lhf = 2.5e-5 * Ref.rho0[Gr.gw -1] * latent_heat(self.Sur.Tsurface) - self.Sur.shf = 6.0e-2 * cpm_c(self.Sur.qsurface) * Ref.rho0[Gr.gw-1] + self.Sur.lhf = 2.5e-5 * Ref.rho0_f[Gr.gw -1] * latent_heat(self.Sur.Tsurface) + self.Sur.shf = 6.0e-2 * cpm_c(self.Sur.qsurface) * Ref.rho0_f[Gr.gw-1] self.Sur.ustar_fixed = False self.Sur.Gr = Gr self.Sur.Ref = Ref @@ -175,43 +178,43 @@ cdef class Bomex(CasesBase): for k in xrange(Gr.gw,Gr.nzg-Gr.gw): #Set Thetal profile - if Gr.z_half[k] <= 520.: + if Gr.z_c[k] <= 520.: thetal[k] = 298.7 - if Gr.z_half[k] > 520.0 and Gr.z_half[k] <= 1480.0: - thetal[k] = 298.7 + (Gr.z_half[k] - 520) * (302.4 - 298.7)/(1480.0 - 520.0) - if Gr.z_half[k] > 1480.0 and Gr.z_half[k] <= 2000: - thetal[k] = 302.4 + (Gr.z_half[k] - 1480.0) * (308.2 - 302.4)/(2000.0 - 1480.0) - if Gr.z_half[k] > 2000.0: - thetal[k] = 308.2 + (Gr.z_half[k] - 2000.0) * (311.85 - 308.2)/(3000.0 - 2000.0) + if Gr.z_c[k] > 520.0 and Gr.z_c[k] <= 1480.0: + thetal[k] = 298.7 + (Gr.z_c[k] - 520) * (302.4 - 298.7)/(1480.0 - 520.0) + if Gr.z_c[k] > 1480.0 and Gr.z_c[k] <= 2000: + thetal[k] = 302.4 + (Gr.z_c[k] - 1480.0) * (308.2 - 302.4)/(2000.0 - 1480.0) + if Gr.z_c[k] > 2000.0: + thetal[k] = 308.2 + (Gr.z_c[k] - 2000.0) * (311.85 - 308.2)/(3000.0 - 2000.0) #Set qt profile - if Gr.z_half[k] <= 520: - GMV.QT.values[k] = (17.0 + (Gr.z_half[k]) * (16.3-17.0)/520.0)/1000.0 - if Gr.z_half[k] > 520.0 and Gr.z_half[k] <= 1480.0: - GMV.QT.values[k] = (16.3 + (Gr.z_half[k] - 520.0)*(10.7 - 16.3)/(1480.0 - 520.0))/1000.0 - if Gr.z_half[k] > 1480.0 and Gr.z_half[k] <= 2000.0: - GMV.QT.values[k] = (10.7 + (Gr.z_half[k] - 1480.0) * (4.2 - 10.7)/(2000.0 - 1480.0))/1000.0 - if Gr.z_half[k] > 2000.0: - GMV.QT.values[k] = (4.2 + (Gr.z_half[k] - 2000.0) * (3.0 - 4.2)/(3000.0 - 2000.0))/1000.0 + if Gr.z_c[k] <= 520: + GMV.QT.values[k] = (17.0 + (Gr.z_c[k]) * (16.3-17.0)/520.0)/1000.0 + if Gr.z_c[k] > 520.0 and Gr.z_c[k] <= 1480.0: + GMV.QT.values[k] = (16.3 + (Gr.z_c[k] - 520.0)*(10.7 - 16.3)/(1480.0 - 520.0))/1000.0 + if Gr.z_c[k] > 1480.0 and Gr.z_c[k] <= 2000.0: + GMV.QT.values[k] = (10.7 + (Gr.z_c[k] - 1480.0) * (4.2 - 10.7)/(2000.0 - 1480.0))/1000.0 + if Gr.z_c[k] > 2000.0: + GMV.QT.values[k] = (4.2 + (Gr.z_c[k] - 2000.0) * (3.0 - 4.2)/(3000.0 - 2000.0))/1000.0 #Set u profile - if Gr.z_half[k] <= 700.0: + if Gr.z_c[k] <= 700.0: GMV.U.values[k] = -8.75 - if Gr.z_half[k] > 700.0: - GMV.U.values[k] = -8.75 + (Gr.z_half[k] - 700.0) * (-4.61 - -8.75)/(3000.0 - 700.0) + if Gr.z_c[k] > 700.0: + GMV.U.values[k] = -8.75 + (Gr.z_c[k] - 700.0) * (-4.61 - -8.75)/(3000.0 - 700.0) if GMV.H.name == 'thetal': for k in xrange(Gr.gw,Gr.nzg-Gr.gw): GMV.H.values[k] = thetal[k] - GMV.T.values[k] = thetal[k] * exner_c(Ref.p0_half[k]) + GMV.T.values[k] = thetal[k] * exner_c(Ref.p0_c[k]) GMV.THL.values[k] = thetal[k] elif GMV.H.name == 's': for k in xrange(Gr.gw,Gr.nzg-Gr.gw): - GMV.T.values[k] = thetal[k] * exner_c(Ref.p0_half[k]) - GMV.H.values[k] = t_to_entropy_c(Ref.p0_half[k],GMV.T.values[k], + GMV.T.values[k] = thetal[k] * exner_c(Ref.p0_c[k]) + GMV.H.values[k] = t_to_entropy_c(Ref.p0_c[k],GMV.T.values[k], GMV.QT.values[k], ql, qi) - GMV.THL.values[k] = thetali_c(Ref.p0_half[k],GMV.T.values[k], + GMV.THL.values[k] = thetali_c(Ref.p0_c[k],GMV.T.values[k], GMV.QT.values[k], ql, qi, latent_heat(GMV.T.values[k])) GMV.U.set_bcs(Gr) @@ -225,8 +228,8 @@ cdef class Bomex(CasesBase): self.Sur.zrough = 1.0e-4 # not actually used, but initialized to reasonable value self.Sur.Tsurface = 299.1 * exner_c(Ref.Pg) self.Sur.qsurface = 22.45e-3 # kg/kg - self.Sur.lhf = 5.2e-5 * Ref.rho0[Gr.gw -1] * latent_heat(self.Sur.Tsurface) - self.Sur.shf = 8.0e-3 * cpm_c(self.Sur.qsurface) * Ref.rho0[Gr.gw-1] + self.Sur.lhf = 5.2e-5 * Ref.rho0_f[Gr.gw -1] * latent_heat(self.Sur.Tsurface) + self.Sur.shf = 8.0e-3 * cpm_c(self.Sur.qsurface) * Ref.rho0_f[Gr.gw-1] self.Sur.ustar_fixed = True self.Sur.ustar = 0.28 # m/s self.Sur.Gr = Gr @@ -240,24 +243,24 @@ cdef class Bomex(CasesBase): cdef Py_ssize_t k for k in xrange(Gr.gw, Gr.nzg-Gr.gw): # Geostrophic velocity profiles. vg = 0 - self.Fo.ug[k] = -10.0 + (1.8e-3)*Gr.z_half[k] + self.Fo.ug[k] = -10.0 + (1.8e-3)*Gr.z_c[k] # Set large-scale cooling - if Gr.z_half[k] <= 1500.0: - self.Fo.dTdt[k] = (-2.0/(3600 * 24.0)) * exner_c(Ref.p0_half[k]) + if Gr.z_c[k] <= 1500.0: + self.Fo.dTdt[k] = (-2.0/(3600 * 24.0)) * exner_c(Ref.p0_c[k]) else: - self.Fo.dTdt[k] = (-2.0/(3600 * 24.0) + (Gr.z_half[k] - 1500.0) - * (0.0 - -2.0/(3600 * 24.0)) / (3000.0 - 1500.0)) * exner_c(Ref.p0_half[k]) + self.Fo.dTdt[k] = (-2.0/(3600 * 24.0) + (Gr.z_c[k] - 1500.0) + * (0.0 - -2.0/(3600 * 24.0)) / (3000.0 - 1500.0)) * exner_c(Ref.p0_c[k]) # Set large-scale drying - if Gr.z_half[k] <= 300.0: + if Gr.z_c[k] <= 300.0: self.Fo.dqtdt[k] = -1.2e-8 #kg/(kg * s) - if Gr.z_half[k] > 300.0 and Gr.z_half[k] <= 500.0: - self.Fo.dqtdt[k] = -1.2e-8 + (Gr.z_half[k] - 300.0)*(0.0 - -1.2e-8)/(500.0 - 300.0) #kg/(kg * s) + if Gr.z_c[k] > 300.0 and Gr.z_c[k] <= 500.0: + self.Fo.dqtdt[k] = -1.2e-8 + (Gr.z_c[k] - 300.0)*(0.0 - -1.2e-8)/(500.0 - 300.0) #kg/(kg * s) #Set large scale subsidence - if Gr.z_half[k] <= 1500.0: - self.Fo.subsidence[k] = 0.0 + Gr.z_half[k]*(-0.65/100.0 - 0.0)/(1500.0 - 0.0) - if Gr.z_half[k] > 1500.0 and Gr.z_half[k] <= 2100.0: - self.Fo.subsidence[k] = -0.65/100 + (Gr.z_half[k] - 1500.0)* (0.0 - -0.65/100.0)/(2100.0 - 1500.0) + if Gr.z_c[k] <= 1500.0: + self.Fo.subsidence[k] = 0.0 + Gr.z_c[k]*(-0.65/100.0 - 0.0)/(1500.0 - 0.0) + if Gr.z_c[k] > 1500.0 and Gr.z_c[k] <= 2100.0: + self.Fo.subsidence[k] = -0.65/100 + (Gr.z_c[k] - 1500.0)* (0.0 - -0.65/100.0)/(2100.0 - 1500.0) return cpdef initialize_io(self, NetCDFIO_Stats Stats): @@ -299,44 +302,44 @@ cdef class life_cycle_Tan2018(CasesBase): double ql=0.0, qi =0.0 # IC of Bomex is cloud-free for k in xrange(Gr.gw,Gr.nzg-Gr.gw): #Set Thetal profile - if Gr.z_half[k] <= 520.: + if Gr.z_c[k] <= 520.: thetal[k] = 298.7 - if Gr.z_half[k] > 520.0 and Gr.z_half[k] <= 1480.0: - thetal[k] = 298.7 + (Gr.z_half[k] - 520) * (302.4 - 298.7)/(1480.0 - 520.0) - if Gr.z_half[k] > 1480.0 and Gr.z_half[k] <= 2000: - thetal[k] = 302.4 + (Gr.z_half[k] - 1480.0) * (308.2 - 302.4)/(2000.0 - 1480.0) - if Gr.z_half[k] > 2000.0: - thetal[k] = 308.2 + (Gr.z_half[k] - 2000.0) * (311.85 - 308.2)/(3000.0 - 2000.0) + if Gr.z_c[k] > 520.0 and Gr.z_c[k] <= 1480.0: + thetal[k] = 298.7 + (Gr.z_c[k] - 520) * (302.4 - 298.7)/(1480.0 - 520.0) + if Gr.z_c[k] > 1480.0 and Gr.z_c[k] <= 2000: + thetal[k] = 302.4 + (Gr.z_c[k] - 1480.0) * (308.2 - 302.4)/(2000.0 - 1480.0) + if Gr.z_c[k] > 2000.0: + thetal[k] = 308.2 + (Gr.z_c[k] - 2000.0) * (311.85 - 308.2)/(3000.0 - 2000.0) #Set qt profile - if Gr.z_half[k] <= 520: - GMV.QT.values[k] = (17.0 + (Gr.z_half[k]) * (16.3-17.0)/520.0)/1000.0 - if Gr.z_half[k] > 520.0 and Gr.z_half[k] <= 1480.0: - GMV.QT.values[k] = (16.3 + (Gr.z_half[k] - 520.0)*(10.7 - 16.3)/(1480.0 - 520.0))/1000.0 - if Gr.z_half[k] > 1480.0 and Gr.z_half[k] <= 2000.0: - GMV.QT.values[k] = (10.7 + (Gr.z_half[k] - 1480.0) * (4.2 - 10.7)/(2000.0 - 1480.0))/1000.0 - if Gr.z_half[k] > 2000.0: - GMV.QT.values[k] = (4.2 + (Gr.z_half[k] - 2000.0) * (3.0 - 4.2)/(3000.0 - 2000.0))/1000.0 + if Gr.z_c[k] <= 520: + GMV.QT.values[k] = (17.0 + (Gr.z_c[k]) * (16.3-17.0)/520.0)/1000.0 + if Gr.z_c[k] > 520.0 and Gr.z_c[k] <= 1480.0: + GMV.QT.values[k] = (16.3 + (Gr.z_c[k] - 520.0)*(10.7 - 16.3)/(1480.0 - 520.0))/1000.0 + if Gr.z_c[k] > 1480.0 and Gr.z_c[k] <= 2000.0: + GMV.QT.values[k] = (10.7 + (Gr.z_c[k] - 1480.0) * (4.2 - 10.7)/(2000.0 - 1480.0))/1000.0 + if Gr.z_c[k] > 2000.0: + GMV.QT.values[k] = (4.2 + (Gr.z_c[k] - 2000.0) * (3.0 - 4.2)/(3000.0 - 2000.0))/1000.0 #Set u profile - if Gr.z_half[k] <= 700.0: + if Gr.z_c[k] <= 700.0: GMV.U.values[k] = -8.75 - if Gr.z_half[k] > 700.0: - GMV.U.values[k] = -8.75 + (Gr.z_half[k] - 700.0) * (-4.61 - -8.75)/(3000.0 - 700.0) + if Gr.z_c[k] > 700.0: + GMV.U.values[k] = -8.75 + (Gr.z_c[k] - 700.0) * (-4.61 - -8.75)/(3000.0 - 700.0) if GMV.H.name == 'thetal': for k in xrange(Gr.gw,Gr.nzg-Gr.gw): GMV.H.values[k] = thetal[k] - GMV.T.values[k] = thetal[k] * exner_c(Ref.p0_half[k]) + GMV.T.values[k] = thetal[k] * exner_c(Ref.p0_c[k]) GMV.THL.values[k] = thetal[k] elif GMV.H.name == 's': for k in xrange(Gr.gw,Gr.nzg-Gr.gw): - GMV.T.values[k] = thetal[k] * exner_c(Ref.p0_half[k]) - GMV.H.values[k] = t_to_entropy_c(Ref.p0_half[k],GMV.T.values[k], + GMV.T.values[k] = thetal[k] * exner_c(Ref.p0_c[k]) + GMV.H.values[k] = t_to_entropy_c(Ref.p0_c[k],GMV.T.values[k], GMV.QT.values[k], ql, qi) - GMV.THL.values[k] = thetali_c(Ref.p0_half[k],GMV.T.values[k], + GMV.THL.values[k] = thetali_c(Ref.p0_c[k],GMV.T.values[k], GMV.QT.values[k], ql, qi, latent_heat(GMV.T.values[k])) GMV.U.set_bcs(Gr) @@ -350,8 +353,8 @@ cdef class life_cycle_Tan2018(CasesBase): self.Sur.zrough = 1.0e-4 # not actually used, but initialized to reasonable value self.Sur.Tsurface = 299.1 * exner_c(Ref.Pg) self.Sur.qsurface = 22.45e-3 # kg/kg - self.Sur.lhf = 5.2e-5 * Ref.rho0[Gr.gw -1] * latent_heat(self.Sur.Tsurface) - self.Sur.shf = 8.0e-3 * cpm_c(self.Sur.qsurface) * Ref.rho0[Gr.gw-1] + self.Sur.lhf = 5.2e-5 * Ref.rho0_f[Gr.gw -1] * latent_heat(self.Sur.Tsurface) + self.Sur.shf = 8.0e-3 * cpm_c(self.Sur.qsurface) * Ref.rho0_f[Gr.gw-1] self.lhf0 = self.Sur.lhf self.shf0 = self.Sur.shf self.Sur.ustar_fixed = True @@ -367,24 +370,24 @@ cdef class life_cycle_Tan2018(CasesBase): self.Fo.initialize(GMV) for k in xrange(Gr.gw, Gr.nzg-Gr.gw): # Geostrophic velocity profiles. vg = 0 - self.Fo.ug[k] = -10.0 + (1.8e-3)*Gr.z_half[k] + self.Fo.ug[k] = -10.0 + (1.8e-3)*Gr.z_c[k] # Set large-scale cooling - if Gr.z_half[k] <= 1500.0: - self.Fo.dTdt[k] = (-2.0/(3600 * 24.0)) * exner_c(Ref.p0_half[k]) + if Gr.z_c[k] <= 1500.0: + self.Fo.dTdt[k] = (-2.0/(3600 * 24.0)) * exner_c(Ref.p0_c[k]) else: - self.Fo.dTdt[k] = (-2.0/(3600 * 24.0) + (Gr.z_half[k] - 1500.0) - * (0.0 - -2.0/(3600 * 24.0)) / (3000.0 - 1500.0)) * exner_c(Ref.p0_half[k]) + self.Fo.dTdt[k] = (-2.0/(3600 * 24.0) + (Gr.z_c[k] - 1500.0) + * (0.0 - -2.0/(3600 * 24.0)) / (3000.0 - 1500.0)) * exner_c(Ref.p0_c[k]) # Set large-scale drying - if Gr.z_half[k] <= 300.0: + if Gr.z_c[k] <= 300.0: self.Fo.dqtdt[k] = -1.2e-8 #kg/(kg * s) - if Gr.z_half[k] > 300.0 and Gr.z_half[k] <= 500.0: - self.Fo.dqtdt[k] = -1.2e-8 + (Gr.z_half[k] - 300.0)*(0.0 - -1.2e-8)/(500.0 - 300.0) #kg/(kg * s) + if Gr.z_c[k] > 300.0 and Gr.z_c[k] <= 500.0: + self.Fo.dqtdt[k] = -1.2e-8 + (Gr.z_c[k] - 300.0)*(0.0 - -1.2e-8)/(500.0 - 300.0) #kg/(kg * s) #Set large scale subsidence - if Gr.z_half[k] <= 1500.0: - self.Fo.subsidence[k] = 0.0 + Gr.z_half[k]*(-0.65/100.0 - 0.0)/(1500.0 - 0.0) - if Gr.z_half[k] > 1500.0 and Gr.z_half[k] <= 2100.0: - self.Fo.subsidence[k] = -0.65/100 + (Gr.z_half[k] - 1500.0)* (0.0 - -0.65/100.0)/(2100.0 - 1500.0) + if Gr.z_c[k] <= 1500.0: + self.Fo.subsidence[k] = 0.0 + Gr.z_c[k]*(-0.65/100.0 - 0.0)/(1500.0 - 0.0) + if Gr.z_c[k] > 1500.0 and Gr.z_c[k] <= 2100.0: + self.Fo.subsidence[k] = -0.65/100 + (Gr.z_c[k] - 1500.0)* (0.0 - -0.65/100.0)/(2100.0 - 1500.0) return cpdef initialize_io(self, NetCDFIO_Stats Stats): @@ -432,33 +435,33 @@ cdef class Rico(CasesBase): Py_ssize_t k for k in xrange(Gr.gw,Gr.nzg-Gr.gw): - GMV.U.values[k] = -9.9 + 2.0e-3 * Gr.z_half[k] + GMV.U.values[k] = -9.9 + 2.0e-3 * Gr.z_c[k] GMV.V.values[k] = -3.8 #Set Thetal profile - if Gr.z_half[k] <= 740.0: + if Gr.z_c[k] <= 740.0: thetal[k] = 297.9 else: - thetal[k] = 297.9 + (317.0-297.9)/(4000.0-740.0)*(Gr.z_half[k] - 740.0) + thetal[k] = 297.9 + (317.0-297.9)/(4000.0-740.0)*(Gr.z_c[k] - 740.0) #Set qt profile - if Gr.z_half[k] <= 740.0: - GMV.QT.values[k] = (16.0 + (13.8 - 16.0)/740.0 * Gr.z_half[k])/1000.0 - elif Gr.z_half[k] > 740.0 and Gr.z_half[k] <= 3260.0: - GMV.QT.values[k] = (13.8 + (2.4 - 13.8)/(3260.0-740.0) * (Gr.z_half[k] - 740.0))/1000.0 + if Gr.z_c[k] <= 740.0: + GMV.QT.values[k] = (16.0 + (13.8 - 16.0)/740.0 * Gr.z_c[k])/1000.0 + elif Gr.z_c[k] > 740.0 and Gr.z_c[k] <= 3260.0: + GMV.QT.values[k] = (13.8 + (2.4 - 13.8)/(3260.0-740.0) * (Gr.z_c[k] - 740.0))/1000.0 else: - GMV.QT.values[k] = (2.4 + (1.8-2.4)/(4000.0-3260.0)*(Gr.z_half[k] - 3260.0))/1000.0 + GMV.QT.values[k] = (2.4 + (1.8-2.4)/(4000.0-3260.0)*(Gr.z_c[k] - 3260.0))/1000.0 if GMV.H.name == 'thetal': for k in xrange(Gr.gw,Gr.nzg-Gr.gw): GMV.H.values[k] = thetal[k] - GMV.T.values[k] = thetal[k] * exner_c(Ref.p0_half[k]) + GMV.T.values[k] = thetal[k] * exner_c(Ref.p0_c[k]) GMV.THL.values[k] = thetal[k] elif GMV.H.name == 's': for k in xrange(Gr.gw,Gr.nzg-Gr.gw): - GMV.T.values[k] = thetal[k] * exner_c(Ref.p0_half[k]) - GMV.H.values[k] = t_to_entropy_c(Ref.p0_half[k],GMV.T.values[k], + GMV.T.values[k] = thetal[k] * exner_c(Ref.p0_c[k]) + GMV.H.values[k] = t_to_entropy_c(Ref.p0_c[k],GMV.T.values[k], GMV.QT.values[k], ql, qi) - GMV.THL.values[k] = thetali_c(Ref.p0_half[k],GMV.T.values[k], + GMV.THL.values[k] = thetali_c(Ref.p0_c[k],GMV.T.values[k], GMV.QT.values[k], ql, qi, latent_heat(GMV.T.values[k])) GMV.U.set_bcs(Gr) @@ -477,7 +480,7 @@ cdef class Rico(CasesBase): self.Sur.ch = 0.001094 self.Sur.cq = 0.001133 # Adjust for non-IC grid spacing - grid_adjust = (np.log(20.0/self.Sur.zrough)/np.log(Gr.z_half[Gr.gw]/self.Sur.zrough))**2 + grid_adjust = (np.log(20.0/self.Sur.zrough)/np.log(Gr.z_c[Gr.gw]/self.Sur.zrough))**2 self.Sur.cm = self.Sur.cm * grid_adjust self.Sur.ch = self.Sur.ch * grid_adjust self.Sur.cq = self.Sur.cq * grid_adjust @@ -491,20 +494,20 @@ cdef class Rico(CasesBase): self.Fo.initialize(GMV) for k in xrange(Gr.nzg): # Geostrophic velocity profiles - self.Fo.ug[k] = -9.9 + 2.0e-3 * Gr.z_half[k] + self.Fo.ug[k] = -9.9 + 2.0e-3 * Gr.z_c[k] self.Fo.vg[k] = -3.8 # Set large-scale cooling - self.Fo.dTdt[k] = (-2.5/(3600.0 * 24.0)) * exner_c(Ref.p0_half[k]) + self.Fo.dTdt[k] = (-2.5/(3600.0 * 24.0)) * exner_c(Ref.p0_c[k]) # Set large-scale moistening - if Gr.z_half[k] <= 2980.0: - self.Fo.dqtdt[k] = (-1.0 + 1.3456/2980.0 * Gr.z_half[k])/86400.0/1000.0 #kg/(kg * s) + if Gr.z_c[k] <= 2980.0: + self.Fo.dqtdt[k] = (-1.0 + 1.3456/2980.0 * Gr.z_c[k])/86400.0/1000.0 #kg/(kg * s) else: self.Fo.dqtdt[k] = 0.3456/86400.0/1000.0 #Set large scale subsidence - if Gr.z_half[k] <= 2260.0: - self.Fo.subsidence[k] = -(0.005/2260.0) * Gr.z_half[k] + if Gr.z_c[k] <= 2260.0: + self.Fo.subsidence[k] = -(0.005/2260.0) * Gr.z_c[k] else: self.Fo.subsidence[k] = -0.005 return @@ -597,19 +600,19 @@ cdef class TRMM_LBA(CasesBase): 5.32, 1.14, -0.65, 5.27, 5.27]) # interpolate to the model grid-points - p1 = np.interp(Gr.z_half,z_in,p_in) - GMV.U.values = np.interp(Gr.z_half,z_in,u_in) - GMV.V.values = np.interp(Gr.z_half,z_in,v_in) + p1 = np.interp(Gr.z_c,z_in,p_in) + GMV.U.values = np.interp(Gr.z_c,z_in,u_in) + GMV.V.values = np.interp(Gr.z_c,z_in,v_in) # get the entropy from RH, p, T RH = np.zeros(Gr.nzg) - RH[Gr.gw:Gr.nzg-Gr.gw] = np.interp(Gr.z_half[Gr.gw:Gr.nzg-Gr.gw],z_in,RH_in) + RH[Gr.gw:Gr.nzg-Gr.gw] = np.interp(Gr.z_c[Gr.gw:Gr.nzg-Gr.gw],z_in,RH_in) RH[0] = RH[3] RH[1] = RH[2] RH[Gr.nzg-Gr.gw+1] = RH[Gr.nzg-Gr.gw-1] T = np.zeros(Gr.nzg) - T[Gr.gw:Gr.nzg-Gr.gw] = np.interp(Gr.z_half[Gr.gw:Gr.nzg-Gr.gw],z_in,T_in) + T[Gr.gw:Gr.nzg-Gr.gw] = np.interp(Gr.z_c[Gr.gw:Gr.nzg-Gr.gw],z_in,T_in) GMV.T.values = T theta_rho = RH*0.0 epsi = 287.1/461.5 @@ -626,15 +629,15 @@ cdef class TRMM_LBA(CasesBase): qv = GMV.QT.values[k] - GMV.QL.values[k] GMV.QT.values[k] = qv_star*RH[k]/100.0 if GMV.H.name == 's': - GMV.H.values[k] = t_to_entropy_c(Ref.p0_half[k],GMV.T.values[k], + GMV.H.values[k] = t_to_entropy_c(Ref.p0_c[k],GMV.T.values[k], GMV.QT.values[k], 0.0, 0.0) elif GMV.H.name == 'thetal': - GMV.H.values[k] = thetali_c(Ref.p0_half[k],GMV.T.values[k], + GMV.H.values[k] = thetali_c(Ref.p0_c[k],GMV.T.values[k], GMV.QT.values[k], 0.0, 0.0, latent_heat(GMV.T.values[k])) - GMV.THL.values[k] = thetali_c(Ref.p0_half[k],GMV.T.values[k], + GMV.THL.values[k] = thetali_c(Ref.p0_c[k],GMV.T.values[k], GMV.QT.values[k], 0.0, 0.0, latent_heat(GMV.T.values[k])) - theta_rho[k] = theta_rho_c(Ref.p0_half[k], GMV.T.values[k], GMV.QT.values[k], qv) + theta_rho[k] = theta_rho_c(Ref.p0_c[k], GMV.T.values[k], GMV.QT.values[k], qv) GMV.QT.set_bcs(Gr) GMV.H.set_bcs(Gr) @@ -645,8 +648,8 @@ cdef class TRMM_LBA(CasesBase): #self.Sur.zrough = 1.0e-4 # not actually used, but initialized to reasonable value self.Sur.Tsurface = (273.15+23) * exner_c(Ref.Pg) self.Sur.qsurface = 22.45e-3 # kg/kg - self.Sur.lhf = 5.2e-5 * Ref.rho0[Gr.gw -1] * latent_heat(self.Sur.Tsurface) - self.Sur.shf = 8.0e-3 * cpm_c(self.Sur.qsurface) * Ref.rho0[Gr.gw-1] + self.Sur.lhf = 5.2e-5 * Ref.rho0_f[Gr.gw -1] * latent_heat(self.Sur.Tsurface) + self.Sur.shf = 8.0e-3 * cpm_c(self.Sur.qsurface) * Ref.rho0_f[Gr.gw-1] self.Sur.ustar_fixed = True self.Sur.ustar = 0.28 # this is taken from Bomex -- better option is to approximate from LES tke above the surface self.Sur.Gr = Gr @@ -775,9 +778,9 @@ cdef class TRMM_LBA(CasesBase): cdef: Py_ssize_t tt, k, ind1, ind2 - A = np.interp(Gr.z_half,z_in,rad_in[0,:]) + A = np.interp(Gr.z_c,z_in,rad_in[0,:]) for tt in xrange(1,36): - A = np.vstack((A, np.interp(Gr.z_half,z_in,rad_in[tt,:]))) + A = np.vstack((A, np.interp(Gr.z_c,z_in,rad_in[tt,:]))) self.rad = np.multiply(A,1.0) # store matrix in self ind1 = int(mt.trunc(10.0/600.0)) @@ -828,7 +831,7 @@ cdef class TRMM_LBA(CasesBase): self.Fo.dTdt[k] = self.rad[ind1,k] else: # in all other cases - interpolate for k in xrange(self.Fo.Gr.nzg): - if self.Fo.Gr.z_half[k] < 22699.48: + if self.Fo.Gr.z_c[k] < 22699.48: self.Fo.dTdt[k] = (self.rad[ind2,k]-self.rad[ind1,k])\ /(self.rad_time[ind2]-self.rad_time[ind1])\ *(TS.t/60.0-self.rad_time[ind1])+self.rad[ind1,k] @@ -867,25 +870,24 @@ cdef class ARM_SGP(CasesBase): Theta_in = np.array([299.0, 301.5, 302.5, 303.53, 303.7, 307.13, 314.0, 343.2]) # K r_in = np.array([15.2,15.17,14.98,14.8,14.7,13.5,3.0,3.0])/1000 # qt should be in kg/kg qt_in = np.divide(r_in,(1+r_in)) - print qt_in # interpolate to the model grid-points - Theta = np.interp(Gr.z_half,z_in,Theta_in) - qt = np.interp(Gr.z_half,z_in,qt_in) + Theta = np.interp(Gr.z_c,z_in,Theta_in) + qt = np.interp(Gr.z_c,z_in,qt_in) for k in xrange(Gr.gw,Gr.nzg-Gr.gw): GMV.U.values[k] = 10.0 GMV.QT.values[k] = qt[k] - GMV.T.values[k] = Theta[k]*exner_c(Ref.p0_half[k]) + GMV.T.values[k] = Theta[k]*exner_c(Ref.p0_c[k]) if GMV.H.name == 's': - GMV.H.values[k] = t_to_entropy_c(Ref.p0_half[k],GMV.T.values[k], + GMV.H.values[k] = t_to_entropy_c(Ref.p0_c[k],GMV.T.values[k], GMV.QT.values[k], 0.0, 0.0) elif GMV.H.name == 'thetal': - GMV.H.values[k] = thetali_c(Ref.p0_half[k],GMV.T.values[k], + GMV.H.values[k] = thetali_c(Ref.p0_c[k],GMV.T.values[k], GMV.QT.values[k], 0.0, 0.0, latent_heat(GMV.T.values[k])) - GMV.THL.values[k] = thetali_c(Ref.p0_half[k],GMV.T.values[k], + GMV.THL.values[k] = thetali_c(Ref.p0_c[k],GMV.T.values[k], GMV.QT.values[k], 0.0, 0.0, latent_heat(GMV.T.values[k])) @@ -958,13 +960,13 @@ cdef class ARM_SGP(CasesBase): double dTdt = np.interp(TS.t,t_in,AT_in) + np.interp(TS.t,t_in,RT_in) double dqtdt = np.interp(TS.t,t_in,Rqt_in) for k in xrange(self.Fo.Gr.nzg): # correct dims - if self.Fo.Gr.z_half[k] <=1000.0: + if self.Fo.Gr.z_c[k] <=1000.0: self.Fo.dTdt[k] = dTdt - self.Fo.dqtdt[k] = dqtdt * exner_c(self.Fo.Ref.p0_half[k]) - elif self.Fo.Gr.z_half[k] > 1000.0 and self.Fo.Gr.z_half[k] <= 2000.0: - self.Fo.dTdt[k] = dTdt*(1-(self.Fo.Gr.z_half[k]-1000.0)/1000.0) - self.Fo.dqtdt[k] = dqtdt * exner_c(self.Fo.Ref.p0_half[k])\ - *(1-(self.Fo.Gr.z_half[k]-1000.0)/1000.0) + self.Fo.dqtdt[k] = dqtdt * exner_c(self.Fo.Ref.p0_c[k]) + elif self.Fo.Gr.z_c[k] > 1000.0 and self.Fo.Gr.z_c[k] <= 2000.0: + self.Fo.dTdt[k] = dTdt*(1-(self.Fo.Gr.z_c[k]-1000.0)/1000.0) + self.Fo.dqtdt[k] = dqtdt * exner_c(self.Fo.Ref.p0_c[k])\ + *(1-(self.Fo.Gr.z_c[k]-1000.0)/1000.0) self.Fo.update(GMV) return @@ -976,15 +978,15 @@ cdef class GATE_III(CasesBase): def __init__(self, paramlist): self.casename = 'GATE_III' self.Sur = Surface.SurfaceFixedCoeffs(paramlist) - self.Fo = Forcing.ForcingStandard() # it was forcing standard - self.inversion_option = 'thetal_maxgrad' + self.Fo = Forcing.ForcingStandard() + self.inversion_option = 'critical_Ri'# 'thetal_maxgrad' self.Fo.apply_subsidence = False self.Fo.apply_coriolis = False return cpdef initialize_reference(self, Grid Gr, ReferenceState Ref, NetCDFIO_Stats Stats): - Ref.Pg = 1013.0*100 #Pressure at ground - Ref.Tg = 299.184 # surface values for reference state (RS) which outputs p0 rho0 alpha0 + Ref.Pg = 1000.0*100 #Pressure at ground + Ref.Tg = 299.88 # surface values for reference state (RS) which outputs p0 rho0 alpha0 Ref.qtg = 16.5/1000#Total water mixing ratio at surface Ref.initialize(Gr, Stats) return @@ -1013,9 +1015,9 @@ cdef class GATE_III(CasesBase): z_T_in = np.array([0.0, 0.492, 0.700, 1.698, 3.928, 6.039, 7.795, 9.137, 11.055, 12.645, 13.521, 14.486, 15.448, 16.436, 17.293, 22.0])*1000.0 # for km # interpolate to the model grid-points - T = np.interp(Gr.z_half,z_T_in,T_in) # interpolate to ref pressure level - qt = np.interp(Gr.z_half,z_in,qt_in) - U = np.interp(Gr.z_half,z_in,U_in) + T = np.interp(Gr.z_c,z_T_in,T_in) # interpolate to ref pressure level + qt = np.interp(Gr.z_c,z_in,qt_in) + U = np.interp(Gr.z_c,z_in,U_in) for k in xrange(Gr.gw,Gr.nzg-Gr.gw): @@ -1024,13 +1026,13 @@ cdef class GATE_III(CasesBase): GMV.U.values[k] = U[k] if GMV.H.name == 's': - GMV.H.values[k] = t_to_entropy_c(Ref.p0_half[k],GMV.T.values[k], + GMV.H.values[k] = t_to_entropy_c(Ref.p0_c[k],GMV.T.values[k], GMV.QT.values[k], 0.0, 0.0) elif GMV.H.name == 'thetal': - GMV.H.values[k] = thetali_c(Ref.p0_half[k],GMV.T.values[k], + GMV.H.values[k] = thetali_c(Ref.p0_c[k],GMV.T.values[k], GMV.QT.values[k], 0.0, 0.0, latent_heat(GMV.T.values[k])) - GMV.THL.values[k] = thetali_c(Ref.p0_half[k],GMV.T.values[k], + GMV.THL.values[k] = thetali_c(Ref.p0_c[k],GMV.T.values[k], GMV.QT.values[k], 0.0, 0.0, latent_heat(GMV.T.values[k])) GMV.U.set_bcs(Gr) GMV.QT.set_bcs(Gr) @@ -1042,6 +1044,7 @@ cdef class GATE_III(CasesBase): cpdef initialize_surface(self, Grid Gr, ReferenceState Ref): self.Sur.Gr = Gr self.Sur.Ref = Ref + self.Sur.zrough = 0.00015 self.Sur.qsurface = 16.5/1000.0 # kg/kg self.Sur.Gr = Gr self.Sur.Ref = Ref @@ -1078,8 +1081,10 @@ cdef class GATE_III(CasesBase): Qtend_in = np.divide(r_tend_in,(1+r_tend_in)) # convert mixing ratio to specific humidity - self.Fo.dqtdt = np.interp(Gr.z_half,z_in,Qtend_in) - self.Fo.dTdt = np.interp(Gr.z_half,z_in,Ttend_in) + np.interp(Gr.z_half,z_in,RAD_in) + self.Fo.dqtdt = np.interp(Gr.z_c,z_in,Qtend_in) + self.Fo.dTdt = np.interp(Gr.z_c,z_in,Ttend_in) + np.interp(Gr.z_c,z_in,RAD_in) + self.Fo.ug = np.interp(Gr.z_c,z_in,u_in) + self.Fo.ug = np.multiply(0.0,self.Fo.ug) return @@ -1180,35 +1185,35 @@ cdef class DYCOMS_RF01(CasesBase): for k in xrange(Gr.gw, Gr.nzg-Gr.gw): # thetal profile as defined in DYCOMS - if Gr.z_half[k] <= 840.0: + if Gr.z_c[k] <= 840.0: thetal[k] = 289.0 - if Gr.z_half[k] > 840.0: - thetal[k] = (297.5 + (Gr.z_half[k] - 840.0)**(1.0/3.0)) + if Gr.z_c[k] > 840.0: + thetal[k] = (297.5 + (Gr.z_c[k] - 840.0)**(1.0/3.0)) # qt profile as defined in DYCOMS - if Gr.z_half[k] <= 840.0: + if Gr.z_c[k] <= 840.0: GMV.QT.values[k] = 9. / 1000.0 - if Gr.z_half[k] > 840.0: + if Gr.z_c[k] > 840.0: GMV.QT.values[k] = 1.5 / 1000.0 # ql and T profile # (calculated by saturation adjustment using thetal and qt values provided in DYCOMS # and using Rd, cp and L constants as defined in DYCOMS) - GMV.T.values[k], GMV.QL.values[k] = self.dycoms_sat_adjst(Ref.p0_half[k], thetal[k], GMV.QT.values[k]) + GMV.T.values[k], GMV.QL.values[k] = self.dycoms_sat_adjst(Ref.p0_c[k], thetal[k], GMV.QT.values[k]) # thermodynamic variable profile (either entropy or thetal) # (calculated based on T and ql profiles. # Here we use Rd, cp and L constants as defined in scampy) - GMV.THL.values[k] = t_to_thetali_c(Ref.p0_half[k], GMV.T.values[k], GMV.QT.values[k], GMV.QL.values[k], qi) + GMV.THL.values[k] = t_to_thetali_c(Ref.p0_c[k], GMV.T.values[k], GMV.QT.values[k], GMV.QL.values[k], qi) if GMV.H.name == 'thetal': - GMV.H.values[k] = t_to_thetali_c(Ref.p0_half[k], GMV.T.values[k], GMV.QT.values[k], GMV.QL.values[k], qi) + GMV.H.values[k] = t_to_thetali_c(Ref.p0_c[k], GMV.T.values[k], GMV.QT.values[k], GMV.QL.values[k], qi) elif GMV.H.name == 's': - GMV.H.values[k] = t_to_entropy_c(Ref.p0_half[k], GMV.T.values[k], GMV.QT.values[k], GMV.QL.values[k], qi) + GMV.H.values[k] = t_to_entropy_c(Ref.p0_c[k], GMV.T.values[k], GMV.QT.values[k], GMV.QL.values[k], qi) # buoyancy profile qv = GMV.QT.values[k] - qi - GMV.QL.values[k] - alpha = alpha_c(Ref.p0_half[k], GMV.T.values[k], GMV.QT.values[k], qv) - GMV.B.values[k] = buoyancy_c(Ref.alpha0_half[k], alpha) + alpha = alpha_c(Ref.p0_c[k], GMV.T.values[k], GMV.QT.values[k], qv) + GMV.B.values[k] = buoyancy_c(Ref.alpha0_c[k], alpha) # velocity profile (geostrophic) GMV.U.values[k] = 7.0 @@ -1241,8 +1246,8 @@ cdef class DYCOMS_RF01(CasesBase): #density_surface = 1.22 # kg/m^3 # buoyancy flux - theta_flux = self.Sur.shf / cpm_c(self.Sur.qsurface) / Ref.rho0[Gr.gw-1] - qt_flux = self.Sur.lhf / latent_heat(self.Sur.Tsurface) / Ref.rho0[Gr.gw-1] + theta_flux = self.Sur.shf / cpm_c(self.Sur.qsurface) / Ref.rho0_f[Gr.gw-1] + qt_flux = self.Sur.lhf / latent_heat(self.Sur.Tsurface) / Ref.rho0_f[Gr.gw-1] theta_surface = self.Sur.Tsurface / exner_c(Ref.Pg) self.Sur.bflux = g * ((theta_flux + (eps_vi - 1.0) * (theta_surface * qt_flux + self.Sur.qsurface * theta_flux)) / (theta_surface * (1.0 + (eps_vi-1) * self.Sur.qsurface))) @@ -1266,7 +1271,7 @@ cdef class DYCOMS_RF01(CasesBase): # To be able to have self.Fo.divergence available here, # we would have to change the signature of ForcingBase class for k in xrange(Gr.gw, Gr.nzg-Gr.gw): - self.Fo.subsidence[k] = - Gr.z_half[k] * divergence + self.Fo.subsidence[k] = - Gr.z_c[k] * divergence # no large-scale drying self.Fo.dqtdt[:] = 0. #kg/(kg * s) @@ -1292,3 +1297,96 @@ cdef class DYCOMS_RF01(CasesBase): cpdef update_forcing(self, GridMeanVariables GMV, TimeStepping TS): self.Fo.update(GMV) return + +cdef class GABLS(CasesBase): + def __init__(self, paramlist): + self.casename = 'GABLS' + self.Sur = Surface.SurfaceMoninObukhov(paramlist) + self.Fo = Forcing.ForcingStandard() + self.inversion_option = 'critical_Ri' + self.Fo.apply_coriolis = True + cdef double latitude = 73.0 + self.Fo.coriolis_param = 1.39e-4 # s^{-1} + # self.Fo.coriolis_param = 2.0 * omega * np.sin(latitude * pi / 180.0 ) # s^{-1} + self.Fo.apply_subsidence = False + return + + cpdef initialize_reference(self, Grid Gr, ReferenceState Ref, NetCDFIO_Stats Stats): + Ref.Pg = 1.0e5 #Pressure at ground + Ref.Tg = 265.0 #Temperature at ground + Ref.qtg = 1.0e-4 #0.02 #Total water mixing ratio at surface. if set to 0, alpha0, rho0, p0 are NaN. + Ref.initialize(Gr, Stats) + return + cpdef initialize_profiles(self, Grid Gr, GridMeanVariables GMV, ReferenceState Ref): + cdef: + double [:] thetal = np.zeros((Gr.nzg,), dtype=np.double, order='c') + double ql=0.0, qi =0.0 # IC of GABLS cloud-free + double [:] theta_pert = np.random.random_sample(Gr.nzg) + Py_ssize_t k + + for k in xrange(Gr.gw,Gr.nzg-Gr.gw): + GMV.U.values[k] = 8.0 + GMV.V.values[k] = 0.0 + #Set Thetal profile + if Gr.z_c[k] <= 100.0: + thetal[k] = 265.0 + else: + thetal[k] = 265.0 + (Gr.z_c[k] - 100.0) * 0.01 + + #Set qt profile + GMV.QT.values[k] = 0.0 + + if GMV.H.name == 'thetal': + for k in xrange(Gr.gw,Gr.nzg-Gr.gw): + GMV.H.values[k] = thetal[k] + GMV.T.values[k] = thetal[k] * exner_c(Ref.p0_c[k]) + GMV.THL.values[k] = thetal[k] + elif GMV.H.name == 's': + for k in xrange(Gr.gw,Gr.nzg-Gr.gw): + GMV.T.values[k] = thetal[k] * exner_c(Ref.p0_c[k]) + GMV.H.values[k] = t_to_entropy_c(Ref.p0_c[k],GMV.T.values[k], + GMV.QT.values[k], ql, qi) + GMV.THL.values[k] = thetali_c(Ref.p0_c[k],GMV.T.values[k], + GMV.QT.values[k], ql, qi, latent_heat(GMV.T.values[k])) + + GMV.U.set_bcs(Gr) + GMV.V.set_bcs(Gr) + GMV.QT.set_bcs(Gr) + GMV.H.set_bcs(Gr) + GMV.T.set_bcs(Gr) + GMV.satadjust() + return + + cpdef initialize_surface(self, Grid Gr, ReferenceState Ref): + self.Sur.Gr = Gr + self.Sur.Ref = Ref + self.Sur.zrough = 0.1 + self.Sur.Tsurface = 265.0 + self.Sur.initialize() + return + + cpdef initialize_forcing(self, Grid Gr, ReferenceState Ref, GridMeanVariables GMV): + self.Fo.Gr = Gr + self.Fo.Ref = Ref + self.Fo.initialize(GMV) + cdef Py_ssize_t k + for k in xrange(Gr.gw, Gr.nzg - Gr.gw): + # Geostrophic velocity profiles. vg = 0 + self.Fo.ug[k] = 8.0 + self.Fo.vg[k] = 0.0 + return + + cpdef initialize_io(self, NetCDFIO_Stats Stats): + CasesBase.initialize_io(self, Stats) + return + cpdef io(self, NetCDFIO_Stats Stats): + CasesBase.io(self,Stats) + return + cpdef update_surface(self, GridMeanVariables GMV, TimeStepping TS): + self.Sur.Tsurface = 265.0 - (0.25/3600.0)*TS.t + self.Sur.update(GMV) + return + + cpdef update_forcing(self, GridMeanVariables GMV, TimeStepping TS): + self.Fo.update(GMV) + return diff --git a/EDMF_Environment.pxd b/EDMF_Environment.pxd index b04feeff..db89f941 100644 --- a/EDMF_Environment.pxd +++ b/EDMF_Environment.pxd @@ -13,6 +13,23 @@ cdef class EnvironmentVariable: str name str units + +cdef class EnvironmentVariable_2m: + cdef: + double [:] values + double [:] dissipation + double [:] shear + double [:] entr_gain + double [:] detr_loss + double [:] press + double [:] buoy + double [:] interdomain + double [:] rain_src + str loc + str kind + str name + str units + cdef class EnvironmentVariables: cdef: @@ -24,12 +41,12 @@ cdef class EnvironmentVariables: EnvironmentVariable THL EnvironmentVariable T EnvironmentVariable B - EnvironmentVariable TKE - EnvironmentVariable Hvar - EnvironmentVariable QTvar - EnvironmentVariable HQTcov + EnvironmentVariable_2m TKE + EnvironmentVariable_2m Hvar + EnvironmentVariable_2m QTvar + EnvironmentVariable_2m HQTcov EnvironmentVariable CF - EnvironmentVariable THVvar + EnvironmentVariable_2m THVvar Grid Gr bint calc_tke bint calc_scalar_var @@ -73,4 +90,4 @@ cdef class EnvironmentThermodynamics: void eos_update_SA_sgs(self, EnvironmentVariables EnvVar, bint in_Env)#, TimeStepping TS) void sommeria_deardorff(self, EnvironmentVariables EnvVar) - cpdef satadjust(self, EnvironmentVariables EnvVar, bint in_Env)#, TimeStepping TS) + cpdef satadjust(self, EnvironmentVariables EnvVar, bint in_Env)#, TimeStepping TS) \ No newline at end of file diff --git a/EDMF_Environment.pyx b/EDMF_Environment.pyx index 5b219779..ebbc5c42 100644 --- a/EDMF_Environment.pyx +++ b/EDMF_Environment.pyx @@ -16,12 +16,13 @@ from libc.math cimport fmax, fmin, sqrt, exp, erf from thermodynamic_functions cimport * from microphysics_functions cimport * + cdef class EnvironmentVariable: def __init__(self, nz, loc, kind, name, units): self.values = np.zeros((nz,),dtype=np.double, order='c') self.flux = np.zeros((nz,),dtype=np.double, order='c') - if loc != 'half' and loc != 'full': - print('Invalid location setting for variable! Must be half or full') + if loc != 'half': + print('Invalid location setting for variable! Must be half ') self.loc = loc if kind != 'scalar' and kind != 'velocity': print ('Invalid kind setting for variable! Must be scalar or velocity') @@ -29,13 +30,32 @@ cdef class EnvironmentVariable: self.name = name self.units = units +cdef class EnvironmentVariable_2m: + def __init__(self, nz, loc, kind, name, units): + self.values = np.zeros((nz,),dtype=np.double, order='c') + self.dissipation = np.zeros((nz,),dtype=np.double, order='c') + self.entr_gain = np.zeros((nz,),dtype=np.double, order='c') + self.detr_loss = np.zeros((nz,),dtype=np.double, order='c') + self.buoy = np.zeros((nz,),dtype=np.double, order='c') + self.press = np.zeros((nz,),dtype=np.double, order='c') + self.shear = np.zeros((nz,),dtype=np.double, order='c') + self.interdomain = np.zeros((nz,),dtype=np.double, order='c') + self.rain_src = np.zeros((nz,),dtype=np.double, order='c') + if loc != 'half': + print('Invalid location setting for variable! Must be half') + self.loc = loc + if kind != 'scalar' and kind != 'velocity': + print ('Invalid kind setting for variable! Must be scalar or velocity') + self.kind = kind + self.name = name + self.units = units cdef class EnvironmentVariables: - def __init__(self, namelist, Grid Gr ): + def __init__(self, namelist, Grid Gr): cdef Py_ssize_t nz = Gr.nzg self.Gr = Gr - self.W = EnvironmentVariable(nz, 'full', 'velocity', 'w','m/s' ) + self.W = EnvironmentVariable(nz, 'half', 'velocity', 'w','m/s' ) self.QT = EnvironmentVariable( nz, 'half', 'scalar', 'qt','kg/kg' ) self.QL = EnvironmentVariable( nz, 'half', 'scalar', 'ql','kg/kg' ) self.QR = EnvironmentVariable( nz, 'half', 'scalar', 'qr','kg/kg' ) @@ -48,7 +68,6 @@ cdef class EnvironmentVariables: self.B = EnvironmentVariable( nz, 'half', 'scalar', 'buoyancy','m^2/s^3' ) self.CF = EnvironmentVariable(nz, 'half', 'scalar','cloud_fraction', '-') - # TKE TODO repeated from Variables.pyx logic if namelist['turbulence']['scheme'] == 'EDMF_PrognosticTKE': self.calc_tke = True else: @@ -69,18 +88,17 @@ cdef class EnvironmentVariables: except: self.EnvThermo_scheme = 'sa_mean' print('Defaulting to saturation adjustment with respect to environmental means') - if self.calc_tke: - self.TKE = EnvironmentVariable( nz, 'half', 'scalar', 'tke','m^2/s^2' ) + self.TKE = EnvironmentVariable_2m( nz, 'half', 'scalar', 'tke','m^2/s^2' ) if self.calc_scalar_var: - self.QTvar = EnvironmentVariable( nz, 'half', 'scalar', 'qt_var','kg^2/kg^2' ) + self.QTvar = EnvironmentVariable_2m( nz, 'half', 'scalar', 'qt_var','kg^2/kg^2' ) if namelist['thermodynamics']['thermal_variable'] == 'entropy': - self.Hvar = EnvironmentVariable(nz, 'half', 'scalar', 's_var', '(J/kg/K)^2') - self.HQTcov = EnvironmentVariable(nz, 'half', 'scalar', 's_qt_covar', '(J/kg/K)(kg/kg)' ) + self.Hvar = EnvironmentVariable_2m(nz, 'half', 'scalar', 's_var', '(J/kg/K)^2') + self.HQTcov = EnvironmentVariable_2m(nz, 'half', 'scalar', 's_qt_covar', '(J/kg/K)(kg/kg)' ) elif namelist['thermodynamics']['thermal_variable'] == 'thetal': - self.Hvar = EnvironmentVariable(nz, 'half', 'scalar', 'thetal_var', 'K^2') - self.HQTcov = EnvironmentVariable(nz, 'half', 'scalar', 'thetal_qt_covar', 'K(kg/kg)' ) + self.Hvar = EnvironmentVariable_2m(nz, 'half', 'scalar', 'thetal_var', 'K^2') + self.HQTcov = EnvironmentVariable_2m(nz, 'half', 'scalar', 'thetal_qt_covar', 'K(kg/kg)' ) if self.EnvThermo_scheme == 'sommeria_deardorff': self.THVvar = EnvironmentVariable(nz, 'half', 'scalar', 'thetav_var', 'K^2' ) @@ -186,7 +204,7 @@ cdef class EnvironmentThermodynamics: EnvVar.QT.values[k] = qt EnvVar.QL.values[k] = ql EnvVar.QR.values[k] += qr - EnvVar.B.values[k] = buoyancy_c(self.Ref.alpha0_half[k], alpha) + EnvVar.B.values[k] = buoyancy_c(self.Ref.alpha0_c[k], alpha) return cdef void update_cloud_dry(self, long k, EnvironmentVariables EnvVar, double T, double th, double qt, double ql, double qv) nogil : @@ -218,9 +236,8 @@ cdef class EnvironmentThermodynamics: with nogil: for k in xrange(gw,self.Gr.nzg-gw): # condensation + autoconversion - sa = eos(self.t_to_prog_fp, self.prog_to_t_fp, self.Ref.p0_half[k], EnvVar.QT.values[k], EnvVar.H.values[k]) - mph = microphysics(sa.T, sa.ql, self.Ref.p0_half[k], EnvVar.QT.values[k], self.max_supersaturation, in_Env) - + sa = eos(self.t_to_prog_fp, self.prog_to_t_fp, self.Ref.p0_c[k], EnvVar.QT.values[k], EnvVar.H.values[k]) + mph = microphysics(sa.T, sa.ql, self.Ref.p0_c[k], EnvVar.QT.values[k], self.max_supersaturation, in_Env) self.update_EnvVar( k, EnvVar, mph.T, mph.thl, mph.qt, mph.ql, mph.qr, mph.alpha) self.update_cloud_dry(k, EnvVar, mph.T, mph.th, mph.qt, mph.ql, mph.qv) return @@ -314,8 +331,8 @@ cdef class EnvironmentThermodynamics: h_hat = sqrt2 * sigma_h_star * abscissas[m_h] + mu_h_star # condensation + autoconversion - sa = eos(self.t_to_prog_fp, self.prog_to_t_fp, self.Ref.p0_half[k], qt_hat, h_hat) - mph = microphysics(sa.T, sa.ql, self.Ref.p0_half[k], qt_hat, self.max_supersaturation, in_Env) + sa = eos(self.t_to_prog_fp, self.prog_to_t_fp, self.Ref.p0_c[k], qt_hat, h_hat) + mph = microphysics(sa.T, sa.ql, self.Ref.p0_c[k], qt_hat, self.max_supersaturation, in_Env) # environmental variables inner_env[i_ql] += mph.ql * weights[m_h] * sqpi_inv @@ -353,11 +370,11 @@ cdef class EnvironmentThermodynamics: # update cloudy/dry variables for buoyancy in TKE EnvVar.CF.values[k] = outer_env[i_cf] self.qt_dry[k] = outer_env[i_qt_dry] - self.th_dry[k] = theta_c(self.Ref.p0_half[k], outer_env[i_T_dry]) + self.th_dry[k] = theta_c(self.Ref.p0_c[k], outer_env[i_T_dry]) self.t_cloudy[k] = outer_env[i_T_cld] self.qv_cloudy[k] = outer_env[i_qt_cld] - outer_env[i_ql] self.qt_cloudy[k] = outer_env[i_qt_cld] - self.th_cloudy[k] = theta_c(self.Ref.p0_half[k], outer_env[i_T_cld]) + self.th_cloudy[k] = theta_c(self.Ref.p0_c[k], outer_env[i_T_cld]) # update var/covar rain sources if in_Env: self.Hvar_rain_dt[k] = outer_src[i_SH_H] - outer_src[i_SH] * EnvVar.H.values[k] @@ -367,8 +384,8 @@ cdef class EnvironmentThermodynamics: else: # the same as in SA_mean - sa = eos(self.t_to_prog_fp, self.prog_to_t_fp, self.Ref.p0_half[k], EnvVar.QT.values[k], EnvVar.H.values[k]) - mph = microphysics(sa.T, sa.ql, self.Ref.p0_half[k], EnvVar.QT.values[k], self.max_supersaturation, in_Env) + sa = eos(self.t_to_prog_fp, self.prog_to_t_fp, self.Ref.p0_c[k], EnvVar.QT.values[k], EnvVar.H.values[k]) + mph = microphysics(sa.T, sa.ql, self.Ref.p0_c[k], EnvVar.QT.values[k], self.max_supersaturation, in_Env) self.update_EnvVar( k, EnvVar, mph.T, mph.thl, mph.qt, mph.ql, mph.qr, mph.alpha) self.update_cloud_dry(k, EnvVar, mph.T, mph.th, mph.qt, mph.ql, mph.qv) @@ -394,13 +411,13 @@ cdef class EnvironmentThermodynamics: Lv = latent_heat(EnvVar.T.values[k]) cp = cpd # paper notation used below - Tl = EnvVar.H.values[k]*exner_c(self.Ref.p0_half[k]) - q_sl = qv_star_t(self.Ref.p0[k], Tl) # using the qv_star_c function instead of the approximation in eq. (4) in SD + Tl = EnvVar.H.values[k]*exner_c(self.Ref.p0_c[k]) + q_sl = qv_star_t(self.Ref.p0_c[k], Tl) # using the qv_star_c function instead of the approximation in eq. (4) in SD beta1 = 0.622*Lv**2/(Rd*cp*Tl**2) # eq. (8) in SD #q_s = q_sl*(1+beta1*EnvVar.QT.values[k])/(1+beta1*q_sl) # eq. (7) in SD lambda1 = 1/(1+beta1*q_sl) # text under eq. (20) in SD # check the pressure units - mb vs pa - alpha1 = (self.Ref.p0[k]/100000.0)**0.286*0.622*Lv*q_sl/Rd/Tl**2 # eq. (14) and eq. (6) in SD + alpha1 = (self.Ref.p0_c[k]/100000.0)**0.286*0.622*Lv*q_sl/Rd/Tl**2 # eq. (14) and eq. (6) in SD # see if there is another way to calculate dq/dT from scmapy sigma1 = EnvVar.QTvar.values[k]-2*alpha1*EnvVar.HQTcov.values[k]+alpha1**2*EnvVar.Hvar.values[k] # eq. (18) in SD , with r from (11) Q1 = (EnvVar.QT.values[k]-q_sl)/sigma1 # eq. (17) in SD @@ -419,17 +436,17 @@ cdef class EnvironmentThermodynamics: EnvVar.T.values[k] = Tl + Lv/cp*EnvVar.QL.values[k] # should this be the differnece in ql - would it work for evaporation as well ? EnvVar.CF.values[k] = R qv = EnvVar.QT.values[k] - EnvVar.QL.values[k] - alpha = alpha_c(self.Ref.p0_half[k], EnvVar.T.values[k], EnvVar.QT.values[k], qv) - EnvVar.B.values[k] = buoyancy_c(self.Ref.alpha0_half[k], alpha) - EnvVar.THL.values[k] = t_to_thetali_c(self.Ref.p0_half[k], EnvVar.T.values[k], EnvVar.QT.values[k], + alpha = alpha_c(self.Ref.p0_c[k], EnvVar.T.values[k], EnvVar.QT.values[k], qv) + EnvVar.B.values[k] = buoyancy_c(self.Ref.alpha0_c[k], alpha) + EnvVar.THL.values[k] = t_to_thetali_c(self.Ref.p0_c[k], EnvVar.T.values[k], EnvVar.QT.values[k], EnvVar.QL.values[k], 0.0) self.qt_dry[k] = EnvVar.QT.values[k] - self.th_dry[k] = EnvVar.T.values[k]/exner_c(self.Ref.p0_half[k]) + self.th_dry[k] = EnvVar.T.values[k]/exner_c(self.Ref.p0_c[k]) self.t_cloudy[k] = EnvVar.T.values[k] self.qv_cloudy[k] = EnvVar.QT.values[k] - EnvVar.QL.values[k] self.qt_cloudy[k] = EnvVar.QT.values[k] - self.th_cloudy[k] = EnvVar.T.values[k]/exner_c(self.Ref.p0_half[k]) + self.th_cloudy[k] = EnvVar.T.values[k]/exner_c(self.Ref.p0_c[k]) #using the approximation in eq. (25) in SD, noting that in the paper there is a typo in the first # condition and 1.6 there should be -1.6 @@ -456,4 +473,4 @@ cdef class EnvironmentThermodynamics: else: sys.exit('EDMF_Environment: Unrecognized EnvThermo_scheme. Possible options: sa_mean, sa_quadrature, sommeria_deardorff') - return + return \ No newline at end of file diff --git a/EDMF_Updrafts.pyx b/EDMF_Updrafts.pyx index 5c2c5950..44d77f52 100644 --- a/EDMF_Updrafts.pyx +++ b/EDMF_Updrafts.pyx @@ -26,8 +26,8 @@ cdef class UpdraftVariable: self.tendencies = np.zeros((nu,nz),dtype=np.double, order='c') self.flux = np.zeros((nu,nz),dtype=np.double, order='c') self.bulkvalues = np.zeros((nz,), dtype=np.double, order = 'c') - if loc != 'half' and loc != 'full': - print('Invalid location setting for variable! Must be half or full') + if loc != 'half': + print('Invalid location setting for variable! Must be half') self.loc = loc if kind != 'scalar' and kind != 'velocity': print ('Invalid kind setting for variable! Must be scalar or velocity') @@ -44,18 +44,17 @@ cdef class UpdraftVariable: n_updrafts = np.shape(self.values)[0] if self.name == 'w': - for i in xrange(n_updrafts): - self.values[i,start_high] = 0.0 - self.values[i,start_low] = 0.0 - for k in xrange(1,Gr.gw): - self.values[i,start_high+ k] = -self.values[i,start_high - k ] - self.values[i,start_low- k] = -self.values[i,start_low + k ] + for k in xrange(Gr.gw): + for i in xrange(n_updrafts): + self.values[i,start_high + k +1] = -self.values[i,start_high - k] + self.values[i,start_low - k] = -self.values[i,start_low + 1 + k] else: for k in xrange(Gr.gw): for i in xrange(n_updrafts): self.values[i,start_high + k +1] = self.values[i,start_high - k] self.values[i,start_low - k] = self.values[i,start_low + 1 + k] + return @@ -67,8 +66,8 @@ cdef class UpdraftVariables: Py_ssize_t nzg = Gr.nzg Py_ssize_t i, k - self.W = UpdraftVariable(nu, nzg, 'full', 'velocity', 'w','m/s' ) - self.Area = UpdraftVariable(nu, nzg, 'full', 'scalar', 'area_fraction','[-]' ) + self.W = UpdraftVariable(nu, nzg, 'half', 'velocity', 'w','m/s' ) + self.Area = UpdraftVariable(nu, nzg, 'half', 'scalar', 'area_fraction','[-]' ) self.QT = UpdraftVariable(nu, nzg, 'half', 'scalar', 'qt','kg/kg' ) self.QL = UpdraftVariable(nu, nzg, 'half', 'scalar', 'ql','kg/kg' ) self.QR = UpdraftVariable(nu, nzg, 'half', 'scalar', 'qr','kg/kg' ) @@ -130,6 +129,8 @@ cdef class UpdraftVariables: self.QT.set_bcs(self.Gr) self.QR.set_bcs(self.Gr) self.H.set_bcs(self.Gr) + self.W.set_bcs(self.Gr) + self.Area.set_bcs(self.Gr) return @@ -235,6 +236,13 @@ cdef class UpdraftVariables: self.THL.values[i,k] = self.THL.new[i,k] self.T.values[i,k] = self.T.new[i,k] self.B.values[i,k] = self.B.new[i,k] + + self.H.set_bcs(self.Gr) + self.QT.set_bcs(self.Gr) + self.QR.set_bcs(self.Gr) + self.W.set_bcs(self.Gr) + self.Area.set_bcs(self.Gr) + return @@ -267,17 +275,18 @@ cdef class UpdraftVariables: cdef Py_ssize_t i, k for i in xrange(self.n_updrafts): - # Todo check the setting of ghost point z_half - self.cloud_base[i] = self.Gr.z_half[self.Gr.nzg-self.Gr.gw-1] + # Todo check the setting of ghost point z_c + self.cloud_base[i] = self.Gr.z_c[self.Gr.nzg-self.Gr.gw-1] self.cloud_top[i] = 0.0 self.cloud_cover[i] = 0.0 for k in xrange(self.Gr.gw,self.Gr.nzg-self.Gr.gw): if self.QL.values[i,k] > 1e-8 and self.Area.values[i,k] > 1e-3: - self.cloud_base[i] = fmin(self.cloud_base[i], self.Gr.z_half[k]) - self.cloud_top[i] = fmax(self.cloud_top[i], self.Gr.z_half[k]) + self.cloud_base[i] = fmin(self.cloud_base[i], self.Gr.z_c[k]) + self.cloud_top[i] = fmax(self.cloud_top[i], self.Gr.z_c[k]) self.cloud_cover[i] = fmax(self.cloud_cover[i], self.Area.values[i,k]) + return cdef class UpdraftThermodynamics: @@ -302,7 +311,7 @@ cdef class UpdraftThermodynamics: with nogil: for i in xrange(self.n_updraft): for k in xrange(self.Gr.nzg): - sa = eos(self.t_to_prog_fp,self.prog_to_t_fp, self.Ref.p0_half[k], + sa = eos(self.t_to_prog_fp,self.prog_to_t_fp, self.Ref.p0_c[k], UpdVar.QT.values[i,k], UpdVar.H.values[i,k]) UpdVar.QL.values[i,k] = sa.ql UpdVar.T.values[i,k] = sa.T @@ -322,8 +331,8 @@ cdef class UpdraftThermodynamics: for i in xrange(self.n_updraft): for k in xrange(self.Gr.nzg): qv = UpdVar.QT.values[i,k] - UpdVar.QL.values[i,k] - alpha = alpha_c(self.Ref.p0_half[k], UpdVar.T.values[i,k], UpdVar.QT.values[i,k], qv) - UpdVar.B.values[i,k] = buoyancy_c(self.Ref.alpha0_half[k], alpha) #- GMV.B.values[k] + alpha = alpha_c(self.Ref.p0_c[k], UpdVar.T.values[i,k], UpdVar.QT.values[i,k], qv) + UpdVar.B.values[i,k] = buoyancy_c(self.Ref.alpha0_c[k], alpha) #- GMV.B.values[k] else: with nogil: for i in xrange(self.n_updraft): @@ -333,17 +342,16 @@ cdef class UpdraftThermodynamics: qv = UpdVar.QT.values[i,k] - UpdVar.QL.values[i,k] h = UpdVar.H.values[i,k] t = UpdVar.T.values[i,k] - alpha = alpha_c(self.Ref.p0_half[k], t, qt, qv) - UpdVar.B.values[i,k] = buoyancy_c(self.Ref.alpha0_half[k], alpha) - + alpha = alpha_c(self.Ref.p0_c[k], t, qt, qv) + UpdVar.B.values[i,k] = buoyancy_c(self.Ref.alpha0_c[k], alpha) else: - sa = eos(self.t_to_prog_fp, self.prog_to_t_fp, self.Ref.p0_half[k], + sa = eos(self.t_to_prog_fp, self.prog_to_t_fp, self.Ref.p0_c[k], qt, h) qt -= sa.ql qv = qt t = sa.T - alpha = alpha_c(self.Ref.p0_half[k], t, qt, qv) - UpdVar.B.values[i,k] = buoyancy_c(self.Ref.alpha0_half[k], alpha) + alpha = alpha_c(self.Ref.p0_c[k], t, qt, qv) + UpdVar.B.values[i,k] = buoyancy_c(self.Ref.alpha0_c[k], alpha) with nogil: for k in xrange(self.Gr.gw, self.Gr.nzg-self.Gr.gw): GMV.B.values[k] = (1.0 - UpdVar.Area.bulkvalues[k]) * EnvVar.B.values[k] @@ -381,10 +389,10 @@ cdef class UpdraftMicrophysics: for i in xrange(self.n_updraft): for k in xrange(self.Gr.nzg): tmp_qr = acnv_instant(UpdVar.QL.values[i,k], UpdVar.QT.values[i,k], self.max_supersaturation,\ - UpdVar.T.values[i,k], self.Ref.p0_half[k]) + UpdVar.T.values[i,k], self.Ref.p0_c[k]) self.prec_source_qt[i,k] = -tmp_qr - self.prec_source_h[i,k] = rain_source_to_thetal(self.Ref.p0_half[k], UpdVar.T.values[i,k],\ - UpdVar.QT.values[i,k], UpdVar.QL.values[i,k], 0.0, tmp_qr) + self.prec_source_h[i,k] = rain_source_to_thetal(self.Ref.p0_c[k], UpdVar.T.values[i,k],\ + UpdVar.QT.values[i,k], UpdVar.QL.values[i,k], 0.0, tmp_qr) #TODO assumes no ice self.prec_source_h_tot = np.sum(np.multiply(self.prec_source_h, UpdVar.Area.values), axis=0) self.prec_source_qt_tot = np.sum(np.multiply(self.prec_source_qt, UpdVar.Area.values), axis=0) diff --git a/Forcing.pyx b/Forcing.pyx index 156c1064..9c34cf65 100644 --- a/Forcing.pyx +++ b/Forcing.pyx @@ -75,7 +75,7 @@ cdef class ForcingStandard(ForcingBase): for k in xrange(self.Gr.gw, self.Gr.nzg-self.Gr.gw): # Apply large-scale horizontal advection tendencies qv = GMV.QT.values[k] - GMV.QL.values[k] - GMV.H.tendencies[k] += self.convert_forcing_prog_fp(self.Ref.p0_half[k],GMV.QT.values[k], + GMV.H.tendencies[k] += self.convert_forcing_prog_fp(self.Ref.p0_c[k],GMV.QT.values[k], qv, GMV.T.values[k], self.dqtdt[k], self.dTdt[k]) GMV.QT.tendencies[k] += self.dqtdt[k] if self.apply_subsidence: @@ -109,7 +109,7 @@ cdef class ForcingStandard(ForcingBase): # for k in xrange(self.Gr.gw, self.Gr.nzg-self.Gr.gw): # # Apply large-scale horizontal advection tendencies # qv = GMV.QT.values[k] - GMV.QL.values[k] -# GMV.H.tendencies[k] += self.convert_forcing_prog_fp(self.Ref.p0_half[k],GMV.QT.values[k], qv, +# GMV.H.tendencies[k] += self.convert_forcing_prog_fp(self.Ref.p0_c[k],GMV.QT.values[k], qv, # GMV.T.values[k], self.dqtdt[k], self.dTdt[k]) # GMV.QT.tendencies[k] += self.dqtdt[k] # @@ -159,35 +159,35 @@ cdef class ForcingDYCOMS_RF01(ForcingBase): if (GMV.QT.values[k] < 8.0 / 1000): idx_zi = k # will be used at cell edges - zi = self.Gr.z[idx_zi] - rhoi = self.Ref.rho0[idx_zi] + zi = self.Gr.z_f[idx_zi] + rhoi = self.Ref.rho0_c[idx_zi] break # cloud-top cooling q_0 = 0.0 self.f_rad[self.Gr.nzg] = self.F0 * np.exp(-q_0) for k in xrange(self.Gr.nzg - 1, -1, -1): - q_0 += self.kappa * self.Ref.rho0_half[k] * GMV.QL.values[k] * self.Gr.dz + q_0 += self.kappa * self.Ref.rho0_c[k] * GMV.QL.values[k] * self.Gr.dz self.f_rad[k] = self.F0 * np.exp(-q_0) # cloud-base warming q_1 = 0.0 self.f_rad[0] += self.F1 * np.exp(-q_1) for k in xrange(1, self.Gr.nzg + 1): - q_1 += self.kappa * self.Ref.rho0_half[k - 1] * GMV.QL.values[k - 1] * self.Gr.dz + q_1 += self.kappa * self.Ref.rho0_c[k - 1] * GMV.QL.values[k - 1] * self.Gr.dz self.f_rad[k] += self.F1 * np.exp(-q_1) # cooling in free troposphere for k in xrange(0, self.Gr.nzg): - if self.Gr.z[k] > zi: - cbrt_z = cbrt(self.Gr.z[k] - zi) + if self.Gr.z_f[k] > zi: + cbrt_z = cbrt(self.Gr.z_f[k] - zi) self.f_rad[k] += rhoi * dycoms_cp * self.divergence * self.alpha_z * (np.power(cbrt_z, 4) / 4.0 + zi * cbrt_z) # condition at the top - cbrt_z = cbrt(self.Gr.z[k] + self.Gr.dz - zi) + cbrt_z = cbrt(self.Gr.z_f[k] + self.Gr.dz - zi) self.f_rad[self.Gr.nzg] += rhoi * dycoms_cp * self.divergence * self.alpha_z * (np.power(cbrt_z, 4) / 4.0 + zi * cbrt_z) for k in xrange(self.Gr.gw, self.Gr.nzg - self.Gr.gw): - self.dTdt[k] = - (self.f_rad[k + 1] - self.f_rad[k]) / self.Gr.dz / self.Ref.rho0_half[k] / dycoms_cp + self.dTdt[k] = - (self.f_rad[k + 1] - self.f_rad[k]) / self.Gr.dz / self.Ref.rho0_c[k] / dycoms_cp return @@ -205,7 +205,7 @@ cdef class ForcingDYCOMS_RF01(ForcingBase): for k in xrange(self.Gr.gw, self.Gr.nzg-self.Gr.gw): # Apply large-scale horizontal advection tendencies qv = GMV.QT.values[k] - GMV.QL.values[k] - GMV.H.tendencies[k] += self.convert_forcing_prog_fp(self.Ref.p0_half[k],GMV.QT.values[k], qv, GMV.T.values[k], self.dqtdt[k], self.dTdt[k]) + GMV.H.tendencies[k] += self.convert_forcing_prog_fp(self.Ref.p0_c[k],GMV.QT.values[k], qv, GMV.T.values[k], self.dqtdt[k], self.dTdt[k]) GMV.QT.tendencies[k] += self.dqtdt[k] # Apply large-scale subsidence tendencies GMV.H.tendencies[k] -= (GMV.H.values[k+1]-GMV.H.values[k]) * self.Gr.dzi * self.subsidence[k] diff --git a/Grid.pxd b/Grid.pxd index 5232ae16..a442b807 100644 --- a/Grid.pxd +++ b/Grid.pxd @@ -12,5 +12,5 @@ cdef class Grid: Py_ssize_t gw Py_ssize_t nz Py_ssize_t nzg - double [:] z - double [:] z_half + double [:] z_f + double [:] z_c diff --git a/Grid.pyx b/Grid.pyx index fae7575b..208f78e4 100644 --- a/Grid.pyx +++ b/Grid.pyx @@ -15,7 +15,6 @@ cdef class Grid: ''' def __init__(self,namelist): ''' - :param namelist: Namelist dictionary :param Parallel: ParallelMPI class :return: @@ -33,19 +32,16 @@ cdef class Grid: self.nz = namelist['grid']['nz'] self.nzg = self.nz + 2 * self.gw - self.z_half = np.empty((self.nz+2*self.gw),dtype=np.double,order='c') - self.z = np.empty((self.nz+2*self.gw),dtype=np.double,order='c') - + self.z_f = np.empty((self.nz+2*self.gw),dtype=np.double,order='c') + self.z_c = np.empty((self.nz+2*self.gw),dtype=np.double,order='c') cdef int i, count = 0 for i in xrange(-self.gw,self.nz+self.gw,1): - self.z[count] = (i + 1) * self.dz - self.z_half[count] = (i+0.5)*self.dz + self.z_f[count] = (i + 1) * self.dz + self.z_c[count] = (i+0.5)*self.dz count += 1 return - - diff --git a/NetCDFIO.pyx b/NetCDFIO.pyx index 298bcdfb..34df8740 100644 --- a/NetCDFIO.pyx +++ b/NetCDFIO.pyx @@ -88,22 +88,22 @@ cdef class NetCDFIO_Stats: profile_grp = root_grp.createGroup('profiles') profile_grp.createDimension('z', self.Gr.nz) profile_grp.createDimension('t', None) - z = profile_grp.createVariable('z', 'f8', ('z')) - z[:] = np.array(self.Gr.z[kmin:kmax]) - z_half = profile_grp.createVariable('z_half', 'f8', ('z')) - z_half[:] = np.array(self.Gr.z_half[kmin:kmax]) + z_f = profile_grp.createVariable('z', 'f8', ('z')) + z_f[:] = np.array(self.Gr.z_f[kmin:kmax]) + z_c = profile_grp.createVariable('z_half', 'f8', ('z')) + z_c[:] = np.array(self.Gr.z_c[kmin:kmax]) profile_grp.createVariable('t', 'f8', ('t')) - del z - del z_half + del z_f + del z_c reference_grp = root_grp.createGroup('reference') reference_grp.createDimension('z', self.Gr.nz) - z = reference_grp.createVariable('z', 'f8', ('z')) - z[:] = np.array(self.Gr.z[kmin:kmax]) - z_half = reference_grp.createVariable('z_half', 'f8', ('z')) - z_half[:] = np.array(self.Gr.z_half[kmin:kmax]) - del z - del z_half + z_f = reference_grp.createVariable('z', 'f8', ('z')) + z_f[:] = np.array(self.Gr.z_f[kmin:kmax]) + z_c = reference_grp.createVariable('z_half', 'f8', ('z')) + z_c[:] = np.array(self.Gr.z_c[kmin:kmax]) + del z_f + del z_c ts_grp = root_grp.createGroup('timeseries') ts_grp.createDimension('t', None) diff --git a/ReferenceState.pxd b/ReferenceState.pxd index d63d2d77..273f07e3 100644 --- a/ReferenceState.pxd +++ b/ReferenceState.pxd @@ -3,13 +3,12 @@ from NetCDFIO cimport NetCDFIO_Stats cdef class ReferenceState: cdef: - double [:] p0 - double [:] p0_half - double [:] alpha0 - double [:] alpha0_half - double [:] rho0 - double [:] rho0_half - + double [:] p0_f + double [:] p0_c + double [:] alpha0_f + double [:] alpha0_c + double [:] rho0_f + double [:] rho0_c double sg double Tg #Temperature at ground level diff --git a/ReferenceState.pyx b/ReferenceState.pyx index 72058ba9..bac4cfed 100644 --- a/ReferenceState.pyx +++ b/ReferenceState.pyx @@ -10,7 +10,6 @@ from Grid cimport Grid from NetCDFIO cimport NetCDFIO_Stats cimport numpy as np import numpy as np -import pylab as plt from scipy.integrate import odeint from thermodynamic_functions cimport t_to_entropy_c, eos_first_guess_entropy, eos, alpha_c @@ -20,12 +19,12 @@ include 'parameters.pxi' cdef class ReferenceState: def __init__(self, Grid Gr ): - self.p0 = np.zeros(Gr.nzg, dtype=np.double, order='c') - self.p0_half = np.zeros(Gr.nzg, dtype=np.double, order='c') - self.alpha0 = np.zeros(Gr.nzg, dtype=np.double, order='c') - self.alpha0_half = np.zeros(Gr.nzg, dtype=np.double, order='c') - self.rho0 = np.zeros(Gr.nzg, dtype=np.double, order='c') - self.rho0_half = np.zeros(Gr.nzg, dtype=np.double, order='c') + self.p0_f = np.zeros(Gr.nzg, dtype=np.double, order='c') + self.p0_c = np.zeros(Gr.nzg, dtype=np.double, order='c') + self.alpha0_f = np.zeros(Gr.nzg, dtype=np.double, order='c') + self.alpha0_c = np.zeros(Gr.nzg, dtype=np.double, order='c') + self.rho0_f = np.zeros(Gr.nzg, dtype=np.double, order='c') + self.rho0_c = np.zeros(Gr.nzg, dtype=np.double, order='c') return @@ -45,7 +44,6 @@ cdef class ReferenceState: self.sg = t_to_entropy_c(self.Pg, self.Tg, self.qtg, 0.0, 0.0) - # Form a right hand side for integrating the hydrostatic equation to # determine the reference pressure ##_____________TO COMPILE______________ @@ -61,96 +59,92 @@ cdef class ReferenceState: ##_____________TO COMPILE______________ # Construct arrays for integration points - z = np.array(Gr.z[Gr.gw - 1:-Gr.gw + 1]) - z_half = np.append([0.0], np.array(Gr.z_half[Gr.gw:-Gr.gw])) + z_f = np.array(Gr.z_f[Gr.gw - 1:-Gr.gw + 1]) + z_c = np.append([0.0], np.array(Gr.z_c[Gr.gw:-Gr.gw])) # We are integrating the log pressure so need to take the log of the # surface pressure p0 = np.log(self.Pg) - p = np.zeros(Gr.nzg, dtype=np.double, order='c') - p_half = np.zeros(Gr.nzg, dtype=np.double, order='c') + p_f = np.zeros(Gr.nzg, dtype=np.double, order='c') + p_c = np.zeros(Gr.nzg, dtype=np.double, order='c') # Perform the integration - p[Gr.gw - 1:-Gr.gw +1] = odeint(rhs, p0, z, hmax=1.0)[:, 0] - p_half[Gr.gw:-Gr.gw] = odeint(rhs, p0, z_half, hmax=1.0)[1:, 0] + p_f[Gr.gw - 1:-Gr.gw +1] = odeint(rhs, p0, z_f, hmax=1.0)[:, 0] + p_c[Gr.gw:-Gr.gw] = odeint(rhs, p0, z_c, hmax=1.0)[1:, 0] # Set boundary conditions - p[:Gr.gw - 1] = p[2 * Gr.gw - 2:Gr.gw - 1:-1] - p[-Gr.gw + 1:] = p[-Gr.gw - 1:-2 * Gr.gw:-1] + p_f[:Gr.gw - 1] = p_f[2 * Gr.gw - 2:Gr.gw - 1:-1] + p_f[-Gr.gw + 1:] = p_f[-Gr.gw - 1:-2 * Gr.gw:-1] - p_half[:Gr.gw] = p_half[2 * Gr.gw - 1:Gr.gw - 1:-1] - p_half[-Gr.gw:] = p_half[-Gr.gw - 1:-2 * Gr.gw - 1:-1] + p_c[:Gr.gw] = p_c[2 * Gr.gw - 1:Gr.gw - 1:-1] + p_c[-Gr.gw:] = p_c[-Gr.gw - 1:-2 * Gr.gw - 1:-1] - p = np.exp(p) - p_half = np.exp(p_half) + p_f = np.exp(p_f) + p_c = np.exp(p_c) - cdef double[:] p_ = p - cdef double[:] p_half_ = p_half - cdef double[:] temperature = np.zeros(Gr.nzg, dtype=np.double, order='c') - cdef double[:] temperature_half = np.zeros(Gr.nzg, dtype=np.double, order='c') - cdef double[:] alpha = np.zeros(Gr.nzg, dtype=np.double, order='c') - cdef double[:] alpha_half = np.zeros(Gr.nzg, dtype=np.double, order='c') + cdef double[:] p_f_ = p_f + cdef double[:] p_c_ = p_c + cdef double[:] temperature_f = np.zeros(Gr.nzg, dtype=np.double, order='c') + cdef double[:] temperature_c = np.zeros(Gr.nzg, dtype=np.double, order='c') + cdef double[:] alpha0_f = np.zeros(Gr.nzg, dtype=np.double, order='c') + cdef double[:] alpha0_c = np.zeros(Gr.nzg, dtype=np.double, order='c') - cdef double[:] ql = np.zeros(Gr.nzg, dtype=np.double, order='c') - cdef double[:] qi = np.zeros(Gr.nzg, dtype=np.double, order='c') - cdef double[:] qv = np.zeros(Gr.nzg, dtype=np.double, order='c') + cdef double[:] ql_f = np.zeros(Gr.nzg, dtype=np.double, order='c') + cdef double[:] qi_f = np.zeros(Gr.nzg, dtype=np.double, order='c') + cdef double[:] qv_f = np.zeros(Gr.nzg, dtype=np.double, order='c') - cdef double[:] ql_half = np.zeros(Gr.nzg, dtype=np.double, order='c') - cdef double[:] qi_half = np.zeros(Gr.nzg, dtype=np.double, order='c') - cdef double[:] qv_half = np.zeros(Gr.nzg, dtype=np.double, order='c') + cdef double[:] ql_c = np.zeros(Gr.nzg, dtype=np.double, order='c') + cdef double[:] qi_c = np.zeros(Gr.nzg, dtype=np.double, order='c') + cdef double[:] qv_c = np.zeros(Gr.nzg, dtype=np.double, order='c') # Compute reference state thermodynamic profiles #_____COMMENTED TO TEST COMPILATION_____________________ for k in xrange(Gr.nzg): - ret = eos(t_to_entropy_c, eos_first_guess_entropy, p_[k], self.qtg, self.sg) - temperature[k] = ret.T - ql[k] = ret.ql - qv[k] = self.qtg - (ql[k] + qi[k]) - alpha[k] = alpha_c(p_[k], temperature[k], self.qtg, qv[k]) - ret = eos(t_to_entropy_c, eos_first_guess_entropy, p_half_[k], self.qtg, self.sg) - temperature_half[k] = ret.T - ql_half[k] = ret.ql - qv_half[k] = self.qtg - (ql_half[k] + qi_half[k]) - alpha_half[k] = alpha_c(p_half_[k], temperature_half[k], self.qtg, qv_half[k]) + ret = eos(t_to_entropy_c, eos_first_guess_entropy, p_f_[k], self.qtg, self.sg) + temperature_f[k] = ret.T + ql_f[k] = ret.ql + qv_f[k] = self.qtg - (ql_f[k] + qi_f[k]) + alpha0_f[k] = alpha_c(p_f_[k], temperature_f[k], self.qtg, qv_f[k]) + ret = eos(t_to_entropy_c, eos_first_guess_entropy, p_c_[k], self.qtg, self.sg) + temperature_c[k] = ret.T + ql_c[k] = ret.ql + qv_c[k] = self.qtg - (ql_c[k] + qi_c[k]) + alpha0_c[k] = alpha_c(p_c_[k], temperature_c[k], self.qtg, qv_c[k]) # Now do a sanity check to make sure that the Reference State entropy profile is uniform following # saturation adjustment cdef double s for k in xrange(Gr.nzg): - s = t_to_entropy_c(p_half[k],temperature_half[k],self.qtg,ql_half[k],qi_half[k]) + s = t_to_entropy_c(p_c[k],temperature_c[k],self.qtg,ql_c[k],qi_c[k]) if np.abs(s - self.sg)/self.sg > 0.01: print('Error in reference profiles entropy not constant !') print('Likely error in saturation adjustment') - - - - - # print(np.array(Gr.extract_local_ghosted(alpha_half,2))) - self.alpha0_half = alpha_half - self.alpha0 = alpha - self.p0 = p_ - self.p0_half = p_half - self.rho0 = 1.0 / np.array(self.alpha0) - self.rho0_half = 1.0 / np.array(self.alpha0_half) - - Stats.add_reference_profile('alpha0') - Stats.write_reference_profile('alpha0', alpha[Gr.gw:-Gr.gw]) - Stats.add_reference_profile('alpha0_half') - Stats.write_reference_profile('alpha0_half', alpha_half[Gr.gw:-Gr.gw]) - - - Stats.add_reference_profile('p0') - Stats.write_reference_profile('p0', p_[Gr.gw:-Gr.gw]) - Stats.add_reference_profile('p0_half') - Stats.write_reference_profile('p0_half', p_half[Gr.gw:-Gr.gw]) - - Stats.add_reference_profile('rho0') - Stats.write_reference_profile('rho0', 1.0 / np.array(alpha[Gr.gw:-Gr.gw])) - Stats.add_reference_profile('rho0_half') - Stats.write_reference_profile('rho0_half', 1.0 / np.array(alpha_half[Gr.gw:-Gr.gw])) + # print(np.array(Gr.extract_local_ghosted(alpha_c,2))) + self.alpha0_c = alpha0_c + self.alpha0_f = alpha0_f + self.p0_f = p_f + self.p0_c = p_c + self.rho0_f = 1.0 / np.array(self.alpha0_f) + self.rho0_c = 1.0 / np.array(self.alpha0_c) + + Stats.add_reference_profile('alpha0_f') + Stats.write_reference_profile('alpha0_f', alpha0_f[Gr.gw:-Gr.gw]) + Stats.add_reference_profile('alpha0_c') + Stats.write_reference_profile('alpha0_c', alpha0_c[Gr.gw:-Gr.gw]) + + + Stats.add_reference_profile('p0_f') + Stats.write_reference_profile('p0_f', p_f[Gr.gw:-Gr.gw]) + Stats.add_reference_profile('p0_c') + Stats.write_reference_profile('p0_c', p_c[Gr.gw:-Gr.gw]) + + Stats.add_reference_profile('rho0_f') + Stats.write_reference_profile('rho0_f', 1.0 / np.array(alpha0_f[Gr.gw:-Gr.gw])) + Stats.add_reference_profile('rho0_c') + Stats.write_reference_profile('rho0_c', 1.0 / np.array(alpha0_c[Gr.gw:-Gr.gw])) # Stats.add_reference_profile('temperature0', Gr, Pa) # Stats.write_reference_profile('temperature0', temperature_half[Gr.dims.gw:-Gr.dims.gw], Pa) diff --git a/Surface.pxd b/Surface.pxd index a1804dc9..b51d1929 100644 --- a/Surface.pxd +++ b/Surface.pxd @@ -26,6 +26,7 @@ cdef class SurfaceBase: bint ustar_fixed Grid Gr ReferenceState Ref + cpdef initialize(self) cpdef update(self, GridMeanVariables GMV) cpdef free_convection_windspeed(self, GridMeanVariables GMV) diff --git a/Surface.pyx b/Surface.pyx index a2969b84..04ce1a97 100644 --- a/Surface.pyx +++ b/Surface.pyx @@ -7,11 +7,12 @@ import numpy as np include "parameters.pxi" import cython -from thermodynamic_functions cimport latent_heat, cpm_c, exner_c, qv_star_t, sd_c, sv_c, pv_star, theta_rho_c -from surface_functions cimport entropy_flux, compute_ustar, buoyancy_flux +from thermodynamic_functions cimport latent_heat, cpm_c, exner_c, qv_star_t, sd_c, sv_c, pv_star, theta_rho_c, t_to_entropy_c, t_to_thetali_c +from surface_functions cimport entropy_flux, compute_ustar, buoyancy_flux, exchange_coefficients_byun from turbulence_functions cimport get_wstar, get_inversion from Variables cimport GridMeanVariables -from libc.math cimport cbrt,fabs +from libc.math cimport cbrt,fabs, sqrt, cos +import pylab as plt @@ -35,8 +36,8 @@ cdef class SurfaceBase: with nogil: for k in xrange(self.Gr.nzg): qv = GMV.QT.values[k] - GMV.QL.values[k] - theta_rho[k] = theta_rho_c(self.Ref.p0_half[k], GMV.T.values[k], GMV.QT.values[k], qv) - zi = get_inversion(&theta_rho[0], &GMV.U.values[0], &GMV.V.values[0], &self.Gr.z_half[0], kmin, kmax, self.Ri_bulk_crit) + theta_rho[k] = theta_rho_c(self.Ref.p0_c[k], GMV.T.values[k], GMV.QT.values[k], qv) + zi = get_inversion(&theta_rho[0], &GMV.U.values[0], &GMV.V.values[0], &self.Gr.z_c[0], kmin, kmax, self.Ri_bulk_crit) wstar = get_wstar(self.bflux, zi) # yair here zi in TRMM should be adjusted self.windspeed = np.sqrt(self.windspeed*self.windspeed + (1.2 *wstar)*(1.2 * wstar) ) return @@ -60,9 +61,9 @@ cdef class SurfaceFixedFlux(SurfaceBase): if GMV.H.name == 'thetal': self.rho_hflux = rho_tflux / exner_c(self.Ref.Pg) elif GMV.H.name == 's': - self.rho_hflux = entropy_flux(rho_tflux/self.Ref.rho0[gw-1],self.rho_qtflux/self.Ref.rho0[gw-1], - self.Ref.p0_half[gw], GMV.T.values[gw], GMV.QT.values[gw]) - self.bflux = buoyancy_flux(self.shf, self.lhf, GMV.T.values[gw], GMV.QT.values[gw],self.Ref.alpha0[gw-1] ) + self.rho_hflux = entropy_flux(rho_tflux/self.Ref.rho0_f[gw-1],self.rho_qtflux/self.Ref.rho0_f[gw-1], + self.Ref.p0_c[gw], GMV.T.values[gw], GMV.QT.values[gw]) + self.bflux = buoyancy_flux(self.shf, self.lhf, GMV.T.values[gw], GMV.QT.values[gw],self.Ref.alpha0_f[gw-1] ) if not self.ustar_fixed: # Correction to windspeed for free convective cases (Beljaars, QJRMS (1994), 121, pp. 255-270) @@ -71,20 +72,26 @@ cdef class SurfaceFixedFlux(SurfaceBase): if self.bflux > 0.0: self.free_convection_windspeed(GMV) else: + print 'Lv = ',latent_heat(self.Tsurface) + print 'cp = ', cpm_c(GMV.QT.values[gw]) print('WARNING: Low windspeed + stable conditions, need to check ustar computation') print('self.bflux ==>',self.bflux ) print('self.shf ==>',self.shf) print('self.lhf ==>',self.lhf) print('GMV.U.values[gw] ==>',GMV.U.values[gw]) - print('GMV.v.values[gw] ==>',GMV.V.values[gw]) + print('GMV.V.values[gw] ==>',GMV.V.values[gw]) print('GMV.QT.values[gw] ==>',GMV.QT.values[gw]) - print('self.Ref.alpha0[gw-1] ==>',self.Ref.alpha0[gw-1]) + print('GMV.T.values[gw] ==>',GMV.T.values[gw]) + print('GMV.H.values[gw] ==>',GMV.H.values[gw]) + print('self.Ref.alpha0_f[gw-1] ==>',self.Ref.alpha0_f[gw-1]) - self.ustar = compute_ustar(self.windspeed, self.bflux, self.zrough, self.Gr.z_half[gw]) + plt.figure() + plt.show() + self.ustar = compute_ustar(self.windspeed, self.bflux, self.zrough, self.Gr.z_c[gw]) self.obukhov_length = -self.ustar *self.ustar *self.ustar /self.bflux /vkb - self.rho_uflux = - self.Ref.rho0[gw-1] * self.ustar * self.ustar / self.windspeed * GMV.U.values[gw] - self.rho_vflux = - self.Ref.rho0[gw-1] * self.ustar * self.ustar / self.windspeed * GMV.V.values[gw] + self.rho_uflux = - self.Ref.rho0_f[gw-1] * self.ustar * self.ustar / self.windspeed * GMV.U.values[gw] + self.rho_vflux = - self.Ref.rho0_f[gw-1] * self.ustar * self.ustar / self.windspeed * GMV.V.values[gw] return cpdef free_convection_windspeed(self, GridMeanVariables GMV): SurfaceBase.free_convection_windspeed(self, GMV) @@ -111,24 +118,21 @@ cdef class SurfaceFixedCoeffs(SurfaceBase): double cp_ = cpm_c(GMV.QT.values[gw]) double lv = latent_heat(GMV.T.values[gw]) double pv, pd, sv, sd - - - self.rho_qtflux = -self.cq * windspeed * (GMV.QT.values[gw] - self.qsurface) * self.Ref.rho0[gw-1] + self.rho_qtflux = -self.cq * windspeed * (GMV.QT.values[gw] - self.qsurface) * self.Ref.rho0_f[gw-1] self.lhf = lv * self.rho_qtflux if GMV.H.name == 'thetal': - self.rho_hflux = -self.ch * windspeed * (GMV.H.values[gw] - self.Tsurface/exner_c(self.Ref.Pg)) * self.Ref.rho0[gw-1] + self.rho_hflux = -self.ch * windspeed * (GMV.H.values[gw] - self.Tsurface/exner_c(self.Ref.Pg)) * self.Ref.rho0_f[gw-1] self.shf = cp_ * self.rho_hflux elif GMV.H.name == 's': - self.rho_hflux = -self.ch * windspeed * (GMV.H.values[gw] - self.s_surface) * self.Ref.rho0[gw-1] + self.rho_hflux = -self.ch * windspeed * (GMV.H.values[gw] - self.s_surface) * self.Ref.rho0_f[gw-1] pv = pv_star(GMV.T.values[gw]) - pd = self.Ref.p0_half[gw] - pv + pd = self.Ref.p0_c[gw] - pv sv = sv_c(pv,GMV.T.values[gw]) sd = sd_c(pd, GMV.T.values[gw]) self.shf = (self.rho_hflux - self.lhf/lv * (sv-sd)) * GMV.T.values[gw] - - self.bflux = buoyancy_flux(self.shf, self.lhf, GMV.T.values[gw], GMV.QT.values[gw],self.Ref.alpha0[gw-1] ) + self.bflux = buoyancy_flux(self.shf, self.lhf, GMV.T.values[gw], GMV.QT.values[gw],self.Ref.alpha0_f[gw-1] ) self.ustar = np.sqrt(self.cm) * windspeed @@ -138,13 +142,14 @@ cdef class SurfaceFixedCoeffs(SurfaceBase): else: self.obukhov_length = -self.ustar *self.ustar *self.ustar /self.bflux /vkb - self.rho_uflux = - self.Ref.rho0[gw-1] * self.ustar * self.ustar / windspeed * GMV.U.values[gw] - self.rho_vflux = - self.Ref.rho0[gw-1] * self.ustar * self.ustar / windspeed * GMV.V.values[gw] + self.rho_uflux = - self.Ref.rho0_f[gw-1] * self.ustar * self.ustar / windspeed * GMV.U.values[gw] + self.rho_vflux = - self.Ref.rho0_f[gw-1] * self.ustar * self.ustar / windspeed * GMV.V.values[gw] return cpdef free_convection_windspeed(self, GridMeanVariables GMV): SurfaceBase.free_convection_windspeed(self, GMV) return + cdef class SurfaceMoninObukhov(SurfaceBase): def __init__(self, paramlist): SurfaceBase.__init__(self, paramlist) @@ -152,10 +157,52 @@ cdef class SurfaceMoninObukhov(SurfaceBase): cpdef initialize(self): return cpdef update(self, GridMeanVariables GMV): + self.qsurface = qv_star_t(self.Ref.Pg, self.Tsurface) cdef: Py_ssize_t k, gw = self.Gr.gw + double zb = self.Gr.z_c[gw] + double theta_rho_g = theta_rho_c(self.Ref.Pg, self.Tsurface, self.qsurface, self.qsurface) + double theta_rho_b = theta_rho_c(self.Ref.p0_c[gw], GMV.T.values[gw], self.qsurface, self.qsurface) + double Nb2, + double h_star + double pv, pd, sv, sd + double lv = latent_heat(GMV.T.values[gw]) + + if GMV.H.name == 'thetal': + h_star = t_to_thetali_c(self.Ref.Pg, self.Tsurface, self.qsurface, 0.0, 0.0) + elif GMV.H.name == 's': + h_star = t_to_entropy_c(self.Ref.Pg, self.Tsurface, self.qsurface, 0.0, 0.0) + self.windspeed = np.sqrt(GMV.U.values[gw]*GMV.U.values[gw] + GMV.V.values[gw] * GMV.V.values[gw]) + Nb2 = g/theta_rho_g*(theta_rho_b-theta_rho_g)/zb + Ri = Nb2 * zb * zb/(self.windspeed * self.windspeed) + + exchange_coefficients_byun(Ri, self.Gr.z_c[gw], self.zrough, &self.cm, &self.ch, &self.obukhov_length) + self.rho_uflux = -self.cm * self.windspeed * (GMV.U.values[gw] ) * self.Ref.rho0_f[gw-1] + self.rho_vflux = -self.cm * self.windspeed * (GMV.V.values[gw] ) * self.Ref.rho0_f[gw-1] + + self.rho_hflux = -self.ch * self.windspeed * (GMV.H.values[gw] - h_star) * self.Ref.rho0_f[gw-1] + self.rho_qtflux = -self.ch * self.windspeed * (GMV.QT.values[gw] - self.qsurface) * self.Ref.rho0_f[gw-1] + self.lhf = lv * self.rho_qtflux + + if GMV.H.name == 'thetal': + self.shf = cpm_c(GMV.QT.values[gw]) * self.rho_hflux + + elif GMV.H.name == 's': + pv = pv_star(GMV.T.values[gw]) + pd = self.Ref.p0_c[gw] - pv + sv = sv_c(pv,GMV.T.values[gw]) + sd = sd_c(pd, GMV.T.values[gw]) + self.shf = (self.rho_hflux - self.lhf/lv * (sv-sd)) * GMV.T.values[gw] + + self.bflux = buoyancy_flux(self.shf, self.lhf, GMV.T.values[gw], GMV.QT.values[gw],self.Ref.alpha0_f[gw-1] ) + self.ustar = sqrt(self.cm) * self.windspeed + # CK--testing this--EDMF scheme checks greater or less than zero, + if fabs(self.bflux) < 1e-10: + self.obukhov_length = 0.0 + else: + self.obukhov_length = -self.ustar *self.ustar *self.ustar /self.bflux /vkb return diff --git a/Turbulence.pyx b/Turbulence.pyx index 7ff232d2..53f1ce3d 100644 --- a/Turbulence.pyx +++ b/Turbulence.pyx @@ -39,8 +39,8 @@ cdef class ParameterizationBase: self.turbulence_tendency = np.zeros((Gr.nzg,), dtype=np.double, order='c') self.Gr = Gr # grid class self.Ref = Ref # reference state class - self.KM = VariableDiagnostic(Gr.nzg,'half', 'scalar','sym', 'diffusivity', 'm^2/s') # eddy viscosity - self.KH = VariableDiagnostic(Gr.nzg,'half', 'scalar','sym', 'viscosity', 'm^2/s') # eddy diffusivity + self.KM = VariableDiagnostic(Gr.nzg,'full', 'scalar','sym', 'diffusivity', 'm^2/s') # eddy viscosity + self.KH = VariableDiagnostic(Gr.nzg,'full', 'scalar','sym', 'viscosity', 'm^2/s') # eddy diffusivity # get values from paramlist self.prandtl_number = paramlist['turbulence']['prandtl_number'] self.Ri_bulk_crit = paramlist['turbulence']['Ri_bulk_crit'] @@ -85,14 +85,14 @@ cdef class ParameterizationBase: with nogil: for k in xrange(gw, self.Gr.nzg-gw): qv = GMV.QT.values[k] - GMV.QL.values[k] - theta_rho[k] = theta_rho_c(self.Ref.p0_half[k], GMV.T.values[k], GMV.QT.values[k], qv) + theta_rho[k] = theta_rho_c(self.Ref.p0_c[k], GMV.T.values[k], GMV.QT.values[k], qv) if option == 'theta_rho': with nogil: for k in xrange(kmin,kmax): if theta_rho[k] > theta_rho[kmin]: - self.zi = self.Gr.z_half[k] + self.zi = self.Gr.z_c[k] break elif option == 'thetal_maxgrad': @@ -101,9 +101,9 @@ cdef class ParameterizationBase: grad = (GMV.THL.values[k+1] - GMV.THL.values[k])*self.Gr.dzi if grad > maxgrad: maxgrad = grad - self.zi = self.Gr.z[k] + self.zi = self.Gr.z_f[k] # make sure this is indeed z_f elif option == 'critical_Ri': - self.zi = get_inversion(&theta_rho[0], &GMV.U.values[0], &GMV.V.values[0], &self.Gr.z_half[0], kmin, kmax, self.Ri_bulk_crit) + self.zi = get_inversion(&theta_rho[0], &GMV.U.values[0], &GMV.V.values[0], &self.Gr.z_c[0], kmin, kmax, self.Ri_bulk_crit) else: print('INVERSION HEIGHT OPTION NOT RECOGNIZED') @@ -129,7 +129,7 @@ cdef class ParameterizationBase: with nogil: for k in xrange(gw,nzg-gw): - zzi = self.Gr.z_half[k]/self.zi + zzi = self.Gr.z_c[k]/self.zi if zzi <= 1.0: self.KH.values[k] = vkb * ( (ustar/self.wstar)**3 + 39.0*vkb*zzi)**(1.0/3.0) * zzi * (1.0-zzi) * (1.0-zzi) * self.wstar * self.zi self.KM.values[k] = self.KH.values[k] * self.prandtl_number @@ -191,18 +191,18 @@ cdef class SimilarityED(ParameterizationBase): with nogil: for k in xrange(nzg-1): - rho_K_m[k] = 0.5 * (self.KH.values[k]+ self.KH.values[k+1]) * self.Ref.rho0[k] + rho_K_m[k] = 0.5 * (self.KH.values[k]+ self.KH.values[k+1]) * self.Ref.rho0_f[k] # Matrix is the same for all variables that use the same eddy diffusivity construct_tridiag_diffusion(nzg, gw, self.Gr.dzi, TS.dt, &rho_K_m[0], - &self.Ref.rho0_half[0], &dummy_ae[0] ,&a[0], &b[0], &c[0]) + &self.Ref.rho0_c[0], &dummy_ae[0] ,&a[0], &b[0], &c[0]) # Solve QT with nogil: for k in xrange(nz): x[k] = GMV.QT.values[k+gw] - x[0] = x[0] + TS.dt * Case.Sur.rho_qtflux * self.Gr.dzi * self.Ref.alpha0_half[gw] + x[0] = x[0] + TS.dt * Case.Sur.rho_qtflux * self.Gr.dzi * self.Ref.alpha0_c[gw] tridiag_solve(self.Gr.nz, &x[0],&a[0], &b[0], &c[0]) with nogil: @@ -214,7 +214,7 @@ cdef class SimilarityED(ParameterizationBase): with nogil: for k in xrange(nz): x[k] = GMV.H.values[k+gw] - x[0] = x[0] + TS.dt * Case.Sur.rho_hflux * self.Gr.dzi * self.Ref.alpha0_half[gw] + x[0] = x[0] + TS.dt * Case.Sur.rho_hflux * self.Gr.dzi * self.Ref.alpha0_c[gw] tridiag_solve(self.Gr.nz, &x[0],&a[0], &b[0], &c[0]) with nogil: @@ -226,7 +226,7 @@ cdef class SimilarityED(ParameterizationBase): with nogil: for k in xrange(nz): x[k] = GMV.U.values[k+gw] - x[0] = x[0] + TS.dt * Case.Sur.rho_uflux * self.Gr.dzi * self.Ref.alpha0_half[gw] + x[0] = x[0] + TS.dt * Case.Sur.rho_uflux * self.Gr.dzi * self.Ref.alpha0_c[gw] tridiag_solve(self.Gr.nz, &x[0],&a[0], &b[0], &c[0]) with nogil: @@ -237,7 +237,7 @@ cdef class SimilarityED(ParameterizationBase): with nogil: for k in xrange(nz): x[k] = GMV.V.values[k+gw] - x[0] = x[0] + TS.dt * Case.Sur.rho_vflux * self.Gr.dzi * self.Ref.alpha0_half[gw] + x[0] = x[0] + TS.dt * Case.Sur.rho_vflux * self.Gr.dzi * self.Ref.alpha0_c[gw] tridiag_solve(self.Gr.nz, &x[0],&a[0], &b[0], &c[0]) with nogil: diff --git a/Turbulence_PrognosticTKE.pxd b/Turbulence_PrognosticTKE.pxd index e30c243e..ce587b4c 100644 --- a/Turbulence_PrognosticTKE.pxd +++ b/Turbulence_PrognosticTKE.pxd @@ -23,6 +23,7 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): bint use_local_micro bint similarity_diffusivity bint use_steady_updrafts + str mixing_length_fp bint calc_scalar_var bint calc_tke double surface_area @@ -62,9 +63,11 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): double max_area_factor double tke_ed_coeff double tke_diss_coeff + double [:] MLS + double [:] ml_ratio + str mixing_scheme + - #double [:] Hvar - #double [:] QTvar double [:] Hvar_shear double [:] QTvar_shear double [:] Hvar_entr_gain @@ -92,52 +95,49 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): cpdef compute_prognostic_updrafts(self, GridMeanVariables GMV, CasesBase Case, TimeStepping TS) cpdef compute_diagnostic_updrafts(self, GridMeanVariables GMV, CasesBase Case) cpdef update_inversion(self, GridMeanVariables GMV, option) - cpdef compute_mixing_length(self, double obukhov_length) + cpdef compute_mixing_length(self, double obukhov_length, GridMeanVariables GMV) cpdef compute_eddy_diffusivities_tke(self, GridMeanVariables GMV, CasesBase Case) - cpdef reset_surface_tke(self, GridMeanVariables GMV, CasesBase Case) cpdef reset_surface_covariance(self, GridMeanVariables GMV, CasesBase Case) cpdef set_updraft_surface_bc(self, GridMeanVariables GMV, CasesBase Case) cpdef decompose_environment(self, GridMeanVariables GMV, whichvals) cpdef compute_entrainment_detrainment(self, GridMeanVariables GMV, CasesBase Case) - cpdef solve_updraft_velocity_area(self, GridMeanVariables GMV, TimeStepping TS) - cpdef solve_updraft_scalars(self, GridMeanVariables GMV, CasesBase Case, TimeStepping TS) + cpdef solve_updraft(self, GridMeanVariables GMV, CasesBase Case, TimeStepping TS) + cpdef upwind_integration(self, EDMF_Updrafts.UpdraftVariable area, + EDMF_Updrafts.UpdraftVariable var, int k, int i, double env_var, double dzi) cpdef update_GMV_MF(self, GridMeanVariables GMV, TimeStepping TS) cpdef update_GMV_ED(self, GridMeanVariables GMV, CasesBase Case, TimeStepping TS) - cpdef compute_tke(self, GridMeanVariables GMV, CasesBase Case, TimeStepping TS) cpdef compute_covariance(self, GridMeanVariables GMV, CasesBase Case, TimeStepping TS) - cpdef initialize_tke(self, GridMeanVariables GMV, CasesBase Case) cpdef initialize_covariance(self, GridMeanVariables GMV, CasesBase Case) cpdef cleanup_covariance(self, GridMeanVariables GMV) cpdef compute_tke_buoy(self, GridMeanVariables GMV) - cpdef compute_tke_dissipation(self) - cpdef compute_covariance_dissipation(self) - cpdef compute_tke_entr(self) - cpdef compute_covariance_entr(self) - cpdef compute_tke_detr(self) - cpdef compute_covariance_detr(self) - cpdef compute_tke_shear(self, GridMeanVariables GMV) - cpdef compute_covariance_shear(self, GridMeanVariables GMV) cpdef compute_tke_pressure(self) + cpdef double compute_zbl_qt_grad(self, GridMeanVariables GMV) + cdef void compute_covariance_detr(self, EDMF_Environment.EnvironmentVariable_2m Covar) + cdef void compute_covariance_entr(self, EDMF_Environment.EnvironmentVariable_2m Covar, EDMF_Updrafts.UpdraftVariable UpdVar1, + EDMF_Updrafts.UpdraftVariable UpdVar2, EDMF_Environment.EnvironmentVariable EnvVar1, EDMF_Environment.EnvironmentVariable EnvVar2) + cdef void compute_covariance_dissipation(self, EDMF_Environment.EnvironmentVariable_2m Covar) + cdef void compute_covariance_shear(self,GridMeanVariables GMV, EDMF_Environment.EnvironmentVariable_2m Covar, double *UpdVar1, double *UpdVar2, double *EnvVar1, double *EnvVar2) + cdef void compute_covariance_interdomain_src(self, EDMF_Updrafts.UpdraftVariable au, EDMF_Updrafts.UpdraftVariable phi_u, EDMF_Updrafts.UpdraftVariable psi_u, + EDMF_Environment.EnvironmentVariable phi_e, EDMF_Environment.EnvironmentVariable psi_e, EDMF_Environment.EnvironmentVariable_2m covar_e) + cdef void update_covariance_ED(self, GridMeanVariables GMV, CasesBase Case,TimeStepping TS, VariablePrognostic GmvVar1, VariablePrognostic GmvVar2, + VariableDiagnostic GmvCovar, EDMF_Environment.EnvironmentVariable_2m Covar, EDMF_Environment.EnvironmentVariable EnvVar1, EDMF_Environment.EnvironmentVariable EnvVar2, + EDMF_Updrafts.UpdraftVariable UpdVar1, EDMF_Updrafts.UpdraftVariable UpdVar2) cpdef compute_covariance_rain(self, TimeStepping TS, GridMeanVariables GMV) - cpdef update_tke_ED(self, GridMeanVariables GMV, CasesBase Case,TimeStepping TS) - cpdef update_covariance_ED(self, GridMeanVariables GMV, CasesBase Case,TimeStepping TS) cpdef update_GMV_diagnostics(self, GridMeanVariables GMV) - cdef get_GMV_TKE(self, EDMF_Updrafts.UpdraftVariable au, EDMF_Updrafts.UpdraftVariable wu, - EDMF_Environment.EnvironmentVariable we, EDMF_Environment.EnvironmentVariable tke_e, - double *gmv_w, double *gmv_tke) - cdef get_env_tke_from_GMV(self, EDMF_Updrafts.UpdraftVariable au, EDMF_Updrafts.UpdraftVariable wu, - EDMF_Environment.EnvironmentVariable we, EDMF_Environment.EnvironmentVariable tke_e, - double *gmv_w, double *gmv_tke) - + # cdef get_env_tke_from_GMV(self, EDMF_Updrafts.UpdraftVariable au, EDMF_Updrafts.UpdraftVariable wu, + # EDMF_Environment.EnvironmentVariable we, EDMF_Environment.EnvironmentVariable tke_e, + # double *gmv_w, double *gmv_tke) cdef get_GMV_CoVar(self, EDMF_Updrafts.UpdraftVariable au, EDMF_Updrafts.UpdraftVariable phi_u, EDMF_Updrafts.UpdraftVariable psi_u, EDMF_Environment.EnvironmentVariable phi_e, EDMF_Environment.EnvironmentVariable psi_e, - EDMF_Environment.EnvironmentVariable covar_e, + EDMF_Environment.EnvironmentVariable_2m covar_e, double *gmv_phi, double *gmv_psi, double *gmv_covar) - cdef get_env_covar_from_GMV(self, EDMF_Updrafts.UpdraftVariable au, EDMF_Updrafts.UpdraftVariable phi_u, EDMF_Updrafts.UpdraftVariable psi_u, EDMF_Environment.EnvironmentVariable phi_e, EDMF_Environment.EnvironmentVariable psi_e, - EDMF_Environment.EnvironmentVariable covar_e, + EDMF_Environment.EnvironmentVariable_2m covar_e, double *gmv_phi, double *gmv_psi, double *gmv_covar) + cpdef nan_check(self, line, GridMeanVariables GMV, int k) + + cpdef nan_check(self, line, GridMeanVariables GMV, int k) diff --git a/Turbulence_PrognosticTKE.pyx b/Turbulence_PrognosticTKE.pyx index 70ae70b9..28158002 100644 --- a/Turbulence_PrognosticTKE.pyx +++ b/Turbulence_PrognosticTKE.pyx @@ -20,8 +20,12 @@ from NetCDFIO cimport NetCDFIO_Stats from thermodynamic_functions cimport * from turbulence_functions cimport * from utility_functions cimport * -from libc.math cimport fmax, sqrt, exp, pow, cbrt, fmin +from libc.math cimport fmax, sqrt, exp, pow, cbrt, fmin, fabs from cpython.mem cimport PyMem_Malloc, PyMem_Realloc, PyMem_Free +import pylab as plt +import sys +import pylab as plt +import netCDF4 as nc cdef class EDMF_PrognosticTKE(ParameterizationBase): # Initialize the class @@ -66,12 +70,14 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): self.entr_detr_fp = entr_detr_inverse_w elif str(namelist['turbulence']['EDMF_PrognosticTKE']['entrainment']) == 'b_w2': self.entr_detr_fp = entr_detr_b_w2 - elif str(namelist['turbulence']['EDMF_PrognosticTKE']['entrainment']) == 'buoyancy_sorting': - self.entr_detr_fp = entr_detr_buoyancy_sorting + elif str(namelist['turbulence']['EDMF_PrognosticTKE']['entrainment']) == 'smean': + self.entr_detr_fp = entr_detr_smean elif str(namelist['turbulence']['EDMF_PrognosticTKE']['entrainment']) == 'entr_detr_tke': self.entr_detr_fp = entr_detr_tke elif str(namelist['turbulence']['EDMF_PrognosticTKE']['entrainment']) == 'entr_detr_tke2': self.entr_detr_fp = entr_detr_tke2 + elif str(namelist['turbulence']['EDMF_PrognosticTKE']['entrainment']) == 'suselj': + self.entr_detr_fp = entr_detr_suselj else: print('Turbulence--EDMF_PrognosticTKE: Entrainment rate namelist option is not recognized') except: @@ -97,6 +103,12 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): self.extrapolate_buoyancy = True print('Turbulence--EDMF_PrognosticTKE: defaulting to extrapolation of updraft buoyancy along a pseudoadiabat') + try: + self.mixing_scheme = str(namelist['turbulence']['EDMF_PrognosticTKE']['mixing_length']) + except: + self.mixing_scheme = 'tke' + + # Get values from paramlist # set defaults at some point? self.surface_area = paramlist['turbulence']['EDMF_PrognosticTKE']['surface_area'] @@ -144,35 +156,6 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): # mixing length self.mixing_length = np.zeros((Gr.nzg,),dtype=np.double, order='c') - if self.calc_tke: - # environmental tke source terms - self.tke_buoy = np.zeros((Gr.nzg,),dtype=np.double, order='c') - self.tke_dissipation = np.zeros((Gr.nzg,),dtype=np.double, order='c') - self.tke_entr_gain = np.zeros((Gr.nzg,),dtype=np.double, order='c') - self.tke_detr_loss = np.zeros((Gr.nzg,),dtype=np.double, order='c') - self.tke_shear = np.zeros((Gr.nzg,),dtype=np.double, order='c') - self.tke_pressure = np.zeros((Gr.nzg,),dtype=np.double, order='c') - - if self.calc_scalar_var: - #self.Hvar = np.zeros((Gr.nzg,),dtype=np.double, order='c') - #self.QTvar = np.zeros((Gr.nzg,),dtype=np.double, order='c') - #self.HQTcov = np.zeros((Gr.nzg,),dtype=np.double, order='c') - self.Hvar_dissipation = np.zeros((Gr.nzg,),dtype=np.double, order='c') - self.QTvar_dissipation = np.zeros((Gr.nzg,),dtype=np.double, order='c') - self.HQTcov_dissipation = np.zeros((Gr.nzg,),dtype=np.double, order='c') - self.Hvar_entr_gain = np.zeros((Gr.nzg,),dtype=np.double, order='c') - self.QTvar_entr_gain = np.zeros((Gr.nzg,),dtype=np.double, order='c') - self.HQTcov_entr_gain = np.zeros((Gr.nzg,),dtype=np.double, order='c') - self.Hvar_detr_loss = np.zeros((Gr.nzg,),dtype=np.double, order='c') - self.QTvar_detr_loss = np.zeros((Gr.nzg,),dtype=np.double, order='c') - self.HQTcov_detr_loss = np.zeros((Gr.nzg,),dtype=np.double, order='c') - self.Hvar_shear = np.zeros((Gr.nzg,),dtype=np.double, order='c') - self.QTvar_shear = np.zeros((Gr.nzg,),dtype=np.double, order='c') - self.HQTcov_shear = np.zeros((Gr.nzg,),dtype=np.double, order='c') - self.Hvar_rain = np.zeros((Gr.nzg,),dtype=np.double, order='c') - self.QTvar_rain = np.zeros((Gr.nzg,),dtype=np.double, order='c') - self.HQTcov_rain = np.zeros((Gr.nzg,),dtype=np.double, order='c') - # Near-surface BC of updraft area fraction self.area_surface_bc= np.zeros((self.n_updrafts,),dtype=np.double, order='c') self.w_surface_bc= np.zeros((self.n_updrafts,),dtype=np.double, order='c') @@ -193,8 +176,9 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): self.massflux_qt = np.zeros((Gr.nzg,),dtype=np.double,order='c') self.diffusive_flux_h = np.zeros((Gr.nzg,),dtype=np.double,order='c') self.diffusive_flux_qt = np.zeros((Gr.nzg,),dtype=np.double,order='c') - if self.calc_tke: - self.massflux_tke = np.zeros((Gr.nzg,),dtype=np.double,order='c') + + self.MLS = np.zeros((Gr.nzg,),dtype=np.double, order='c') + self.ml_ratio = np.zeros((Gr.nzg,),dtype=np.double, order='c') return @@ -226,6 +210,8 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): Stats.add_profile('mixing_length') Stats.add_profile('updraft_qt_precip') Stats.add_profile('updraft_thetal_precip') + Stats.add_profile('ed_length_scheme') + Stats.add_profile('mixing_length_ratio') if self.calc_tke: Stats.add_profile('tke_buoy') @@ -234,7 +220,7 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): Stats.add_profile('tke_detr_loss') Stats.add_profile('tke_shear') Stats.add_profile('tke_pressure') - Stats.add_profile('massflux_tke') + Stats.add_profile('tke_interdomain') if self.calc_scalar_var: Stats.add_profile('Hvar_dissipation') @@ -242,16 +228,19 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): Stats.add_profile('HQTcov_dissipation') Stats.add_profile('Hvar_entr_gain') Stats.add_profile('QTvar_entr_gain') - Stats.add_profile('HQTcov_entr_gain') Stats.add_profile('Hvar_detr_loss') Stats.add_profile('QTvar_detr_loss') Stats.add_profile('HQTcov_detr_loss') + Stats.add_profile('HQTcov_entr_gain') Stats.add_profile('Hvar_shear') Stats.add_profile('QTvar_shear') Stats.add_profile('HQTcov_shear') Stats.add_profile('Hvar_rain') Stats.add_profile('QTvar_rain') Stats.add_profile('HQTcov_rain') + Stats.add_profile('Hvar_interdomain') + Stats.add_profile('QTvar_interdomain') + Stats.add_profile('HQTcov_interdomain') return @@ -299,44 +288,50 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): Stats.write_profile('mixing_length', self.mixing_length[kmin:kmax]) Stats.write_profile('updraft_qt_precip', self.UpdMicro.prec_source_qt_tot[kmin:kmax]) Stats.write_profile('updraft_thetal_precip', self.UpdMicro.prec_source_h_tot[kmin:kmax]) + Stats.write_profile('ed_length_scheme', self.MLS[kmin:kmax]) + Stats.write_profile('mixing_length_ratio', self.ml_ratio[kmin:kmax]) + # can these pointer function called inside the write command , or should they be called before it? if self.calc_tke: - Stats.write_profile('tke_buoy', self.tke_buoy[kmin:kmax]) - self.compute_tke_dissipation() - Stats.write_profile('tke_dissipation', self.tke_dissipation[kmin:kmax]) - Stats.write_profile('tke_entr_gain', self.tke_entr_gain[kmin:kmax]) - self.compute_tke_detr() - Stats.write_profile('tke_detr_loss', self.tke_detr_loss[kmin:kmax]) - Stats.write_profile('tke_shear', self.tke_shear[kmin:kmax]) - Stats.write_profile('tke_pressure', self.tke_pressure[kmin:kmax]) - Stats.write_profile('massflux_tke', self.massflux_tke[kmin-1:kmax-1]) + self.compute_covariance_dissipation(self.EnvVar.TKE) + Stats.write_profile('tke_dissipation', self.EnvVar.TKE.dissipation[kmin:kmax]) + Stats.write_profile('tke_entr_gain', self.EnvVar.TKE.entr_gain[kmin:kmax]) + self.compute_covariance_detr(self.EnvVar.TKE) + Stats.write_profile('tke_detr_loss', self.EnvVar.TKE.detr_loss[kmin:kmax]) + Stats.write_profile('tke_shear', self.EnvVar.TKE.shear[kmin:kmax]) + Stats.write_profile('tke_buoy', self.EnvVar.TKE.buoy[kmin:kmax]) + Stats.write_profile('tke_pressure', self.EnvVar.TKE.press[kmin:kmax]) + Stats.write_profile('tke_interdomain', self.EnvVar.TKE.interdomain[kmin:kmax]) if self.calc_scalar_var: - #Stats.write_profile('Hvar', self.Hvar[kmin:kmax]) - #Stats.write_profile('QTvar', self.QTvar[kmin:kmax]) - #Stats.write_profile('HQTcov', self.HQTcov[kmin:kmax]) - self.compute_covariance_dissipation() - Stats.write_profile('Hvar_dissipation', self.Hvar_dissipation[kmin:kmax]) - Stats.write_profile('QTvar_dissipation', self.QTvar_dissipation[kmin:kmax]) - Stats.write_profile('HQTcov_dissipation', self.HQTcov_dissipation[kmin:kmax]) - Stats.write_profile('Hvar_entr_gain', self.Hvar_entr_gain[kmin:kmax]) - Stats.write_profile('QTvar_entr_gain', self.QTvar_entr_gain[kmin:kmax]) - Stats.write_profile('HQTcov_entr_gain', self.HQTcov_entr_gain[kmin:kmax]) - self.compute_covariance_detr() - Stats.write_profile('Hvar_detr_loss', self.Hvar_detr_loss[kmin:kmax]) - Stats.write_profile('QTvar_detr_loss', self.QTvar_detr_loss[kmin:kmax]) - Stats.write_profile('HQTcov_detr_loss', self.HQTcov_detr_loss[kmin:kmax]) - Stats.write_profile('Hvar_shear', self.Hvar_shear[kmin:kmax]) - Stats.write_profile('QTvar_shear', self.QTvar_shear[kmin:kmax]) - Stats.write_profile('HQTcov_shear', self.HQTcov_shear[kmin:kmax]) - Stats.write_profile('Hvar_rain', self.Hvar_rain[kmin:kmax]) - Stats.write_profile('QTvar_rain', self.QTvar_rain[kmin:kmax]) - Stats.write_profile('HQTcov_rain', self.HQTcov_rain[kmin:kmax]) + self.compute_covariance_dissipation(self.EnvVar.Hvar) + Stats.write_profile('Hvar_dissipation', self.EnvVar.Hvar.dissipation[kmin:kmax]) + self.compute_covariance_dissipation(self.EnvVar.QTvar) + Stats.write_profile('QTvar_dissipation', self.EnvVar.QTvar.dissipation[kmin:kmax]) + self.compute_covariance_dissipation(self.EnvVar.HQTcov) + Stats.write_profile('HQTcov_dissipation', self.EnvVar.HQTcov.dissipation[kmin:kmax]) + Stats.write_profile('Hvar_entr_gain', self.EnvVar.Hvar.entr_gain[kmin:kmax]) + Stats.write_profile('QTvar_entr_gain', self.EnvVar.QTvar.entr_gain[kmin:kmax]) + Stats.write_profile('HQTcov_entr_gain', self.EnvVar.HQTcov.entr_gain[kmin:kmax]) + self.compute_covariance_detr(self.EnvVar.Hvar) + self.compute_covariance_detr(self.EnvVar.QTvar) + self.compute_covariance_detr(self.EnvVar.HQTcov) + Stats.write_profile('Hvar_detr_loss', self.EnvVar.Hvar.detr_loss[kmin:kmax]) + Stats.write_profile('QTvar_detr_loss', self.EnvVar.QTvar.detr_loss[kmin:kmax]) + Stats.write_profile('HQTcov_detr_loss', self.EnvVar.HQTcov.detr_loss[kmin:kmax]) + Stats.write_profile('Hvar_shear', self.EnvVar.Hvar.shear[kmin:kmax]) + Stats.write_profile('QTvar_shear', self.EnvVar.QTvar.shear[kmin:kmax]) + Stats.write_profile('HQTcov_shear', self.EnvVar.HQTcov.shear[kmin:kmax]) + Stats.write_profile('Hvar_rain', self.EnvVar.Hvar.rain_src[kmin:kmax]) + Stats.write_profile('QTvar_rain', self.EnvVar.QTvar.rain_src[kmin:kmax]) + Stats.write_profile('HQTcov_rain', self.EnvVar.HQTcov.rain_src[kmin:kmax]) + Stats.write_profile('Hvar_interdomain', self.EnvVar.Hvar.interdomain[kmin:kmax]) + Stats.write_profile('QTvar_interdomain', self.EnvVar.QTvar.interdomain[kmin:kmax]) + Stats.write_profile('HQTcov_interdomain', self.EnvVar.HQTcov.interdomain[kmin:kmax]) return - # Perform the update of the scheme cpdef update(self,GridMeanVariables GMV, CasesBase Case, TimeStepping TS): @@ -344,16 +339,10 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): Py_ssize_t k Py_ssize_t kmin = self.Gr.gw Py_ssize_t kmax = self.Gr.nzg - self.Gr.gw - self.update_inversion(GMV, Case.inversion_option) - self.wstar = get_wstar(Case.Sur.bflux, self.zi) - if TS.nstep == 0: - if self.calc_tke: - self.initialize_tke(GMV, Case) - if self.calc_scalar_var: - self.initialize_covariance(GMV, Case) + self.initialize_covariance(GMV, Case) with nogil: for k in xrange(self.Gr.nzg): if self.calc_tke: @@ -362,6 +351,9 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): self.EnvVar.Hvar.values[k] = GMV.Hvar.values[k] self.EnvVar.QTvar.values[k] = GMV.QTvar.values[k] self.EnvVar.HQTcov.values[k] = GMV.HQTcov.values[k] + self.decompose_environment(GMV, 'values') + self.EnvThermo.satadjust(self.EnvVar, GMV) + self.UpdThermo.buoyancy(self.UpdVar, self.EnvVar,GMV, self.extrapolate_buoyancy) self.decompose_environment(GMV, 'values') @@ -386,12 +378,8 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): self.UpdThermo.buoyancy(self.UpdVar, self.EnvVar, GMV, self.extrapolate_buoyancy) self.compute_eddy_diffusivities_tke(GMV, Case) - self.update_GMV_ED(GMV, Case, TS) - if self.calc_tke: - self.compute_tke(GMV, Case, TS) - if self.calc_scalar_var: - self.compute_covariance(GMV, Case, TS) + self.compute_covariance(GMV, Case, TS) # Back out the tendencies of the grid mean variables for the whole timestep by differencing GMV.new and # GMV.values @@ -404,15 +392,13 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): cdef: Py_ssize_t iter_ double time_elapsed = 0.0 - self.UpdVar.set_new_with_values() self.UpdVar.set_old_with_values() self.set_updraft_surface_bc(GMV, Case) - self.dt_upd = np.minimum(TS.dt, 0.5 * self.Gr.dz/fmax(np.max(self.UpdVar.W.values),1e-10)) + self.dt_upd = np.minimum(TS.dt, 0.2 * self.Gr.dz/fmax(np.max(self.UpdVar.W.values),1e-10)) while time_elapsed < TS.dt: self.compute_entrainment_detrainment(GMV, Case) - self.solve_updraft_velocity_area(GMV,TS) - self.solve_updraft_scalars(GMV, Case, TS) + self.solve_updraft(GMV,Case,TS) self.UpdVar.set_values_with_new() time_elapsed += self.dt_upd self.dt_upd = np.minimum(TS.dt-time_elapsed, 0.5 * self.Gr.dz/fmax(np.max(self.UpdVar.W.values),1e-10)) @@ -424,6 +410,7 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): self.decompose_environment(GMV, 'values') self.EnvThermo.satadjust(self.EnvVar, False) self.UpdThermo.buoyancy(self.UpdVar, self.EnvVar, GMV, self.extrapolate_buoyancy) + return cpdef compute_diagnostic_updrafts(self, GridMeanVariables GMV, CasesBase Case): @@ -447,25 +434,25 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): self.UpdVar.H.values[i,gw] = self.h_surface_bc[i] self.UpdVar.QT.values[i,gw] = self.qt_surface_bc[i] # Find the cloud liquid content - sa = eos(self.UpdThermo.t_to_prog_fp,self.UpdThermo.prog_to_t_fp, self.Ref.p0_half[gw], + sa = eos(self.UpdThermo.t_to_prog_fp,self.UpdThermo.prog_to_t_fp, self.Ref.p0_c[gw], self.UpdVar.QT.values[i,gw], self.UpdVar.H.values[i,gw]) self.UpdVar.QL.values[i,gw] = sa.ql self.UpdVar.T.values[i,gw] = sa.T - self.UpdMicro.compute_update_combined_local_thetal(self.Ref.p0_half[gw], self.UpdVar.T.values[i,gw], + self.UpdMicro.compute_update_combined_local_thetal(self.Ref.p0_c[gw], self.UpdVar.T.values[i,gw], &self.UpdVar.QT.values[i,gw], &self.UpdVar.QL.values[i,gw], &self.UpdVar.QR.values[i,gw], &self.UpdVar.H.values[i,gw], - i, gw) + i, gw) for k in xrange(gw+1, self.Gr.nzg-gw): denom = 1.0 + self.entr_sc[i,k] * dz self.UpdVar.H.values[i,k] = (self.UpdVar.H.values[i,k-1] + self.entr_sc[i,k] * dz * GMV.H.values[k])/denom self.UpdVar.QT.values[i,k] = (self.UpdVar.QT.values[i,k-1] + self.entr_sc[i,k] * dz * GMV.QT.values[k])/denom - sa = eos(self.UpdThermo.t_to_prog_fp,self.UpdThermo.prog_to_t_fp, self.Ref.p0_half[k], + sa = eos(self.UpdThermo.t_to_prog_fp,self.UpdThermo.prog_to_t_fp, self.Ref.p0_c[k], self.UpdVar.QT.values[i,k], self.UpdVar.H.values[i,k]) self.UpdVar.QL.values[i,k] = sa.ql self.UpdVar.T.values[i,k] = sa.T - self.UpdMicro.compute_update_combined_local_thetal(self.Ref.p0_half[k], self.UpdVar.T.values[i,k], + self.UpdMicro.compute_update_combined_local_thetal(self.Ref.p0_c[k], self.UpdVar.T.values[i,k], &self.UpdVar.QT.values[i,k], &self.UpdVar.QL.values[i,k], &self.UpdVar.QR.values[i,k], &self.UpdVar.H.values[i,k], i, k) @@ -484,12 +471,12 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): self.entr_sc[i,gw] = 2.0 /dz self.detr_sc[i,gw] = 0.0 for k in range(self.Gr.gw, self.Gr.nzg-self.Gr.gw): - area_k = interp2pt(self.UpdVar.Area.values[i,k], self.UpdVar.Area.values[i,k+1]) + area_k = self.UpdVar.Area.values[i,k] if area_k >= self.minimum_area: w_km = self.UpdVar.W.values[i,k-1] - entr_w = interp2pt(self.entr_sc[i,k], self.entr_sc[i,k+1]) - detr_w = interp2pt(self.detr_sc[i,k], self.detr_sc[i,k+1]) - B_k = interp2pt(self.UpdVar.B.values[i,k], self.UpdVar.B.values[i,k+1]) + entr_w = self.entr_sc[i,k] + detr_w = self.detr_sc[i,k] + B_k = self.UpdVar.B.values[i,k] w2 = ((self.vel_buoy_coeff * B_k + 0.5 * w_km * w_km * dzi) /(0.5 * dzi +entr_w + self.vel_pressure_coeff/sqrt(fmax(area_k,self.minimum_area)))) if w2 > 0.0: @@ -511,20 +498,20 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): au_lim = self.max_area_factor * self.area_surface_bc[i] self.UpdVar.Area.values[i,gw] = self.area_surface_bc[i] w_mid = 0.5* (self.UpdVar.W.values[i,gw]) - for k in xrange(gw+1, self.Gr.nzg): + for k in xrange(gw, self.Gr.nzg): # yair +1 w_low = w_mid - w_mid = interp2pt(self.UpdVar.W.values[i,k],self.UpdVar.W.values[i,k-1]) + w_mid = self.UpdVar.W.values[i,k] if w_mid > 0.0: if self.entr_sc[i,k]>(0.9/dz): self.entr_sc[i,k] = 0.9/dz - self.UpdVar.Area.values[i,k] = (self.Ref.rho0_half[k-1]*self.UpdVar.Area.values[i,k-1]*w_low/ - (1.0-(self.entr_sc[i,k]-self.detr_sc[i,k])*dz)/w_mid/self.Ref.rho0_half[k]) + self.UpdVar.Area.values[i,k] = (self.Ref.rho0_c[k-1]*self.UpdVar.Area.values[i,k-1]*w_low/ + (1.0-(self.entr_sc[i,k]-self.detr_sc[i,k])*dz)/w_mid/self.Ref.rho0_c[k]) # # Limit the increase in updraft area when the updraft decelerates if self.UpdVar.Area.values[i,k] > au_lim: self.UpdVar.Area.values[i,k] = au_lim - self.detr_sc[i,k] =(self.Ref.rho0_half[k-1] * self.UpdVar.Area.values[i,k-1] - * w_low / au_lim / w_mid / self.Ref.rho0_half[k] + self.entr_sc[i,k] * dz -1.0)/dz + self.detr_sc[i,k] =(self.Ref.rho0_c[k-1] * self.UpdVar.Area.values[i,k-1] + * w_low / au_lim / w_mid / self.Ref.rho0_c[k] + self.entr_sc[i,k] * dz -1.0)/dz else: # the updraft has terminated so set its area fraction to zero at this height and all heights above self.UpdVar.Area.values[i,k] = 0.0 @@ -534,7 +521,7 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): #TODO wouldnt it be more consistent to have here? #self.UpdVar.QL.values[i,k] = GMV.QL.values[k] #self.UpdVar.T.values[i,k] = GMV.T.values[k] - sa = eos(self.UpdThermo.t_to_prog_fp,self.UpdThermo.prog_to_t_fp, self.Ref.p0_half[k], + sa = eos(self.UpdThermo.t_to_prog_fp,self.UpdThermo.prog_to_t_fp, self.Ref.p0_c[k], self.UpdVar.QT.values[i,k], self.UpdVar.H.values[i,k]) self.UpdVar.QL.values[i,k] = sa.ql self.UpdVar.T.values[i,k] = sa.T @@ -551,62 +538,141 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): return - cpdef compute_tke(self, GridMeanVariables GMV, CasesBase Case, TimeStepping TS): - if self.similarity_diffusivity: # otherwise, we computed mixing length when we computed D_T - self.compute_mixing_length(Case.Sur.obukhov_length) - - self.compute_tke_buoy(GMV) - self.compute_tke_entr() - self.compute_tke_shear(GMV) - self.compute_tke_pressure() - - self.reset_surface_tke(GMV, Case) - self.update_tke_ED(GMV, Case, TS) - - - return - - cpdef initialize_tke(self, GridMeanVariables GMV, CasesBase Case): - cdef: - Py_ssize_t k - double ws= self.wstar, us = Case.Sur.ustar, zs = self.zi, z - # Similarity profile initialization of TKE - # Need to consider what to do when neutral/stable - if ws > 0.0: - with nogil: - for k in xrange(self.Gr.nzg): - z = self.Gr.z_half[k] - GMV.TKE.values[k] = ws * 1.3 * cbrt((us*us*us)/(ws*ws*ws) + 0.6 * z/zs) * sqrt(fmax(1.0-z/zs,0.0)) - - - self.reset_surface_tke(GMV, Case) - self.compute_mixing_length(Case.Sur.obukhov_length) - return - cpdef update_inversion(self,GridMeanVariables GMV, option): ParameterizationBase.update_inversion(self, GMV,option) return - cpdef compute_mixing_length(self, double obukhov_length): + cpdef compute_mixing_length(self, double obukhov_length, GridMeanVariables GMV): cdef: Py_ssize_t k Py_ssize_t gw = self.Gr.gw double tau = get_mixing_tau(self.zi, self.wstar) - double l1, l2, z_ + double l1, l2, l3, l4, l5, l234, z_ double grad, grad2, H + double du = 0.0 + double dv = 0.0 + double dw = 2.0 * self.EnvVar.W.values[gw] * self.Gr.dzi + double H_lapse_rate ,QT_lapse_rate + double l[5], pr_vec[2] - with nogil: + if self.mixing_scheme == 'SBL': + g = 9.81 for k in xrange(gw, self.Gr.nzg-gw): - l1 = tau * sqrt(fmax(self.EnvVar.TKE.values[k],0.0)) - z_ = self.Gr.z_half[k] + z_ = self.Gr.z_c[k] + shear2 = pow((GMV.U.values[k+1] - GMV.U.values[k-1]) * 0.5 * self.Gr.dzi, 2) + \ + pow((GMV.V.values[k+1] - GMV.V.values[k-1]) * 0.5 * self.Gr.dzi, 2) + ri_bulk = g * (GMV.THL.values[k] - GMV.THL.values[gw]) * self.Gr.z_c[k]/ \ + GMV.THL.values[gw] / (GMV.U.values[k] * GMV.U.values[k] + GMV.V.values[k] * GMV.V.values[k]) + THL_lapse_rate = fmax(fabs((self.EnvVar.THL.values[k+1]-self.EnvVar.THL.values[k-1])*0.5*self.Gr.dzi),1e-10) + QT_lapse_rate = fmax(fabs((self.EnvVar.QT.values[k+1]-self.EnvVar.QT.values[k-1])*0.5*self.Gr.dzi),1e-10) + + # kz scale (surface layer terms) if obukhov_length < 0.0: #unstable - l2 = vkb * z_ * ( (1.0 - 100.0 * z_/obukhov_length)**0.2 ) + l2 = vkb * z_ # * ( (1.0 - 100.0 * z_/obukhov_length)**0.2 ) elif obukhov_length > 0.0: #stable - l2 = vkb * z_ / (1. + 2.7 *z_/obukhov_length) + l2 = vkb * z_ #/ (1. + 2.7 *z_/obukhov_length) else: l2 = vkb * z_ - self.mixing_length[k] = fmax( 1.0/(1.0/fmax(l1,1e-10) + 1.0/l2), 1e-3) + + # Shear-dissipation TKE equilibrium scale (Stable) + qt_dry = self.EnvThermo.qt_dry[k] + th_dry = self.EnvThermo.th_dry[k] + t_cloudy = self.EnvThermo.t_cloudy[k] + qv_cloudy = self.EnvThermo.qv_cloudy[k] + qt_cloudy = self.EnvThermo.qt_cloudy[k] + th_cloudy = self.EnvThermo.th_cloudy[k] + + lh = latent_heat(t_cloudy) + cpm = cpm_c(qt_cloudy) + grad_thl_plus = (self.EnvVar.THL.values[k+1] - self.EnvVar.THL.values[k]) * self.Gr.dzi + grad_qt_plus = (self.EnvVar.QT.values[k+1] - self.EnvVar.QT.values[k]) * self.Gr.dzi + + prefactor = g * ( Rd / self.Ref.alpha0_c[k] /self.Ref.p0_c[k]) * exner_c(self.Ref.p0_c[k]) + + d_alpha_thetal_dry = prefactor * (1.0 + (eps_vi-1.0) * qt_dry) + d_alpha_qt_dry = prefactor * th_dry * (eps_vi-1.0) + + if self.EnvVar.CF.values[k] > 0.0: + d_alpha_thetal_cloudy = (prefactor * (1.0 + eps_vi * (1.0 + lh / Rv / t_cloudy) * qv_cloudy - qt_cloudy ) + / (1.0 + lh * lh / cpm / Rv / t_cloudy / t_cloudy * qv_cloudy)) + d_alpha_qt_cloudy = (lh / cpm / t_cloudy * d_alpha_thetal_cloudy - prefactor) * th_cloudy + else: + d_alpha_thetal_cloudy = 0.0 + d_alpha_qt_cloudy = 0.0 + + d_alpha_thetal_total = (self.EnvVar.CF.values[k] * d_alpha_thetal_cloudy + + (1.0-self.EnvVar.CF.values[k]) * d_alpha_thetal_dry) + d_alpha_qt_total = (self.EnvVar.CF.values[k] * d_alpha_qt_cloudy + + (1.0-self.EnvVar.CF.values[k]) * d_alpha_qt_dry) + + ri_thl = grad_thl_plus * d_alpha_thetal_total / fmax(shear2, 1e-10) + ri_qt = grad_qt_plus * d_alpha_qt_total / fmax(shear2, 1e-10) + + # if (z_<50.0): + # prandtl = 0.8 + 0.8 * z_/50.0 + # else: + # prandtl = 1.6 + + # if (ri_bulk<.05): + # prandtl = 0.8 + 0.8 * ri_bulk/0.05 + # else: + # prandtl = 1.6 + pr_vec[0] = 1.6; pr_vec[1] = 0.6 + 1.0 * (ri_thl+ri_qt)/0.066 + prandtl = smooth_minimum(pr_vec, 7.0) + + l3 = sqrt(self.tke_diss_coeff/self.tke_ed_coeff) * sqrt(fmax(self.EnvVar.TKE.values[k],0.0))/fmax(sqrt(shear2), 1.0e-10) + l3 /= sqrt(fmax(1.0 - ri_thl/prandtl - ri_qt/prandtl, 1e-7)) + if (sqrt(shear2)< 1.0e-10 or 1.0 - ri_thl/prandtl - ri_qt/prandtl < 1e-7): + l3 = 1.0e6 + l3 = fmin(l3, 1.0e7) + + # Temp variance length scale + l4 = sqrt(self.tke_diss_coeff/self.tke_ed_coeff) * sqrt(fmax(self.EnvVar.Hvar.values[k],0.0))/fmax(sqrt(grad_thl_plus*grad_thl_plus), 1.0e-10) + l5 = sqrt(self.tke_diss_coeff/self.tke_ed_coeff) * sqrt(fmax(self.EnvVar.QTvar.values[k],0.0))/fmax(sqrt(grad_qt_plus*grad_qt_plus), 1.0e-10) + + # Limiting stratification scale + N = fmax( 1e-8, sqrt(fmax(g/GMV.THL.values[k]*grad_thl_plus, 0.0))) + l1 = fmin(sqrt(fmax(0.35*self.EnvVar.TKE.values[k],0.0))/N, 1000.0) + if (N<1e-7): + l1 = 1.0e5 + l2 = fmin(l2, 1000.0) + l[0]=l2; l[1]=l1; l[2]=l3; l[3]=1.0e5; l[4]=1.0e5 + # self.mixing_length[k] = smooth_minimum(l, 0.1*self.Gr.dz) # + j = 0 + while(j 0.0: #stable + l2 = vkb * z_ / (1. + 2.7 *z_/obukhov_length) + else: + l2 = vkb * z_ + self.mixing_length[k] = fmax( 1.0/(1.0/fmax(l1,1e-10) + 1.0/l2), 1e-3) + return cpdef compute_eddy_diffusivities_tke(self, GridMeanVariables GMV, CasesBase Case): @@ -614,12 +680,12 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): Py_ssize_t k Py_ssize_t gw = self.Gr.gw double lm - double we_half + double we if self.similarity_diffusivity: ParameterizationBase.compute_eddy_diffusivities_similarity(self,GMV, Case) else: - self.compute_mixing_length(Case.Sur.obukhov_length) + self.compute_mixing_length(Case.Sur.obukhov_length, GMV) with nogil: for k in xrange(gw, self.Gr.nzg-gw): lm = self.mixing_length[k] @@ -634,10 +700,10 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): self.wstar = get_wstar(Case.Sur.bflux, self.zi) cdef: - Py_ssize_t i, gw = self.Gr.gw - double zLL = self.Gr.z_half[gw] + Py_ssize_i, gw = self.Gr.gw + double zLL = self.Gr.z_c[gw] double ustar = Case.Sur.ustar, oblength = Case.Sur.obukhov_length - double alpha0LL = self.Ref.alpha0_half[gw] + double alpha0LL = self.Ref.alpha0_c[gw] double qt_var = get_surface_variance(Case.Sur.rho_qtflux*alpha0LL, Case.Sur.rho_qtflux*alpha0LL, ustar, zLL, oblength) double h_var = get_surface_variance(Case.Sur.rho_hflux*alpha0LL, @@ -650,35 +716,12 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): for i in xrange(self.n_updrafts): surface_scalar_coeff= percentile_bounds_mean_norm(1.0-self.surface_area+i*a_, 1.0-self.surface_area + (i+1)*a_ , 1000) - + # use the w equation with w[gw-1] = 0 and dzi divided by 2 to obtain w[gw] - this need to change for diagnostic updrafts self.area_surface_bc[i] = self.surface_area/self.n_updrafts - self.w_surface_bc[i] = 0.0 self.h_surface_bc[i] = (GMV.H.values[gw] + surface_scalar_coeff * sqrt(h_var)) self.qt_surface_bc[i] = (GMV.QT.values[gw] + surface_scalar_coeff * sqrt(qt_var)) return - cpdef reset_surface_tke(self, GridMeanVariables GMV, CasesBase Case): - GMV.TKE.values[self.Gr.gw] = get_surface_tke(Case.Sur.ustar, - self.wstar, - self.Gr.z_half[self.Gr.gw], - Case.Sur.obukhov_length) - return - - - cpdef reset_surface_covariance(self, GridMeanVariables GMV, CasesBase Case): - - cdef: - double zLL = self.Gr.z_half[self.Gr.gw] - double ustar = Case.Sur.ustar, oblength = Case.Sur.obukhov_length - double flux1 = Case.Sur.rho_hflux * self.Ref.alpha0_half[self.Gr.gw] - double flux2 = Case.Sur.rho_qtflux * self.Ref.alpha0_half[self.Gr.gw] - - GMV.Hvar.values[self.Gr.gw] = get_surface_variance(flux1, flux1, ustar, zLL, oblength) - GMV.QTvar.values[self.Gr.gw] = get_surface_variance(flux2, flux2, ustar, zLL, oblength) - GMV.HQTcov.values[self.Gr.gw] = get_surface_variance(flux1,flux2, ustar, zLL, oblength) - - return - # Find values of environmental variables by subtracting updraft values from grid mean values # whichvals used to check which substep we are on--correspondingly use 'GMV.SomeVar.value' (last timestep value) @@ -690,53 +733,41 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): cdef: Py_ssize_t k, gw = self.Gr.gw - double val1, val2, au_full + double val1, val2 double Hvar_e, QTvar_e, HQTcov_e, Hvar_u, QTvar_u, HQTcov_u if whichvals == 'values': with nogil: - for k in xrange(self.Gr.nzg-1): + for k in xrange(self.Gr.nzg): val1 = 1.0/(1.0-self.UpdVar.Area.bulkvalues[k]) val2 = self.UpdVar.Area.bulkvalues[k] * val1 self.EnvVar.QT.values[k] = val1 * GMV.QT.values[k] - val2 * self.UpdVar.QT.bulkvalues[k] self.EnvVar.H.values[k] = val1 * GMV.H.values[k] - val2 * self.UpdVar.H.bulkvalues[k] - # Have to account for staggering of W--interpolate area fraction to the "full" grid points - # Assuming GMV.W = 0! - au_full = 0.5 * (self.UpdVar.Area.bulkvalues[k+1] + self.UpdVar.Area.bulkvalues[k]) - self.EnvVar.W.values[k] = -au_full/(1.0-au_full) * self.UpdVar.W.bulkvalues[k] + self.EnvVar.W.values[k] = -self.UpdVar.Area.bulkvalues[k]/(1.0-self.UpdVar.Area.bulkvalues[k]) * self.UpdVar.W.bulkvalues[k] if self.calc_tke: - self.get_GMV_TKE(self.UpdVar.Area,self.UpdVar.W, self.EnvVar.W, self.EnvVar.TKE, - &GMV.W.values[0], &GMV.TKE.values[0]) - + self.get_GMV_CoVar(self.UpdVar.Area,self.UpdVar.W, self.UpdVar.W, self.EnvVar.W, self.EnvVar.W, self.EnvVar.TKE, &GMV.W.values[0],&GMV.W.values[0], &GMV.TKE.values[0]) if self.calc_scalar_var: - self.get_GMV_CoVar(self.UpdVar.Area,self.UpdVar.H, self.UpdVar.H, self.EnvVar.H, self.EnvVar.H, self.EnvVar.Hvar, - &GMV.H.values[0],&GMV.H.values[0], &GMV.Hvar.values[0]) - self.get_GMV_CoVar(self.UpdVar.Area,self.UpdVar.QT, self.UpdVar.QT, self.EnvVar.QT, self.EnvVar.QT, self.EnvVar.QTvar, - &GMV.QT.values[0],&GMV.QT.values[0], &GMV.QTvar.values[0]) - self.get_GMV_CoVar(self.UpdVar.Area,self.UpdVar.H, self.UpdVar.QT, self.EnvVar.H, self.EnvVar.QT, self.EnvVar.HQTcov, - &GMV.H.values[0], &GMV.QT.values[0], &GMV.HQTcov.values[0]) + self.get_GMV_CoVar(self.UpdVar.Area,self.UpdVar.H, self.UpdVar.H, self.EnvVar.H, self.EnvVar.H, self.EnvVar.Hvar, &GMV.H.values[0],&GMV.H.values[0], &GMV.Hvar.values[0]) + self.get_GMV_CoVar(self.UpdVar.Area,self.UpdVar.QT,self.UpdVar.QT,self.EnvVar.QT,self.EnvVar.QT,self.EnvVar.QTvar, &GMV.QT.values[0],&GMV.QT.values[0], &GMV.QTvar.values[0]) + self.get_GMV_CoVar(self.UpdVar.Area,self.UpdVar.H, self.UpdVar.QT,self.EnvVar.H, self.EnvVar.QT,self.EnvVar.HQTcov, &GMV.H.values[0],&GMV.QT.values[0], &GMV.HQTcov.values[0]) elif whichvals == 'mf_update': # same as above but replace GMV.SomeVar.values with GMV.SomeVar.mf_update with nogil: - for k in xrange(self.Gr.nzg-1): + for k in xrange(self.Gr.nzg): val1 = 1.0/(1.0-self.UpdVar.Area.bulkvalues[k]) val2 = self.UpdVar.Area.bulkvalues[k] * val1 self.EnvVar.QT.values[k] = val1 * GMV.QT.mf_update[k] - val2 * self.UpdVar.QT.bulkvalues[k] self.EnvVar.H.values[k] = val1 * GMV.H.mf_update[k] - val2 * self.UpdVar.H.bulkvalues[k] - # Have to account for staggering of W # Assuming GMV.W = 0! - au_full = 0.5 * (self.UpdVar.Area.bulkvalues[k+1] + self.UpdVar.Area.bulkvalues[k]) - self.EnvVar.W.values[k] = -au_full/(1.0-au_full) * self.UpdVar.W.bulkvalues[k] - + self.EnvVar.W.values[k] = -self.UpdVar.Area.bulkvalues[k]/(1.0-self.UpdVar.Area.bulkvalues[k]) * self.UpdVar.W.bulkvalues[k] if self.calc_tke: - self.get_GMV_TKE(self.UpdVar.Area,self.UpdVar.W, self.EnvVar.W, self.EnvVar.TKE, - &GMV.W.values[0], &GMV.TKE.values[0]) - + self.get_GMV_CoVar(self.UpdVar.Area,self.UpdVar.W, self.UpdVar.W, self.EnvVar.W, self.EnvVar.W, self.EnvVar.TKE, + &GMV.W.values[0],&GMV.W.values[0], &GMV.TKE.values[0]) if self.calc_scalar_var: self.get_GMV_CoVar(self.UpdVar.Area,self.UpdVar.H, self.UpdVar.H, self.EnvVar.H, self.EnvVar.H, self.EnvVar.Hvar, &GMV.H.values[0],&GMV.H.values[0], &GMV.Hvar.values[0]) @@ -747,100 +778,61 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): return - cdef get_GMV_TKE(self, EDMF_Updrafts.UpdraftVariable au, EDMF_Updrafts.UpdraftVariable wu, - EDMF_Environment.EnvironmentVariable we, EDMF_Environment.EnvironmentVariable tke_e, - double *gmv_w, double *gmv_tke): - cdef: - Py_ssize_t i,k - double [:] ae = np.subtract(np.ones((self.Gr.nzg,),dtype=np.double, order='c'),au.bulkvalues) - double interp_w_diff - - with nogil: - for k in xrange(self.Gr.nzg): - interp_w_diff = interp2pt(we.values[k-1]-gmv_w[k-1],we.values[k]-gmv_w[k]) - gmv_tke[k] = ae[k] * interp_w_diff * interp_w_diff + ae[k] * tke_e.values[k] - for i in xrange(self.n_updrafts): - interp_w_diff = interp2pt(wu.values[i,k-1]-gmv_w[k-1],wu.values[i,k]-gmv_w[k]) - gmv_tke[k] += au.values[i,k] *interp_w_diff * interp_w_diff - return - - - - cdef get_env_tke_from_GMV(self, EDMF_Updrafts.UpdraftVariable au, EDMF_Updrafts.UpdraftVariable wu, - EDMF_Environment.EnvironmentVariable we, EDMF_Environment.EnvironmentVariable tke_e, - double *gmv_w, double *gmv_tke): - cdef: - Py_ssize_t i,k - double [:] ae = np.subtract(np.ones((self.Gr.nzg,),dtype=np.double, order='c'),au.bulkvalues) - double interp_w_diff - - with nogil: - for k in xrange(self.Gr.nzg): - if ae[k] > 0.0: - interp_w_diff = interp2pt(we.values[k-1]-gmv_w[k-1],we.values[k]-gmv_w[k]) - tke_e.values[k] = gmv_tke[k] - ae[k] * interp_w_diff * interp_w_diff - - for i in xrange(self.n_updrafts): - interp_w_diff = interp2pt(wu.values[i,k-1]-gmv_w[k-1],wu.values[i,k]-gmv_w[k]) - tke_e.values[k] -= au.values[i,k] *interp_w_diff * interp_w_diff - tke_e.values[k] = tke_e.values[k]/ae[k] - else: - tke_e.values[k] = 0.0 - return - - # Note: this assumes all variables are defined on half levels not full levels (i.e. phi, psi are not w) + cdef get_GMV_CoVar(self, EDMF_Updrafts.UpdraftVariable au, EDMF_Updrafts.UpdraftVariable phi_u, EDMF_Updrafts.UpdraftVariable psi_u, EDMF_Environment.EnvironmentVariable phi_e, EDMF_Environment.EnvironmentVariable psi_e, - EDMF_Environment.EnvironmentVariable covar_e, + EDMF_Environment.EnvironmentVariable_2m covar_e, double *gmv_phi, double *gmv_psi, double *gmv_covar): cdef: Py_ssize_t i,k double [:] ae = np.subtract(np.ones((self.Gr.nzg,),dtype=np.double, order='c'),au.bulkvalues) double phi_diff, psi_diff + double tke_factor = 1.0 + if covar_e.name == 'tke': + tke_factor = 0.5 with nogil: for k in xrange(self.Gr.nzg): phi_diff = phi_e.values[k]-gmv_phi[k] psi_diff = psi_e.values[k]-gmv_psi[k] - gmv_covar[k] = ae[k] * phi_diff * psi_diff + ae[k] * covar_e.values[k] + gmv_covar[k] = tke_factor * ae[k] * phi_diff * psi_diff + ae[k] * covar_e.values[k] for i in xrange(self.n_updrafts): phi_diff = phi_u.values[i,k]-gmv_phi[k] psi_diff = psi_u.values[i,k]-gmv_psi[k] - gmv_covar[k] += au.values[i,k] * phi_diff * psi_diff + gmv_covar[k] += tke_factor * au.values[i,k] * phi_diff * psi_diff return - cdef get_env_covar_from_GMV(self, EDMF_Updrafts.UpdraftVariable au, EDMF_Updrafts.UpdraftVariable phi_u, EDMF_Updrafts.UpdraftVariable psi_u, EDMF_Environment.EnvironmentVariable phi_e, EDMF_Environment.EnvironmentVariable psi_e, - EDMF_Environment.EnvironmentVariable covar_e, + EDMF_Environment.EnvironmentVariable_2m covar_e, double *gmv_phi, double *gmv_psi, double *gmv_covar): cdef: Py_ssize_t i,k double [:] ae = np.subtract(np.ones((self.Gr.nzg,),dtype=np.double, order='c'),au.bulkvalues) double phi_diff, psi_diff + double tke_factor = 1.0 + if covar_e.name == 'tke': + tke_factor = 0.5 with nogil: for k in xrange(self.Gr.nzg): if ae[k] > 0.0: - phi_diff = phi_e.values[k]-gmv_phi[k] + phi_diff = phi_e.values[k] - gmv_phi[k] psi_diff = psi_e.values[k] - gmv_psi[k] - covar_e.values[k] = gmv_covar[k] - ae[k] * phi_diff * psi_diff + covar_e.values[k] = gmv_covar[k] - tke_factor * ae[k] * phi_diff * psi_diff for i in xrange(self.n_updrafts): - phi_diff = phi_u.values[i,k]-gmv_phi[k] + phi_diff = phi_u.values[i,k] - gmv_phi[k] psi_diff = psi_u.values[i,k] - gmv_psi[k] - covar_e.values[k] -= au.values[i,k] * phi_diff * psi_diff + covar_e.values[k] -= tke_factor * au.values[i,k] * phi_diff * psi_diff covar_e.values[k] = covar_e.values[k]/ae[k] else: covar_e.values[k] = 0.0 return - - - cpdef compute_entrainment_detrainment(self, GridMeanVariables GMV, CasesBase Case): cdef: Py_ssize_t k @@ -848,232 +840,254 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): entr_in_struct input eos_struct sa + double [:] Poisson_rand + double logfn + long quadrature_order = 3 + double transport_plus, transport_minus - self.UpdVar.get_cloud_base_top_cover() + self.UpdVar.get_cloud_base_top_cover() + input.dz = self.Gr.dz input.wstar = self.wstar + input.zbl = self.compute_zbl_qt_grad(GMV) + for i in xrange(self.n_updrafts): + input.zi = self.UpdVar.cloud_base[i] + Poisson_rand = np.random.poisson(10.0,self.Gr.nzg).astype(np.float) + Poisson_rand= np.clip(Poisson_rand,0.01,100.0) + for k in xrange(self.Gr.gw, self.Gr.nzg-self.Gr.gw): + input.quadrature_order = quadrature_order + input.b = self.UpdVar.B.values[i,k] + input.b_mean = GMV.B.values[k] + input.w = self.UpdVar.W.values[i,k] + input.dw = (self.UpdVar.W.values[i,k+1]-self.UpdVar.W.values[i,k-1])/self.Gr.dz/2.0 + input.z = self.Gr.z_c[k] + input.af = self.UpdVar.Area.values[i,k] + input.ml = self.mixing_length[k] + input.qt_env = self.EnvVar.QT.values[k] + input.ql_env = self.EnvVar.QL.values[k] + input.T_env = self.EnvVar.T.values[k] + input.H_env = self.EnvVar.H.values[k] + input.env_Hvar = self.EnvVar.Hvar.values[k] + input.env_QTvar = self.EnvVar.QTvar.values[k] + input.env_HQTcov = self.EnvVar.HQTcov.values[k] + input.w_env = self.EnvVar.W.values[k] + input.dw_env = (self.EnvVar.W.values[k+1]-self.EnvVar.W.values[k-1])/self.Gr.dz/2.0 + input.H_up = self.UpdVar.H.values[i,k] + input.qt_up = self.UpdVar.QT.values[i,k] + input.ql_up = self.UpdVar.QL.values[i,k] + input.T_up = self.UpdVar.T.values[i,k] + input.p0 = self.Ref.p0_c[k] + input.alpha0 = self.Ref.alpha0_c[k] + input.n_up = self.n_updrafts + + if self.calc_tke: + input.tke = self.EnvVar.TKE.values[k] + input.tke_ed_coeff = self.tke_ed_coeff + + input.Poisson_rand = Poisson_rand[k]/10.0 + input.L = 20000.0 # need to define the scale of the GCM grid resolution + + input.thv_e = theta_virt_c(self.Ref.p0_c[k], self.EnvVar.T.values[k], self.EnvVar.QT.values[k], + self.EnvVar.QL.values[k], self.EnvVar.QR.values[k]) + input.thv_u = theta_virt_c(self.Ref.p0_c[k], self.UpdVar.T.bulkvalues[k], self.UpdVar.QT.bulkvalues[k], + self.UpdVar.QL.bulkvalues[k], self.UpdVar.QR.bulkvalues[k]) + input.dwdz = (self.UpdVar.Area.values[i,k+1]* + interp2pt(self.UpdVar.W.values[i,k+1],self.UpdVar.W.values[i,k]) + + (1.0-self.UpdVar.Area.values[i,k+1])*self.EnvVar.W.values[k+1] - + (self.UpdVar.Area.values[i,k-1]* + interp2pt(self.UpdVar.W.values[i,k-1],self.UpdVar.W.values[i,k-2]) + + (1.0-self.UpdVar.Area.values[i,k-1])*self.EnvVar.W.values[k-1]) )/(2.0*self.Gr.dz) + + transport_plus = ( self.UpdVar.Area.values[i,k+1]*(1.0-self.UpdVar.Area.values[i,k+1])* + (interp2pt(self.UpdVar.W.values[i,k+1],self.UpdVar.W.values[i,k]) - self.EnvVar.W.values[k+1])* + (1.0-2.0*self.UpdVar.Area.values[i,k+1])* + (interp2pt(self.UpdVar.W.values[i,k+1],self.UpdVar.W.values[i,k]) - self.EnvVar.W.values[k+1])* + (interp2pt(self.UpdVar.W.values[i,k+1],self.UpdVar.W.values[i,k]) - self.EnvVar.W.values[k+1]) ) + + transport_minus = ( self.UpdVar.Area.values[i,k-1]*(1.0-self.UpdVar.Area.values[i,k-1])* + (interp2pt(self.UpdVar.W.values[i,k-1],self.UpdVar.W.values[i,k-2]) - self.EnvVar.W.values[k-1])* + (1.0-2.0*self.UpdVar.Area.values[i,k+1])* + (interp2pt(self.UpdVar.W.values[i,k-1],self.UpdVar.W.values[i,k-2]) - self.EnvVar.W.values[k-1])* + (interp2pt(self.UpdVar.W.values[i,k-1],self.UpdVar.W.values[i,k-2]) - self.EnvVar.W.values[k-1]) ) + + input.transport_der = (transport_plus - transport_minus)/2.0/self.Gr.dz + + if input.zbl-self.UpdVar.cloud_base[i] > 0.0: + input.poisson = np.random.poisson(self.Gr.dz/((input.zbl-self.UpdVar.cloud_base[i])/10.0)) + else: + input.poisson = 0.0 + ret = self.entr_detr_fp(input) + self.entr_sc[i,k] = ret.entr_sc * self.entrainment_factor + self.detr_sc[i,k] = ret.detr_sc * self.detrainment_factor - with nogil: - for i in xrange(self.n_updrafts): - input.zi = self.UpdVar.cloud_base[i] - for k in xrange(self.Gr.gw, self.Gr.nzg-self.Gr.gw): - input.b = self.UpdVar.B.values[i,k] - input.w = interp2pt(self.UpdVar.W.values[i,k],self.UpdVar.W.values[i,k-1]) - input.z = self.Gr.z_half[k] - input.af = self.UpdVar.Area.values[i,k] - input.ml = self.mixing_length[k] - input.qt_env = self.EnvVar.QT.values[k] - input.ql_env = self.EnvVar.QL.values[k] - input.H_env = self.EnvVar.H.values[k] - input.b_env = self.EnvVar.B.values[k] - input.w_env = self.EnvVar.W.values[k] - input.H_up = self.UpdVar.H.values[i,k] - input.qt_up = self.UpdVar.QT.values[i,k] - input.ql_up = self.UpdVar.QL.values[i,k] - input.p0 = self.Ref.p0_half[k] - input.alpha0 = self.Ref.alpha0_half[k] - input.T_mean = (self.EnvVar.T.values[k]+self.UpdVar.T.values[i,k])/2 - input.L = 20000.0 # need to define the scale of the GCM grid resolution - if self.calc_tke: - input.tke = self.EnvVar.TKE.values[k] - input.tke_ed_coeff = self.tke_ed_coeff + return - ret = self.entr_detr_fp(input) - self.entr_sc[i,k] = ret.entr_sc * self.entrainment_factor - self.detr_sc[i,k] = ret.detr_sc * self.detrainment_factor + cpdef double compute_zbl_qt_grad(self, GridMeanVariables GMV): + cdef: + double qt_up, qt_, z_, zbl_qt, qt_grad = 0.0 - return + for k in xrange(self.Gr.gw, self.Gr.nzg-self.Gr.gw): + z_ = self.Gr.z_c[k] + qt_up = GMV.QT.values[k+1] + qt_ = GMV.QT.values[k] + + if fabs(qt_up-qt_)*self.Gr.dzi > qt_grad: + qt_grad = fabs(qt_up-qt_)*self.Gr.dzi + zbl_qt = z_ + return zbl_qt - cpdef solve_updraft_velocity_area(self, GridMeanVariables GMV, TimeStepping TS): + cpdef solve_updraft(self, GridMeanVariables GMV, CasesBase Case, TimeStepping TS): cdef: Py_ssize_t i, k Py_ssize_t gw = self.Gr.gw double dzi = self.Gr.dzi double dti_ = 1.0/self.dt_upd double dt_ = 1.0/dti_ - double whalf_kp, whalf_k - double a1, a2 # groupings of terms in area fraction discrete equation - double au_lim - double anew_k, a_k, a_km, entr_w, detr_w, B_k, entr_term, detr_term, rho_ratio - double adv, buoy, exch, press, press_buoy, press_drag # groupings of terms in velocity discrete equation + double wtemp + eos_struct sa - with nogil: - for i in xrange(self.n_updrafts): - self.entr_sc[i,gw] = 2.0 * dzi - self.detr_sc[i,gw] = 0.0 - self.UpdVar.W.new[i,gw-1] = self.w_surface_bc[i] - self.UpdVar.Area.new[i,gw] = self.area_surface_bc[i] - au_lim = self.area_surface_bc[i] * self.max_area_factor - - for k in range(gw, self.Gr.nzg-gw): - - # First solve for updated area fraction at k+1 - whalf_kp = interp2pt(self.UpdVar.W.values[i,k], self.UpdVar.W.values[i,k+1]) - whalf_k = interp2pt(self.UpdVar.W.values[i,k-1], self.UpdVar.W.values[i,k]) - adv = -self.Ref.alpha0_half[k+1] * dzi *( self.Ref.rho0_half[k+1] * self.UpdVar.Area.values[i,k+1] * whalf_kp - -self.Ref.rho0_half[k] * self.UpdVar.Area.values[i,k] * whalf_k) - entr_term = self.UpdVar.Area.values[i,k+1] * whalf_kp * (self.entr_sc[i,k+1] ) - detr_term = self.UpdVar.Area.values[i,k+1] * whalf_kp * (- self.detr_sc[i,k+1]) - - - self.UpdVar.Area.new[i,k+1] = fmax(dt_ * (adv + entr_term + detr_term) + self.UpdVar.Area.values[i,k+1], 0.0) - if self.UpdVar.Area.new[i,k+1] > au_lim: - self.UpdVar.Area.new[i,k+1] = au_lim - if self.UpdVar.Area.values[i,k+1] > 0.0: - self.detr_sc[i,k+1] = (((au_lim-self.UpdVar.Area.values[i,k+1])* dti_ - adv -entr_term)/(-self.UpdVar.Area.values[i,k+1] * whalf_kp)) - else: - # this detrainment rate won't affect scalars but would affect velocity - self.detr_sc[i,k+1] = (((au_lim-self.UpdVar.Area.values[i,k+1])* dti_ - adv -entr_term)/(-au_lim * whalf_kp)) - - # Now solve for updraft velocity at k - rho_ratio = self.Ref.rho0[k-1]/self.Ref.rho0[k] - anew_k = interp2pt(self.UpdVar.Area.new[i,k], self.UpdVar.Area.new[i,k+1]) - if anew_k >= self.minimum_area: - a_k = interp2pt(self.UpdVar.Area.values[i,k], self.UpdVar.Area.values[i,k+1]) - a_km = interp2pt(self.UpdVar.Area.values[i,k-1], self.UpdVar.Area.values[i,k]) - entr_w = interp2pt(self.entr_sc[i,k], self.entr_sc[i,k+1]) - detr_w = interp2pt(self.detr_sc[i,k], self.detr_sc[i,k+1]) - B_k = interp2pt(self.UpdVar.B.values[i,k], self.UpdVar.B.values[i,k+1]) - adv = (self.Ref.rho0[k] * a_k * self.UpdVar.W.values[i,k] * self.UpdVar.W.values[i,k] * dzi - - self.Ref.rho0[k-1] * a_km * self.UpdVar.W.values[i,k-1] * self.UpdVar.W.values[i,k-1] * dzi) - exch = (self.Ref.rho0[k] * a_k * self.UpdVar.W.values[i,k] - * (entr_w * self.EnvVar.W.values[k] - detr_w * self.UpdVar.W.values[i,k] )) - buoy= self.Ref.rho0[k] * a_k * B_k - press_buoy = -1.0 * self.Ref.rho0[k] * a_k * B_k * self.pressure_buoy_coeff - press_drag = -1.0 * self.Ref.rho0[k] * a_k * (self.pressure_drag_coeff/self.pressure_plume_spacing - * (self.UpdVar.W.values[i,k] -self.EnvVar.W.values[k])**2.0/sqrt(fmax(a_k,self.minimum_area))) - press = press_buoy + press_drag - self.updraft_pressure_sink[i,k] = press - self.UpdVar.W.new[i,k] = (self.Ref.rho0[k] * a_k * self.UpdVar.W.values[i,k] * dti_ - -adv + exch + buoy + press)/(self.Ref.rho0[k] * anew_k * dti_) - - if self.UpdVar.W.new[i,k] <= 0.0: - self.UpdVar.W.new[i,k:] = 0.0 - self.UpdVar.Area.new[i,k+1:] = 0.0 - break - else: - self.UpdVar.W.new[i,k:] = 0.0 - self.UpdVar.Area.new[i,k+1:] = 0.0 - # keep this in mind if we modify updraft top treatment! - self.updraft_pressure_sink[i,k:] = 0.0 - break - # the above lines were replaced by the followings to allow integration above negative w - # the model output is sensitive to the choice of value inthe condition : <= 0.01 - # if self.UpdVar.W.new[i,k] <= 0.01: - # self.UpdVar.W.new[i,k] = 0.0 - # self.UpdVar.Area.new[i,k+1] = 0.0 - # #break - # else: - # self.UpdVar.W.new[i,k] = 0.0 - # self.UpdVar.Area.new[i,k+1] = 0.0 - # #break - # plt.figure('area') - # plt.plot(self.UpdVar.Area.new[0,:], self.Gr.z_half) - # plt.show() + for i in xrange(self.n_updrafts): + self.entr_sc[i,gw] = 2.0 * dzi + self.detr_sc[i,gw] = 0.0 + self.UpdVar.Area.new[i,gw] = self.area_surface_bc[i] + self.UpdVar.H.new[i,gw] = self.h_surface_bc[i] + self.UpdVar.QT.new[i,gw] = self.qt_surface_bc[i] + + self.upwind_integration(self.UpdVar.Area, self.UpdVar.W, gw, i, self.EnvVar.W.values[gw], dzi) + if self.UpdVar.W.new[i,gw]<=0.0: + print self.UpdVar.W.new[i,gw], self.UpdVar.B.values[i,gw] + plt.figure() + plt.show() + + sa = eos(self.UpdThermo.t_to_prog_fp,self.UpdThermo.prog_to_t_fp, + self.Ref.p0_c[gw], self.UpdVar.QT.new[i,gw], self.UpdVar.H.new[i,gw]) + + self.UpdVar.QL.new[i,gw] = sa.ql + self.UpdVar.T.new[i,gw] = sa.T + self.UpdMicro.compute_update_combined_local_thetal(self.Ref.p0_c[gw], self.UpdVar.T.new[i,gw], + &self.UpdVar.QT.new[i,gw], &self.UpdVar.QL.new[i,gw], + &self.UpdVar.QR.new[i,gw], &self.UpdVar.H.new[i,gw], + i, gw) + for k in range(gw+1, self.Gr.nzg-gw): + self.upwind_integration(self.UpdVar.Area, self.UpdVar.Area, k, i, 1.0, dzi) - return + if self.UpdVar.Area.new[i,k] >= self.minimum_area: + self.upwind_integration(self.UpdVar.Area, self.UpdVar.W, k, i, self.EnvVar.W.values[k],dzi) - cpdef solve_updraft_scalars(self, GridMeanVariables GMV, CasesBase Case, TimeStepping TS): - cdef: - Py_ssize_t k, i - double dzi = self.Gr.dzi - double dti_ = 1.0/self.dt_upd - double m_k, m_km - Py_ssize_t gw = self.Gr.gw - double H_entr, QT_entr - double c1, c2, c3, c4 - eos_struct sa - double qt_var, h_var + else: + self.UpdVar.W.new[i,k] = 0.0 + self.UpdVar.Area.new[i,k] = 0.0 + self.updraft_pressure_sink[i,k] = 0.0 # keep this in mind if we modify updraft top treatment! - with nogil: - for i in xrange(self.n_updrafts): - self.UpdVar.H.new[i,gw] = self.h_surface_bc[i] - self.UpdVar.QT.new[i,gw] = self.qt_surface_bc[i] - self.UpdVar.QR.new[i,gw] = 0.0 #TODO + if self.UpdVar.Area.new[i,k] >= self.minimum_area: + self.upwind_integration(self.UpdVar.Area, self.UpdVar.H, k, i, self.EnvVar.H.values[k], dzi) + self.upwind_integration(self.UpdVar.Area, self.UpdVar.QT, k, i, self.EnvVar.QT.values[k], dzi) + else: - if self.use_local_micro: - # do saturation adjustment - sa = eos(self.UpdThermo.t_to_prog_fp,self.UpdThermo.prog_to_t_fp, - self.Ref.p0_half[gw], self.UpdVar.QT.new[i,gw], self.UpdVar.H.new[i,gw]) - self.UpdVar.QL.new[i,gw] = sa.ql - self.UpdVar.T.new[i,gw] = sa.T - # remove precipitation (update QT, QL and H) - self.UpdMicro.compute_update_combined_local_thetal(self.Ref.p0_half[gw], self.UpdVar.T.new[i,gw], - &self.UpdVar.QT.new[i,gw], &self.UpdVar.QL.new[i,gw], - &self.UpdVar.QR.new[i,gw], &self.UpdVar.H.new[i,gw], - i, gw) - - # starting from the bottom do entrainment at each level - for k in xrange(gw+1, self.Gr.nzg-gw): - H_entr = self.EnvVar.H.values[k] - QT_entr = self.EnvVar.QT.values[k] - - # write the discrete equations in form: - # c1 * phi_new[k] = c2 * phi[k] + c3 * phi[k-1] + c4 * phi_entr - if self.UpdVar.Area.new[i,k] >= self.minimum_area: - m_k = (self.Ref.rho0_half[k] * self.UpdVar.Area.values[i,k] - * interp2pt(self.UpdVar.W.values[i,k-1], self.UpdVar.W.values[i,k])) - m_km = (self.Ref.rho0_half[k-1] * self.UpdVar.Area.values[i,k-1] - * interp2pt(self.UpdVar.W.values[i,k-2], self.UpdVar.W.values[i,k-1])) - c1 = self.Ref.rho0_half[k] * self.UpdVar.Area.new[i,k] * dti_ - c2 = (self.Ref.rho0_half[k] * self.UpdVar.Area.values[i,k] * dti_ - - m_k * (dzi + self.detr_sc[i,k])) - c3 = m_km * dzi - c4 = m_k * self.entr_sc[i,k] - - self.UpdVar.H.new[i,k] = (c2 * self.UpdVar.H.values[i,k] + c3 * self.UpdVar.H.values[i,k-1] - + c4 * H_entr)/c1 - self.UpdVar.QT.new[i,k] = (c2 * self.UpdVar.QT.values[i,k] + c3 * self.UpdVar.QT.values[i,k-1] - + c4* QT_entr)/c1 - else: - self.UpdVar.H.new[i,k] = GMV.H.values[k] - self.UpdVar.QT.new[i,k] = GMV.QT.values[k] + self.UpdVar.H.new[i,k] = GMV.H.values[k] + self.UpdVar.QT.new[i,k] = GMV.QT.values[k] - # find new temperature - sa = eos(self.UpdThermo.t_to_prog_fp,self.UpdThermo.prog_to_t_fp, self.Ref.p0_half[k], + sa = eos(self.UpdThermo.t_to_prog_fp,self.UpdThermo.prog_to_t_fp, self.Ref.p0_c[k], self.UpdVar.QT.new[i,k], self.UpdVar.H.new[i,k]) - self.UpdVar.QL.new[i,k] = sa.ql - self.UpdVar.T.new[i,k] = sa.T - if self.use_local_micro: - # remove precipitation (pdate QT, QL and H) - self.UpdMicro.compute_update_combined_local_thetal(self.Ref.p0_half[k], self.UpdVar.T.new[i,k], + self.UpdVar.QL.new[i,k] = sa.ql + self.UpdVar.T.new[i,k] = sa.T + if self.use_local_micro: + self.UpdMicro.compute_update_combined_local_thetal(self.Ref.p0_c[k], self.UpdVar.T.new[i,k], &self.UpdVar.QT.new[i,k], &self.UpdVar.QL.new[i,k], &self.UpdVar.QR.new[i,k], &self.UpdVar.H.new[i,k], i, k) if self.use_local_micro: - # save the total source terms for H and QT due to precipitation - # TODO - add QR source - self.UpdMicro.prec_source_h_tot = np.sum(np.multiply(self.UpdMicro.prec_source_h, - self.UpdVar.Area.values), axis=0) - self.UpdMicro.prec_source_qt_tot = np.sum(np.multiply(self.UpdMicro.prec_source_qt, - self.UpdVar.Area.values), axis=0) + self.UpdMicro.prec_source_h_tot = np.sum(np.multiply(self.UpdMicro.prec_source_h,self.UpdVar.Area.values), axis=0) + self.UpdMicro.prec_source_qt_tot = np.sum(np.multiply(self.UpdMicro.prec_source_qt,self.UpdVar.Area.values), axis=0) else: - # Compute the updraft microphysical sources (precipitation) - #after the entrainment loop is finished self.UpdMicro.compute_sources(self.UpdVar) # Update updraft variables with microphysical source tendencies self.UpdMicro.update_updraftvars(self.UpdVar) - self.UpdVar.H.set_bcs(self.Gr) - self.UpdVar.QT.set_bcs(self.Gr) - self.UpdVar.QR.set_bcs(self.Gr) return - # After updating the updraft variables themselves: - # 1. compute the mass fluxes (currently not stored as class members, probably will want to do this - # for output purposes) - # 2. Apply mass flux tendencies and updraft microphysical tendencies to GMV.SomeVar.Values (old time step values) - # thereby updating to GMV.SomeVar.mf_update - # mass flux tendency is computed as 1st order upwind + cpdef upwind_integration(self, EDMF_Updrafts.UpdraftVariable area, EDMF_Updrafts.UpdraftVariable var, int k, int i, double env_var, double dzi): + cdef: + + double dti_ = 1.0/self.dt_upd + double dt_ = self.dt_upd + double adv, exch, press_buoy, press_drag, entr_term, buoy, press + double var_kp ,var_k, var_km, area_new, sgn_w + double au_lim = self.area_surface_bc[i] * self.max_area_factor + + if var.name == 'w': + buoy = self.Ref.rho0_c[k] * self.UpdVar.Area.values[i,k] * self.UpdVar.B.values[i,k] + press_buoy = - self.Ref.rho0_c[k] * self.UpdVar.Area.values[i,k] * self.UpdVar.B.values[i,k] * self.pressure_buoy_coeff + press_drag = - self.Ref.rho0_c[k]*(sqrt(self.UpdVar.Area.values[i,k] )*self.pressure_drag_coeff/self.pressure_plume_spacing + * (self.UpdVar.W.values[i,k] -self.EnvVar.W.values[k])*fabs(self.UpdVar.W.values[i,k] -self.EnvVar.W.values[k])) + press = press_buoy + press_drag + area_new = area.new[i,k] + var_kp = var.values[i,k+1] + var_k = var.values[i,k] + var_km = var.values[i,k-1] + self.updraft_pressure_sink[i,k] = press + + elif var.name == 'thetal' or var.name == 'qt': + area_new = area.new[i,k] + var_kp = var.values[i,k+1] + var_k = var.values[i,k] + var_km = var.values[i,k-1] + press = 0.0 + buoy = 0.0 + + elif var.name =='area_fraction': + area_new = 1.0 + var_kp = 1.0 + var_k = 1.0 + var_km = 1.0 + press = 0.0 + buoy = 0.0 + env_var = 1.0 + + with nogil: + if self.UpdVar.W.values[i,k]<0: + sgn_w = -1.0 + adv = (self.Ref.rho0_c[k+1] * area.values[i,k+1] * self.UpdVar.W.values[i,k+1] * var_kp + - self.Ref.rho0_c[k] *area.values[i,k] * self.UpdVar.W.values[i,k] * var_k )* dzi + else: + sgn_w = 1.0 + adv = (self.Ref.rho0_c[k] * area.values[i,k] * self.UpdVar.W.values[i,k] * var_k + - self.Ref.rho0_c[k-1] * area.values[i,k-1] * self.UpdVar.W.values[i,k-1] * var_km)* dzi + + exch = sgn_w*(self.Ref.rho0_c[k] * area.values[i,k] * self.UpdVar.W.values[i,k] + * (self.entr_sc[i,k] * env_var - self.detr_sc[i,k] * var_k )) + + var.new[i,k] = (self.Ref.rho0_c[k] * area.values[i,k] * var_k * dti_ -adv + exch + buoy + press)\ + /(self.Ref.rho0_c[k] * area_new * dti_) + + if var.name =='area_fraction': + var.new[i,k] = fmax(var.new[i,k] , 0.0) + entr_term = sgn_w *self.UpdVar.Area.values[i,k] * self.UpdVar.W.values[i,k] * self.entr_sc[i,k] + + if var.new[i,k] > au_lim: + var.new[i,k] = au_lim + if var.values[i,k] > 0.0: + self.detr_sc[i,k] = (((au_lim-var.values[i,k])* dti_ +self.Ref.alpha0_c[k] * adv - entr_term)/(-var.values[i,k] * self.UpdVar.W.values[i,k])) + else: + self.detr_sc[i,k] = (((au_lim-var.values[i,k])* dti_ +self.Ref.alpha0_c[k] * adv - entr_term)/(-au_lim * self.UpdVar.W.values[i,k])) + + # uncomment this for clipping and avoiding downward integration + # if var.name == 'w': + # if self.UpdVar.W.new[i,k] < 0.0: + # print 'clipping',k, self.UpdVar.W.new[i,k],self.UpdVar.Area.new[i,k] + # self.UpdVar.W.new[i,k] = 0.0 + # self.UpdVar.Area.new[i,k] = 0.0 + + return cpdef update_GMV_MF(self, GridMeanVariables GMV, TimeStepping TS): cdef: Py_ssize_t k, i Py_ssize_t gw = self.Gr.gw double mf_tend_h=0.0, mf_tend_qt=0.0 - double env_h_interp, env_qt_interp + double env_h_interp, env_qt_interp, dw_kp, dw_k self.massflux_h[:] = 0.0 self.massflux_qt[:] = 0.0 @@ -1082,8 +1096,9 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): for i in xrange(self.n_updrafts): self.m[i,gw-1] = 0.0 for k in xrange(self.Gr.gw, self.Gr.nzg-1): - self.m[i,k] = ((self.UpdVar.W.values[i,k] - self.EnvVar.W.values[k] )* self.Ref.rho0[k] - * interp2pt(self.UpdVar.Area.values[i,k],self.UpdVar.Area.values[i,k+1])) + dw_kp = (self.UpdVar.W.values[i,k+1] - self.EnvVar.W.values[k+1] ) + dw_k = (self.UpdVar.W.values[i,k] - self.EnvVar.W.values[k] ) + self.m[i,k] = interp2pt(dw_kp,dw_k)*self.Ref.rho0_f[k]*interp2pt(self.UpdVar.Area.values[i,k+1],self.UpdVar.Area.values[i,k]) self.massflux_h[gw-1] = 0.0 self.massflux_qt[gw-1] = 0.0 @@ -1099,13 +1114,14 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): self.massflux_qt[k] += self.m[i,k] * (interp2pt(self.UpdVar.QT.values[i,k], self.UpdVar.QT.values[i,k+1]) - env_qt_interp ) + # Compute the mass flux tendencies # Adjust the values of the grid mean variables with nogil: for k in xrange(self.Gr.gw, self.Gr.nzg): - mf_tend_h = -(self.massflux_h[k] - self.massflux_h[k-1]) * (self.Ref.alpha0_half[k] * self.Gr.dzi) - mf_tend_qt = -(self.massflux_qt[k] - self.massflux_qt[k-1]) * (self.Ref.alpha0_half[k] * self.Gr.dzi) + mf_tend_h = -(self.massflux_h[k] - self.massflux_h[k-1]) * (self.Ref.alpha0_c[k] * self.Gr.dzi) + mf_tend_qt = -(self.massflux_qt[k] - self.massflux_qt[k-1]) * (self.Ref.alpha0_c[k] * self.Gr.dzi) GMV.H.mf_update[k] = GMV.H.values[k] + TS.dt * mf_tend_h + self.UpdMicro.prec_source_h_tot[k] GMV.QT.mf_update[k] = GMV.QT.values[k] + TS.dt * mf_tend_qt + self.UpdMicro.prec_source_qt_tot[k] @@ -1117,7 +1133,6 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): self.massflux_tendency_h[k] = mf_tend_h self.massflux_tendency_qt[k] = mf_tend_qt - GMV.H.set_bcs(self.Gr) GMV.QT.set_bcs(self.Gr) GMV.QR.set_bcs(self.Gr) @@ -1146,17 +1161,17 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): with nogil: for k in xrange(nzg-1): - rho_ae_K_m[k] = 0.5 * (ae[k]*self.KH.values[k]+ ae[k+1]*self.KH.values[k+1]) * self.Ref.rho0[k] + rho_ae_K_m[k] = 0.5 * (ae[k]*self.KH.values[k]+ ae[k+1]*self.KH.values[k+1]) * self.Ref.rho0_f[k] # Matrix is the same for all variables that use the same eddy diffusivity, we can construct once and reuse - construct_tridiag_diffusion(nzg, gw, dzi, TS.dt, &rho_ae_K_m[0], &self.Ref.rho0_half[0], + construct_tridiag_diffusion(nzg, gw, dzi, TS.dt, &rho_ae_K_m[0], &self.Ref.rho0_c[0], &ae[0], &a[0], &b[0], &c[0]) # Solve QT with nogil: for k in xrange(nz): x[k] = self.EnvVar.QT.values[k+gw] - x[0] = x[0] + TS.dt * Case.Sur.rho_qtflux * dzi * self.Ref.alpha0_half[gw]/ae[gw] + x[0] = x[0] + TS.dt * Case.Sur.rho_qtflux * dzi * self.Ref.alpha0_c[gw]/ae[gw] tridiag_solve(self.Gr.nz, &x[0],&a[0], &b[0], &c[0]) with nogil: @@ -1165,13 +1180,13 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): # get the diffusive flux self.diffusive_flux_qt[gw] = interp2pt(Case.Sur.rho_qtflux, -rho_ae_K_m[gw] * dzi *(self.EnvVar.QT.values[gw+1]-self.EnvVar.QT.values[gw]) ) for k in xrange(self.Gr.gw+1, self.Gr.nzg-self.Gr.gw): - self.diffusive_flux_qt[k] = -0.5 * self.Ref.rho0_half[k]*ae[k] * self.KH.values[k] * dzi * (self.EnvVar.QT.values[k+1]-self.EnvVar.QT.values[k-1]) + self.diffusive_flux_qt[k] = -0.5 * self.Ref.rho0_c[k]*ae[k] * self.KH.values[k] * dzi * (self.EnvVar.QT.values[k+1]-self.EnvVar.QT.values[k-1]) # Solve H with nogil: for k in xrange(nz): x[k] = self.EnvVar.H.values[k+gw] - x[0] = x[0] + TS.dt * Case.Sur.rho_hflux * dzi * self.Ref.alpha0_half[gw]/ae[gw] + x[0] = x[0] + TS.dt * Case.Sur.rho_hflux * dzi * self.Ref.alpha0_c[gw]/ae[gw] tridiag_solve(self.Gr.nz, &x[0],&a[0], &b[0], &c[0]) with nogil: @@ -1181,20 +1196,20 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): # get the diffusive flux self.diffusive_flux_h[gw] = interp2pt(Case.Sur.rho_hflux, -rho_ae_K_m[gw] * dzi *(self.EnvVar.H.values[gw+1]-self.EnvVar.H.values[gw]) ) for k in xrange(self.Gr.gw+1, self.Gr.nzg-self.Gr.gw): - self.diffusive_flux_h[k] = -0.5 * self.Ref.rho0_half[k]*ae[k] * self.KH.values[k] * dzi * (self.EnvVar.H.values[k+1]-self.EnvVar.H.values[k-1]) + self.diffusive_flux_h[k] = -0.5 * self.Ref.rho0_c[k]*ae[k] * self.KH.values[k] * dzi * (self.EnvVar.H.values[k+1]-self.EnvVar.H.values[k-1]) # Solve U with nogil: for k in xrange(nzg-1): - rho_ae_K_m[k] = 0.5 * (ae[k]*self.KM.values[k]+ ae[k+1]*self.KM.values[k+1]) * self.Ref.rho0[k] + rho_ae_K_m[k] = 0.5 * (ae[k]*self.KM.values[k]+ ae[k+1]*self.KM.values[k+1]) * self.Ref.rho0_f[k] # Matrix is the same for all variables that use the same eddy diffusivity, we can construct once and reuse - construct_tridiag_diffusion(nzg, gw, dzi, TS.dt, &rho_ae_K_m[0], &self.Ref.rho0_half[0], + construct_tridiag_diffusion(nzg, gw, dzi, TS.dt, &rho_ae_K_m[0], &self.Ref.rho0_c[0], &ae[0], &a[0], &b[0], &c[0]) with nogil: for k in xrange(nz): x[k] = GMV.U.values[k+gw] - x[0] = x[0] + TS.dt * Case.Sur.rho_uflux * dzi * self.Ref.alpha0_half[gw]/ae[gw] + x[0] = x[0] + TS.dt * Case.Sur.rho_uflux * dzi * self.Ref.alpha0_c[gw]/ae[gw] tridiag_solve(self.Gr.nz, &x[0],&a[0], &b[0], &c[0]) with nogil: @@ -1205,7 +1220,7 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): with nogil: for k in xrange(nz): x[k] = GMV.V.values[k+gw] - x[0] = x[0] + TS.dt * Case.Sur.rho_vflux * dzi * self.Ref.alpha0_half[gw]/ae[gw] + x[0] = x[0] + TS.dt * Case.Sur.rho_vflux * dzi * self.Ref.alpha0_c[gw]/ae[gw] tridiag_solve(self.Gr.nz, &x[0],&a[0], &b[0], &c[0]) with nogil: @@ -1250,7 +1265,7 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): grad_thl_plus = (self.EnvVar.THL.values[k+1] - self.EnvVar.THL.values[k]) * self.Gr.dzi grad_qt_plus = (self.EnvVar.QT.values[k+1] - self.EnvVar.QT.values[k]) * self.Gr.dzi - prefactor = Rd * exner_c(self.Ref.p0_half[k])/self.Ref.p0_half[k] + prefactor = Rd * exner_c(self.Ref.p0_c[k])/self.Ref.p0_c[k] d_alpha_thetal_dry = prefactor * (1.0 + (eps_vi-1.0) * qt_dry) d_alpha_qt_dry = prefactor * th_dry * (eps_vi-1.0) @@ -1267,177 +1282,37 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): + (1.0-self.EnvVar.CF.values[k]) * d_alpha_thetal_dry) d_alpha_qt_total = (self.EnvVar.CF.values[k] * d_alpha_qt_cloudy + (1.0-self.EnvVar.CF.values[k]) * d_alpha_qt_dry) - - # TODO - check - self.tke_buoy[k] = g / self.Ref.alpha0_half[k] * ae[k] * self.Ref.rho0_half[k] \ + self.EnvVar.TKE.buoy[k] = g / self.Ref.alpha0_c[k] * ae[k] * self.Ref.rho0_c[k] \ * ( \ - self.KH.values[k] * interp2pt(grad_thl_plus, grad_thl_minus) * d_alpha_thetal_total \ - self.KH.values[k] * interp2pt(grad_qt_plus, grad_qt_minus) * d_alpha_qt_total\ ) - return - - - # Note we need mixing length again here.... - cpdef compute_tke_dissipation(self): - cdef: - Py_ssize_t k - double [:] ae = np.subtract(np.ones((self.Gr.nzg,),dtype=np.double, order='c'),self.UpdVar.Area.bulkvalues) - #tke diss coeff - - # does mixing length need to be recomputed? Even if no change in GMV.TKE, if updraft area changes - # this would change environmental tke (assuming it is still adjusted based on tke) - # first pass...assume we can re-use - with nogil: - for k in xrange(self.Gr.gw, self.Gr.nzg-self.Gr.gw): - self.tke_dissipation[k] = (self.Ref.rho0_half[k] * ae[k] * pow(fmax(self.EnvVar.TKE.values[k],0), 1.5) - /fmax(self.mixing_length[k],1.0) * self.tke_diss_coeff) + # yair - old verion had this without inter2pt maybe that made the difference ? return # Note updrafts' (total) entrainment rate = environment's (total) detrainment rate # and updrafts' (total) detrainment rate = environment's (total) entrainment rate # Therefore, fractional xxtrainment rates must be properly multiplied by the right component mass fluxes # Here we use the terminology entrainment/detrainment relative to the __environment__ - cpdef compute_tke_entr(self): - cdef: - Py_ssize_t i, k - double w_u, w_e - - with nogil: - for k in xrange(self.Gr.gw, self.Gr.nzg-self.Gr.gw): - self.tke_entr_gain[k] = 0.0 - w_e = interp2pt(self.EnvVar.W.values[k-1], self.EnvVar.W.values[k]) - for i in xrange(self.n_updrafts): - w_u = interp2pt(self.UpdVar.W.values[i,k-1], self.UpdVar.W.values[i,k]) - self.tke_entr_gain[k] += self.UpdVar.Area.values[i,k] * w_u * self.detr_sc[i,k] * (w_u - w_e) * (w_u - w_e) - self.tke_entr_gain[k] *= 0.5 * self.Ref.rho0_half[k] - return - - - cpdef compute_tke_detr(self): - cdef: - Py_ssize_t i, k - double w_u - - with nogil: - for k in xrange(self.Gr.gw, self.Gr.nzg-self.Gr.gw): - self.tke_detr_loss[k] = 0.0 - for i in xrange(self.n_updrafts): - w_u = interp2pt(self.UpdVar.W.values[i,k-1], self.UpdVar.W.values[i,k]) - self.tke_detr_loss[k] += self.UpdVar.Area.values[i,k] * w_u * self.entr_sc[i,k] - self.tke_detr_loss[k] *= self.Ref.rho0_half[k] * self.EnvVar.TKE.values[k] - return - - cpdef compute_tke_shear(self, GridMeanVariables GMV): - cdef: - Py_ssize_t k - Py_ssize_t gw = self.Gr.gw - double [:] ae = np.subtract(np.ones((self.Gr.nzg,),dtype=np.double, order='c'),self.UpdVar.Area.bulkvalues) # area of environment - double du_high = 0.0 - double dv_high = 0.0 - double dw_high = 2.0 * self.EnvVar.W.values[gw] * self.Gr.dzi - double du_low, dv_low, dw_low, - - with nogil: - for k in xrange(self.Gr.gw, self.Gr.nzg-self.Gr.gw): - du_low = du_high - dv_low = dv_high - dw_low = dw_high - du_high = (GMV.U.values[k+1] - GMV.U.values[k]) * self.Gr.dzi - dv_high = (GMV.V.values[k+1] - GMV.V.values[k]) * self.Gr.dzi - dw_high = (self.EnvVar.W.values[k+1] - self.EnvVar.W.values[k]) * self.Gr.dzi - self.tke_shear[k] =( self.Ref.rho0_half[k] * ae[k] * self.KM.values[k] * - ( pow(interp2pt(du_low, du_high),2.0) + pow(interp2pt(dv_low, dv_high),2.0) - + pow(interp2pt(dw_low, dw_high),2.0))) - return cpdef compute_tke_pressure(self): cdef: Py_ssize_t k Py_ssize_t gw = self.Gr.gw - double wu_half, we_half + double wu, we double press_buoy, press_drag with nogil: for k in xrange(self.Gr.gw, self.Gr.nzg-self.Gr.gw): - self.tke_pressure[k] = 0.0 + self.EnvVar.TKE.press[k] = 0.0 for i in xrange(self.n_updrafts): - wu_half = interp2pt(self.UpdVar.W.values[i,k-1], self.UpdVar.W.values[i,k]) - we_half = interp2pt(self.EnvVar.W.values[k-1], self.EnvVar.W.values[k]) - press_buoy= (-1.0 * self.Ref.rho0_half[k] * self.UpdVar.Area.values[i,k] + wu = self.UpdVar.W.values[i,k] + we = self.EnvVar.W.values[k] + press_buoy= (-1.0 * self.Ref.rho0_c[k] * self.UpdVar.Area.values[i,k] * self.UpdVar.B.values[i,k] * self.pressure_buoy_coeff) - press_drag = (-1.0 * self.Ref.rho0_half[k] * sqrt(self.UpdVar.Area.values[i,k]) - * (self.pressure_drag_coeff/self.pressure_plume_spacing* (wu_half -we_half)**2.0)) - self.tke_pressure[k] += (we_half - wu_half) * (press_buoy + press_drag) - return - - cpdef update_tke_ED(self, GridMeanVariables GMV, CasesBase Case,TimeStepping TS): - cdef: - Py_ssize_t k, kk, i - Py_ssize_t gw = self.Gr.gw - Py_ssize_t nzg = self.Gr.nzg - Py_ssize_t nz = self.Gr.nz - double dzi = self.Gr.dzi - double dti = TS.dti - double [:] a = np.zeros((nz,),dtype=np.double, order='c') # for tridiag solver - double [:] b = np.zeros((nz,),dtype=np.double, order='c') # for tridiag solver - double [:] c = np.zeros((nz,),dtype=np.double, order='c') # for tridiag solver - double [:] x = np.zeros((nz,),dtype=np.double, order='c') # for tridiag solver - double [:] ae = np.subtract(np.ones((nzg,),dtype=np.double, order='c'),self.UpdVar.Area.bulkvalues) # area of environment - double [:] ae_old = np.subtract(np.ones((nzg,),dtype=np.double, order='c'), np.sum(self.UpdVar.Area.old,axis=0)) - double [:] rho_ae_K_m = np.zeros((nzg,),dtype=np.double, order='c') - double [:] whalf = np.zeros((nzg,),dtype=np.double, order='c') - double D_env = 0.0 - double wu_half, we_half,a_half, tke_0_surf,press_k - - - - with nogil: - for k in xrange(1,nzg-1): - rho_ae_K_m[k] = 0.5 * (ae[k]*self.KM.values[k]+ ae[k+1]*self.KM.values[k+1]) * self.Ref.rho0[k] - whalf[k] = interp2pt(self.EnvVar.W.values[k-1], self.EnvVar.W.values[k]) - wu_half = interp2pt(self.UpdVar.W.bulkvalues[gw-1], self.UpdVar.W.bulkvalues[gw]) - GMV.TKE.values[gw] = get_surface_tke(Case.Sur.ustar, self.wstar, self.Gr.z_half[gw], Case.Sur.obukhov_length) - self.get_env_tke_from_GMV(self.UpdVar.Area, self.UpdVar.W, self.EnvVar.W, - self.EnvVar.TKE, &GMV.W.values[0], &GMV.TKE.values[0]) - - tke_0_surf = self.EnvVar.TKE.values[gw] - - - with nogil: - for kk in xrange(nz): - k = kk+gw - D_env = 0.0 - - for i in xrange(self.n_updrafts): - wu_half = interp2pt(self.UpdVar.W.values[i,k-1], self.UpdVar.W.values[i,k]) - D_env += self.Ref.rho0_half[k] * self.UpdVar.Area.values[i,k] * wu_half * self.entr_sc[i,k] - - a[kk] = (- rho_ae_K_m[k-1] * dzi * dzi ) - b[kk] = (self.Ref.rho0_half[k] * ae[k] * dti - self.Ref.rho0_half[k] * ae[k] * whalf[k] * dzi - + rho_ae_K_m[k] * dzi * dzi + rho_ae_K_m[k-1] * dzi * dzi - + D_env - + self.Ref.rho0_half[k] * ae[k] * self.tke_diss_coeff * sqrt(fmax(self.EnvVar.TKE.values[k],0.0))/fmax(self.mixing_length[k],1.0)) - c[kk] = (self.Ref.rho0_half[k+1] * ae[k+1] * whalf[k+1] * dzi - rho_ae_K_m[k] * dzi * dzi) - x[kk] = (self.Ref.rho0_half[k] * ae_old[k] * self.EnvVar.TKE.values[k] * dti - + self.tke_shear[k] + self.tke_buoy[k] + self.tke_entr_gain[k] + self.tke_pressure[k]) - a[0] = 0.0 - b[0] = 1.0 - c[0] = 0.0 - x[0] = tke_0_surf - - b[nz-1] += c[nz-1] - c[nz-1] = 0.0 - tridiag_solve(self.Gr.nz, &x[0],&a[0], &b[0], &c[0]) - - with nogil: - for kk in xrange(nz): - k = kk + gw - self.EnvVar.TKE.values[k] = fmax(x[kk], 0.0) - wu_half = interp2pt(self.UpdVar.W.bulkvalues[k-1], self.UpdVar.W.bulkvalues[k]) - - self.get_GMV_TKE(self.UpdVar.Area,self.UpdVar.W, self.EnvVar.W, self.EnvVar.TKE, - &GMV.W.values[0], &GMV.TKE.values[0]) - + press_drag = (-1.0 * self.Ref.rho0_c[k] * sqrt(self.UpdVar.Area.values[i,k]) + * (self.pressure_drag_coeff/self.pressure_plume_spacing*(wu -we)*fabs(wu -we))) + self.EnvVar.TKE.press[k] += (we - wu) * (press_buoy + press_drag) return cpdef update_GMV_diagnostics(self, GridMeanVariables GMV): @@ -1445,7 +1320,6 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): Py_ssize_t k double qv, alpha - with nogil: for k in xrange(self.Gr.gw, self.Gr.nzg-self.Gr.gw): GMV.QL.values[k] = (self.UpdVar.Area.bulkvalues[k] * self.UpdVar.QL.bulkvalues[k] @@ -1459,53 +1333,90 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): + (1.0 - self.UpdVar.Area.bulkvalues[k]) * self.EnvVar.T.values[k]) qv = GMV.QT.values[k] - GMV.QL.values[k] - GMV.THL.values[k] = t_to_thetali_c(self.Ref.p0_half[k], GMV.T.values[k], GMV.QT.values[k], + GMV.THL.values[k] = t_to_thetali_c(self.Ref.p0_c[k], GMV.T.values[k], GMV.QT.values[k], GMV.QL.values[k], 0.0) - - GMV.B.values[k] = (self.UpdVar.Area.bulkvalues[k] * self.UpdVar.B.bulkvalues[k] + (1.0 - self.UpdVar.Area.bulkvalues[k]) * self.EnvVar.B.values[k]) - return - - cpdef compute_covariance(self, GridMeanVariables GMV, CasesBase Case, TimeStepping TS): - #if TS.nstep > 0: #TODO - its already initialized in t=0 here + #if TS.nstep > 0: if self.similarity_diffusivity: # otherwise, we computed mixing length when we computed - self.compute_mixing_length(Case.Sur.obukhov_length) + self.compute_mixing_length(Case.Sur.obukhov_length, GMV) + if self.calc_tke: + self.compute_tke_buoy(GMV) + self.compute_covariance_entr(self.EnvVar.TKE, self.UpdVar.W, self.UpdVar.W, self.EnvVar.W, self.EnvVar.W) + self.compute_covariance_shear(GMV, self.EnvVar.TKE, &self.UpdVar.W.values[0,0], &self.UpdVar.W.values[0,0], &self.EnvVar.W.values[0], &self.EnvVar.W.values[0]) + self.compute_covariance_interdomain_src(self.UpdVar.Area,self.UpdVar.W,self.UpdVar.W,self.EnvVar.W, self.EnvVar.W, self.EnvVar.TKE) + self.compute_tke_pressure() + if self.calc_scalar_var: + self.compute_covariance_entr(self.EnvVar.Hvar, self.UpdVar.H, self.UpdVar.H, self.EnvVar.H, self.EnvVar.H) + self.compute_covariance_entr(self.EnvVar.QTvar, self.UpdVar.QT, self.UpdVar.QT, self.EnvVar.QT, self.EnvVar.QT) + self.compute_covariance_entr(self.EnvVar.HQTcov, self.UpdVar.H, self.UpdVar.QT, self.EnvVar.H, self.EnvVar.QT) + self.compute_covariance_shear(GMV, self.EnvVar.Hvar, &self.UpdVar.H.values[0,0], &self.UpdVar.H.values[0,0], &self.EnvVar.H.values[0], &self.EnvVar.H.values[0]) + self.compute_covariance_shear(GMV, self.EnvVar.QTvar, &self.UpdVar.QT.values[0,0], &self.UpdVar.QT.values[0,0], &self.EnvVar.QT.values[0], &self.EnvVar.QT.values[0]) + self.compute_covariance_shear(GMV, self.EnvVar.HQTcov, &self.UpdVar.H.values[0,0], &self.UpdVar.QT.values[0,0], &self.EnvVar.H.values[0], &self.EnvVar.QT.values[0]) + self.compute_covariance_interdomain_src(self.UpdVar.Area,self.UpdVar.H,self.UpdVar.H,self.EnvVar.H, self.EnvVar.H, self.EnvVar.Hvar) + self.compute_covariance_interdomain_src(self.UpdVar.Area,self.UpdVar.QT,self.UpdVar.QT,self.EnvVar.QT, self.EnvVar.QT, self.EnvVar.QTvar) + self.compute_covariance_interdomain_src(self.UpdVar.Area,self.UpdVar.H,self.UpdVar.QT,self.EnvVar.H, self.EnvVar.QT, self.EnvVar.HQTcov) + self.compute_covariance_rain(TS, GMV) # need to update this one - self.compute_covariance_entr() - self.compute_covariance_shear(GMV) - self.compute_covariance_rain(TS, GMV) self.reset_surface_covariance(GMV, Case) - self.update_covariance_ED(GMV, Case, TS) - self.cleanup_covariance(GMV) - #else: #TODO - its initialized in the update calls - # self.initialize_covariance(GMV, Case) - + if self.calc_tke: + self.update_covariance_ED(GMV, Case,TS, GMV.W, GMV.W, GMV.TKE, self.EnvVar.TKE, self.EnvVar.W, self.EnvVar.W, self.UpdVar.W, self.UpdVar.W) + if self.calc_scalar_var: + self.update_covariance_ED(GMV, Case,TS, GMV.H, GMV.H, GMV.Hvar, self.EnvVar.Hvar, self.EnvVar.H, self.EnvVar.H, self.UpdVar.H, self.UpdVar.H) + self.update_covariance_ED(GMV, Case,TS, GMV.QT,GMV.QT, GMV.QTvar, self.EnvVar.QTvar, self.EnvVar.QT, self.EnvVar.QT, self.UpdVar.QT, self.UpdVar.QT) + self.update_covariance_ED(GMV, Case,TS, GMV.H, GMV.QT, GMV.HQTcov, self.EnvVar.HQTcov, self.EnvVar.H, self.EnvVar.QT, self.UpdVar.H, self.UpdVar.QT) + self.cleanup_covariance(GMV) return - cpdef initialize_covariance(self, GridMeanVariables GMV, CasesBase Case): cdef: Py_ssize_t k - double ws= self.wstar, us = Case.Sur.ustar, zs = self.zi, z self.reset_surface_covariance(GMV, Case) - with nogil: - for k in xrange(self.Gr.nzg): - z = self.Gr.z_half[k] - GMV.Hvar.values[k] = GMV.Hvar.values[self.Gr.gw] * GMV.TKE.values[k] / GMV.TKE.values[self.Gr.gw] - GMV.QTvar.values[k] = GMV.QTvar.values[self.Gr.gw] * GMV.TKE.values[k] / GMV.TKE.values[self.Gr.gw] - GMV.HQTcov.values[k] = GMV.HQTcov.values[self.Gr.gw] * GMV.TKE.values[k] / GMV.TKE.values[self.Gr.gw] + if self.calc_tke: + if ws > 0.0: + with nogil: + for k in xrange(self.Gr.nzg): + z = self.Gr.z_c[k] + GMV.TKE.values[k] = ws * 1.3 * cbrt((us*us*us)/(ws*ws*ws) + 0.6 * z/zs) * sqrt(fmax(1.0-z/zs,0.0)) + if self.calc_scalar_var: + if ws > 0.0: + with nogil: + for k in xrange(self.Gr.nzg): + z = self.Gr.z_c[k] + # need to rethink of how to initilize the covarinace profiles - for nowmI took the TKE profile + GMV.Hvar.values[k] = GMV.Hvar.values[self.Gr.gw] * ws * 1.3 * cbrt((us*us*us)/(ws*ws*ws) + 0.6 * z/zs) * sqrt(fmax(1.0-z/zs,0.0)) + GMV.QTvar.values[k] = GMV.QTvar.values[self.Gr.gw] * ws * 1.3 * cbrt((us*us*us)/(ws*ws*ws) + 0.6 * z/zs) * sqrt(fmax(1.0-z/zs,0.0)) + GMV.HQTcov.values[k] = GMV.HQTcov.values[self.Gr.gw] * ws * 1.3 * cbrt((us*us*us)/(ws*ws*ws) + 0.6 * z/zs) * sqrt(fmax(1.0-z/zs,0.0)) + self.reset_surface_covariance(GMV, Case) + self.compute_mixing_length(Case.Sur.obukhov_length, GMV) - self.compute_mixing_length(Case.Sur.obukhov_length) + return + cpdef reset_surface_covariance(self, GridMeanVariables GMV, CasesBase Case): + flux1 = Case.Sur.rho_hflux + flux2 = Case.Sur.rho_qtflux + cdef: + double zLL = self.Gr.z_c[self.Gr.gw] + double ustar = Case.Sur.ustar, oblength = Case.Sur.obukhov_length + double alpha0LL = self.Ref.alpha0_c[self.Gr.gw] + #double get_surface_variance = get_surface_variance(flux1, flux2 ,ustar, zLL, oblength) + if self.calc_tke: + GMV.TKE.values[self.Gr.gw] = get_surface_tke(Case.Sur.ustar, + self.wstar, + self.Gr.z_c[self.Gr.gw], + Case.Sur.obukhov_length) + if self.calc_scalar_var: + GMV.Hvar.values[self.Gr.gw] = get_surface_variance(flux1*alpha0LL,flux1*alpha0LL, ustar, zLL, oblength) + GMV.QTvar.values[self.Gr.gw] = get_surface_variance(flux2*alpha0LL,flux2*alpha0LL, ustar, zLL, oblength) + GMV.HQTcov.values[self.Gr.gw] = get_surface_variance(flux1*alpha0LL,flux2*alpha0LL, ustar, zLL, oblength) return cpdef cleanup_covariance(self, GridMeanVariables GMV): @@ -1518,75 +1429,105 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): GMV.Hvar.values[k] = 0.0 if GMV.QTvar.values[k] < tmp_eps: GMV.QTvar.values[k] = 0.0 + if fabs(GMV.HQTcov.values[k]) < tmp_eps: + GMV.HQTcov.values[k] = 0.0 if self.EnvVar.Hvar.values[k] < tmp_eps: self.EnvVar.Hvar.values[k] = 0.0 if self.EnvVar.QTvar.values[k] < tmp_eps: self.EnvVar.QTvar.values[k] = 0.0 + if fabs(self.EnvVar.HQTcov.values[k]) < tmp_eps: + self.EnvVar.HQTcov.values[k] = 0.0 + + return - cpdef compute_covariance_shear(self, GridMeanVariables GMV): + cdef void compute_covariance_shear(self,GridMeanVariables GMV, EDMF_Environment.EnvironmentVariable_2m Covar, double *UpdVar1, double *UpdVar2, double *EnvVar1, double *EnvVar2): cdef: Py_ssize_t k Py_ssize_t gw = self.Gr.gw - double [:] ae = np.subtract(np.ones((self.Gr.nzg,),dtype=np.double, order='c'),self.UpdVar.Area.bulkvalues) # area of environment - double dH_high = 0.0 - double dQT_high = 0.0 - double dH_low, dQT_low + double [:] ae = np.subtract(np.ones((self.Gr.nzg,),dtype=np.double, order='c'),self.UpdVar.Area.bulkvalues) + double diff_var1 = 0.0 + double diff_var2 = 0.0 + double du = 0.0 + double dv = 0.0 + double tke_factor = 1.0 + + for k in xrange(self.Gr.gw, self.Gr.nzg-self.Gr.gw): + if Covar.name == 'tke': + du = (GMV.U.values[k+1] - GMV.U.values[k-1]) * self.Gr.dzi/2.0 + dv = (GMV.V.values[k+1] - GMV.V.values[k-1]) * self.Gr.dzi/2.0 + tke_factor = 0.5 + with nogil: + diff_var1 = (EnvVar1[k+1] - EnvVar1[k-1]) * self.Gr.dzi/2.0 + diff_var2 = (EnvVar2[k+1] - EnvVar2[k-1]) * self.Gr.dzi/2.0 + Covar.shear[k] = tke_factor*2.0*(self.Ref.rho0_c[k] * ae[k] * self.KH.values[k] * + (diff_var1*diff_var2 + pow(du,2.0) + pow(dv,2.0))) + return + + cdef void compute_covariance_interdomain_src(self, EDMF_Updrafts.UpdraftVariable au, + EDMF_Updrafts.UpdraftVariable phi_u, EDMF_Updrafts.UpdraftVariable psi_u, + EDMF_Environment.EnvironmentVariable phi_e, EDMF_Environment.EnvironmentVariable psi_e, + EDMF_Environment.EnvironmentVariable_2m Covar): + cdef: + Py_ssize_t i,k + double phi_diff, psi_diff, tke_factor + + if Covar.name == 'tke': + tke_factor = 0.5 + else: + tke_factor = 1.0 + + with nogil: + for k in xrange(self.Gr.nzg): + Covar.interdomain[k] = 0.0 + for i in xrange(self.n_updrafts): + phi_diff = phi_u.values[i,k]-phi_e.values[k] + psi_diff = psi_u.values[i,k]-psi_e.values[k] + Covar.interdomain[k] += tke_factor*au.values[i,k] * (1.0-au.values[i,k]) * phi_diff * psi_diff + return + + cdef void compute_covariance_dissipation(self, EDMF_Environment.EnvironmentVariable_2m Covar): + cdef: + Py_ssize_t i + double m + Py_ssize_t k + double [:] ae = np.subtract(np.ones((self.Gr.nzg,),dtype=np.double, order='c'),self.UpdVar.Area.bulkvalues) with nogil: for k in xrange(self.Gr.gw, self.Gr.nzg-self.Gr.gw): - dH_low = dH_high - dH_high = (self.EnvVar.H.values[k+1] - self.EnvVar.H.values[k]) * self.Gr.dzi - dQT_low = dQT_high - dQT_high = (self.EnvVar.QT.values[k+1] - self.EnvVar.QT.values[k]) * self.Gr.dzi - self.Hvar_shear[k] = 2.0*(self.Ref.rho0_half[k] * ae[k] * self.KH.values[k] *pow(interp2pt(dH_low, dH_high),2.0)) - self.QTvar_shear[k] = 2.0*(self.Ref.rho0_half[k] * ae[k] * self.KH.values[k] *pow(interp2pt(dQT_low, dQT_high),2.0)) - self.HQTcov_shear[k] = 2.0*(self.Ref.rho0_half[k] * ae[k] * self.KH.values[k] *interp2pt(dH_low, dH_high)*interp2pt(dQT_low, dQT_high)) + Covar.dissipation[k] = (self.Ref.rho0_c[k] * ae[k] * Covar.values[k] + *pow(fmax(self.EnvVar.TKE.values[k],0), 0.5)/fmax(self.mixing_length[k],1.0) * self.tke_diss_coeff) return - cpdef compute_covariance_entr(self): + cdef void compute_covariance_entr(self, EDMF_Environment.EnvironmentVariable_2m Covar, EDMF_Updrafts.UpdraftVariable UpdVar1, + EDMF_Updrafts.UpdraftVariable UpdVar2, EDMF_Environment.EnvironmentVariable EnvVar1, EDMF_Environment.EnvironmentVariable EnvVar2): cdef: Py_ssize_t i, k - double H_u, H_env, QT_u, QT_env + double tke_factor = 1.0 + if Covar.name =='tke': + tke_factor = 0.5 with nogil: for k in xrange(self.Gr.gw, self.Gr.nzg-self.Gr.gw): - self.Hvar_entr_gain[k] = 0.0 - self.QTvar_entr_gain[k] = 0.0 - self.HQTcov_entr_gain[k] = 0.0 - H_env = self.EnvVar.H.values[k] - QT_env = self.EnvVar.QT.values[k] + Covar.entr_gain[k] = 0.0 for i in xrange(self.n_updrafts): - H_u = self.UpdVar.H.values[i,k] - QT_u = self.UpdVar.QT.values[i,k] - w_u = interp2pt(self.UpdVar.W.values[i,k-1], self.UpdVar.W.values[i,k]) - self.Hvar_entr_gain[k] += self.UpdVar.Area.values[i,k] * w_u * self.detr_sc[i,k] * (H_u - H_env) * (H_u - H_env) - self.QTvar_entr_gain[k] += self.UpdVar.Area.values[i,k] * w_u * self.detr_sc[i,k] * (QT_u - QT_env) * (QT_u - QT_env) - self.HQTcov_entr_gain[k] += self.UpdVar.Area.values[i,k] * w_u * self.detr_sc[i,k] * (H_u - H_env) * (QT_u - QT_env) - self.Hvar_entr_gain[k] *= self.Ref.rho0_half[k] - self.QTvar_entr_gain[k] *= self.Ref.rho0_half[k] - self.HQTcov_entr_gain[k] *= self.Ref.rho0_half[k] + Covar.entr_gain[k] += tke_factor*self.UpdVar.Area.values[i,k] * fabs(self.UpdVar.W.values[i,k]) * self.detr_sc[i,k] * \ + (UpdVar1.values[i,k] - EnvVar1.values[k]) * (UpdVar2.values[i,k] - EnvVar2.values[k]) + Covar.entr_gain[k] *= self.Ref.rho0_c[k] return - cpdef compute_covariance_detr(self): + cdef void compute_covariance_detr(self, EDMF_Environment.EnvironmentVariable_2m Covar): cdef: Py_ssize_t i, k - with nogil: for k in xrange(self.Gr.gw, self.Gr.nzg-self.Gr.gw): - self.Hvar_detr_loss[k] = 0.0 - self.QTvar_detr_loss[k] = 0.0 - self.HQTcov_detr_loss[k] = 0.0 + Covar.detr_loss[k] = 0.0 for i in xrange(self.n_updrafts): - w_u = interp2pt(self.UpdVar.W.values[i,k-1], self.UpdVar.W.values[i,k]) - self.Hvar_detr_loss[k] += self.UpdVar.Area.values[i,k] * w_u * self.entr_sc[i,k] - self.QTvar_detr_loss[k] += self.UpdVar.Area.values[i,k] * w_u * self.entr_sc[i,k] - self.HQTcov_detr_loss[k] += self.UpdVar.Area.values[i,k] * w_u * self.entr_sc[i,k] - self.Hvar_detr_loss[k] *= self.Ref.rho0_half[k] * self.EnvVar.Hvar.values[k] - self.QTvar_detr_loss[k] *= self.Ref.rho0_half[k] * self.EnvVar.QTvar.values[k] - self.HQTcov_detr_loss[k] *= self.Ref.rho0_half[k] * self.EnvVar.HQTcov.values[k] + Covar.detr_loss[k] += self.UpdVar.Area.values[i,k] * fabs(self.UpdVar.W.values[i,k]) * self.entr_sc[i,k] + Covar.detr_loss[k] *= self.Ref.rho0_c[k] * Covar.values[k] return + cpdef compute_covariance_rain(self, TimeStepping TS, GridMeanVariables GMV): cdef: Py_ssize_t i, k @@ -1595,13 +1536,16 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): with nogil: for k in xrange(self.Gr.gw, self.Gr.nzg-self.Gr.gw): - self.Hvar_rain[k] = self.Ref.rho0_half[k] * ae[k] * 2. * self.EnvThermo.Hvar_rain_dt[k] * TS.dti - self.QTvar_rain[k] = self.Ref.rho0_half[k] * ae[k] * 2. * self.EnvThermo.QTvar_rain_dt[k] * TS.dti - self.HQTcov_rain[k] = self.Ref.rho0_half[k] * ae[k] * self.EnvThermo.HQTcov_rain_dt[k] * TS.dti + self.EnvVar.TKE.rain_src[k] = 0.0 + self.EnvVar.Hvar.rain_src[k] = self.Ref.rho0_c[k] * ae[k] * 2. * self.EnvThermo.Hvar_rain_dt[k] * TS.dti + self.EnvVar.QTvar.rain_src[k] = self.Ref.rho0_c[k] * ae[k] * 2. * self.EnvThermo.QTvar_rain_dt[k] * TS.dti + self.EnvVar.HQTcov.rain_src[k] = self.Ref.rho0_c[k] * ae[k] * self.EnvThermo.HQTcov_rain_dt[k] * TS.dti return - cpdef update_covariance_ED(self, GridMeanVariables GMV, CasesBase Case,TimeStepping TS): + cdef void update_covariance_ED(self, GridMeanVariables GMV, CasesBase Case,TimeStepping TS, VariablePrognostic GmvVar1, VariablePrognostic GmvVar2, + VariableDiagnostic GmvCovar, EDMF_Environment.EnvironmentVariable_2m Covar, EDMF_Environment.EnvironmentVariable EnvVar1, EDMF_Environment.EnvironmentVariable EnvVar2, + EDMF_Updrafts.UpdraftVariable UpdVar1, EDMF_Updrafts.UpdraftVariable UpdVar2): cdef: Py_ssize_t k, kk, i Py_ssize_t gw = self.Gr.gw @@ -1609,184 +1553,114 @@ cdef class EDMF_PrognosticTKE(ParameterizationBase): Py_ssize_t nz = self.Gr.nz double dzi = self.Gr.dzi double dti = TS.dti - double alpha0LL = self.Ref.alpha0_half[self.Gr.gw] - double zLL = self.Gr.z_half[self.Gr.gw] - double [:] a = np.zeros((nz,),dtype=np.double, order='c') # for tridiag solver - double [:] b = np.zeros((nz,),dtype=np.double, order='c') # for tridiag solver - double [:] c = np.zeros((nz,),dtype=np.double, order='c') # for tridiag solver - double [:] x = np.zeros((nz,),dtype=np.double, order='c') # for tridiag solver - double [:] ae = np.subtract(np.ones((nzg,),dtype=np.double, order='c'),self.UpdVar.Area.bulkvalues) # area of environment + double alpha0LL = self.Ref.alpha0_c[self.Gr.gw] + double zLL = self.Gr.z_c[self.Gr.gw] + double [:] a = np.zeros((nz,),dtype=np.double, order='c') + double [:] b = np.zeros((nz,),dtype=np.double, order='c') + double [:] c = np.zeros((nz,),dtype=np.double, order='c') + double [:] x = np.zeros((nz,),dtype=np.double, order='c') + double [:] ae = np.subtract(np.ones((nzg,),dtype=np.double, order='c'),self.UpdVar.Area.bulkvalues) double [:] ae_old = np.subtract(np.ones((nzg,),dtype=np.double, order='c'), np.sum(self.UpdVar.Area.old,axis=0)) double [:] rho_ae_K_m = np.zeros((nzg,),dtype=np.double, order='c') - double [:] whalf = np.zeros((nzg,),dtype=np.double, order='c') - double [:] Hhalf = np.zeros((nzg,),dtype=np.double, order='c') - double [:] QThalf = np.zeros((nzg,),dtype=np.double, order='c') - double D_env = 0.0 - double Hu_half, He_half, a_half, QTu_half, QTe_half - double wu_half, we_half, Hvar_0_surf, QTvar_0_surf, HQTcov_0_surf - + double Covar_surf with nogil: for k in xrange(1,nzg-1): - rho_ae_K_m[k] = 0.5 * (ae[k]*self.KH.values[k]+ ae[k+1]*self.KH.values[k+1]) * self.Ref.rho0[k] - whalf[k] = interp2pt(self.EnvVar.W.values[k-1], self.EnvVar.W.values[k]) - Hhalf[k] = self.EnvVar.H.values[k] - QThalf[k] = self.EnvVar.QT.values[k] - wu_half = interp2pt(self.UpdVar.W.bulkvalues[gw-1], self.UpdVar.W.bulkvalues[gw]) - Hu_half = self.UpdVar.H.bulkvalues[gw] - QTu_half = self.UpdVar.QT.bulkvalues[gw] - - GMV.Hvar.values[gw] = get_surface_variance(Case.Sur.rho_hflux * alpha0LL, Case.Sur.rho_hflux * alpha0LL, Case.Sur.ustar, zLL, Case.Sur.obukhov_length) - GMV.QTvar.values[gw] = get_surface_variance(Case.Sur.rho_qtflux * alpha0LL, Case.Sur.rho_qtflux * alpha0LL, Case.Sur.ustar, zLL, Case.Sur.obukhov_length) - GMV.HQTcov.values[gw] = get_surface_variance(Case.Sur.rho_hflux * alpha0LL, Case.Sur.rho_qtflux * alpha0LL, Case.Sur.ustar, zLL, Case.Sur.obukhov_length) - self.get_env_covar_from_GMV(self.UpdVar.Area, self.UpdVar.H, self.UpdVar.H, self.EnvVar.H, self.EnvVar.H, - self.EnvVar.Hvar, &GMV.H.values[0], &GMV.H.values[0], &GMV.Hvar.values[0]) - self.get_env_covar_from_GMV(self.UpdVar.Area, self.UpdVar.QT, self.UpdVar.QT, self.EnvVar.QT, self.EnvVar.QT, - self.EnvVar.QTvar, &GMV.QT.values[0], &GMV.QT.values[0], &GMV.QTvar.values[0]) - self.get_env_covar_from_GMV(self.UpdVar.Area, self.UpdVar.H, self.UpdVar.QT, self.EnvVar.H, self.EnvVar.QT, - self.EnvVar.HQTcov, &GMV.H.values[0], &GMV.QT.values[0], &GMV.HQTcov.values[0]) - + rho_ae_K_m[k] = 0.5 * (ae[k]*self.KH.values[k]+ ae[k+1]*self.KH.values[k+1])* self.Ref.rho0_f[k] + if GmvCovar.name=='tke': + GmvCovar.values[gw] =get_surface_tke(Case.Sur.ustar, self.wstar, self.Gr.z_c[gw], Case.Sur.obukhov_length) + elif GmvCovar.name=='thetal_var': + GmvCovar.values[gw] = get_surface_variance(Case.Sur.rho_hflux * alpha0LL, Case.Sur.rho_hflux * alpha0LL, Case.Sur.ustar, zLL, Case.Sur.obukhov_length) + elif GmvCovar.name=='qt_var': + GmvCovar.values[gw] = get_surface_variance(Case.Sur.rho_qtflux * alpha0LL, Case.Sur.rho_qtflux * alpha0LL, Case.Sur.ustar, zLL, Case.Sur.obukhov_length) + elif GmvCovar.name=='thetal_qt_covar': + GmvCovar.values[gw] = get_surface_variance(Case.Sur.rho_hflux * alpha0LL, Case.Sur.rho_qtflux * alpha0LL, Case.Sur.ustar, zLL, Case.Sur.obukhov_length) - # BC at the surface - Hvar_0_surf = self.EnvVar.Hvar.values[gw] - QTvar_0_surf = self.EnvVar.QTvar.values[gw] - HQTcov_0_surf = self.EnvVar.HQTcov.values[gw] + self.get_env_covar_from_GMV(self.UpdVar.Area, UpdVar1, UpdVar2, EnvVar1, EnvVar2, Covar, &GmvVar1.values[0], &GmvVar2.values[0], &GmvCovar.values[0]) - # run tridiagonal solver for Hvar - with nogil: - for kk in xrange(nz): - k = kk+gw - D_env = 0.0 - - for i in xrange(self.n_updrafts): - wu_half = interp2pt(self.UpdVar.W.values[i,k-1], self.UpdVar.W.values[i,k]) - D_env += self.Ref.rho0_half[k] * self.UpdVar.Area.values[i,k] * wu_half * self.entr_sc[i,k] - - a[kk] = (- rho_ae_K_m[k-1] * dzi * dzi ) - b[kk] = (self.Ref.rho0_half[k] * ae[k] * dti - self.Ref.rho0_half[k] * ae[k] * whalf[k] * dzi - + rho_ae_K_m[k] * dzi * dzi + rho_ae_K_m[k-1] * dzi * dzi - + D_env - + self.Ref.rho0_half[k] * ae[k] *sqrt(fmax(self.EnvVar.TKE.values[k],0))/fmax(self.mixing_length[k],1.0) * self.tke_diss_coeff) - c[kk] = (self.Ref.rho0_half[k+1] * ae[k+1] * whalf[k+1] * dzi - rho_ae_K_m[k] * dzi * dzi) - x[kk] = (self.Ref.rho0_half[k] * ae_old[k] * self.EnvVar.Hvar.values[k] * dti - + self.Hvar_shear[k] + self.Hvar_entr_gain[k] + self.Hvar_rain[k]) - - a[0] = 0.0 - b[0] = 1.0 - c[0] = 0.0 - x[0] = Hvar_0_surf - - b[nz-1] += c[nz-1] - c[nz-1] = 0.0 - tridiag_solve(self.Gr.nz, &x[0],&a[0], &b[0], &c[0]) - - with nogil: - for kk in xrange(nz): - k = kk + gw - self.EnvVar.Hvar.values[k] = x[kk] - GMV.Hvar.values[k] = (ae[k] * (self.EnvVar.Hvar.values[k] + (Hhalf[k]-GMV.H.values[k]) * (Hhalf[k]-GMV.H.values[k])) - + self.UpdVar.Area.bulkvalues[k] * (self.UpdVar.H.bulkvalues[k]-GMV.H.values[k]) * (self.UpdVar.H.bulkvalues[k]-GMV.H.values[k])) - - self.get_GMV_CoVar(self.UpdVar.Area, self.UpdVar.H, self.UpdVar.H, self.EnvVar.H, self.EnvVar.H, self.EnvVar.Hvar, - &GMV.H.values[0],&GMV.H.values[0], &GMV.Hvar.values[0]) - - # run tridiagonal solver for QTvar - with nogil: - for kk in xrange(nz): - k = kk+gw - D_env = 0.0 - - for i in xrange(self.n_updrafts): - wu_half = interp2pt(self.UpdVar.W.values[i,k-1], self.UpdVar.W.values[i,k]) - D_env += self.Ref.rho0_half[k] * self.UpdVar.Area.values[i,k] * wu_half * self.entr_sc[i,k] - - a[kk] = (- rho_ae_K_m[k-1] * dzi * dzi ) - b[kk] = (self.Ref.rho0_half[k] * ae[k] * dti - self.Ref.rho0_half[k] * ae[k] * whalf[k] * dzi - + rho_ae_K_m[k] * dzi * dzi + rho_ae_K_m[k-1] * dzi * dzi - + D_env - + self.Ref.rho0_half[k] * ae[k] * pow(fmax(self.EnvVar.TKE.values[k],0), 0.5)/fmax(self.mixing_length[k],1.0) * self.tke_diss_coeff) - c[kk] = (self.Ref.rho0_half[k+1] * ae[k+1] * whalf[k+1] * dzi - rho_ae_K_m[k] * dzi * dzi) - x[kk] = (self.Ref.rho0_half[k] * ae_old[k] * self.EnvVar.QTvar.values[k] * dti - + self.QTvar_shear[k] + self.QTvar_entr_gain[k] + self.QTvar_rain[k]) - - a[0] = 0.0 - b[0] = 1.0 - c[0] = 0.0 - x[0] = QTvar_0_surf - - b[nz-1] += c[nz-1] - c[nz-1] = 0.0 - tridiag_solve(self.Gr.nz, &x[0],&a[0], &b[0], &c[0]) - - with nogil: - for kk in xrange(nz): - k = kk + gw - #self.EnvVar.Hvar.values[k] = fmax(x[kk], 0.0) - self.EnvVar.QTvar.values[k] = x[kk] - GMV.QTvar.values[k] = (ae[k] * (self.EnvVar.QTvar.values[k] + (QThalf[k]-GMV.QT.values[k]) * (QThalf[k]-GMV.QT.values[k])) - + self.UpdVar.Area.bulkvalues[k] * (self.UpdVar.QT.bulkvalues[k]-GMV.QT.values[k]) * (self.UpdVar.QT.bulkvalues[k]-GMV.QT.values[k])) - - self.get_GMV_CoVar(self.UpdVar.Area, self.UpdVar.QT, self.UpdVar.QT, self.EnvVar.QT, self.EnvVar.QT, self.EnvVar.QTvar, - &GMV.QT.values[0],&GMV.QT.values[0], &GMV.QTvar.values[0]) + Covar_surf = Covar.values[gw] - # run tridiagonal solver for HQTcov with nogil: for kk in xrange(nz): k = kk+gw D_env = 0.0 for i in xrange(self.n_updrafts): - wu_half = self.UpdVar.W.values[i,k] - D_env += self.Ref.rho0_half[k] * self.UpdVar.Area.values[i,k] * wu_half * self.entr_sc[i,k] + D_env += self.Ref.rho0_c[k] * self.UpdVar.Area.values[i,k] * self.UpdVar.W.values[i,k] * self.entr_sc[i,k] a[kk] = (- rho_ae_K_m[k-1] * dzi * dzi ) - b[kk] = (self.Ref.rho0_half[k] * ae[k] * dti - self.Ref.rho0_half[k] * ae[k] * whalf[k] * dzi + b[kk] = (self.Ref.rho0_c[k] * ae[k] * dti - self.Ref.rho0_c[k] * ae[k] * self.EnvVar.W.values[k] * dzi + rho_ae_K_m[k] * dzi * dzi + rho_ae_K_m[k-1] * dzi * dzi + D_env - + self.Ref.rho0_half[k] * ae[k] - * pow(fmax(self.EnvVar.TKE.values[k],0), 0.5)/fmax(self.mixing_length[k],1.0) * self.tke_diss_coeff) - c[kk] = (self.Ref.rho0_half[k+1] * ae[k+1] * whalf[k+1] * dzi - rho_ae_K_m[k] * dzi * dzi) - x[kk] = (self.Ref.rho0_half[k] * ae_old[k] * self.EnvVar.HQTcov.values[k] * dti - + self.HQTcov_shear[k] + self.HQTcov_entr_gain[k] + self.HQTcov_rain[k]) - - a[0] = 0.0 - b[0] = 1.0 - c[0] = 0.0 - x[0] = HQTcov_0_surf - - b[nz-1] += c[nz-1] - c[nz-1] = 0.0 + + self.Ref.rho0_c[k] * ae[k] * self.tke_diss_coeff + *sqrt(fmax(self.EnvVar.TKE.values[k],0))/fmax(self.mixing_length[k],1.0) ) + c[kk] = (self.Ref.rho0_c[k+1] * ae[k+1] * self.EnvVar.W.values[k+1] * dzi - rho_ae_K_m[k] * dzi * dzi) + x[kk] = (self.Ref.rho0_c[k] * ae_old[k] * Covar.values[k] * dti + + Covar.press[k] + Covar.buoy[k] + Covar.shear[k] + Covar.entr_gain[k] + Covar.rain_src[k]) # + + a[0] = 0.0 + b[0] = 1.0 + c[0] = 0.0 + x[0] = Covar_surf + + b[nz-1] += c[nz-1] + c[nz-1] = 0.0 tridiag_solve(self.Gr.nz, &x[0],&a[0], &b[0], &c[0]) - with nogil: - for kk in xrange(nz): - k = kk + gw - self.EnvVar.HQTcov.values[k] = x[kk] - GMV.HQTcov.values[k] = (ae[k] * (self.EnvVar.HQTcov.values[k] + (Hhalf[k]-GMV.H.values[k]) * (QThalf[k]-GMV.QT.values[k])) - + self.UpdVar.Area.bulkvalues[k] * (self.UpdVar.H.bulkvalues[k]-GMV.H.values[k]) * (self.UpdVar.QT.bulkvalues[k]-GMV.QT.values[k])) + for kk in xrange(nz): + k = kk + gw + if Covar.name == 'thetal_qt_covar': + Covar.values[k] = fmax(x[kk], - sqrt(self.EnvVar.Hvar.values[k]*self.EnvVar.QTvar.values[k])) + Covar.values[k] = fmin(x[kk], sqrt(self.EnvVar.Hvar.values[k]*self.EnvVar.QTvar.values[k])) + else: + Covar.values[k] = fmax(x[kk],0.0) - self.get_GMV_CoVar(self.UpdVar.Area, self.UpdVar.H, self.UpdVar.QT, self.EnvVar.H, self.EnvVar.QT, self.EnvVar.HQTcov, - &GMV.H.values[0], &GMV.QT.values[0], &GMV.HQTcov.values[0]) + self.get_GMV_CoVar(self.UpdVar.Area, UpdVar1, UpdVar2, EnvVar1, EnvVar2, Covar, &GmvVar1.values[0], &GmvVar2.values[0], &GmvCovar.values[0]) return - cpdef compute_covariance_dissipation(self): + cpdef nan_check(self, line, GridMeanVariables GMV, int k): cdef: - Py_ssize_t k - double [:] ae = np.subtract(np.ones((self.Gr.nzg,),dtype=np.double, order='c'),self.UpdVar.Area.bulkvalues) - - with nogil: - for k in xrange(self.Gr.gw, self.Gr.nzg-self.Gr.gw): - self.Hvar_dissipation[k] = (self.Ref.rho0_half[k] * ae[k] * self.EnvVar.Hvar.values[k] - *pow(fmax(self.EnvVar.TKE.values[k],0), 0.5)/fmax(self.mixing_length[k],1.0) * self.tke_diss_coeff) - self.QTvar_dissipation[k] = (self.Ref.rho0_half[k] * ae[k] * self.EnvVar.QTvar.values[k] - *pow(fmax(self.EnvVar.TKE.values[k],0), 0.5)/fmax(self.mixing_length[k],1.0) * self.tke_diss_coeff) - self.HQTcov_dissipation[k] = (self.Ref.rho0_half[k] * ae[k] * self.EnvVar.HQTcov.values[k] - *pow(fmax(self.EnvVar.TKE.values[k],0), 0.5)/fmax(self.mixing_length[k],1.0) * self.tke_diss_coeff) - - return - - + double var + + var = np.sum(self.UpdVar.W.values[0,k])*np.sum(self.UpdVar.H.values[0,k])*np.sum(self.UpdVar.QT.values[0,k])*\ + np.sum(self.UpdVar.T.values[0,k])*np.sum(self.UpdVar.Area.values[0,k])*np.sum(self.UpdVar.QL.values[0,k])*\ + np.sum(self.EnvVar.T.values[k])*np.sum(self.EnvVar.QL.values[k])*\ + np.sum(self.EnvVar.W.values[k])*np.sum(self.EnvVar.H.values[k])*np.sum(self.EnvVar.QT.values[k])*\ + np.sum(GMV.W.values[k])*np.sum(GMV.H.values[k])*np.sum(GMV.QT.values[k])*\ + np.sum(GMV.T.values[k])*np.sum(GMV.QL.values)*\ + np.sum(self.UpdVar.W.new[0,k])*np.sum(self.UpdVar.H.new[0,k])*np.sum(self.UpdVar.QT.new[0,k])*\ + np.sum(self.UpdVar.T.new[0,k])*np.sum(self.UpdVar.Area.new[0,k])*np.sum(self.UpdVar.QL.new[0,k]) + + if np.isnan(var): + print 'nan check' + print line, k, var + print 'H ',self.UpdVar.H.new[0,k], self.UpdVar.H.values[0,k] + print 'QT ', self.UpdVar.QT.new[0,k],self.UpdVar.QT.values[0,k] + print 'T ', self.UpdVar.T.new[0,k], self.UpdVar.T.values[0,k] + print 'a ', self.UpdVar.Area.new[0,k], self.UpdVar.Area.values[0,k] + print 'QL ', self.UpdVar.QL.new[0,k], self.UpdVar.QL.values[0,k] + print 'W ',self.UpdVar.W.new[0,k], self.UpdVar.W.values[0,k] + print 'GMV.H ',GMV.H.new[k], GMV.H.values[k] + print 'GMV.QT ',GMV.QT.new[k], GMV.QT.values[k] + print 'GMV.T ', GMV.T.values[k] + print 'GMV.QL ', GMV.QL.values[k] + print 'Env', self.EnvVar.T.values[k], self.EnvVar.QL.values[k], self.EnvVar.W.values[k] ,self.EnvVar.H.values[k] ,self.EnvVar.QT.values[k] + + plt.figure() + plt.show() + + if self.UpdVar.QT.new[0,k] < 0: + print 'negative qt', line, k, self.UpdVar.QT.values[0,k] ,self.UpdVar.QT.new[0,k] + plt.figure() + plt.show() + if self.UpdVar.H.new[0,k] < 290 or self.UpdVar.H.new[0,k] > 310: + print 'wrong H', line, k, self.UpdVar.H.values[0,k] ,self.UpdVar.H.new[0,k] + plt.figure() + plt.show() + + + return \ No newline at end of file diff --git a/Variables.pyx b/Variables.pyx index fb7fe586..e3c79c15 100644 --- a/Variables.pyx +++ b/Variables.pyx @@ -25,8 +25,8 @@ cdef class VariablePrognostic: self.mf_update = np.zeros((nz_tot,),dtype=np.double, order='c') self.tendencies = np.zeros((nz_tot,),dtype=np.double, order='c') # Placement on staggered grid - if loc != 'half' and loc != 'full': - print('Invalid location setting for variable! Must be half or full') + if loc != 'half': + print('Invalid location setting for variable! Must be half') self.loc = loc if kind != 'scalar' and kind != 'velocity': print ('Invalid kind setting for variable! Must be scalar or velocity') @@ -50,7 +50,6 @@ cdef class VariablePrognostic: Py_ssize_t start_low = Gr.gw - 1 Py_ssize_t start_high = Gr.nzg - Gr.gw - 1 - if self.bc == 'sym': for k in xrange(Gr.gw): self.values[start_high + k +1] = self.values[start_high - k] @@ -65,24 +64,16 @@ cdef class VariablePrognostic: else: - self.values[start_high] = 0.0 - self.values[start_low] = 0.0 + for k in xrange(Gr.gw): + self.values[start_high + k +1] = -self.values[start_high - k] + self.values[start_low - k] = -self.values[start_low + 1 + k] - self.mf_update[start_high] = 0.0 - self.mf_update[start_low] = 0.0 + self.mf_update[start_high + k +1] = -self.mf_update[start_high - k] + self.mf_update[start_low - k] = -self.mf_update[start_low + 1 + k] - self.new[start_high] = 0.0 - self.new[start_low] = 0.0 + self.new[start_high + k +1] = -self.new[start_high - k] + self.new[start_low - k] = -self.new[start_low + 1 + k] - for k in xrange(1,Gr.gw): - self.values[start_high+ k] = -self.values[start_high - k ] - self.values[start_low- k] = -self.values[start_low + k ] - - self.mf_update[start_high+ k] = -self.mf_update[start_high - k ] - self.mf_update[start_low- k] = -self.mf_update[start_low + k ] - - self.new[start_high+ k] = -self.new[start_high - k ] - self.new[start_low- k] = -self.new[start_low + k ] return @@ -109,6 +100,7 @@ cdef class VariableDiagnostic: Py_ssize_t start_high = Gr.nzg - Gr.gw + if self.bc == 'sym': for k in xrange(Gr.gw): self.values[start_high + k] = self.values[start_high - 1] @@ -116,12 +108,9 @@ cdef class VariableDiagnostic: else: - self.values[start_high] = 0.0 - self.values[start_low] = 0.0 for k in xrange(1,Gr.gw): - self.values[start_high+ k] = 0.0 #-self.values[start_high - k ] - self.values[start_low- k] = 0.0 #-self.values[start_low + k ] - + self.values[start_high+ k] = -self.values[start_high - k ] + self.values[start_low- k] = -self.values[start_low + k ] return @@ -135,7 +124,7 @@ cdef class GridMeanVariables: self.U = VariablePrognostic(Gr.nzg, 'half', 'velocity', 'sym','u', 'm/s' ) self.V = VariablePrognostic(Gr.nzg, 'half', 'velocity','sym', 'v', 'm/s' ) # Just leave this zero for now! - self.W = VariablePrognostic(Gr.nzg, 'full', 'velocity','sym', 'v', 'm/s' ) + self.W = VariablePrognostic(Gr.nzg, 'half', 'velocity','asym', 'v', 'm/s' ) # Create thermodynamic variables self.QT = VariablePrognostic(Gr.nzg, 'half', 'scalar','sym', 'qt', 'kg/kg') @@ -222,6 +211,7 @@ cdef class GridMeanVariables: self.H.set_bcs(self.Gr) self.QT.set_bcs(self.Gr) self.QR.set_bcs(self.Gr) + self.W.set_bcs(self.Gr) if self.calc_tke: self.TKE.set_bcs(self.Gr) @@ -286,7 +276,7 @@ cdef class GridMeanVariables: Stats.write_profile('HQTcov_mean',self.HQTcov.values[self.Gr.gw:self.Gr.nzg-self.Gr.gw]) for k in xrange(self.Gr.gw, self.Gr.nzg-self.Gr.gw): - lwp += self.Ref.rho0_half[k]*self.QL.values[k]*self.Gr.dz + lwp += self.Ref.rho0_c[k]*self.QL.values[k]*self.Gr.dz Stats.write_ts('lwp', lwp) return @@ -301,13 +291,13 @@ cdef class GridMeanVariables: for k in xrange(self.Gr.nzg): h = self.H.values[k] qt = self.QT.values[k] - p0 = self.Ref.p0_half[k] + p0 = self.Ref.p0_c[k] sa = eos(self.t_to_prog_fp,self.prog_to_t_fp, p0, qt, h ) self.QL.values[k] = sa.ql self.T.values[k] = sa.T qv = qt - sa.ql self.THL.values[k] = t_to_thetali_c(p0, sa.T, qt, sa.ql,0.0) alpha = alpha_c(p0, sa.T, qt, qv) - self.B.values[k] = buoyancy_c(self.Ref.alpha0_half[k], alpha) + self.B.values[k] = buoyancy_c(self.Ref.alpha0_c[k], alpha) return diff --git a/generate_namelist.py b/generate_namelist.py index dd52060a..69f06d7b 100644 --- a/generate_namelist.py +++ b/generate_namelist.py @@ -31,6 +31,8 @@ def main(): namelist = GATE_III() elif case_name == 'DYCOMS_RF01': namelist = DYCOMS_RF01() + elif case_name == 'GABLS': + namelist = GABLS() else: print('Not a valid case name') exit() @@ -90,7 +92,7 @@ def Bomex(): namelist['grid']['dims'] = 1 namelist['grid']['nz'] = 75 namelist['grid']['gw'] = 2 - namelist['grid']['dz'] = 100 / 2.5 + namelist['grid']['dz'] = 40 namelist['thermodynamics'] = {} namelist['thermodynamics']['thermal_variable'] = 'thetal' @@ -105,12 +107,15 @@ def Bomex(): namelist['turbulence']['EDMF_PrognosticTKE'] = {} namelist['turbulence']['EDMF_PrognosticTKE']['updraft_number'] = 1 namelist['turbulence']['EDMF_PrognosticTKE']['entrainment'] = 'b_w2' + namelist['turbulence']['EDMF_PrognosticTKE']['mixing_length'] = 'SBL' namelist['turbulence']['EDMF_PrognosticTKE']['extrapolate_buoyancy'] = True namelist['turbulence']['EDMF_PrognosticTKE']['use_steady_updrafts'] = False + namelist['turbulence']['EDMF_PrognosticTKE']['calc_scalar_var'] = True namelist['turbulence']['EDMF_PrognosticTKE']['use_local_micro'] = True namelist['turbulence']['EDMF_PrognosticTKE']['use_similarity_diffusivity'] = False namelist['turbulence']['EDMF_PrognosticTKE']['constant_area'] = False - #namelist['turbulence']['EDMF_PrognosticTKE']['calc_scalar_var'] = True + namelist['turbulence']['EDMF_PrognosticTKE']['calculate_tke'] = True + namelist['output'] = {} namelist['output']['output_root'] = './' @@ -133,7 +138,7 @@ def life_cycle_Tan2018(): namelist['grid']['dims'] = 1 namelist['grid']['nz'] = 75 namelist['grid']['gw'] = 2 - namelist['grid']['dz'] = 100 / 2.5 + namelist['grid']['dz'] = 40 namelist['thermodynamics'] = {} namelist['thermodynamics']['saturation'] = 'sa_mean' @@ -148,8 +153,14 @@ def life_cycle_Tan2018(): namelist['turbulence']['EDMF_PrognosticTKE'] = {} namelist['turbulence']['EDMF_PrognosticTKE']['updraft_number'] = 1 namelist['turbulence']['EDMF_PrognosticTKE']['entrainment'] = 'b_w2' + namelist['turbulence']['EDMF_PrognosticTKE']['extrapolate_buoyancy'] = True namelist['turbulence']['EDMF_PrognosticTKE']['use_steady_updrafts'] = False - #namelist['turbulence']['EDMF_PrognosticTKE']['calc_scalar_var'] = False + namelist['turbulence']['EDMF_PrognosticTKE']['mixing length'] = 'tke' + namelist['turbulence']['EDMF_PrognosticTKE']['use_local_micro'] = True + namelist['turbulence']['EDMF_PrognosticTKE']['use_similarity_diffusivity'] = False + namelist['turbulence']['EDMF_PrognosticTKE']['constant_area'] = False + namelist['turbulence']['EDMF_PrognosticTKE']['calculate_tke'] = True + namelist['turbulence']['EDMF_PrognosticTKE']['calc_scalar_var'] = True namelist['output'] = {} namelist['output']['output_root'] = './' @@ -186,11 +197,14 @@ def Rico(): namelist['turbulence']['EDMF_PrognosticTKE'] = {} namelist['turbulence']['EDMF_PrognosticTKE']['updraft_number'] = 1 namelist['turbulence']['EDMF_PrognosticTKE']['entrainment'] = 'b_w2' - namelist['turbulence']['EDMF_PrognosticTKE']['use_local_micro'] = True - namelist['turbulence']['EDMF_PrognosticTKE']['use_similarity_diffusivity'] = False namelist['turbulence']['EDMF_PrognosticTKE']['extrapolate_buoyancy'] = True namelist['turbulence']['EDMF_PrognosticTKE']['use_steady_updrafts'] = False - #namelist['turbulence']['EDMF_PrognosticTKE']['calc_scalar_var'] = False + namelist['turbulence']['EDMF_PrognosticTKE']['mixing length'] = 'Ellison_scale' + namelist['turbulence']['EDMF_PrognosticTKE']['use_local_micro'] = True + namelist['turbulence']['EDMF_PrognosticTKE']['use_similarity_diffusivity'] = False + namelist['turbulence']['EDMF_PrognosticTKE']['constant_area'] = False + namelist['turbulence']['EDMF_PrognosticTKE']['calculate_tke'] = True + namelist['turbulence']['EDMF_PrognosticTKE']['calc_scalar_var'] = True namelist['output'] = {} namelist['output']['output_root'] = './' @@ -205,35 +219,36 @@ def Rico(): return namelist -def TRMM_LBA(): # yair +def TRMM_LBA(): namelist = {} namelist['grid'] = {} namelist['grid']['dims'] = 1 - namelist['grid']['nz'] = 2000 + namelist['grid']['nz'] = 400 namelist['grid']['gw'] = 2 - namelist['grid']['dz'] = 10 + namelist['grid']['dz'] = 40 namelist['thermodynamics'] = {} namelist['thermodynamics']['saturation'] = 'sa_mean' namelist['thermodynamics']['thermal_variable'] = 'thetal' namelist['time_stepping'] = {} - namelist['time_stepping']['dt'] = 5.0 + namelist['time_stepping']['dt'] = 30.0 namelist['time_stepping']['t_max'] = 21590.0 namelist['turbulence'] = {} namelist['turbulence']['scheme'] = 'EDMF_PrognosticTKE' namelist['turbulence']['EDMF_PrognosticTKE'] = {} namelist['turbulence']['EDMF_PrognosticTKE']['updraft_number'] = 1 - namelist['turbulence']['EDMF_PrognosticTKE']['entrainment'] = 'b_w2' + namelist['turbulence']['EDMF_PrognosticTKE']['entrainment'] = 'inverse_w' namelist['turbulence']['EDMF_PrognosticTKE']['use_local_micro'] = True - namelist['turbulence']['EDMF_PrognosticTKE']['use_similarity_diffusivity'] = True #False + namelist['turbulence']['EDMF_PrognosticTKE']['use_similarity_diffusivity'] = True namelist['turbulence']['EDMF_PrognosticTKE']['updraft_surface_height'] = 0.0 namelist['turbulence']['EDMF_PrognosticTKE']['extrapolate_buoyancy'] = True namelist['turbulence']['EDMF_PrognosticTKE']['use_steady_updrafts'] = False - #namelist['turbulence']['EDMF_PrognosticTKE']['calc_scalar_var'] = False + namelist['turbulence']['EDMF_PrognosticTKE']['calculate_tke'] = True + namelist['turbulence']['EDMF_PrognosticTKE']['calc_scalar_var'] = True namelist['output'] = {} namelist['output']['output_root'] = './' @@ -276,7 +291,8 @@ def ARM_SGP(): namelist['turbulence']['EDMF_PrognosticTKE']['updraft_surface_height'] = 0.0 namelist['turbulence']['EDMF_PrognosticTKE']['extrapolate_buoyancy'] = True namelist['turbulence']['EDMF_PrognosticTKE']['use_steady_updrafts'] = False - #namelist['turbulence']['EDMF_PrognosticTKE']['calc_scalar_var'] = False + namelist['turbulence']['EDMF_PrognosticTKE']['calculate_tke'] = True + namelist['turbulence']['EDMF_PrognosticTKE']['calc_scalar_var'] = True namelist['output'] = {} namelist['output']['output_root'] = './' @@ -291,36 +307,37 @@ def ARM_SGP(): return namelist -def GATE_III(): # yair +def GATE_III(): # adopted from: "Large eddy simulation of Maritime Deep Tropical Convection", # By Khairoutdinov et al (2009) JAMES, vol. 1, article #15 namelist = {} namelist['grid'] = {} namelist['grid']['dims'] = 1 - namelist['grid']['nz'] = 1700 + namelist['grid']['nz'] = 400 namelist['grid']['gw'] = 2 - namelist['grid']['dz'] = 10 + namelist['grid']['dz'] = 40 namelist['thermodynamics'] = {} namelist['thermodynamics']['saturation'] = 'sa_mean' namelist['thermodynamics']['thermal_variable'] = 'thetal' namelist['time_stepping'] = {} - namelist['time_stepping']['dt'] = 5.0 + namelist['time_stepping']['dt'] = 30.0 namelist['time_stepping']['t_max'] = 3600.0 * 24.0 namelist['turbulence'] = {} namelist['turbulence']['scheme'] = 'EDMF_PrognosticTKE' namelist['turbulence']['EDMF_PrognosticTKE'] = {} namelist['turbulence']['EDMF_PrognosticTKE']['updraft_number'] = 1 - namelist['turbulence']['EDMF_PrognosticTKE']['entrainment'] = 'b_w2' + namelist['turbulence']['EDMF_PrognosticTKE']['entrainment'] = 'inverse_w' namelist['turbulence']['EDMF_PrognosticTKE']['use_local_micro'] = True - namelist['turbulence']['EDMF_PrognosticTKE']['use_similarity_diffusivity'] = True # False + namelist['turbulence']['EDMF_PrognosticTKE']['use_similarity_diffusivity'] = True namelist['turbulence']['EDMF_PrognosticTKE']['updraft_surface_height'] = 0.0 namelist['turbulence']['EDMF_PrognosticTKE']['extrapolate_buoyancy'] = True namelist['turbulence']['EDMF_PrognosticTKE']['use_steady_updrafts'] = False - #namelist['turbulence']['EDMF_PrognosticTKE']['calc_scalar_var'] = False + namelist['turbulence']['EDMF_PrognosticTKE']['calculate_tke'] = True + namelist['turbulence']['EDMF_PrognosticTKE']['calc_scalar_var'] = True namelist['output'] = {} namelist['output']['output_root'] = './' @@ -335,6 +352,52 @@ def GATE_III(): # yair return namelist +def GABLS(): + + namelist = {} + + namelist['grid'] = {} + namelist['grid']['dims'] = 1 + namelist['grid']['nz'] = 128 + namelist['grid']['gw'] = 2 + namelist['grid']['dz'] = 3.125 + + namelist['thermodynamics'] = {} + namelist['thermodynamics']['thermal_variable'] = 'thetal' + namelist['thermodynamics']['saturation'] = 'sa_mean' + + namelist['time_stepping'] = {} + namelist['time_stepping']['dt'] = 0.5 + namelist['time_stepping']['t_max'] = 9 * 3600.0 + + namelist['turbulence'] = {} + namelist['turbulence']['scheme'] = 'EDMF_PrognosticTKE' + namelist['turbulence']['EDMF_PrognosticTKE'] = {} + namelist['turbulence']['EDMF_PrognosticTKE']['updraft_number'] = 1 + namelist['turbulence']['EDMF_PrognosticTKE']['constant_area'] = False + namelist['turbulence']['EDMF_PrognosticTKE']['entrainment'] = 'b_w2' + namelist['turbulence']['EDMF_PrognosticTKE']['mixing_length'] = 'SBL' + namelist['turbulence']['EDMF_PrognosticTKE']['use_local_micro'] = False + namelist['turbulence']['EDMF_PrognosticTKE']['use_similarity_diffusivity'] = False + namelist['turbulence']['EDMF_PrognosticTKE']['updraft_surface_height'] = 0.0 + namelist['turbulence']['EDMF_PrognosticTKE']['extrapolate_buoyancy'] = True + namelist['turbulence']['EDMF_PrognosticTKE']['use_steady_updrafts'] = False + namelist['turbulence']['EDMF_PrognosticTKE']['calculate_tke'] = True + namelist['turbulence']['EDMF_PrognosticTKE']['calc_scalar_var'] = True + + namelist['output'] = {} + namelist['output']['output_root'] = './' + + namelist['stats_io'] = {} + namelist['stats_io']['stats_dir'] = 'stats' + namelist['stats_io']['frequency'] = 60.0 + + namelist['meta'] = {} + namelist['meta']['simname'] = 'GABLS' + namelist['meta']['casename'] = 'GABLS' + return namelist + + def DYCOMS_RF01(): namelist = {} @@ -357,13 +420,14 @@ def DYCOMS_RF01(): namelist['turbulence']['scheme'] = 'EDMF_PrognosticTKE' namelist['turbulence']['EDMF_PrognosticTKE'] = {} namelist['turbulence']['EDMF_PrognosticTKE']['entrainment'] = 'b_w2' + namelist['turbulence']['EDMF_PrognosticTKE']['mixing_length'] = 'SBL' namelist['turbulence']['EDMF_PrognosticTKE']['updraft_number'] = 1 namelist['turbulence']['EDMF_PrognosticTKE']['use_steady_updrafts'] = False namelist['turbulence']['EDMF_PrognosticTKE']['use_local_micro'] = True namelist['turbulence']['EDMF_PrognosticTKE']['use_similarity_diffusivity'] = False namelist['turbulence']['EDMF_PrognosticTKE']['extrapolate_buoyancy'] = True - #namelist['turbulence']['EDMF_PrognosticTKE']['constant_area'] = False - #namelist['turbulence']['EDMF_PrognosticTKE']['calc_scalar_var'] = True + namelist['turbulence']['EDMF_PrognosticTKE']['calculate_tke'] = True + namelist['turbulence']['EDMF_PrognosticTKE']['calc_scalar_var'] = True namelist['output'] = {} namelist['output']['output_root'] = './' diff --git a/generate_paramlist.py b/generate_paramlist.py index 8aff192d..ccf6bc0b 100644 --- a/generate_paramlist.py +++ b/generate_paramlist.py @@ -48,6 +48,8 @@ def main(): paramlist = GATE_III() elif case_name == 'DYCOMS_RF01': paramlist = DYCOMS_RF01() + elif case_name == 'GABLS': + paramlist = GABLS() else: print('Not a valid case name') exit() @@ -195,14 +197,14 @@ def TRMM_LBA(): paramlist['turbulence']['EDMF_PrognosticTKE']['surface_area'] = 0.1 paramlist['turbulence']['EDMF_PrognosticTKE']['tke_ed_coeff'] = 0.1 paramlist['turbulence']['EDMF_PrognosticTKE']['tke_diss_coeff'] = 2.0 - paramlist['turbulence']['EDMF_PrognosticTKE']['max_area_factor'] = 9.9 + paramlist['turbulence']['EDMF_PrognosticTKE']['max_area_factor'] = 5.0 paramlist['turbulence']['EDMF_PrognosticTKE']['entrainment_factor'] = 1.0 paramlist['turbulence']['EDMF_PrognosticTKE']['detrainment_factor'] = 1.0 paramlist['turbulence']['EDMF_PrognosticTKE']['pressure_buoy_coeff'] = 1.0 / 3.0 paramlist['turbulence']['EDMF_PrognosticTKE']['pressure_drag_coeff'] = 0.375 - paramlist['turbulence']['EDMF_PrognosticTKE']['pressure_plume_spacing'] = 500.0 + paramlist['turbulence']['EDMF_PrognosticTKE']['pressure_plume_spacing'] = 1000.0 paramlist['turbulence']['updraft_microphysics'] = {} - paramlist['turbulence']['updraft_microphysics']['max_supersaturation'] = 0.1 + paramlist['turbulence']['updraft_microphysics']['max_supersaturation'] = 0.01 return paramlist @@ -233,7 +235,6 @@ def ARM_SGP(): def GATE_III(): - paramlist = {} paramlist['meta'] = {} paramlist['meta']['casename'] = 'GATE_III' @@ -245,15 +246,15 @@ def GATE_III(): paramlist['turbulence']['EDMF_PrognosticTKE'] = {} paramlist['turbulence']['EDMF_PrognosticTKE']['surface_area'] = 0.1 paramlist['turbulence']['EDMF_PrognosticTKE']['tke_ed_coeff'] = 0.1 - paramlist['turbulence']['EDMF_PrognosticTKE']['tke_diss_coeff'] = 0.7 - paramlist['turbulence']['EDMF_PrognosticTKE']['max_area_factor'] = 9.9 + paramlist['turbulence']['EDMF_PrognosticTKE']['tke_diss_coeff'] = 2.0 + paramlist['turbulence']['EDMF_PrognosticTKE']['max_area_factor'] = 5.0 paramlist['turbulence']['EDMF_PrognosticTKE']['entrainment_factor'] = 1.0 paramlist['turbulence']['EDMF_PrognosticTKE']['detrainment_factor'] = 1.0 paramlist['turbulence']['EDMF_PrognosticTKE']['pressure_buoy_coeff'] = 1.0 / 3.0 - paramlist['turbulence']['EDMF_PrognosticTKE']['pressure_drag_coeff'] = 0.075 - paramlist['turbulence']['EDMF_PrognosticTKE']['pressure_plume_spacing'] = 100.0 + paramlist['turbulence']['EDMF_PrognosticTKE']['pressure_drag_coeff'] = 0.375 + paramlist['turbulence']['EDMF_PrognosticTKE']['pressure_plume_spacing'] = 1000.0 paramlist['turbulence']['updraft_microphysics'] = {} - paramlist['turbulence']['updraft_microphysics']['max_supersaturation'] = 0.1 + paramlist['turbulence']['updraft_microphysics']['max_supersaturation'] = 0.01 return paramlist @@ -290,6 +291,31 @@ def DYCOMS_RF01(): return paramlist +def GABLS(): + + paramlist = {} + paramlist['meta'] = {} + paramlist['meta']['casename'] = 'GABLS' + + paramlist['turbulence'] = {} + paramlist['turbulence']['prandtl_number'] = 0.8 + paramlist['turbulence']['Ri_bulk_crit'] = 0.2 + + paramlist['turbulence']['EDMF_PrognosticTKE'] = {} + paramlist['turbulence']['EDMF_PrognosticTKE']['surface_area'] = 0.1 + paramlist['turbulence']['EDMF_PrognosticTKE']['tke_ed_coeff'] = 0.15 + paramlist['turbulence']['EDMF_PrognosticTKE']['tke_diss_coeff'] = 0.14 + paramlist['turbulence']['EDMF_PrognosticTKE']['max_area_factor'] = 9.9 + paramlist['turbulence']['EDMF_PrognosticTKE']['entrainment_factor'] = 1.0 + paramlist['turbulence']['EDMF_PrognosticTKE']['detrainment_factor'] = 1.0 + paramlist['turbulence']['EDMF_PrognosticTKE']['pressure_buoy_coeff'] = 1.0 / 3.0 + paramlist['turbulence']['EDMF_PrognosticTKE']['pressure_drag_coeff'] = 0.075 + paramlist['turbulence']['EDMF_PrognosticTKE']['pressure_plume_spacing'] = 100.0 + paramlist['turbulence']['updraft_microphysics'] = {} + paramlist['turbulence']['updraft_microphysics']['max_supersaturation'] = 0.1 + + return paramlist + def write_file(paramlist): diff --git a/microphysics_functions.pxd b/microphysics_functions.pxd index 5c0d87e6..e5c7dc2a 100644 --- a/microphysics_functions.pxd +++ b/microphysics_functions.pxd @@ -20,3 +20,4 @@ cdef double evap_rate(double rho, double qv, double qr, double qt, double T, dou cdef double terminal_velocity(double rho, double rho0, double qr, double qt) nogil cdef mph_struct microphysics(double T, double ql, double p0, double qt,\ double max_supersat, bint in_Env) nogil + diff --git a/microphysics_functions.pyx b/microphysics_functions.pyx index 1fbe8df5..82f267ae 100644 --- a/microphysics_functions.pyx +++ b/microphysics_functions.pyx @@ -115,3 +115,4 @@ cdef mph_struct microphysics(double T, double ql, double p0, double qt,\ _ret.thl += _ret.thl_rain_src return _ret + diff --git a/surface_functions.pxd b/surface_functions.pxd index 50410e8c..dfdc0363 100644 --- a/surface_functions.pxd +++ b/surface_functions.pxd @@ -9,18 +9,11 @@ include "parameters.pxi" import cython cdef double buoyancy_flux(double shf, double lhf, double T_b, double qt_b, double alpha0_0) - cdef double psi_m_unstable(double zeta, double zeta0) - cdef double psi_m_unstable(double zeta, double zeta0) - cdef double psi_h_unstable(double zeta, double zeta0) - cdef double psi_m_stable(double zeta, double zeta0) - cdef double psi_h_stable(double zeta, double zeta0) - cpdef double entropy_flux(tflux,qtflux, p0_1, T_1, qt_1) - - cpdef double compute_ustar(double windspeed, double buoyancy_flux, double z0, double z1) +cdef void exchange_coefficients_byun(double Ri, double zb, double z0, double* cm, double* ch, double* lmo) \ No newline at end of file diff --git a/surface_functions.pyx b/surface_functions.pyx index a856d215..e273faa8 100644 --- a/surface_functions.pyx +++ b/surface_functions.pyx @@ -1,6 +1,7 @@ import numpy as np from thermodynamic_functions cimport latent_heat, pd_c, pv_c, sd_c, sv_c, cpm_c, theta_rho_c from turbulence_functions cimport get_wstar, get_inversion +from libc.math cimport acos, sqrt, cbrt, fabs, cos include "parameters.pxi" #Adapated from PyCLES: https://github.com/pressel/pycles @@ -101,3 +102,45 @@ cpdef double compute_ustar(double windspeed, double buoyancy_flux, double z0, do return ustar + + +cdef void exchange_coefficients_byun(double Ri, double zb, double z0, double *cm, double *ch, double *lmo): + + #Monin-Obukhov similarity based on + #Daewon W. Byun, 1990: On the Analytical Solutions of Flux-Profile Relationships for the Atmospheric Surface Layer. J. Appl. Meteor., 29, 652–657. + #doi: http://dx.doi.org/10.1175/1520-0450(1990)029<0652:OTASOF>2.0.CO;2 + cdef: + double logz = np.log(zb/z0) + double zfactor = zb/(zb-z0)*logz + double zeta, zeta0, psi_m, psi_h + double sb = Ri/Pr0 + double qb, pb, crit, angle, tb + double cu, cth + + + if Ri > 0.0: + zeta = zfactor/(2.0*beta_h*(beta_m*Ri -1.0))*((1.0-2.0*beta_h*Ri)-sqrt(1.0+4.0*(beta_h - beta_m)*sb)) + lmo[0] = zb/zeta + zeta0 = z0/lmo[0] + psi_m = psi_m_stable(zeta, zeta0) + psi_h = psi_h_stable(zeta,zeta0) + else: + qb = 1.0/9.0 * (1.0 /(gamma_m * gamma_m) + 3.0 * gamma_h/gamma_m * sb * sb) + pb = 1.0/54.0 * (-2.0/(gamma_m*gamma_m*gamma_m) + 9.0/gamma_m * (-gamma_h/gamma_m + 3.0)*sb * sb) + crit = qb * qb *qb - pb * pb + if crit < 0.0: + tb = cbrt(sqrt(-crit) + fabs(pb)) + zeta = zfactor * (1.0/(3.0*gamma_m)-(tb + qb/tb)) + else: + angle = acos(pb/sqrt(qb * qb * qb)) + zeta = zfactor * (-2.0 * sqrt(qb) * cos(angle/3.0)+1.0/(3.0*gamma_m)) + lmo[0] = zb/zeta + zeta0 = z0/lmo[0] + psi_m = psi_m_unstable(zeta, zeta0) + psi_h = psi_h_unstable(zeta,zeta0) + + cu = vkb/(logz-psi_m) + cth = vkb/(logz-psi_h)/Pr0 + cm[0] = cu * cu + ch[0] = cu * cth + return \ No newline at end of file diff --git a/thermodynamic_functions.pxd b/thermodynamic_functions.pxd index 73010cc8..f6b3f518 100644 --- a/thermodynamic_functions.pxd +++ b/thermodynamic_functions.pxd @@ -14,6 +14,7 @@ cdef double density_temperature_c(double T, double qt, double qv) nogil cdef double theta_rho_c(double p0, double T, double qt, double qv) nogil cdef double cpm_c(double qt) nogil cdef double thetas_entropy_c(double s, double qt) nogil +cdef double theta_virt_c(double p0, double T, double qt, double ql, double qr) nogil cdef double thetas_t_c(double p0, double T, double qt, double qv, double qc, double L) nogil cdef double entropy_from_thetas_c(double thetas, double qt) nogil cdef double buoyancy_c(double alpha0, double alpha) nogil diff --git a/thermodynamic_functions.pyx b/thermodynamic_functions.pyx index 2933ac48..34dc0604 100644 --- a/thermodynamic_functions.pyx +++ b/thermodynamic_functions.pyx @@ -72,6 +72,10 @@ cdef double qv_star_c(const double p0, const double qt, const double pv) nogil cdef double alpha_c(double p0, double T, double qt, double qv) nogil : return (Rd * T)/p0 * (1.0 - qt + eps_vi * qv) +cdef double theta_virt_c( double p0, double T, double qt, double ql, double qr) nogil : + # Virtual potential temperature, mixing ratios are approximated by specific humidities. + return theta_c(p0, T) * (1.0 + 0.61 * (qr) - ql) + cdef double t_to_entropy_c(double p0, double T, double qt, double ql, double qi) nogil : cdef double qv = qt - ql - qi diff --git a/turbulence_functions.pxd b/turbulence_functions.pxd index 4717f582..31402c4e 100644 --- a/turbulence_functions.pxd +++ b/turbulence_functions.pxd @@ -6,44 +6,62 @@ cdef struct evap_struct: double T double ql - - cdef struct entr_in_struct: double zi double wstar double z + double dz double w + double dw double b + double dt + double b_mean double af double tke double ml double T_mean double p0 double alpha0 + double T_up double qt_up double ql_up + double T_env double qt_env double ql_env double H_up double H_env - double b_env double w_env + double env_Hvar + double env_QTvar + double env_HQTcov + double dw_env double L double tke_ed_coeff + double Poisson_rand + double logfn + double zbl + double poisson + double n_up + double thv_e + double thv_u + double dwdz + double transport_der + double dynamic_entr_detr + long quadrature_order cdef entr_struct entr_detr_dry(entr_in_struct entr_in) nogil cdef entr_struct entr_detr_inverse_z(entr_in_struct entr_in) nogil cdef entr_struct entr_detr_inverse_w(entr_in_struct entr_in) nogil cdef entr_struct entr_detr_b_w2(entr_in_struct entr_in) nogil -cdef entr_struct entr_detr_buoyancy_sorting(entr_in_struct entr_in) nogil +cdef entr_struct entr_detr_smean(entr_in_struct entr_in) nogil +cdef evap_struct evap_sat_adjust(double p0, double thetal_, double qt_mix) nogil +cdef double entr_detr_buoyancy_sorting_old(entr_in_struct entr_in) nogil +cdef double entr_detr_buoyancy_sorting(entr_in_struct entr_in) nogil cdef entr_struct entr_detr_tke(entr_in_struct entr_in) nogil +cdef entr_struct entr_detr_suselj(entr_in_struct entr_in) nogil cdef entr_struct entr_detr_tke2(entr_in_struct entr_in) nogil - -cdef evap_struct evap_sat_adjust(double p0, double thetal_, double qt_mix, double T_1, double qs_1, double ql_mix) nogil - - cdef double get_wstar(double bflux, double zi ) -cdef double get_inversion(double *theta_rho, double *u, double *v, double *z_half, +cdef double get_inversion(double *theta_rho, double *u, double *v, double *z_c, Py_ssize_t kmin, Py_ssize_t kmax, double Ri_bulk_crit) cdef double get_mixing_tau(double zi, double wstar) nogil diff --git a/turbulence_functions.pyx b/turbulence_functions.pyx index d5a5b499..36271438 100644 --- a/turbulence_functions.pyx +++ b/turbulence_functions.pyx @@ -1,9 +1,10 @@ import numpy as np cimport numpy as np -from libc.math cimport cbrt, sqrt, log, fabs,atan, exp, fmax, pow, fmin +from libc.math cimport cbrt, sqrt, log, fabs,atan, exp, fmax, pow, fmin, tanh, erf from cpython.mem cimport PyMem_Malloc, PyMem_Realloc, PyMem_Free include "parameters.pxi" from thermodynamic_functions cimport * +from utility_functions cimport smooth_minimum, smooth_maximum # Entrainment Rates cdef entr_struct entr_detr_dry(entr_in_struct entr_in)nogil: @@ -27,45 +28,83 @@ cdef entr_struct entr_detr_inverse_z(entr_in_struct entr_in) nogil: cdef entr_struct entr_detr_inverse_w(entr_in_struct entr_in) nogil: cdef: entr_struct _ret - double tau = get_mixing_tau(entr_in.zi, entr_in.wstar) - # in cloud portion from Soares 2004 - if entr_in.z >= entr_in.zi : - _ret.detr_sc= 3.0e-3 + + eps_w = 1.0/(fmax(fabs(entr_in.w),1.0)* 500) + #eps_w = 0.12*fabs(entr_in.b) / fmax(entr_in.w * entr_in.w, 1.0) + if entr_in.af>0.0: + partiation_func = entr_detr_buoyancy_sorting(entr_in) + _ret.entr_sc = partiation_func*eps_w/2.0 + _ret.detr_sc = (1.0-partiation_func/2.0)*eps_w else: + _ret.entr_sc = 0.0 _ret.detr_sc = 0.0 - - _ret.entr_sc = 1.0/(tau * fmax(entr_in.w,0.1)) #sets baseline to avoid errors return _ret -cdef entr_struct entr_detr_buoyancy_sorting(entr_in_struct entr_in) nogil: + +cdef entr_struct entr_detr_smean(entr_in_struct entr_in) nogil: cdef: entr_struct _ret - double cp_d, Lv + double eps_w, eps_b_w2, eps_max, eps_min, partiation_func + double del_w, del_b_w2, del_max, del_min, inv_w, eps_z + double [2] epsi + double [2] delt - qt_mix = (entr_in.qt_up+entr_in.qt_env)/2 - ql_mix = (entr_in.ql_up+entr_in.ql_env)/2 - qv_mix = qt_mix-ql_mix - thetal_ = t_to_thetali_c(entr_in.p0, entr_in.T_mean, qt_mix, ql_mix, 0.0) - qs_1 =qv_star_t(entr_in.p0, entr_in.T_mean) - evap = evap_sat_adjust(entr_in.p0, thetal_, qt_mix, entr_in.T_mean, qs_1, ql_mix) + if entr_in.af>0.0: + if entr_in.z >= entr_in.zi : + del_b_w2= 4.0e-3 + 0.12* fabs(fmin(entr_in.b,0.0)) / fmax(entr_in.w * entr_in.w, 1e-2) + else: + del_b_w2 = 0.0 + eps_b_w2 = 0.12*fabs(entr_in.b) / fmax(entr_in.w * entr_in.w, 1.0) + else: + eps_w = 0.0 + del_w = 0.0 - qv_2 = qt_mix-evap.ql - alpha_mix = alpha_c(entr_in.p0, evap.T, qt_mix, qv_2) - bmix = buoyancy_c(entr_in.alpha0, alpha_mix) - eps_w = 1.0/(500.0 * fmax(fabs(entr_in.w),0.1)) # inverse w + eps_z = vkb/entr_in.z + inv_w = 1.0/(fmax(fabs(entr_in.w),1.0)* 500) if entr_in.af>0.0: - if bmix >= 0.0: - _ret.entr_sc = eps_w - _ret.detr_sc = 0.0 - else: - _ret.entr_sc = 0.0 - _ret.detr_sc = eps_w + partiation_func = entr_detr_buoyancy_sorting(entr_in) + #with gil: + # print partiation_func + eps_w = partiation_func*inv_w/2.0 + del_w = (1.0-partiation_func/2.0)*inv_w else: - _ret.entr_sc = 0.0 - _ret.detr_sc = 0.0 + eps_w = 0.0 + del_w = 0.0 + with gil: + + epsi = [eps_w , eps_b_w2] + delt = [del_w , del_b_w2] + + # eps_min = smooth_minimum(epsi, 1.0) + # eps_max = smooth_maximum(epsi,1.0) + # del_min = smooth_minimum(delt,1.0) + # del_max = smooth_maximum(delt,1.0) + # _ret.entr_sc = (eps_min + eps_max)/2.0 + # _ret.detr_sc = (del_min + del_max)/2.0 + _ret.entr_sc = 2.0 + _ret.detr_sc = 2.0 + return _ret +cdef entr_struct entr_detr_suselj(entr_in_struct entr_in) nogil: + cdef: + entr_struct _ret + double entr_dry = 2.5e-3 + double l0 + double mc, mg_prod, turb_trans, buoy_prod + + l0 = (entr_in.zbl - entr_in.zi)/10.0 + if entr_in.z >= entr_in.zi : + _ret.detr_sc= 4.0e-3 + 0.12* fabs(fmin(entr_in.b,0.0)) / fmax(entr_in.w * entr_in.w, 1e-2) + _ret.entr_sc = 0.1 / fmax(entr_in.dz * entr_in.poisson,1.0) + + else: + _ret.detr_sc = 0.0 + _ret.entr_sc = 0.0 #entr_dry # Very low entrainment rate needed for Dycoms to work + + return _ret + cdef entr_struct entr_detr_tke2(entr_in_struct entr_in) nogil: cdef entr_struct _ret @@ -105,6 +144,7 @@ cdef entr_struct entr_detr_b_w2(entr_in_struct entr_in) nogil: cdef entr_struct _ret # in cloud portion from Soares 2004 if entr_in.z >= entr_in.zi : + #if entr_in.ql_up >= 0.0: _ret.detr_sc= 4.0e-3 + 0.12* fabs(fmin(entr_in.b,0.0)) / fmax(entr_in.w * entr_in.w, 1e-2) else: _ret.detr_sc = 0.0 @@ -113,53 +153,175 @@ cdef entr_struct entr_detr_b_w2(entr_in_struct entr_in) nogil: return _ret + # w_mix = (entr_in.w+entr_in.w_env)/2 + # eps_w = 0.12* fabs(fmin(entr_in.b,0.0)) / fmax(entr_in.w * entr_in.w, 1e-2) + # + # if entr_in.af>0.0: + # + # partiation_func = entr_detr_buoyancy_sorting(entr_in) + # + # _ret.entr_sc = partiation_func*eps_w + # _ret.detr_sc = (1.0-partiation_func)*eps_w + # else: + # _ret.entr_sc = 0.0 + # _ret.detr_sc = 0.0 + # return _ret +cdef double entr_detr_buoyancy_sorting(entr_in_struct entr_in) nogil: + + cdef: + Py_ssize_t m_q, m_h + #double[:] inner + int i_b + + double h_hat, qt_hat, sd_h, sd_q, corr, mu_h_star, sigma_h_star, qt_var + double sqpi_inv = 1.0/sqrt(pi) + double sqrt2 = sqrt(2.0) + double sd_q_lim, bmix, qv_ + double partiation_func = 0.0 + double inner_partiation_func = 0.0 + eos_struct sa + double [:] weights + double [:] abscissas + with gil: + abscissas, weights = np.polynomial.hermite.hermgauss(entr_in.quadrature_order) + #print np.multiply(weights[0],1.0), np.multiply(weights[1],1.0), np.multiply(weights[2],1.0) + + if entr_in.env_QTvar != 0.0 and entr_in.env_Hvar != 0.0: + sd_q = sqrt(entr_in.env_QTvar) + sd_h = sqrt(entr_in.env_Hvar) + corr = fmax(fmin(entr_in.env_HQTcov/fmax(sd_h*sd_q, 1e-13),1.0),-1.0) + + # limit sd_q to prevent negative qt_hat + sd_q_lim = (1e-10 - entr_in.qt_env)/(sqrt2 * abscissas[0]) + sd_q = fmin(sd_q, sd_q_lim) + qt_var = sd_q * sd_q + sigma_h_star = sqrt(fmax(1.0-corr*corr,0.0)) * sd_h + + for m_q in xrange(entr_in.quadrature_order): + qt_hat = (entr_in.qt_env + sqrt2 * sd_q * abscissas[m_q] + entr_in.qt_up)/2.0 + mu_h_star = entr_in.H_env + sqrt2 * corr * sd_h * abscissas[m_q] + inner_partiation_func = 0.0 + for m_h in xrange(entr_in.quadrature_order): + h_hat = (sqrt2 * sigma_h_star * abscissas[m_h] + mu_h_star + entr_in.H_up)/2.0 + # condensation + sa = eos(t_to_thetali_c, eos_first_guess_thetal, entr_in.p0, qt_hat, h_hat) + # calcualte buoyancy + qv_ = qt_hat - sa.ql + alpha_mix = alpha_c(entr_in.p0, sa.T, qt_hat, qv_) + bmix = buoyancy_c(entr_in.alpha0, alpha_mix) - entr_in.b_mean + + # sum only the points with positive buoyancy to get the buoyant fraction + if bmix >0.0: + inner_partiation_func += weights[m_h] * sqpi_inv + partiation_func += inner_partiation_func * weights[m_q] * sqpi_inv + + else: + h_hat = ( entr_in.H_env + entr_in.H_up)/2.0 + qt_hat = ( entr_in.qt_env + entr_in.qt_up)/2.0 + + # condensation + sa = eos(t_to_thetali_c, eos_first_guess_thetal, entr_in.p0, qt_hat, h_hat) + # calcualte buoyancy + alpha_mix = alpha_c(entr_in.p0, sa.T, qt_hat, qt_hat - sa.ql) + bmix = buoyancy_c(entr_in.alpha0, alpha_mix) - entr_in.b_mean + + return partiation_func -cdef evap_struct evap_sat_adjust(double p0, double thetal_, double qt_mix, double T_1, double qs_1, double ql_mix) nogil: +cdef double entr_detr_buoyancy_sorting_old(entr_in_struct entr_in) nogil: + cdef: + + double wdw_mix, wdw_env, sigma, brel_mix, brel_env, w_env, dw_env + # take random fractions of upd and env air to mix + + w_mix = (entr_in.w+entr_in.w_env)/2 + T_mean = (entr_in.T_up+entr_in.T_env)/2 + qt_mix = (entr_in.qt_up+entr_in.qt_env)/2 + ql_mix = (entr_in.ql_up+entr_in.ql_env)/2 + dw_mix = (entr_in.dw+entr_in.dw_env)/2 + # calculate thermo. properties + #qv_mix = qt_mix-ql_mix + thetal_ = t_to_thetali_c(entr_in.p0, T_mean, qt_mix, ql_mix, 0.0) + evap = evap_sat_adjust(entr_in.p0, thetal_, qt_mix) + qv_mix = qt_mix-evap.ql + Tmix = evap.T + alpha_mix = alpha_c(entr_in.p0, Tmix, qt_mix, qv_mix) + bmix = buoyancy_c(entr_in.alpha0, alpha_mix) - entr_in.b_mean + alpha_env = alpha_c(entr_in.p0, entr_in.T_env, entr_in.qt_env, entr_in.qt_env-entr_in.ql_env) + alpha_up = alpha_c(entr_in.p0, entr_in.T_up, entr_in.qt_up, entr_in.qt_up-entr_in.ql_up) + b_env = buoyancy_c(entr_in.alpha0, alpha_env) - entr_in.b_mean + b_up = buoyancy_c(entr_in.alpha0, alpha_up) - entr_in.b_mean + wdw_mix = w_mix*dw_mix + wdw_env = entr_in.w_env*entr_in.dw_env + wdw_up = entr_in.w*entr_in.dw + # b_rel = buoy + momentum + brel_mix = bmix# + wdw_mix + brel_env = b_env# + wdw_env + brel_up = b_up# + wdw_up + + x0 = brel_mix/fmax(fabs(brel_env),1e-6) + sigma = entr_in.Poisson_rand*(brel_up-brel_env)/fmax(fabs(brel_env),1e-6) + if sigma == 0.0: + partiation_func = 0.5 + else: + partiation_func = (1-erf((brel_env/fmax(fabs(brel_env),1e-6)-x0)/(1.4142135623*sigma)))/2 + + return partiation_func + +cdef evap_struct evap_sat_adjust(double p0, double thetal_, double qt_mix) nogil: cdef: evap_struct evap - double ql_1, T_2, ql_2, f_1, f_2, cp, Lv + double ql_1, T_2, ql_2, f_1, f_2, qv_mix, T_1 + if qt_mix>10.0: + with gil: + print qt_mix + qv_mix = qt_mix + ql = 0.0 - evap.T = T_1 - evap.ql = ql_mix - cp = cpm_c(qt_mix) - Lv = latent_heat(T_1) + pv_1 = pv_c(p0,qt_mix,qt_mix) + pd_1 = p0 - pv_1 # evaporate and cool - T_1 = T_1 + ql_mix * Lv / cp - - if qt_mix >= qs_1: # is the mixture is saturated - run saturation adjust - ql_1 = qt_mix - qs_1 - f_1 = thetal_ - t_to_thetali_c(p0, T_1, qt_mix, ql_1, 0.0) - cp = cpm_c(qt_mix) - Lv = latent_heat(T_1) - T_2 = T_1 + Lv* ql_1 / cp - pv_star_2 = pv_star(T_2) - qs_2 = qv_star_c(p0, qt_mix, pv_star_2) - ql_2 = qt_mix - qs_2 - - while fabs(T_2 - T_1) >= 1e-9: + T_1 = eos_first_guess_thetal(thetal_, pd_1, pv_1, qt_mix) + pv_star_1 = pv_star(T_1) + qv_star_1 = qv_star_c(p0,qt_mix,pv_star_1) + + if(qt_mix <= qv_star_1): + evap.T = T_1 + evap.ql = 0.0 + + else: + ql_1 = qt_mix - qv_star_1 + prog_1 = t_to_thetali_c(p0, T_1, qt_mix, ql_1, 0.0) + f_1 = thetal_ - prog_1 + T_2 = T_1 + ql_1 * latent_heat(T_1) /((1.0 - qt_mix)*cpd + qv_star_1 * cpv) + delta_T = fabs(T_2 - T_1) + + while delta_T > 1.0e-3 or ql_2 < 0.0: pv_star_2 = pv_star(T_2) - qs_2 = qv_star_c(p0, qt_mix, pv_star_2) - ql_2 = qt_mix - qs_2 - f_2 = thetal_ - t_to_thetali_c(p0, T_2, qt_mix, ql_1, 0.0) - T_n = T_2 - f_2 * (T_2 - T_1)/(f_2 - f_1) + qv_star_2 = qv_star_c(p0,qt_mix,pv_star_2) + pv_2 = pv_c(p0, qt_mix, qv_star_2) + pd_2 = p0 - pv_2 + ql_2 = qt_mix - qv_star_2 + prog_2 = t_to_thetali_c(p0,T_2,qt_mix, ql_2, 0.0) + f_2 = thetal_ - prog_2 + T_n = T_2 - f_2*(T_2 - T_1)/(f_2 - f_1) T_1 = T_2 T_2 = T_n f_1 = f_2 + delta_T = fabs(T_2 - T_1) evap.T = T_2 - qv = qs_2 + qv = qv_star_2 evap.ql = ql_2 return evap - # convective velocity scale cdef double get_wstar(double bflux, double zi ): return cbrt(fmax(bflux * zi, 0.0)) # BL height -cdef double get_inversion(double *theta_rho, double *u, double *v, double *z_half, +cdef double get_inversion(double *theta_rho, double *u, double *v, double *z_c, Py_ssize_t kmin, Py_ssize_t kmax, double Ri_bulk_crit): cdef: double theta_rho_b = theta_rho[kmin] @@ -173,15 +335,15 @@ cdef double get_inversion(double *theta_rho, double *u, double *v, double *z_hal for k in xrange(kmin,kmax): if theta_rho[k] > theta_rho_b: break - h = (z_half[k] - z_half[k-1])/(theta_rho[k] - theta_rho[k-1]) * (theta_rho_b - theta_rho[k-1]) + z_half[k-1] + h = (z_c[k] - z_c[k-1])/(theta_rho[k] - theta_rho[k-1]) * (theta_rho_b - theta_rho[k-1]) + z_c[k-1] else: with nogil: for k in xrange(kmin,kmax): Ri_bulk_low = Ri_bulk - Ri_bulk = g * (theta_rho[k] - theta_rho_b) * z_half[k]/theta_rho_b / (u[k] * u[k] + v[k] * v[k]) + Ri_bulk = g * (theta_rho[k] - theta_rho_b) * z_c[k]/theta_rho_b / (u[k] * u[k] + v[k] * v[k]) if Ri_bulk > Ri_bulk_crit: break - h = (z_half[k] - z_half[k-1])/(Ri_bulk - Ri_bulk_low) * (Ri_bulk_crit - Ri_bulk_low) + z_half[k-1] + h = (z_c[k] - z_c[k-1])/(Ri_bulk - Ri_bulk_low) * (Ri_bulk_crit - Ri_bulk_low) + z_c[k-1] return h @@ -311,8 +473,6 @@ cdef void tridiag_solve(Py_ssize_t nz, double *x, double *a, double *b, double * - - # Dustbin cdef bint set_cloudbase_flag(double ql, bint current_flag) nogil: diff --git a/utility_functions.pxd b/utility_functions.pxd index 108a86e6..e79d791c 100644 --- a/utility_functions.pxd +++ b/utility_functions.pxd @@ -1,4 +1,6 @@ cdef double interp2pt(double val1, double val2) nogil cdef double logistic(double x, double slope, double mid) nogil cpdef double percentile_mean_norm(double percentile, Py_ssize_t nsamples) -cpdef double percentile_bounds_mean_norm(double low_percentile, double high_percentile, Py_ssize_t nsamples) \ No newline at end of file +cpdef double percentile_bounds_mean_norm(double low_percentile, double high_percentile, Py_ssize_t nsamples) +cdef double smooth_minimum(double [:] x, double a) nogil +cdef double smooth_maximum(double [:] x, double a) nogil \ No newline at end of file diff --git a/utility_functions.pyx b/utility_functions.pyx index 78698c33..710424d1 100644 --- a/utility_functions.pyx +++ b/utility_functions.pyx @@ -1,7 +1,8 @@ import numpy as np import scipy.special as sp -from libc.math cimport exp +from libc.math cimport exp, fmax, log from scipy.stats import norm +cimport cython # compute the mean of the values above a given percentile (0 to 1) for a standard normal distribution # this gives the surface scalar coefficient for a single updraft or nth updraft of n updrafts @@ -27,3 +28,37 @@ cdef double interp2pt(double val1, double val2) nogil: cdef double logistic(double x, double slope, double mid) nogil: return 1.0/(1.0 + exp( -slope * (x-mid))) +@cython.boundscheck(False) +@cython.wraparound(False) +cdef double smooth_minimum(double [:] x, double a) nogil: + cdef: + unsigned int i = 0 + double num, den, leng + with gil: + leng = len(x) + num = 0; den = 0 + while(i1.0e-5): + num += x[i]*exp(-a*(x[i])) + den += exp(-a*(x[i])) + i += 1 + smin = num/den + return smin + + +@cython.boundscheck(False) +@cython.wraparound(False) +cdef double smooth_maximum(double [:] x, double a) nogil: + cdef: + unsigned int i = 0 + double num, den, leng + with gil: + leng = len(x) + num = 0; den = 0 + while(i1.0e-5): + num += x[i]*exp(a*(x[i])) + den += exp(a*(x[i])) + i += 1 + smin = num/den + return smin \ No newline at end of file