def __init__(self, state): super().__init__(state) # obtain our fields self.theta = state.fields('theta') self.water_v = state.fields('water_v') self.rain = state.fields('rain') rho = state.fields('rho') try: water_c = state.fields('water_c') water_l = self.rain + water_c except NotImplementedError: water_l = self.rain # declare function space Vt = self.theta.function_space() # make rho variables # we recover rho into theta space if state.vertical_degree == 0 and state.horizontal_degree == 0: boundary_method = Boundary_Method.physics else: boundary_method = None Vt_broken = FunctionSpace(state.mesh, BrokenElement(Vt.ufl_element())) rho_averaged = Function(Vt) self.rho_recoverer = Recoverer(rho, rho_averaged, VDG=Vt_broken, boundary_method=boundary_method) # define some parameters as attributes dt = state.timestepping.dt R_d = state.parameters.R_d cp = state.parameters.cp cv = state.parameters.cv c_pv = state.parameters.c_pv c_pl = state.parameters.c_pl c_vv = state.parameters.c_vv R_v = state.parameters.R_v # make useful fields Pi = thermodynamics.pi(state.parameters, rho_averaged, self.theta) T = thermodynamics.T(state.parameters, self.theta, Pi, r_v=self.water_v) p = thermodynamics.p(state.parameters, Pi) L_v = thermodynamics.Lv(state.parameters, T) R_m = R_d + R_v * self.water_v c_pml = cp + c_pv * self.water_v + c_pl * water_l c_vml = cv + c_vv * self.water_v + c_pl * water_l # use Teten's formula to calculate w_sat w_sat = thermodynamics.r_sat(state.parameters, T, p) # expression for ventilation factor a = Constant(1.6) b = Constant(124.9) c = Constant(0.2046) C = a + b * (rho_averaged * self.rain)**c # make appropriate condensation rate f = Constant(5.4e5) g = Constant(2.55e6) h = Constant(0.525) dot_r_evap = (((1 - self.water_v / w_sat) * C * (rho_averaged * self.rain)**h) / (rho_averaged * (f + g / (p * w_sat)))) # make evap_rate function, needs to be the same for all updates in one time step evap_rate = Function(Vt) # adjust evap rate so negative rain doesn't occur self.lim_evap_rate = Interpolator( conditional( dot_r_evap < 0, 0.0, conditional(self.rain < 0.0, 0.0, min_value(dot_r_evap, self.rain / dt))), evap_rate) # tell the prognostic fields what to update to self.water_v_new = Interpolator(self.water_v + dt * evap_rate, Vt) self.rain_new = Interpolator(self.rain - dt * evap_rate, Vt) self.theta_new = Interpolator( self.theta * (1.0 - dt * evap_rate * (cv * L_v / (c_vml * cp * T) - R_v * cv * c_pml / (R_m * cp * c_vml))), Vt)
def __init__(self, state, iterations=1): super().__init__(state) self.iterations = iterations # obtain our fields self.theta = state.fields('theta') self.water_v = state.fields('water_v') self.water_c = state.fields('water_c') rho = state.fields('rho') try: rain = state.fields('rain') water_l = self.water_c + rain except NotImplementedError: water_l = self.water_c # declare function space Vt = self.theta.function_space() # make rho variables # we recover rho into theta space if state.vertical_degree == 0 and state.horizontal_degree == 0: boundary_method = Boundary_Method.physics else: boundary_method = None Vt_broken = FunctionSpace(state.mesh, BrokenElement(Vt.ufl_element())) rho_averaged = Function(Vt) self.rho_recoverer = Recoverer(rho, rho_averaged, VDG=Vt_broken, boundary_method=boundary_method) # define some parameters as attributes dt = state.timestepping.dt R_d = state.parameters.R_d cp = state.parameters.cp cv = state.parameters.cv c_pv = state.parameters.c_pv c_pl = state.parameters.c_pl c_vv = state.parameters.c_vv R_v = state.parameters.R_v # make useful fields Pi = thermodynamics.pi(state.parameters, rho_averaged, self.theta) T = thermodynamics.T(state.parameters, self.theta, Pi, r_v=self.water_v) p = thermodynamics.p(state.parameters, Pi) L_v = thermodynamics.Lv(state.parameters, T) R_m = R_d + R_v * self.water_v c_pml = cp + c_pv * self.water_v + c_pl * water_l c_vml = cv + c_vv * self.water_v + c_pl * water_l # use Teten's formula to calculate w_sat w_sat = thermodynamics.r_sat(state.parameters, T, p) # make appropriate condensation rate dot_r_cond = ((self.water_v - w_sat) / (dt * (1.0 + ((L_v**2.0 * w_sat) / (cp * R_v * T**2.0))))) # make cond_rate function, that needs to be the same for all updates in one time step cond_rate = Function(Vt) # adjust cond rate so negative concentrations don't occur self.lim_cond_rate = Interpolator( conditional(dot_r_cond < 0, max_value(dot_r_cond, -self.water_c / dt), min_value(dot_r_cond, self.water_v / dt)), cond_rate) # tell the prognostic fields what to update to self.water_v_new = Interpolator(self.water_v - dt * cond_rate, Vt) self.water_c_new = Interpolator(self.water_c + dt * cond_rate, Vt) self.theta_new = Interpolator( self.theta * (1.0 + dt * cond_rate * (cv * L_v / (c_vml * cp * T) - R_v * cv * c_pml / (R_m * cp * c_vml))), Vt)
def run_cond_evap(dirname, process): # declare grid shape, with length L and height H L = 1000. H = 1000. nlayers = int(H / 10.) ncolumns = int(L / 10.) # make mesh m = PeriodicIntervalMesh(ncolumns, L) mesh = ExtrudedMesh(m, layers=nlayers, layer_height=(H / nlayers)) x, z = SpatialCoordinate(mesh) dt = 2.0 tmax = dt output = OutputParameters(dirname=dirname + "/cond_evap", dumpfreq=1, dumplist=['u']) parameters = CompressibleParameters() state = State(mesh, dt=dt, output=output, parameters=parameters, diagnostic_fields=[ Sum('vapour_mixing_ratio', 'cloud_liquid_mixing_ratio') ]) # spaces Vt = state.spaces("theta", degree=1) Vr = state.spaces("DG", "DG", degree=1) # Set up equation -- use compressible to set up these spaces # However the equation itself will be unused _ = CompressibleEulerEquations(state, "CG", 1) # Declare prognostic fields rho0 = state.fields("rho") theta0 = state.fields("theta") water_v0 = state.fields("vapour_mixing_ratio", Vt) water_c0 = state.fields("cloud_liquid_mixing_ratio", Vt) # Set a background state with constant pressure and temperature pressure = Function(Vr).interpolate(Constant(100000.)) temperature = Function(Vt).interpolate(Constant(300.)) theta_d = td.theta(parameters, temperature, pressure) mv_sat = td.r_v(parameters, Constant(1.0), temperature, pressure) Lv_over_cpT = td.Lv(parameters, temperature) / (parameters.cp * temperature) # Apply perturbation xc = L / 2. zc = H / 2. rc = L / 4. r = sqrt((x - xc)**2 + (z - zc)**2) pert = conditional(r < rc, 1.0, 0.0) if process == "evaporation": water_v0.interpolate(0.96 * mv_sat) water_c0.interpolate(0.005 * mv_sat * pert) # Approximate answers # Rate of change is roughly (m_sat - m_v) / 4 so should evaporate everything mc_true = Function(Vt).interpolate(Constant(0.0)) theta_d_true = Function(Vt).interpolate(theta_d + 0.005 * mv_sat * pert * Lv_over_cpT) mv_true = Function(Vt).interpolate(mv_sat * (0.96 + 0.005 * pert)) elif process == "condensation": water_v0.interpolate(mv_sat * (1.0 + 0.04 * pert)) # Approximate answers -- rate of change is roughly (m_v - m_sat) / 4 mc_true = Function(Vt).interpolate(0.01 * mv_sat * pert) theta_d_true = Function(Vt).interpolate(theta_d - 0.01 * mv_sat * pert * Lv_over_cpT) mv_true = Function(Vt).interpolate(mv_sat * (1.0 + 0.03 * pert)) # Set prognostic variables theta0.project(theta_d * (1 + water_v0 * parameters.R_v / parameters.R_d)) rho0.interpolate(pressure / (temperature * parameters.R_d * (1 + water_v0 * parameters.R_v / parameters.R_d))) mc_init = Function(Vt).assign(water_c0) # Have empty problem as only thing is condensation / evaporation problem = [] physics_list = [Condensation(state)] # build time stepper stepper = PrescribedTransport(state, problem, physics_list=physics_list) stepper.run(t=0, tmax=tmax) return state, mv_true, mc_true, theta_d_true, mc_init