Ejemplo n.º 1
0
 def apply_Neumann(self, grid, value):
     n_hat_zmin = grid.n_hat(Zmin())
     n_hat_zmax = grid.n_hat(Zmax())
     k_1 = grid.first_interior(Zmin())
     k_2 = grid.first_interior(Zmax())
     self.values[0:k_1] = self.values[k_1] - n_hat_zmin * grid.dz * value
     self.values[k_2 + 1:] = self.values[k_2] - n_hat_zmax * grid.dz * value
Ejemplo n.º 2
0
 def apply_Neumann(self, grid, value):
     n_hat_zmin = grid.n_hat(Zmin())
     n_hat_zmax = grid.n_hat(Zmax())
     k_1 = grid.boundary(Zmin())
     k_2 = grid.boundary(Zmax())
     self.values[0:k_1] = 2.0 * self.values[k_1] - self.values[
         k_1 - n_hat_zmin] + 2.0 * grid.dz * value * n_hat_zmin
     self.values[k_2 + 1:] = 2.0 * self.values[k_2] - self.values[
         k_2 - n_hat_zmax] + 2.0 * grid.dz * value * n_hat_zmax
Ejemplo n.º 3
0
def compute_tendencies_gm(grid, q_tendencies, q, Case, TS, tmp, tri_diag):
    i_gm, i_env, i_uds, i_sd = q.domain_idx()
    k_1 = grid.first_interior(Zmin())
    dzi = grid.dzi
    α_1 = tmp['α_0'][k_1]
    ae_1 = q['a', i_env][k_1]
    slice_all_c = grid.slice_all(Center())

    q_tendencies['q_tot', i_gm][slice_all_c] += [
        tmp['mf_tend_q_tot'][k] + tmp['prec_src_q_tot', i_gm][k] * TS.Δti
        for k in grid.over_elems(Center())
    ]
    q_tendencies['q_tot',
                 i_gm][k_1] += Case.Sur.rho_q_tot_flux * dzi * α_1 / ae_1

    q_tendencies['θ_liq', i_gm][slice_all_c] += [
        tmp['mf_tend_θ_liq'][k] + tmp['prec_src_θ_liq', i_gm][k] * TS.Δti
        for k in grid.over_elems(Center())
    ]
    q_tendencies['θ_liq',
                 i_gm][k_1] += Case.Sur.rho_θ_liq_flux * dzi * α_1 / ae_1

    q_tendencies['U', i_gm][k_1] += Case.Sur.rho_uflux * dzi * α_1 / ae_1
    q_tendencies['V', i_gm][k_1] += Case.Sur.rho_vflux * dzi * α_1 / ae_1
    return
Ejemplo n.º 4
0
    def update(self, grid, q, tmp):
        i_gm, i_env, i_uds, i_sd = tmp.domain_idx()
        k_1 = grid.first_interior(Zmin())
        ρ_0_surf = tmp.surface(grid, 'ρ_0')
        α_0_surf = tmp.surface(grid, 'α_0')
        T_1 = tmp['T', i_gm][k_1]
        θ_liq_1 = q['θ_liq', i_gm][k_1]
        q_tot_1 = q['q_tot', i_gm][k_1]
        V_1 = q['V', i_gm][k_1]
        U_1 = q['U', i_gm][k_1]

        cp_ = cpm_c(q_tot_1)
        lv = latent_heat(T_1)
        windspeed = compute_windspeed(grid, q, 0.01)
        self.rho_q_tot_flux = -self.cq * windspeed * (q_tot_1 - self.qsurface) * ρ_0_surf
        self.rho_θ_liq_flux = -self.ch * windspeed * (θ_liq_1 - self.Tsurface/exner_c(self.Ref.Pg)) * ρ_0_surf

        self.lhf = lv * self.rho_q_tot_flux
        self.shf = cp_  * self.rho_θ_liq_flux

        self.bflux = buoyancy_flux(self.shf, self.lhf, T_1, q_tot_1, α_0_surf)
        self.ustar =  np.sqrt(self.cm) * windspeed
        self.obukhov_length = compute_MO_len(self.ustar, self.bflux)

        self.rho_uflux = - ρ_0_surf *  self.ustar * self.ustar / windspeed * U_1
        self.rho_vflux = - ρ_0_surf *  self.ustar * self.ustar / windspeed * V_1
        return
 def initialize_vars(self, grid, q, q_tendencies, tmp, tmp_O2, UpdVar, Case,
                     TS, tri_diag):
     i_gm, i_env, i_uds, i_sd = q.domain_idx()
     self.zi = compute_inversion(grid, q, Case.inversion_option, tmp,
                                 self.Ri_bulk_crit, tmp['temp_C'])
     zs = self.zi
     self.wstar = compute_convective_velocity(Case.Sur.bflux, zs)
     ws = self.wstar
     ws3 = ws**3.0
     us3 = Case.Sur.ustar**3.0
     k_1 = grid.first_interior(Zmin())
     cv_θ_liq_1 = q['cv_θ_liq', i_gm][k_1]
     cv_q_tot_1 = q['cv_q_tot', i_gm][k_1]
     cv_θ_liq_q_tot_1 = q['cv_θ_liq_q_tot', i_gm][k_1]
     reset_surface_covariance(grid, q, tmp, Case, ws)
     if ws > 0.0:
         for k in grid.over_elems(Center()):
             z = grid.z_half[k]
             temp = ws * 1.3 * np.cbrt(us3 / ws3 + 0.6 * z / zs) * np.sqrt(
                 np.fmax(1.0 - z / zs, 0.0))
             q['tke', i_gm][k] = temp
             q['cv_θ_liq', i_gm][k] = cv_θ_liq_1 * temp
             q['cv_q_tot', i_gm][k] = cv_q_tot_1 * temp
             q['cv_θ_liq_q_tot', i_gm][k] = cv_θ_liq_q_tot_1 * temp
         reset_surface_covariance(grid, q, tmp, Case, ws)
         compute_mixing_length(grid, q, tmp, Case.Sur.obukhov_length,
                               self.zi, self.wstar)
     self.pre_compute_vars(grid, q, q_tendencies, tmp, tmp_O2, UpdVar, Case,
                           TS, tri_diag)
     return
Ejemplo n.º 6
0
def compute_cv_env_tendencies(grid, q_tendencies, tmp_O2, cv):
    i_gm, i_env, i_uds, i_sd = q_tendencies.domain_idx()
    k_1 = grid.first_interior(Zmin())
    for k in grid.over_elems_real(Center()):
        q_tendencies[cv, i_env][k] = tmp_O2[cv]['press'][k] + tmp_O2[cv][
            'buoy'][k] + tmp_O2[cv]['shear'][k] + tmp_O2[cv]['entr_gain'][
                k] + tmp_O2[cv]['rain_src'][k]
    q_tendencies[cv, i_env][k_1] = 0.0
    return
Ejemplo n.º 7
0
    def calculate_radiation(self, tmp):
        """
        see eq. 3 in Stevens et. al. 2005 DYCOMS paper
        """

        # find z_i (level of 8.0 g/kg isoline of q_tot)
        k_1 = grid.first_interior(Zmin())
        z_i = grid.z[k_1]
        for k in grid.over_elems_real(Center()):
            if (q['q_tot', i_gm][k] < 8.0 / 1000):
                idx_zi = k
                # will be used at cell edges
                z_i = grid.z[idx_zi]
                rhoi = tmp['ρ_0'][idx_zi]
                break

        self.f_rad = Full(grid)
        k_2 = grid.boundary(Zmax())
        k_1 = 0
        k_2 = grid.nzg - 1

        # cloud-top cooling
        q_0 = 0.0

        self.f_rad[k_2] = self.F0 * np.exp(-q_0)
        for k in range(k_2 - 1, -1, -1):
            q_0 += self.kappa * tmp['ρ_0'][k] * tmp['q_liq', i_gm][k] * grid.dz
            self.f_rad[k] = self.F0 * np.exp(-q_0)

        # cloud-base warming
        q_1 = 0.0
        self.f_rad[k_1] += self.F1 * np.exp(-q_1)
        for k in range(1, k_2 + 1):
            q_1 += self.kappa * tmp['ρ_0'][k - 1] * tmp['q_liq',
                                                        i_gm][k - 1] * grid.dz
            self.f_rad[k] += self.F1 * np.exp(-q_1)

        # cooling in free troposphere
        for k in range(k_1, k_2):
            if grid.z[k] > z_i:
                cbrt_z = np.cbrt(grid.z[k] - z_i)
                self.f_rad[
                    k] += rhoi * dycoms_cp * self.divergence * self.alpha_z * (
                        np.power(cbrt_z, 4) / 4.0 + z_i * cbrt_z)
        # condition at the top
        cbrt_z = np.cbrt(grid.z[k] + grid.dz - z_i)
        self.f_rad[
            k_2] += rhoi * dycoms_cp * self.divergence * self.alpha_z * (
                np.power(cbrt_z, 4) / 4.0 + z_i * cbrt_z)

        for k in grid.over_elems_real(Center()):
            self.dTdt[k] = -(self.f_rad[k + 1] - self.f_rad[k]
                             ) / grid.dz / tmp['ρ_0'][k] / dycoms_cp

        return
Ejemplo n.º 8
0
def construct_tridiag_diffusion_O1(grid, dt, tri_diag, rho, ae):
    k_1 = grid.first_interior(Zmin())
    k_2 = grid.first_interior(Zmax())
    dzi = grid.dzi
    for k in grid.over_elems_real(Center()):
        ρaK_dual = tri_diag.ρaK.Dual(k)
        X = rho[k] * ae[k] / dt
        Z = ρaK_dual[0] * dzi * dzi
        Y = ρaK_dual[1] * dzi * dzi
        if k == k_1:
            Z = 0.0
        elif k == k_2:
            Y = 0.0
        tri_diag.a[k] = -Z / X
        tri_diag.b[k] = 1.0 + Y / X + Z / X
        tri_diag.c[k] = -Y / X
    return
Ejemplo n.º 9
0
def update_cv_env(grid, q, q_tendencies, tmp, tmp_O2, TS, cv, tri_diag,
                  tke_diss_coeff):
    i_gm, i_env, i_uds, i_sd = q.domain_idx()
    construct_tridiag_diffusion_O2(grid, q, tmp, TS, tri_diag, tke_diss_coeff)
    k_1 = grid.first_interior(Zmin())

    slice_all_c = grid.slice_all(Center())
    a_e = q['a', i_env]
    tri_diag.f[slice_all_c] = [
        tmp['ρ_0'][k] * a_e[k] * q[cv, i_env][k] * TS.Δti +
        q_tendencies[cv, i_env][k] for k in grid.over_elems(Center())
    ]
    tri_diag.f[k_1] = tmp['ρ_0'][k_1] * a_e[k_1] * q[
        cv, i_env][k_1] * TS.Δti + q[cv, i_env][k_1]
    solve_tridiag_wrapper(grid, q[cv, i_env], tri_diag)

    return
Ejemplo n.º 10
0
def construct_tridiag_diffusion_O2(grid, q, tmp, TS, tri_diag, tke_diss_coeff):
    i_gm, i_env, i_uds, i_sd = q.domain_idx()
    dzi = grid.dzi
    dzi2 = grid.dzi**2.0
    dti = TS.Δti
    k_1 = grid.first_interior(Zmin())
    k_2 = grid.first_interior(Zmax())

    a_env = q['a', i_env]
    w_env = q['w', i_env]
    ρ_0_half = tmp['ρ_0']
    for k in grid.over_elems_real(Center()):
        ρ_0_cut = ρ_0_half.Cut(k)
        ae_cut = a_env.Cut(k)
        w_cut = w_env.DualCut(k)
        ρa_K_cut = a_env.DualCut(k) * tmp['K_h'].DualCut(k) * ρ_0_half.DualCut(
            k)

        D_env = sum([
            ρ_0_cut[1] * q['a', i][k] * q['w', i].Mid(k) * tmp['entr_sc', i][k]
            for i in i_uds
        ])

        l_mix = np.fmax(tmp['l_mix'][k], 1.0)
        tke_env = np.fmax(q['tke', i_env][k], 0.0)

        tri_diag.a[k] = (-ρa_K_cut[0] * dzi2)
        tri_diag.b[k] = (
            ρ_0_cut[1] * ae_cut[1] * dti -
            ρ_0_cut[1] * ae_cut[1] * w_cut[1] * dzi + ρa_K_cut[1] * dzi2 +
            ρa_K_cut[0] * dzi2 + D_env +
            ρ_0_cut[1] * ae_cut[1] * tke_diss_coeff * np.sqrt(tke_env) / l_mix)
        tri_diag.c[k] = (ρ_0_cut[2] * ae_cut[2] * w_cut[2] * dzi -
                         ρa_K_cut[1] * dzi2)

    tri_diag.a[k_1] = 0.0
    tri_diag.b[k_1] = 1.0
    tri_diag.c[k_1] = 0.0

    tri_diag.b[k_2] += tri_diag.c[k_2]
    tri_diag.c[k_2] = 0.0
    return
Ejemplo n.º 11
0
    def update(self, grid, q, tmp):
        i_gm, i_env, i_uds, i_sd = tmp.domain_idx()
        k_1 = grid.first_interior(Zmin())
        z_1 = grid.z_half[k_1]
        p_0_1 = tmp['p_0'][k_1]
        α_0_1 = tmp['α_0'][k_1]
        ρ_0_surf = tmp.surface(grid, 'ρ_0')
        T_1 = tmp['T', i_gm][k_1]
        θ_liq_1 = q['θ_liq', i_gm][k_1]
        q_tot_1 = q['q_tot', i_gm][k_1]
        V_1 = q['V', i_gm][k_1]
        U_1 = q['U', i_gm][k_1]

        self.qsurface = qv_star_t(self.Ref.Pg, self.Tsurface)

        theta_rho_g = theta_rho_c(self.Ref.Pg, self.Tsurface, self.qsurface, self.qsurface)
        theta_rho_b = theta_rho_c(p_0_1, T_1, self.qsurface, self.qsurface)
        lv = latent_heat(T_1)
        T0 = p_0_1 * α_0_1/Rd

        theta_flux = 0.24

        θ_liq_star = thetali_c(self.Ref.Pg, self.Tsurface, self.qsurface, 0.0, 0.0)

        self.windspeed = compute_windspeed(grid, q, 0.0)
        Nb2 = g/theta_rho_g*(theta_rho_b-theta_rho_g)/z_1
        Ri = Nb2 * z_1 * z_1/(self.windspeed * self.windspeed)

        self.cm, self.ch, self.obukhov_length = exchange_coefficients_byun(Ri, z_1, self.zrough)

        self.rho_uflux = -self.cm * self.windspeed * U_1 * ρ_0_surf
        self.rho_vflux = -self.cm * self.windspeed * V_1 * ρ_0_surf
        self.rho_θ_liq_flux =  -self.ch * self.windspeed * (θ_liq_1 - θ_liq_star) * ρ_0_surf
        self.rho_q_tot_flux = -self.ch * self.windspeed * (q_tot_1 - self.qsurface) * ρ_0_surf
        self.lhf = lv * self.rho_q_tot_flux
        self.shf = cpm_c(q_tot_1)  * self.rho_θ_liq_flux

        self.bflux = g * theta_flux * exner_c(p_0_1) / T0
        self.ustar =  sqrt(self.cm) * self.windspeed
        self.obukhov_length = compute_MO_len(self.ustar, self.bflux)
        return
Ejemplo n.º 12
0
def reset_surface_covariance(grid, q, tmp, Case, wstar):
    i_gm, i_env, i_uds, i_sd = q.domain_idx()
    flux1 = Case.Sur.rho_θ_liq_flux
    flux2 = Case.Sur.rho_q_tot_flux
    k_1 = grid.first_interior(Zmin())
    zLL = grid.z_half[k_1]
    alpha0LL = tmp['α_0'][k_1]
    ustar = Case.Sur.ustar
    oblength = Case.Sur.obukhov_length
    q['tke', i_gm][k_1] = surface_tke(Case.Sur.ustar, wstar, zLL,
                                      Case.Sur.obukhov_length)
    q['cv_θ_liq',
      i_gm][k_1] = surface_variance(flux1 * alpha0LL, flux1 * alpha0LL, ustar,
                                    zLL, oblength)
    q['cv_q_tot',
      i_gm][k_1] = surface_variance(flux2 * alpha0LL, flux2 * alpha0LL, ustar,
                                    zLL, oblength)
    q['cv_θ_liq_q_tot',
      i_gm][k_1] = surface_variance(flux1 * alpha0LL, flux2 * alpha0LL, ustar,
                                    zLL, oblength)
    return
Ejemplo n.º 13
0
    def update(self, grid, q, tmp):
        i_gm, i_env, i_uds, i_sd = tmp.domain_idx()
        k_1 = grid.first_interior(Zmin())
        z_1 = grid.z_half[k_1]
        ρ_0_surf = tmp.surface(grid, 'ρ_0')
        α_0_surf = tmp.surface(grid, 'α_0')
        T_1 = tmp['T', i_gm][k_1]
        θ_liq_1 = q['θ_liq', i_gm][k_1]
        q_tot_1 = q['q_tot', i_gm][k_1]
        V_1 = q['V', i_gm][k_1]
        U_1 = q['U', i_gm][k_1]

        rho_tflux =  self.shf /(cpm_c(self.qsurface))
        self.windspeed = compute_windspeed(grid, q, 0.0)
        self.rho_q_tot_flux = self.lhf/(latent_heat(self.Tsurface))
        self.rho_θ_liq_flux = rho_tflux / exner_c(self.Ref.Pg)
        self.bflux = buoyancy_flux(self.shf, self.lhf, T_1, q_tot_1, α_0_surf)

        if not self.ustar_fixed:
            # Correction to windspeed for free convective cases (Beljaars, QJRMS (1994), 121, pp. 255-270)
            # Value 1.2 is empirical, but should be O(1)
            if self.windspeed < 0.1:  # Limit here is heuristic
                if self.bflux > 0.0:
                   self.free_convection_windspeed(grid, q, tmp)
                else:
                    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('U_1  ==>', U_1)
                    print('V_1  ==>', V_1)
                    print('q_tot_1 ==>', q_tot_1)
                    print('α_0_surf ==>', α_0_surf)

            self.ustar = compute_ustar(self.windspeed, self.bflux, self.zrough, z_1)

        self.obukhov_length = compute_MO_len(self.ustar, self.bflux)
        self.rho_uflux = - ρ_0_surf *  self.ustar * self.ustar / self.windspeed * U_1
        self.rho_vflux = - ρ_0_surf *  self.ustar * self.ustar / self.windspeed * V_1
        return
 def set_updraft_surface_bc(self, grid, q, tmp, UpdVar, Case):
     i_gm, i_env, i_uds, i_sd = tmp.domain_idx()
     k_1 = grid.first_interior(Zmin())
     zLL = grid.z_half[k_1]
     θ_liq_1 = q['θ_liq', i_gm][k_1]
     q_tot_1 = q['q_tot', i_gm][k_1]
     alpha0LL = tmp['α_0'][k_1]
     S = Case.Sur
     cv_q_tot = surface_variance(S.rho_q_tot_flux * alpha0LL,
                                 S.rho_q_tot_flux * alpha0LL, S.ustar, zLL,
                                 S.obukhov_length)
     cv_θ_liq = surface_variance(S.rho_θ_liq_flux * alpha0LL,
                                 S.rho_θ_liq_flux * alpha0LL, S.ustar, zLL,
                                 S.obukhov_length)
     for i in i_uds:
         UpdVar[i].area_surface_bc = self.surface_area / self.n_updrafts
         UpdVar[i].w_surface_bc = 0.0
         UpdVar[i].θ_liq_surface_bc = (
             θ_liq_1 + UpdVar[i].surface_scalar_coeff * np.sqrt(cv_θ_liq))
         UpdVar[i].q_tot_surface_bc = (
             q_tot_1 + UpdVar[i].surface_scalar_coeff * np.sqrt(cv_q_tot))
     return
Ejemplo n.º 15
0
def compute_inversion_height(theta_rho, u, v, grid, Ri_bulk_crit):
    theta_rho_b = theta_rho.first_interior(grid)
    h = 0.0
    Ri_bulk=0.0
    Ri_bulk_low = 0.0
    kmin = grid.first_interior(Zmin())
    k = kmin
    z = grid.z_half
    # test if we need to look at the free convective limit
    if (u[kmin] * u[kmin] + v[kmin] * v[kmin]) <= 0.01:
        for k in grid.over_elems_real(Center()):
            if theta_rho[k] > theta_rho_b:
                break
        h = (z[k] - z[k-1])/(theta_rho[k] - theta_rho[k-1]) * (theta_rho_b - theta_rho[k-1]) + z[k-1]
    else:
        for k in grid.over_elems_real(Center()):
            Ri_bulk_low = Ri_bulk
            Ri_bulk = g * (theta_rho[k] - theta_rho_b) * z[k]/theta_rho_b / (u[k] * u[k] + v[k] * v[k])
            if Ri_bulk > Ri_bulk_crit:
                break
        h = (z[k] - z[k-1])/(Ri_bulk - Ri_bulk_low) * (Ri_bulk_crit - Ri_bulk_low) + z[k-1]

    return h
Ejemplo n.º 16
0
    def setup_stats_file(self, grid):
        k_b_1 = grid.boundary(Zmin())
        k_b_2 = grid.boundary(Zmax())
        k_1 = k_b_1
        k_2 = k_b_2
        # k_1 = grid.first_interior(Zmin()) # IO assumes full and half fields are equal sizes
        # k_2 = grid.first_interior(Zmax()) # IO assumes full and half fields are equal sizes

        root_grp = nc.Dataset(self.path_plus_file, 'w', format='NETCDF4')

        # Set profile dimensions
        profile_grp = root_grp.createGroup('profiles')
        profile_grp.createDimension('z', grid.nz)
        profile_grp.createDimension('t', None)
        z = profile_grp.createVariable('z', 'f8', ('z'))
        z[:] = np.array(grid.z[k_b_1:k_b_2])
        z_half = profile_grp.createVariable('z_half', 'f8', ('z'))
        z_half[:] = np.array(grid.z_half[k_1:k_2])
        profile_grp.createVariable('t', 'f8', ('t'))
        del z
        del z_half

        reference_grp = root_grp.createGroup('reference')
        reference_grp.createDimension('z', grid.nz)
        z = reference_grp.createVariable('z', 'f8', ('z'))
        z[:] = np.array(grid.z[k_b_1:k_b_2])
        z_half = reference_grp.createVariable('z_half', 'f8', ('z'))
        z_half[:] = np.array(grid.z_half[k_1:k_2])
        del z
        del z_half

        ts_grp = root_grp.createGroup('timeseries')
        ts_grp.createDimension('t', None)
        ts_grp.createVariable('t', 'f8', ('t'))

        root_grp.close()
        return
Ejemplo n.º 17
0
def initialize_updrafts(grid, tmp, q, updraft_fraction):
    i_gm, i_env, i_uds, i_sd = q.domain_idx()
    k_1 = grid.first_interior(Zmin())
    n_updrafts = len(i_uds)
    for i in i_uds:
        for k in grid.over_elems(Center()):
            q['w', i][k] = 0.0
            q['a', i][k] = 0.0
            q['q_tot', i][k] = q['q_tot', i_gm][k]
            tmp['q_liq', i][k] = tmp['q_liq', i_gm][k]
            q['q_rai', i][k] = q['q_rai', i_gm][k]
            q['θ_liq', i][k] = q['θ_liq', i_gm][k]
            tmp['T', i][k] = tmp['T', i_gm][k]
            tmp['B', i][k] = 0.0
        q['a', i][k_1] = updraft_fraction / n_updrafts
    for i in i_uds:
        q['q_tot', i].apply_bc(grid, 0.0)
    for i in i_uds:
        q['q_rai', i].apply_bc(grid, 0.0)
    for i in i_uds:
        q['θ_liq', i].apply_bc(grid, 0.0)
    for k in grid.over_elems(Center()):
        q['a', i_env][k] = 1.0 - np.sum([q['a', i][k] for i in i_uds])
    return
Ejemplo n.º 18
0
 def first_interior(self, grid):
     k_b = grid.boundary(Zmin())
     return (self.values[k_b] + self.values[k_b + 1]) / 2.0
Ejemplo n.º 19
0
 def apply_Dirichlet(self, grid, value):
     self.values[0:grid.boundary(Zmin()) + 1] = value
     self.values[grid.boundary(Zmax()):] = value
Ejemplo n.º 20
0
 def surface(self, grid):
     k_i = grid.first_interior(Zmin())
     return (self.values[k_i] + self.values[k_i - 1]) / 2.0
Ejemplo n.º 21
0
 def first_interior(self, grid):
     k_i = grid.first_interior(Zmin())
     return self.values[k_i]
Ejemplo n.º 22
0
 def extrap(self, grid):
     for k in reversed(grid.over_elems_ghost(Center(), Zmin())):
         self.values[k] = 2.0 * self.values[k + 1] - self.values[k + 2]
     for k in grid.over_elems_ghost(Center(), Zmax()):
         self.values[k] = 2.0 * self.values[k - 1] - self.values[k - 2]
Ejemplo n.º 23
0
 def apply_Dirichlet(self, grid, value):
     k_1 = grid.first_interior(Zmin())
     k_2 = grid.first_interior(Zmax())
     self.values[0:k_1] = 2 * value - self.values[k_1]
     self.values[k_2 + 1:] = 2 * value - self.values[k_2]
Ejemplo n.º 24
0
def solve_updraft_scalars(grid, q_new, q, q_tendencies, tmp, UpdVar, TS,
                          params):
    i_gm, i_env, i_uds, i_sd = q.domain_idx()
    dzi = grid.dzi
    k_1 = grid.first_interior(Zmin())

    for i in i_uds:
        q_new['θ_liq', i][k_1] = UpdVar[i].θ_liq_surface_bc
        q_new['q_tot', i][k_1] = UpdVar[i].q_tot_surface_bc

        for k in grid.over_elems_real(Center())[1:]:
            θ_liq_env = q['θ_liq', i_env][k]
            q_tot_env = q['q_tot', i_env][k]

            if q_new['a', i][k] >= params.minimum_area:
                a_k = q['a', i][k]
                a_cut = q['a', i].Cut(k)
                a_k_new = q_new['a', i][k]
                θ_liq_cut = q['θ_liq', i].Cut(k)
                q_tot_cut = q['q_tot', i].Cut(k)
                ρ_k = tmp['ρ_0'][k]
                ρ_cut = tmp['ρ_0'].Cut(k)
                w_cut = q['w', i].DualCut(k)
                ε_sc = tmp['entr_sc', i][k]
                δ_sc = tmp['detr_sc', i][k]
                ρa_k = ρ_k * a_k

                ρaw_cut = ρ_cut * a_cut * w_cut
                ρawθ_liq_cut = ρaw_cut * θ_liq_cut
                ρawq_tot_cut = ρaw_cut * q_tot_cut
                ρa_new_k = ρ_k * a_k_new

                tendencies_θ_liq = -advect(
                    ρawθ_liq_cut, w_cut, grid) + ρaw_cut[1] * (
                        ε_sc * θ_liq_env - δ_sc * θ_liq_cut[1])
                tendencies_q_tot = -advect(
                    ρawq_tot_cut, w_cut, grid) + ρaw_cut[1] * (
                        ε_sc * q_tot_env - δ_sc * q_tot_cut[1])

                q_new['θ_liq', i][k] = ρa_k / ρa_new_k * θ_liq_cut[
                    1] + TS.Δt_up * tendencies_θ_liq / ρa_new_k
                q_new['q_tot', i][k] = ρa_k / ρa_new_k * q_tot_cut[
                    1] + TS.Δt_up * tendencies_q_tot / ρa_new_k
            else:
                q_new['θ_liq', i][k] = q['θ_liq', i_gm][k]
                q_new['q_tot', i][k] = q['q_tot', i_gm][k]

    if params.use_local_micro:
        for i in i_uds:
            for k in grid.over_elems_real(Center()):
                θ_liq = q_new['θ_liq', i][k]
                q_tot = q_new['q_tot', i][k]
                p_0 = tmp['p_0'][k]
                T, q_liq = eos(p_0, q_tot, θ_liq)
                tmp['T', i][k] = T
                tmp_qr = acnv_instant(q_liq, q_tot, params.max_supersaturation,
                                      T, p_0)
                s = -tmp_qr
                tmp['prec_src_q_tot', i][k] = s
                r_src = rain_source_to_thetal(p_0, T, q_tot, q_liq, 0.0,
                                              tmp_qr)
                tmp['prec_src_θ_liq', i][k] = r_src
                q_new['q_tot', i][k] += s
                q_new['q_rai', i][k] -= s
                q_new['θ_liq', i][k] += r_src
                tmp['q_liq', i][k] = q_liq + s
            q_new['q_rai', i][k_1] = 0.0

    return
Ejemplo n.º 25
0
 def surface(self, grid, var_name, i_sd=0):
     k = grid.first_interior(Zmin())
     return self[var_name, i_sd].Dual(k)[0]
Ejemplo n.º 26
0
 def surface(self, grid):
     return self.values[grid.boundary(Zmin())]
Ejemplo n.º 27
0
def compute_windspeed(grid, q, windspeed_min):
    i_gm, i_env, i_uds, i_sd = q.domain_idx()
    k_1 = grid.first_interior(Zmin())
    return np.maximum(np.sqrt(q['U', i_gm][k_1]**2.0 + q['V', i_gm][k_1]**2.0), windspeed_min)
Ejemplo n.º 28
0
def solve_updraft_velocity_area(grid, q_new, q, q_tendencies, tmp, UpdVar, TS,
                                params):
    i_gm, i_env, i_uds, i_sd = q.domain_idx()
    k_1 = grid.first_interior(Zmin())
    kb_1 = grid.boundary(Zmin())
    dzi = grid.dzi

    # Solve for area fraction
    for i in i_uds:
        au_lim = UpdVar[i].area_surface_bc * params.max_area_factor
        for k in grid.over_elems_real(Center()):

            a_k = q['a', i][k]
            α_0_kp = tmp['α_0'][k]
            w_k = q['w', i].Mid(k)

            w_cut = q['w', i].DualCut(k)
            a_cut = q['a', i].Cut(k)
            ρ_cut = tmp['ρ_0'].Cut(k)
            tendencies = 0.0

            ρaw_cut = ρ_cut * a_cut * w_cut
            adv = -α_0_kp * advect(ρaw_cut, w_cut, grid)
            tendencies += adv

            ε_term = a_k * w_k * (+tmp['entr_sc', i][k])
            tendencies += ε_term
            δ_term = a_k * w_k * (-tmp['detr_sc', i][k])
            tendencies += δ_term

            a_predict = a_k + TS.Δt_up * tendencies

            needs_limiter = a_predict > au_lim
            q_new['a', i][k] = np.fmin(np.fmax(a_predict, 0.0), au_lim)

            unsteady = (q_new['a', i][k] - a_k) / TS.Δt_up
            # δ_limiter = unsteady - tendencies if needs_limiter else 0.0
            # tendencies+=δ_limiter
            # a_correct = a_k + TS.Δt_up * tendencies

            if needs_limiter:
                δ_term_new = unsteady - adv - ε_term
                if a_k > 0.0:
                    tmp['detr_sc', i][k] = δ_term_new / (-a_k * w_k)
                else:
                    tmp['detr_sc', i][k] = δ_term_new / (-au_lim * w_k)

        tmp['entr_sc', i][k_1] = 2.0 * dzi
        tmp['detr_sc', i][k_1] = 0.0
        q_new['a', i][k_1] = UpdVar[i].area_surface_bc

    # Solve for updraft velocity
    for i in i_uds:
        q_new['a', i][kb_1] = UpdVar[i].w_surface_bc
        for k in grid.over_elems_real(Center()):
            a_new_k = q_new['a', i].Mid(k)
            if a_new_k >= params.minimum_area:

                ρ_k = tmp['ρ_0'].Mid(k)
                w_i = q['w', i][k]
                w_env = q['w', i_env].values[k]
                a_k = q['a', i].Mid(k)
                entr_w = tmp['entr_sc', i].Mid(k)
                detr_w = tmp['detr_sc', i].Mid(k)
                B_k = tmp['B', i].Mid(k)

                a_cut = q['a', i].DualCut(k)
                ρ_cut = tmp['ρ_0'].DualCut(k)
                w_cut = q['w', i].Cut(k)

                ρa_k = ρ_k * a_k
                ρa_new_k = ρ_k * a_new_k
                ρaw_k = ρa_k * w_i
                ρaww_cut = ρ_cut * a_cut * w_cut * w_cut

                adv = -advect(ρaww_cut, w_cut, grid)
                exch = ρaw_k * (-detr_w * w_i + entr_w * w_env)
                buoy = ρa_k * B_k
                press_buoy = -ρa_k * B_k * params.pressure_buoy_coeff
                p_coeff = params.pressure_drag_coeff / params.pressure_plume_spacing
                press_drag = -ρa_k * (p_coeff * (w_i - w_env)**2.0 / np.sqrt(
                    np.fmax(a_k, params.minimum_area)))
                nh_press = press_buoy + press_drag

                q_new['w', i][k] = ρaw_k / ρa_new_k + TS.Δt_up / ρa_new_k * (
                    adv + exch + buoy + nh_press)

    # Filter results
    for i in i_uds:
        for k in grid.over_elems_real(Center()):
            if q_new['a', i].Mid(k) >= params.minimum_area:
                if q_new['w', i][k] <= 0.0:
                    q_new['w', i][k:] = 0.0
                    q_new['a', i][k + 1:] = 0.0
                    break
            else:
                q_new['w', i][k:] = 0.0
                q_new['a', i][k + 1:] = 0.0
                break

    return
Ejemplo n.º 29
0
def initialize_ref_state(grid, Stats, p_0, ρ_0, α_0, loc, sg, Pg, Tg, qtg):
    sg = t_to_entropy_c(Pg, Tg, qtg, 0.0, 0.0)

    # Form a right hand side for integrating the hydrostatic equation to
    # determine the reference pressure
    def rhs(p, z):
        T, q_l = eos_entropy(np.exp(p), qtg, sg)
        q_i = 0.0
        R_m = Rd * (1.0 - qtg + eps_vi * (qtg - q_l - q_i))
        return -g / (R_m * T)

    # Construct arrays for integration points
    z_full = [grid.z[k] for k in grid.over_elems_real(Node())]
    z_half = [grid.z_half[k] for k in grid.over_elems_real(Center())]
    z = z_full if isinstance(loc, Node) else z_half

    # We are integrating the log pressure so need to take the log of the
    # surface pressure
    q_liq = Field.field(grid, loc)
    q_ice = Field.field(grid, loc)
    q_vap = Field.field(grid, loc)
    temperature = Field.field(grid, loc)

    p0 = np.log(Pg)
    p_0[grid.slice_real(loc)] = odeint(rhs, p0, z, hmax=1.0)[:, 0]
    p_0.apply_Neumann(grid, 0.0)
    p_0[:] = np.exp(p_0[:])

    # Compute reference state thermodynamic profiles
    for k in grid.over_elems_real(loc):
        temperature[k], q_liq[k] = eos_entropy(p_0[k], qtg, sg)
        q_vap[k] = qtg - (q_liq[k] + q_ice[k])
        α_0[k] = alpha_c(p_0[k], temperature[k], qtg, q_vap[k])
        ρ_0[k] = 1.0 / α_0[k]

    # Sanity check: make sure Reference State entropy is uniform
    for k in grid.over_elems(loc):
        s = t_to_entropy_c(p_0[k], temperature[k], qtg, q_liq[k], q_ice[k])
        if np.abs(s - sg) / sg > 0.01:
            print('Error in reference profiles entropy not constant !')
            print('Likely error in saturation adjustment')

    α_0.extrap(grid)
    p_0.extrap(grid)
    ρ_0.extrap(grid)

    p_0_name = nice_name('p_0') + str(loc.__class__.__name__)
    ρ_0_name = nice_name('ρ_0') + str(loc.__class__.__name__)
    α_0_name = nice_name('α_0') + str(loc.__class__.__name__)

    plt.plot(p_0.values, grid.z)
    plt.title(p_0_name + ' vs z')
    plt.xlabel(p_0_name)
    plt.ylabel('z')
    plt.savefig(Stats.figpath + p_0_name + '.png')
    plt.close()

    plt.plot(ρ_0.values, grid.z)
    plt.title(ρ_0_name + ' vs z')
    plt.xlabel(ρ_0_name)
    plt.ylabel('z')
    plt.savefig(Stats.figpath + ρ_0_name + '.png')
    plt.close()

    plt.plot(α_0.values, grid.z)
    plt.title(α_0_name + ' vs z')
    plt.xlabel(α_0_name)
    plt.ylabel('z')
    plt.savefig(Stats.figpath + α_0_name + '.png')
    plt.close()

    p_0.export_data(grid, Stats.outpath + p_0_name + '.dat')
    ρ_0.export_data(grid, Stats.outpath + ρ_0_name + '.dat')
    α_0.export_data(grid, Stats.outpath + α_0_name + '.dat')

    k_1 = grid.boundary(Zmin())
    k_2 = grid.boundary(Zmax())

    Stats.add_reference_profile(p_0_name)
    Stats.write_reference_profile(p_0_name, α_0[k_1:k_2])
    Stats.add_reference_profile(ρ_0_name)
    Stats.write_reference_profile(ρ_0_name, p_0[k_1:k_2])
    Stats.add_reference_profile(α_0_name)
    Stats.write_reference_profile(α_0_name, ρ_0[k_1:k_2])
    return
Ejemplo n.º 30
0
 def write_profile_new(self, var_name, grid, data):
     var = self.profiles_grp.variables[var_name]
     k_1 = grid.boundary(Zmin())
     k_2 = grid.boundary(Zmax())
     var[-1, :] = np.array(data[k_1:k_2])
     return