def data(request): # initial values RH_init = .99999 T_init = 280. p_init = 100000. r_init = common.eps * RH_init * common.p_vs(T_init) / (p_init - RH_init * common.p_vs(T_init)) # lists to store RH_max and N at the end of the simulation from each test run RH_list = [] N_list = [] for dt in Dt_list: print "\nt time step", dt outfile_nc = "timesteptest_dt=" + str(dt) + ".nc" parcel(dt=dt, outfreq = int(100/dt), outfile = outfile_nc,\ w = 1., T_0 = T_init, p_0 = p_init, r_0 = r_init, z_max = 200, \ mean_r = 5e-8, gstdev = 1.5, n_tot = 1e9, sd_conc = 1000, \ out_bin = '{"radii": {"rght": 1, "moms": [0], "drwt": "wet", "nbin": 1, "lnli": "lin", "left": 1e-06}}' ) f_out = netcdf.netcdf_file(outfile_nc, "r") RH_max = f_out.RH_max N_end = f_out.variables["radii_m0"][-1,0] # concentration of drops > 1e-6 m RH_list.append((RH_max - 1)*100) # [%] N_list.append(N_end / 1e6) # [1/mg] data = {"RH" : RH_list, "N" : N_list, "dt" : Dt_list} # removing all netcdf files after all tests def removing_files(): for file in glob.glob("timesteptest_dt*"): subprocess.call(["rm", file]) request.addfinalizer(removing_files) return data
def main(dt_list = [1e-3, 1.5e-3, 2e-3, 3e-3, 4e-3, 8e-3, 1e-2, 2e-2, 4e-2, 8e-2, 1e-1, 2e-1, 4e-1, 8e-1, 1.]): # initial values z_max = 200. w = 1. RH_init = .99999 T_init = 280. p_init = 100000. r_init = common.eps * RH_init * common.p_vs(T_init) / (p_init - RH_init * common.p_vs(T_init)) # lists to store RH_max and N at the end of the simulation from each test run RH_list = [] N_list = [] for dt in dt_list: print("\nt time step", dt) outfile_nc = "timesteptest_dt=" + str(dt) + ".nc" parcel(dt=dt, outfreq = int(z_max/w/dt), outfile = outfile_nc,\ w = w, T_0 = T_init, p_0 = p_init, r_0 = r_init, z_max = z_max, \ mean_r = 5e-8, gstdev = 1.5, n_tot = 1e9, sd_conc = 1000, \ radii = 1e-6 * pow(10, -3 + np.arange(26) * .2) ) f_out = netcdf.netcdf_file(outfile_nc, "r") RH_max = f_out.RH_max N_end = sum(f_out.variables["conc"][-1, -9:]) # concentration of drops > 1e-6 m RH_list.append((RH_max - 1)*100) # [%] N_list.append(N_end / 1e6) # [1/mg] subprocess.call(["rm", outfile_nc]) data = {"RH" : RH_list, "N" : N_list, "dt" : dt_list} timestep_plot(data)
def data(request): # initial condition RH_init = .999999 T_init = 300. p_init = 100000. r_init = cm.eps * RH_init * cm.p_vs(T_init) / (p_init - RH_init * cm.p_vs(T_init)) # calculate rhod for gas init cond th_0 = T_init * (cm.p_1000 / p_init)**(cm.R_d / cm.c_pd) rhod_init = cm.rhod(p_init, th_0, r_init) # init cond for trace gases SO2_g_init = fn.mole_frac_to_mix_ratio(200e-12, p_init, cm.M_SO2, T_init, rhod_init) O3_g_init = fn.mole_frac_to_mix_ratio(50e-9, p_init, cm.M_O3, T_init, rhod_init) H2O2_g_init = fn.mole_frac_to_mix_ratio(500e-12, p_init, cm.M_H2O2, T_init, rhod_init) CO2_g_init = fn.mole_frac_to_mix_ratio(360e-6, p_init, cm.M_CO2, T_init, rhod_init) NH3_g_init = fn.mole_frac_to_mix_ratio(100e-12, p_init, cm.M_NH3, T_init, rhod_init) HNO3_g_init = fn.mole_frac_to_mix_ratio(100e-12, p_init, cm.M_HNO3, T_init, rhod_init) # aerosol size distribution mean_r = .08e-6 / 2 gstdev = 2. n_tot = 566.e6 # output sd_conc = 1 outfreq = 50 z_max = 300. outfile = "test_chem_henry.nc" dt = 0.1 wait = 100 parcel(dt = dt, z_max = z_max, outfreq = outfreq, wait=wait,\ T_0 = T_init, p_0 = p_init, r_0 = r_init,\ SO2_g = SO2_g_init, O3_g = O3_g_init, H2O2_g = H2O2_g_init,\ CO2_g = CO2_g_init, NH3_g = NH3_g_init, HNO3_g = HNO3_g_init,\ outfile = outfile,\ chem_dsl = True, chem_dsc = True, chem_rct = False,\ aerosol = \ '{"test": {"kappa": 0.5, "mean_r": [' + str(mean_r) + '], "gstdev": [' + str(gstdev) + '], "n_tot": [' + str(n_tot) + ']}}',\ sd_conc = sd_conc,\ out_bin = \ '{"radii": {"rght": 1.0, "left": 0.0, "drwt": "wet", "lnli": "lin", "nbin": 1, "moms": [0, 3]},\ "chem" : {"rght": 1.0, "left": 0.0, "drwt": "wet", "lnli": "lin", "nbin": 1,\ "moms": ["O3_a", "H2O2_a", "SO2_a", "CO2_a", "NH3_a", "HNO3_a", "H"]}}') data = netcdf.netcdf_file("test_chem_henry.nc", "r") # removing all netcdf files after all tests def removing_files(): subprocess.call(["rm", "test_chem_henry.nc"]) request.addfinalizer(removing_files) return data
def main(): RH_init = .99999 T_init = 300. p_init = 100000. r_init = cm.eps * RH_init * cm.p_vs(T_init) / (p_init - RH_init * cm.p_vs(T_init)) # calculate rhod for initial gas mixing ratio th_0 = T_init * (cm.p_1000 / p_init)**(cm.R_d / cm.c_pd) rhod_init = cm.rhod(p_init, th_0, r_init) SO2_g_init = fn.mole_frac_to_mix_ratio(200e-12, p_init, cm.M_SO2, T_init, rhod_init) O3_g_init = fn.mole_frac_to_mix_ratio(50e-9, p_init, cm.M_O3, T_init, rhod_init) H2O2_g_init = fn.mole_frac_to_mix_ratio(500e-12, p_init, cm.M_H2O2, T_init, rhod_init) CO2_g_init = fn.mole_frac_to_mix_ratio(360e-6, p_init, cm.M_CO2, T_init, rhod_init) NH3_g_init = fn.mole_frac_to_mix_ratio(100e-12, p_init, cm.M_NH3, T_init, rhod_init) HNO3_g_init = fn.mole_frac_to_mix_ratio(100e-12, p_init, cm.M_HNO3, T_init, rhod_init) outfreq = 50 z_max = 50. outfile = "test_chem_henry.nc" dt = 0.1 wait = 1000 sd_conc = 1 # run parcel run! parcel(dt = dt, z_max = z_max, outfreq = outfreq, wait=wait,\ T_0 = T_init, p_0 = p_init, r_0 = r_init, sd_conc=sd_conc,\ SO2_g = SO2_g_init, O3_g = O3_g_init, H2O2_g = H2O2_g_init,\ CO2_g = CO2_g_init, NH3_g = NH3_g_init, HNO3_g = HNO3_g_init,\ outfile = outfile,\ chem_dsl = True, chem_dsc = False, chem_rct = False,\ out_bin = \ '{"radii": {"rght": 1, "left": 0, "drwt": "wet", "lnli": "lin", "nbin": 1, "moms": [0, 3]},\ "chem" : {"rght": 1, "left": 0, "drwt": "wet", "lnli": "lin", "nbin": 1,\ "moms": ["O3_a", "H2O2_a", "SO2_a", "CO2_a", "NH3_a", "HNO3_a", "H"]}}' ) data = netcdf.netcdf_file(outfile, "r") #plot plot_henry(data, output_folder="../outputs") #cleanup data.close() subprocess.call(["rm", "test_chem_henry.nc"])
def main(): RH_init = .99999 T_init = 300. p_init = 100000. r_init = cm.eps * RH_init * cm.p_vs(T_init) / (p_init - RH_init * cm.p_vs(T_init)) # calculate rhod for initial gas mixing ratio th_0 = T_init * (cm.p_1000 / p_init)**(cm.R_d / cm.c_pd) rhod_init = cm.rhod(p_init, th_0, r_init) SO2_g_init = fn.mole_frac_to_mix_ratio(200e-12, p_init, cm.M_SO2, T_init, rhod_init) O3_g_init = fn.mole_frac_to_mix_ratio(50e-9, p_init, cm.M_O3, T_init, rhod_init) H2O2_g_init = fn.mole_frac_to_mix_ratio(500e-12, p_init, cm.M_H2O2, T_init, rhod_init) CO2_g_init = fn.mole_frac_to_mix_ratio(360e-6, p_init, cm.M_CO2, T_init, rhod_init) NH3_g_init = fn.mole_frac_to_mix_ratio(100e-12, p_init, cm.M_NH3, T_init, rhod_init) HNO3_g_init = fn.mole_frac_to_mix_ratio(100e-12, p_init, cm.M_HNO3, T_init, rhod_init) outfreq = 50 z_max = 50. outfile = "test_chem_henry.nc" dt = 0.1 wait = 1000 sd_conc = 1 # run parcel run! parcel(dt = dt, z_max = z_max, outfreq = outfreq, wait=wait,\ T_0 = T_init, p_0 = p_init, r_0 = r_init, sd_conc=sd_conc,\ SO2_g = SO2_g_init, O3_g = O3_g_init, H2O2_g = H2O2_g_init,\ CO2_g = CO2_g_init, NH3_g = NH3_g_init, HNO3_g = HNO3_g_init,\ outfile = outfile,\ chem_dsl = True, chem_dsc = False, chem_rct = False,\ out_bin = \ '{"radii": {"rght": 1, "left": 0, "drwt": "wet", "lnli": "lin", "nbin": 1, "moms": [0, 3]},\ "chem" : {"rght": 1, "left": 0, "drwt": "wet", "lnli": "lin", "nbin": 1,\ "moms": ["O3_a", "H2O2_a", "SO2_a", "CO2_a", "NH3_a", "HNO3_a", "H"]}}') data = netcdf.netcdf_file(outfile,"r") #plot plot_henry(data, output_folder = "../outputs") #cleanup data.close() subprocess.call(["rm", "test_chem_henry.nc"])
def main(dt_list=[1e-3, 1.5e-3, 2e-3, 3e-3, 4e-3, 8e-3, 1e-2, 2e-2, 4e-2, 8e-2, 1e-1, 2e-1, 4e-1, 8e-1, 1.0]): # initial values z_max = 200.0 w = 1.0 RH_init = 0.99999 T_init = 280.0 p_init = 100000.0 r_init = common.eps * RH_init * common.p_vs(T_init) / (p_init - RH_init * common.p_vs(T_init)) # lists to store RH_max and N at the end of the simulation from each test run RH_list = [] N_list = [] for dt in dt_list: print "\nt time step", dt outfile_nc = "timesteptest_dt=" + str(dt) + ".nc" parcel( dt=dt, outfreq=int(z_max / w / dt), outfile=outfile_nc, w=w, T_0=T_init, p_0=p_init, r_0=r_init, z_max=z_max, mean_r=5e-8, gstdev=1.5, n_tot=1e9, sd_conc=1000, radii=1e-6 * pow(10, -3 + np.arange(26) * 0.2), ) f_out = netcdf.netcdf_file(outfile_nc, "r") RH_max = f_out.RH_max N_end = sum(f_out.variables["conc"][-1, -9:]) # concentration of drops > 1e-6 m RH_list.append((RH_max - 1) * 100) # [%] N_list.append(N_end / 1e6) # [1/mg] subprocess.call(["rm", outfile_nc]) data = {"RH": RH_list, "N": N_list, "dt": dt_list} timestep_plot(data)
def data(request): # initial values RH_init = .99999 T_init = 280. p_init = 100000. r_init = common.eps * RH_init * common.p_vs(T_init) / ( p_init - RH_init * common.p_vs(T_init)) # lists to store RH_max and N at the end of the simulation from each test run RH_list = [] N_list = [] for dt in Dt_list: print("\nt time step", dt) outfile_nc = "timesteptest_dt=" + str(dt) + ".nc" parcel(dt=dt, outfreq = int(100/dt), outfile = outfile_nc,\ w = 1., T_0 = T_init, p_0 = p_init, r_0 = r_init, z_max = 200, \ sd_conc = 1000, \ aerosol = '{"ammonium_sulfate": {"kappa": 0.61, "mean_r": [5e-8], "gstdev": [1.5], "n_tot": [1e9]}}', out_bin = '{"radii": {"rght": 1, "moms": [0], "drwt": "wet", "nbin": 1, "lnli": "lin", "left": 1e-06}}' ) f_out = netcdf.netcdf_file(outfile_nc, "r") RH_max = f_out.RH_max N_end = f_out.variables["radii_m0"][ -1, 0] # concentration of drops > 1e-6 m RH_list.append((RH_max - 1) * 100) # [%] N_list.append(N_end / 1e6) # [1/mg] data = {"RH": RH_list, "N": N_list, "dt": Dt_list} # removing all netcdf files after all tests def removing_files(): for file in glob.glob("timesteptest_dt*"): subprocess.call(["rm", file]) request.addfinalizer(removing_files) return data
def rh_to_rv(RH, T, p): """ convert relative humidity [%] to water vapor mixing ratio [kg/kg] """ return cm.eps * RH * cm.p_vs(T) / (p - RH * cm.p_vs(T))
def test_pvs(arg, epsilon = 0.03): pvs_md = common.p_vs(arg["T"]) pvs_anpy = anpy.press_sat(arg["T"]) assert abs(pvs_anpy - pvs_md) <= epsilon * pvs_anpy
def data(request): # initial condition RH_init = .999999 T_init = 300. p_init = 100000. r_init = cm.eps * RH_init * cm.p_vs(T_init) / (p_init - RH_init * cm.p_vs(T_init)) # calculate rhod for gas init cond th_0 = T_init * (cm.p_1000 / p_init)**(cm.R_d / cm.c_pd) rhod_init = cm.rhod(p_init, th_0, r_init) # init cond for trace gases SO2_g_init = fn.mole_frac_to_mix_ratio(200e-12, p_init, cm.M_SO2, T_init, rhod_init) O3_g_init = fn.mole_frac_to_mix_ratio(50e-9, p_init, cm.M_O3, T_init, rhod_init) H2O2_g_init = fn.mole_frac_to_mix_ratio(500e-12, p_init, cm.M_H2O2, T_init, rhod_init) CO2_g_init = fn.mole_frac_to_mix_ratio(360e-6, p_init, cm.M_CO2, T_init, rhod_init) NH3_g_init = fn.mole_frac_to_mix_ratio(100e-12, p_init, cm.M_NH3, T_init, rhod_init) HNO3_g_init = fn.mole_frac_to_mix_ratio(100e-12, p_init, cm.M_HNO3, T_init, rhod_init) # aerosol size distribution mean_r = .08e-6 / 2 gstdev = 2. n_tot = 566.e6 # output sd_conc = 1 outfreq = 50 z_max = 300. outfile = "test_chem_henry.nc" dt = 0.1 wait = 100 parcel(dt = dt, z_max = z_max, outfreq = outfreq, wait=wait,\ T_0 = T_init, p_0 = p_init, r_0 = r_init,\ SO2_g = SO2_g_init, O3_g = O3_g_init, H2O2_g = H2O2_g_init,\ CO2_g = CO2_g_init, NH3_g = NH3_g_init, HNO3_g = HNO3_g_init,\ outfile = outfile,\ chem_dsl = True, chem_dsc = True, chem_rct = False,\ aerosol = \ '{"test": {"kappa": 0.5, "mean_r": [' + str(mean_r) + '], "gstdev": [' + str(gstdev) + '], "n_tot": [' + str(n_tot) + ']}}',\ sd_conc = sd_conc,\ out_bin = \ '{"radii": {"rght": 1.0, "left": 0.0, "drwt": "wet", "lnli": "lin", "nbin": 1, "moms": [0, 3]},\ "chem" : {"rght": 1.0, "left": 0.0, "drwt": "wet", "lnli": "lin", "nbin": 1,\ "moms": ["O3_a", "H2O2_a", "SO2_a", "CO2_a", "NH3_a", "HNO3_a", "H"]}}' ) data = netcdf.netcdf_file("test_chem_henry.nc", "r") # removing all netcdf files after all tests def removing_files(): subprocess.call(["rm", "test_chem_henry.nc"]) request.addfinalizer(removing_files) return data
from rhs_blk_2m import rhs_blk_2m from rhs_lgrngn import rhs_lgrngn from libcloudphxx.common import th_std2dry, th_dry2std from libcloudphxx.common import p_vs from libcloudphxx.common import eps, p_1000, R_d, c_pd from libcloudphxx.lgrngn import chem_species_t from numpy import array as arr_t from math import exp, log, sqrt, pi # initial parameters T = arr_t([282.2]) p = arr_t([95000.]) p_v = arr_t([0.95 * p_vs(T[0])]) p_d = p - p_v r_v = eps * p_v / p_d #th_d = arr_t([th_std2dry(300., r_v[0])]) th_d = T * pow(p_1000 / p_d[0], R_d / c_pd) w = 0.5 dt = .1 nt = int(600 / w / dt) # 600 metres # blk_2m-specific parameter # TODO: spectrum # lgrngn-specific parameters sd_conc = 44 def lognormal(lnr): mean_r = .08e-6 / 2
prsr_lgr.add_argument('--kappa', type=float, required=True, help='aerosol hygroscopicity parameter [1]') prsr_lgr.add_argument('--n_tot', type=float, required=True, help='aerosol concentration @STP [m-3]') prsr_lgr.add_argument('--meanr', type=float, required=True, help='aerosol mean dry radius [m]') prsr_lgr.add_argument('--gstdv', type=float, required=True, help='aerosol geometric standard deviation [1]') prsr_lgr.add_argument('--chem_SO2', type=float, default=0, help='SO2 volume concentration [1]') prsr_lgr.add_argument('--chem_O3', type=float, default=0, help='O3 volume concentration [1]') prsr_lgr.add_argument('--chem_H2O2', type=float, default=0, help='H2O2 volume concentration [1]') ## blk_2m options prsr_b2m = sprsr.add_parser('blk_2m') #TODO... args = prsr.parse_args() # computing state variables p_v = arr_t([args.RH * p_vs(args.T)]) p_d = args.p - p_v r_v = eps * p_v / p_d th_d = args.T * pow(p_1000 / p_d, R_d / c_pd) class lognormal: def __init__(self, n_tot, meanr, gstdv): self.meanr = meanr self.stdev = gstdv self.n_tot = n_tot def __call__(self, lnr): return self.n_tot * exp( -pow((lnr - log(self.meanr)), 2) / 2 / pow(log(self.stdev),2) ) / log(self.stdev) / sqrt(2*pi);
prsr_lgr.add_argument('--gstdv', type=float, required=(dflts.gstdv is None), default=dflts.gstdv, help='aerosol geometric standard deviation [1]', nargs='+') prsr_lgr.add_argument('--cloud_r_min', type=float, required=(dflts.cloud_r_min is None), default=dflts.cloud_r_min, help='minimum radius of cloud droplet range [m]') prsr_lgr.add_argument('--cloud_r_max', type=float, required=(dflts.cloud_r_max is None), default=dflts.cloud_r_max, help='maximum radius of cloud droplet range [m]') prsr_lgr.add_argument('--cloud_n_bin', type=int, required=(dflts.cloud_n_bin is None), default=dflts.cloud_n_bin, help='number of bins in the cloud droplet range [1]') prsr_lgr.add_argument('--chem_SO2', type=float, default=dflts.chem_SO2, help='SO2 volume concentration [1]') prsr_lgr.add_argument('--chem_O3', type=float, default=dflts.chem_O3, help='O3 volume concentration [1]') prsr_lgr.add_argument('--chem_H2O2', type=float, default=dflts.chem_H2O2, help='H2O2 volume concentration [1]') ## blk_2m options prsr_b2m = sprsr.add_parser('blk_2m') #TODO... args = prsr.parse_args() # computing state variables p_v = np.array([args.RH * libcom.p_vs(args.T)]) p_d = args.p - p_v r_v = libcom.eps * p_v / p_d th_d = args.T * pow(libcom.p_1000 / p_d, libcom.R_d / libcom.c_pd) chem_gas = None if args.chem_SO2 + args.chem_O3 + args.chem_H2O2 > 0: chem_gas = { libcl.lgrngn.chem_species_t.SO2 : args.chem_SO2, libcl.lgrngn.chem_species_t.O3 : args.chem_O3, libcl.lgrngn.chem_species_t.H2O2 : args.chem_H2O2 } # performing the simulation rhs = rhs_lgrngn.rhs_lgrngn(
def _stats(state, info): state["T"] = np.array([common.T(state["th_d"][0], state["rhod"][0])]) state["RH"] = state["p"] * state["r_v"] / ( state["r_v"] + common.eps) / common.p_vs(state["T"][0]) info["RH_max"] = max(info["RH_max"], state["RH"])
from parcel import parcel from rhs_blk_2m import rhs_blk_2m from rhs_lgrngn import rhs_lgrngn from libcloudphxx.common import th_std2dry, th_dry2std from libcloudphxx.common import p_vs from libcloudphxx.common import eps, p_1000, R_d, c_pd from libcloudphxx.lgrngn import chem_species_t from numpy import array as arr_t from math import exp, log, sqrt, pi # initial parameters T = arr_t([282.2]) p = arr_t([95000.]) p_v = arr_t([0.95 * p_vs(T[0])]) p_d = p - p_v r_v = eps * p_v / p_d #th_d = arr_t([th_std2dry(300., r_v[0])]) th_d = T * pow(p_1000 / p_d[0], R_d / c_pd) w = 0.5 dt = .1 nt = int(600 / w / dt) # 600 metres # blk_2m-specific parameter # TODO: spectrum # lgrngn-specific parameters sd_conc = 44
import sys sys.path.insert(0, "../../bindings/python/") #<listing-1> from libcloudphxx import common, git_revision print(git_revision) print("common.p_vs(273.16)=", common.p_vs(273.16)) assert abs(common.p_vs(273.16) - 611.73) < .001 #</listing-1> print("R_d =", common.R_d) print("c_pd =", common.c_pd) print("g =", common.g) print("p_1000 =", common.p_1000) print("eps =", common.eps) print("rho_w =", common.rho_w) th = 300 rv = .01 print(common.th_dry2std(th, rv)) assert common.th_std2dry(common.th_dry2std(th, rv), rv) == th rd3 = (.2e-6)**3 assert common.rw3_cr(rd3, .5, 300) > rd3 assert common.S_cr(rd3, .5, 300) > 1 # just testing if pressure at 200m is lower than at 100m assert common.p_hydro(100, 300, .01, 0, 100000) > common.p_hydro(
def parcel( dt=.1, z_max=200., w=1., T_0=300., p_0=101300., r_0=-1., RH_0=-1., #if none specified, the default will be r_0=.022, outfile="test.nc", pprof="pprof_piecewise_const_rhod", outfreq=100, sd_conc=64, aerosol='{"ammonium_sulfate": {"kappa": 0.61, "mean_r": [0.02e-6], "gstdev": [1.4], "n_tot": [60.0e6]}}', out_bin='{"radii": {"rght": 0.0001, "moms": [0], "drwt": "wet", "nbin": 1, "lnli": "log", "left": 1e-09}}', SO2_g=0., O3_g=0., H2O2_g=0., CO2_g=0., HNO3_g=0., NH3_g=0., chem_dsl=False, chem_dsc=False, chem_rct=False, chem_rho=1.8e3, sstp_cond=1, sstp_chem=1, wait=0): """ Args: dt (Optional[float]): timestep [s] z_max (Optional[float]): maximum vertical displacement [m] w (Optional[float]): updraft velocity [m/s] T_0 (Optional[float]): initial temperature [K] p_0 (Optional[float]): initial pressure [Pa] r_0 (Optional[float]): initial water vapour mass mixing ratio [kg/kg] RH_0 (Optional[float]): initial relative humidity outfile (Optional[string]): output netCDF file name outfreq (Optional[int]): output interval (in number of time steps) sd_conc (Optional[int]): number of moving bins (super-droplets) aerosol (Optional[json str]): dict of dicts defining aerosol distribution, e.g.: {"ammonium_sulfate": {"kappa": 0.61, "mean_r": [0.02e-6, 0.07e-7], "gstdev": [1.4, 1.2], "n_tot": [120.0e6, 80.0e6]} "gccn" : {"kappa": 1.28, "mean_r": [2e-6], "gstdev": [1.6], "n_tot": [1e2]}} where kappa - hygroscopicity parameter (see doi:10.5194/acp-7-1961-2007) mean_r - lognormal distribution mean radius [m] (list if multimodal distribution) gstdev - lognormal distribution geometric standard deviation (list if multimodal distribution) n_tot - lognormal distribution total concentration under standard conditions (T=20C, p=1013.25 hPa, rv=0) [m^-3] (list if multimodal distribution) out_bin (Optional[json str]): dict of dicts defining spectrum diagnostics, e.g.: {"radii": {"rght": 0.0001, "moms": [0], "drwt": "wet", "nbin": 26, "lnli": "log", "left": 1e-09}, "cloud": {"rght": 2.5e-05, "moms": [0, 1, 2, 3], "drwt": "wet", "nbin": 49, "lnli": "lin", "left": 5e-07}} will generate five output spectra: - 0-th spectrum moment for 26 bins spaced logarithmically between 0 and 1e-4 m for dry radius - 0,1,2 & 3-rd moments for 49 bins spaced linearly between .5e-6 and 25e-6 for wet radius It can also define spectrum diagnostics for chemical compounds, e.g.: {"chem" : {"rght": 1e-6, "left": 1e-10, "drwt": "dry", "lnli": "log", "nbin": 100, "moms": ["S_VI", "NH4_a"]}} will output the total mass of H2SO4 and NH4 ions in each sizedistribution bin Valid "moms" for chemistry are: "O3_a", "H2O2_a", "H", "SO2_a", "S_VI", "CO2_a", "NH3_a", "HNO3_a", SO2_g (Optional[float]): initial SO2 gas mixing ratio [kg / kg dry air] O3_g (Optional[float]): initial O3 gas mixing ratio [kg / kg dry air] H2O2_g (Optional[float]): initial H2O2 gas mixing ratio [kg / kg dry air] CO2_g (Optional[float]): initial CO2 gas mixing ratio [kg / kg dry air] NH3_g (Optional[float]): initial NH3 gas mixing ratio [kg / kg dry air] HNO3_g (Optional[float]): initial HNO3 gas mixing ratio [kg / kg dry air] chem_dsl (Optional[bool]): on/off for dissolving chem species into droplets chem_dsc (Optional[bool]): on/off for dissociation of chem species in droplets chem_rct (Optional[bool]): on/off for oxidation of S_IV to S_VI pprof (Optional[string]): method to calculate pressure profile used to calculate dry air density that is used by the super-droplet scheme valid options are: pprof_const_th_rv, pprof_const_rhod, pprof_piecewise_const_rhod wait (Optional[float]): number of timesteps to run parcel model with vertical velocity=0 at the end of simulation (added for testing) """ # packing function arguments into "opts" dictionary args, _, _, _ = inspect.getargvalues(inspect.currentframe()) opts = dict(zip(args, [locals()[k] for k in args])) # parsing json specification of output spectra spectra = json.loads(opts["out_bin"]) # parsing json specification of init aerosol spectra aerosol = json.loads(opts["aerosol"]) # default water content if ((opts["r_0"] < 0) and (opts["RH_0"] < 0)): print "both r_0 and RH_0 negative, using default r_0 = 0.022" r_0 = .022 # water coontent specified with RH if ((opts["r_0"] < 0) and (opts["RH_0"] >= 0)): r_0 = common.eps * opts["RH_0"] * common.p_vs(T_0) / ( p_0 - opts["RH_0"] * common.p_vs(T_0)) # sanity checks for arguments _arguments_checking(opts, spectra, aerosol) th_0 = T_0 * (common.p_1000 / p_0)**(common.R_d / common.c_pd) nt = int(z_max / (w * dt)) state = { "t": 0, "z": 0, "r_v": np.array([r_0]), "p": p_0, "th_d": np.array([common.th_std2dry(th_0, r_0)]), "rhod": np.array([common.rhod(p_0, th_0, r_0)]), "T": None, "RH": None } if opts["chem_dsl"] or opts["chem_dsc"] or opts["chem_rct"]: for key in _Chem_g_id.iterkeys(): state.update({key: np.array([opts[key]])}) info = { "RH_max": 0, "libcloud_Git_revision": libcloud_version, "parcel_Git_revision": parcel_version } micro = _micro_init(aerosol, opts, state, info) with _output_init(micro, opts, spectra) as fout: # adding chem state vars if micro.opts_init.chem_switch: state.update({ "SO2_a": 0., "O3_a": 0., "H2O2_a": 0., }) state.update({"CO2_a": 0., "HNO3_a": 0.}) micro.diag_all() # selecting all particles micro.diag_chem(_Chem_a_id["NH3_a"]) state.update({"NH3_a": np.frombuffer(micro.outbuf())[0]}) # t=0 : init & save _output(fout, opts, micro, state, 0, spectra) # timestepping for it in range(1, nt + 1): # diagnostics # the reasons to use analytic solution: # - independent of dt # - same as in 2D kinematic model state["z"] += w * dt state["t"] = it * dt # pressure if pprof == "pprof_const_th_rv": # as in icicle model p_hydro = _p_hydro_const_th_rv(state["z"], p_0, th_0, r_0) elif pprof == "pprof_const_rhod": # as in Grabowski and Wang 2009 rho = 1.13 # kg/m3 1.13 state["p"] = _p_hydro_const_rho(state["z"], p_0, rho) elif pprof == "pprof_piecewise_const_rhod": # as in Grabowski and Wang 2009 but calculating pressure # for rho piecewise constant per each time step state["p"] = _p_hydro_const_rho(w * dt, state["p"], state["rhod"][0]) else: raise Exception( "pprof should be pprof_const_th_rv, pprof_const_rhod, or pprof_piecewise_const_rhod" ) # dry air density if pprof == "pprof_const_th_rv": state["rhod"][0] = common.rhod(p_hydro, th_0, r_0) state["p"] = common.p( state["rhod"][0], state["r_v"][0], common.T(state["th_d"][0], state["rhod"][0])) else: state["rhod"][0] = common.rhod( state["p"], common.th_dry2std(state["th_d"][0], state["r_v"][0]), state["r_v"][0]) # microphysics _micro_step(micro, state, info, opts, it, fout) # TODO: only if user wants to stop @ RH_max #if (state["RH"] < info["RH_max"]): break # output if (it % outfreq == 0): print str(round(it / (nt * 1.) * 100, 2)) + " %" rec = it / outfreq _output(fout, opts, micro, state, rec, spectra) _save_attrs(fout, info) _save_attrs(fout, opts) if wait != 0: for it in range(nt + 1, nt + wait): state["t"] = it * dt _micro_step(micro, state, info, opts, it, fout) if (it % outfreq == 0): rec = it / outfreq _output(fout, opts, micro, state, rec, spectra)
def _stats(state, info): state["T"] = np.array([common.T(state["th_d"][0], state["rhod"][0])]) state["RH"] = state["p"] * state["r_v"] / (state["r_v"] + common.eps) / common.p_vs(state["T"][0]) info["RH_max"] = max(info["RH_max"], state["RH"])
def parcel(dt=.1, z_max=200., w=1., T_0=300., p_0=101300., r_0=-1., RH_0=-1., #if none specified, the default will be r_0=.022, outfile="test.nc", pprof="pprof_piecewise_const_rhod", outfreq=100, sd_conc=64, aerosol = '{"ammonium_sulfate": {"kappa": 0.61, "mean_r": [0.02e-6], "gstdev": [1.4], "n_tot": [60.0e6]}}', out_bin = '{"radii": {"rght": 0.0001, "moms": [0], "drwt": "wet", "nbin": 1, "lnli": "log", "left": 1e-09}}', SO2_g = 0., O3_g = 0., H2O2_g = 0., CO2_g = 0., HNO3_g = 0., NH3_g = 0., chem_dsl = False, chem_dsc = False, chem_rct = False, chem_rho = 1.8e3, sstp_cond = 1, sstp_chem = 1, wait = 0 ): """ Args: dt (Optional[float]): timestep [s] z_max (Optional[float]): maximum vertical displacement [m] w (Optional[float]): updraft velocity [m/s] T_0 (Optional[float]): initial temperature [K] p_0 (Optional[float]): initial pressure [Pa] r_0 (Optional[float]): initial water vapour mass mixing ratio [kg/kg] RH_0 (Optional[float]): initial relative humidity outfile (Optional[string]): output netCDF file name outfreq (Optional[int]): output interval (in number of time steps) sd_conc (Optional[int]): number of moving bins (super-droplets) aerosol (Optional[json str]): dict of dicts defining aerosol distribution, e.g.: {"ammonium_sulfate": {"kappa": 0.61, "mean_r": [0.02e-6, 0.07e-7], "gstdev": [1.4, 1.2], "n_tot": [120.0e6, 80.0e6]} "gccn" : {"kappa": 1.28, "mean_r": [2e-6], "gstdev": [1.6], "n_tot": [1e2]}} where kappa - hygroscopicity parameter (see doi:10.5194/acp-7-1961-2007) mean_r - lognormal distribution mean radius [m] (list if multimodal distribution) gstdev - lognormal distribution geometric standard deviation (list if multimodal distribution) n_tot - lognormal distribution total concentration under standard conditions (T=20C, p=1013.25 hPa, rv=0) [m^-3] (list if multimodal distribution) out_bin (Optional[json str]): dict of dicts defining spectrum diagnostics, e.g.: {"radii": {"rght": 0.0001, "moms": [0], "drwt": "wet", "nbin": 26, "lnli": "log", "left": 1e-09}, "cloud": {"rght": 2.5e-05, "moms": [0, 1, 2, 3], "drwt": "wet", "nbin": 49, "lnli": "lin", "left": 5e-07}} will generate five output spectra: - 0-th spectrum moment for 26 bins spaced logarithmically between 0 and 1e-4 m for dry radius - 0,1,2 & 3-rd moments for 49 bins spaced linearly between .5e-6 and 25e-6 for wet radius It can also define spectrum diagnostics for chemical compounds, e.g.: {"chem" : {"rght": 1e-6, "left": 1e-10, "drwt": "dry", "lnli": "log", "nbin": 100, "moms": ["S_VI", "NH4_a"]}} will output the total mass of H2SO4 and NH4 ions in each sizedistribution bin Valid "moms" for chemistry are: "O3_a", "H2O2_a", "H", "SO2_a", "S_VI", "CO2_a", "NH3_a", "HNO3_a", SO2_g (Optional[float]): initial SO2 gas mixing ratio [kg / kg dry air] O3_g (Optional[float]): initial O3 gas mixing ratio [kg / kg dry air] H2O2_g (Optional[float]): initial H2O2 gas mixing ratio [kg / kg dry air] CO2_g (Optional[float]): initial CO2 gas mixing ratio [kg / kg dry air] NH3_g (Optional[float]): initial NH3 gas mixing ratio [kg / kg dry air] HNO3_g (Optional[float]): initial HNO3 gas mixing ratio [kg / kg dry air] chem_dsl (Optional[bool]): on/off for dissolving chem species into droplets chem_dsc (Optional[bool]): on/off for dissociation of chem species in droplets chem_rct (Optional[bool]): on/off for oxidation of S_IV to S_VI pprof (Optional[string]): method to calculate pressure profile used to calculate dry air density that is used by the super-droplet scheme valid options are: pprof_const_th_rv, pprof_const_rhod, pprof_piecewise_const_rhod wait (Optional[float]): number of timesteps to run parcel model with vertical velocity=0 at the end of simulation (added for testing) """ # packing function arguments into "opts" dictionary args, _, _, _ = inspect.getargvalues(inspect.currentframe()) opts = dict(zip(args, [locals()[k] for k in args])) # parsing json specification of output spectra spectra = json.loads(opts["out_bin"]) # parsing json specification of init aerosol spectra aerosol = json.loads(opts["aerosol"]) # default water content if ((opts["r_0"] < 0) and (opts["RH_0"] < 0)): print "both r_0 and RH_0 negative, using default r_0 = 0.022" r_0 = .022 # water coontent specified with RH if ((opts["r_0"] < 0) and (opts["RH_0"] >= 0)): r_0 = common.eps * opts["RH_0"] * common.p_vs(T_0) / (p_0 - opts["RH_0"] * common.p_vs(T_0)) # sanity checks for arguments _arguments_checking(opts, spectra, aerosol) th_0 = T_0 * (common.p_1000 / p_0)**(common.R_d / common.c_pd) nt = int(z_max / (w * dt)) state = { "t" : 0, "z" : 0, "r_v" : np.array([r_0]), "p" : p_0, "th_d" : np.array([common.th_std2dry(th_0, r_0)]), "rhod" : np.array([common.rhod(p_0, th_0, r_0)]), "T" : None, "RH" : None } if opts["chem_dsl"] or opts["chem_dsc"] or opts["chem_rct"]: for key in _Chem_g_id.iterkeys(): state.update({ key : np.array([opts[key]])}) info = { "RH_max" : 0, "libcloud_Git_revision" : libcloud_version, "parcel_Git_revision" : parcel_version } micro = _micro_init(aerosol, opts, state, info) with _output_init(micro, opts, spectra) as fout: # adding chem state vars if micro.opts_init.chem_switch: state.update({ "SO2_a" : 0.,"O3_a" : 0.,"H2O2_a" : 0.,}) state.update({ "CO2_a" : 0.,"HNO3_a" : 0.}) micro.diag_all() # selecting all particles micro.diag_chem(_Chem_a_id["NH3_a"]) state.update({"NH3_a": np.frombuffer(micro.outbuf())[0]}) # t=0 : init & save _output(fout, opts, micro, state, 0, spectra) # timestepping for it in range(1,nt+1): # diagnostics # the reasons to use analytic solution: # - independent of dt # - same as in 2D kinematic model state["z"] += w * dt state["t"] = it * dt # pressure if pprof == "pprof_const_th_rv": # as in icicle model p_hydro = _p_hydro_const_th_rv(state["z"], p_0, th_0, r_0) elif pprof == "pprof_const_rhod": # as in Grabowski and Wang 2009 rho = 1.13 # kg/m3 1.13 state["p"] = _p_hydro_const_rho(state["z"], p_0, rho) elif pprof == "pprof_piecewise_const_rhod": # as in Grabowski and Wang 2009 but calculating pressure # for rho piecewise constant per each time step state["p"] = _p_hydro_const_rho(w*dt, state["p"], state["rhod"][0]) else: raise Exception("pprof should be pprof_const_th_rv, pprof_const_rhod, or pprof_piecewise_const_rhod") # dry air density if pprof == "pprof_const_th_rv": state["rhod"][0] = common.rhod(p_hydro, th_0, r_0) state["p"] = common.p( state["rhod"][0], state["r_v"][0], common.T(state["th_d"][0], state["rhod"][0]) ) else: state["rhod"][0] = common.rhod( state["p"], common.th_dry2std(state["th_d"][0], state["r_v"][0]), state["r_v"][0] ) # microphysics _micro_step(micro, state, info, opts, it, fout) # TODO: only if user wants to stop @ RH_max #if (state["RH"] < info["RH_max"]): break # output if (it % outfreq == 0): print str(round(it / (nt * 1.) * 100, 2)) + " %" rec = it/outfreq _output(fout, opts, micro, state, rec, spectra) _save_attrs(fout, info) _save_attrs(fout, opts) if wait != 0: for it in range (nt+1, nt+wait): state["t"] = it * dt _micro_step(micro, state, info, opts, it, fout) if (it % outfreq == 0): rec = it/outfreq _output(fout, opts, micro, state, rec, spectra)
import sys sys.path.insert(0, "../../bindings/python/") #<listing-1> from libcloudphxx import common, git_revision print git_revision print "common.p_vs(273.16)=", common.p_vs(273.16) assert abs(common.p_vs(273.16) - 611.73) < .001 #</listing-1> print "R_d =", common.R_d print "c_pd =", common.c_pd print "g =", common.g print "p_1000 =", common.p_1000 print "eps =", common.eps print "rho_w =", common.rho_w th = 300 rv = .01 print common.th_dry2std(th, rv) assert common.th_std2dry(common.th_dry2std(th, rv), rv) == th rd3 = (.2e-6)**3 assert common.rw3_cr(rd3, .5, 300) > rd3 assert common.S_cr(rd3, .5, 300) > 1 # just testing if pressure at 200m is lower than at 100m assert common.p_hydro(100, 300, .01, 0, 100000) > common.p_hydro(200, 300, .01, 0, 100000)