def test(RH_formula, step_count, substep_count, exact_substep, constp): print "[RH_formula = ", RH_formula, "]" print "step_count = ", step_count, " substep_count = ", substep_count, "exact substepping = ", exact_substep, "constp = ", constp opts_init.sstp_cond = substep_count opts_init.exact_sstp_cond = exact_substep opts_init.RH_formula = RH_formula rhod, th, rv, p = initial_state() rv_init = rv.copy() # in constp mode, th_std is expected instead of th_dry if constp == True: # dry/std conversions assume p = rhod (Rd + rv * Rv) T # which in general is not true in constp, but is true at init so we use it here th[0] = common.th_dry2std(th[0], rv[0]) th_init = th.copy() prtcls = lgrngn.factory(backend, opts_init) if constp == False: prtcls.init(th, rv, rhod) else: prtcls.init(th, rv, rhod, p) ss = supersaturation(prtcls) print "initial supersaturation", ss exectime = 0 # first step without condesnation just to see diag output opts.cond = False for step in arange(step_count): wrapped = wrapper(prtcls.step_sync, opts, th, rv, rhod) exectime += timeit.timeit(wrapped, number=1) prtcls.step_async(opts) opts.cond = True # print step, supersaturation(prtcls), temperature(prtcls), pressure(prtcls), th[0], rv[0] ss_post_cond = supersaturation(prtcls) print "supersaturation after condensation", ss_post_cond, th[0], rv[0] assert (abs(th[0] - exp_th[constp]) < 1e-4 * exp_th[constp]) assert (abs(rv[0] - exp_rv[constp]) < 1e-3 * exp_rv[constp]) rv_diff = rv_init.copy() - rv[0].copy() # change to subsaturated air - test evaporation rv[0] = 0.002 rv_init = rv.copy() for step in arange(step_count): wrapped = wrapper(prtcls.step_sync, opts, th, rv, rhod) exectime += timeit.timeit(wrapped, number=1) prtcls.step_async(opts) # print step, supersaturation(prtcls), temperature(prtcls), pressure(prtcls), th[0], rv[0] ss_post_evap = supersaturation(prtcls) print "supersaturation after evaporation", ss_post_evap, th[0], rv[0] print 'execution time: ', exectime return ss_post_cond, th[0] - th_init[0], rv[0] - rv_init[0] - rv_diff[0]
def test(RH_formula, step_count, substep_count, exact_substep, constp): print "[RH_formula = ", RH_formula,"]" print "step_count = ", step_count, " substep_count = ", substep_count, "exact substepping = ", exact_substep, "constp = ", constp opts_init.sstp_cond=substep_count opts_init.exact_sstp_cond=exact_substep opts_init.RH_formula = RH_formula rhod, th, rv, p = initial_state() rv_init = rv.copy() # in constp mode, th_std is expected instead of th_dry if constp == True: # dry/std conversions assume p = rhod (Rd + rv * Rv) T # which in general is not true in constp, but is true at init so we use it here th[0] = common.th_dry2std(th[0], rv[0]) th_init = th.copy() prtcls = lgrngn.factory(backend, opts_init) if constp == False: prtcls.init(th, rv, rhod) else: prtcls.init(th, rv, rhod, p) ss = supersaturation(prtcls) print "initial supersaturation", ss exectime = 0 # first step without condesnation just to see diag output opts.cond = False for step in arange(step_count): wrapped = wrapper(prtcls.step_sync, opts, th, rv, rhod) exectime += timeit.timeit(wrapped, number=1) prtcls.step_async(opts) opts.cond = True # print step, supersaturation(prtcls), temperature(prtcls), pressure(prtcls), th[0], rv[0] ss_post_cond = supersaturation(prtcls) print "supersaturation after condensation", ss_post_cond, th[0], rv[0] assert(abs(th[0] - exp_th[constp]) < 1e-4 * exp_th[constp]) assert(abs(rv[0] - exp_rv[constp]) < 1e-3 * exp_rv[constp]) rv_diff = rv_init.copy() - rv[0].copy() # change to subsaturated air - test evaporation rv[0] = 0.002 rv_init = rv.copy() for step in arange(step_count): wrapped = wrapper(prtcls.step_sync, opts, th, rv, rhod) exectime += timeit.timeit(wrapped, number=1) prtcls.step_async(opts) # print step, supersaturation(prtcls), temperature(prtcls), pressure(prtcls), th[0], rv[0] ss_post_evap = supersaturation(prtcls) print "supersaturation after evaporation", ss_post_evap, th[0], rv[0] print 'execution time: ', exectime return ss_post_cond, th[0] - th_init[0], rv[0] - rv_init[0] - rv_diff[0]
def test_adj_cellwise_nwtrph(init_sup_sat, nwtrph_iters=nwtrph_iters_def): opts.nwtrph_iters = nwtrph_iters print("[nwtrph adj_cellwise]") rhod, th, rv, rc, rr, dt = initial_state(init_sup_sat) # define pressure consistent with adj_cellwise to compare results p = arr_t([common.p(rhod[0], rv[0], common.T(th[0], rhod[0]))]) #nwtrph requires th_std input th_std = arr_t([common.th_dry2std(th[0], rv[0])]) blk_1m.adj_cellwise_nwtrph(opts, p, th_std, rv, rc, dt) T = common.exner(p[0]) * th_std[0] ss = supersaturation(T, p[0], rv[0]) print("final supersaturation", ss, th_std[0], rv[0]) return ss
def test_adj_cellwise_nwtrph(init_sup_sat, nwtrph_iters = nwtrph_iters_def): opts.nwtrph_iters = nwtrph_iters print "[nwtrph adj_cellwise]" rhod, th, rv, rc, rr, dt = initial_state(init_sup_sat) # define pressure consistent with adj_cellwise to compare results p = arr_t([common.p(rhod[0], rv[0], common.T(th[0], rhod[0]))]) #nwtrph requires th_std input th_std = arr_t([common.th_dry2std(th[0], rv[0])]) blk_1m.adj_cellwise_nwtrph(opts, p, th_std, rv, rc, dt) T = common.exner(p[0]) * th_std[0] ss = supersaturation(T, p[0], rv[0]) print "final supersaturation", ss, th_std[0], rv[0] return ss
def test_adj_cellwise_constp(init_sup_sat, r_eps = r_eps_def): opts.r_eps = r_eps print "[constp adj_cellwise]" rhod, th, rv, rc, rr, dt = initial_state(init_sup_sat) # define pressure consistent with adj_cellwise to compare results p = arr_t([common.p(rhod[0], rv[0], common.T(th[0], rhod[0]))]) #constp requires th_std input th_std = arr_t([common.th_dry2std(th[0], rv[0])]) blk_1m.adj_cellwise_constp(opts, rhod, p, th_std, rv, rc, rr, dt) T = common.exner(p[0]) * th_std[0] ss = supersaturation(T, p[0], rv[0]) print "final supersaturation", ss, th_std[0], rv[0] return ss
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 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 parcel(dt=.1, z_max=200., w=1., T_0=300., p_0=101300., r_0=.022, outfile="test.nc", pprof="pprof_piecewise_const_rhod", outfreq=100, sd_conc=64, kappa=.5, mean_r = .04e-6 / 2, gstdev = 1.4, n_tot = 60.e6, out_bin = '{"radii": {"rght": 0.0001, "moms": [0], "drwt": "wet", "nbin": 26, "lnli": "log", "left": 1e-09}}', SO2_g_0 = 0., O3_g_0 = 0., H2O2_g_0 = 0., chem_sys = 'open', chem_dsl = False, chem_dsc = False, chem_rct = False, chem_spn = 1, chem_rho = 1.8e3 ): """ 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] 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) kappa (Optional[float]): kappa hygroscopicity parameter (see doi:10.5194/acp-7-1961-2007) mean_r (Optional[float]): lognormal distribution mode diameter [m] gstdev (Optional[float]): lognormal distribution geometric standard deviation [1] n_tot (Optional[float]): lognormal distribution total concentration under standard conditions (T=20C, p=1013.25 hPa, rv=0) [m-3] 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 (TODO - add chemistry output description) SO2_g_0 (Optional[float]): initial SO2 gas volume concentration (mole fraction) [1] O3_g_0 (Optional[float]): initial O3 gas volume concentration (mole fraction) [1] H2O2_g_0 (Optional[float]): initial H2O2 gas volume concentration (mole fraction) [1] chem_sys (Optional[string]): accepted values: 'open', 'closed' (in open/closed system gas volume concentration in the air doesn't/does change due to chemical reactions) 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 chem_spn (Optional[int]): number of spinup timesteps before enabling chemical reactions 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 """ # 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"]) # sanity checks for arguments _arguments_checking(opts, spectra) 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 } info = { "RH_max" : 0, "libcloud_Git_revision" : libcloud_version, "parcel_Git_revision" : parcel_version } micro = _micro_init(opts, state, info) with _output_init(micro, opts, spectra) as fout: # adding chem state vars if micro.opts_init.chem_switch: state.update({ "SO2_g" : SO2_g_0, "O3_g" : O3_g_0, "H2O2_g" : H2O2_g_0 }) state.update({ "SO2_a" : 0., "O3_a" : 0., "H2O2_a" : 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: assert(False) # 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) # TODO: only if user wants to stop @ RH_max #if (state["RH"] < info["RH_max"]): break # output if (it % outfreq == 0): rec = it/outfreq _output(fout, opts, micro, state, rec, spectra) _save_attrs(fout, info) _save_attrs(fout, opts)
# lgrngn-specific parameters sd_conc = 44 def lognormal(lnr): mean_r = .08e-6 / 2 stdev = 2 n_tot = 566e6 return n_tot * exp(-pow( (lnr - log(mean_r)), 2) / 2 / pow(log(stdev), 2)) / log(stdev) / sqrt( 2 * pi) kappa = .61 #TODO - check # rho = 1.8 # TODO chem_gas = { chem_species_t.SO2: 200e-12, chem_species_t.O3: 50e-9, chem_species_t.H2O2: 500e-12 } # running all three for rhs in [ rhs_blk_2m(dt), rhs_lgrngn(dt, sd_conc, {kappa: lognormal}, chem_gas) ]: parcel(p_d, th_d, r_v, w, dt, nt, rhs) print p_d, arr_t([th_dry2std(th_d[0], r_v[0])]), r_v
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) # just testing if the density is > 1 kg / m3 assert common.rhod(100000, 300, 0) > 1
# blk_2m-specific parameter # TODO: spectrum # lgrngn-specific parameters sd_conc = 44 def lognormal(lnr): mean_r = .08e-6 / 2 stdev = 2 n_tot = 566e6 return n_tot * exp( -pow((lnr - log(mean_r)), 2) / 2 / pow(log(stdev),2) ) / log(stdev) / sqrt(2*pi); kappa = .61 #TODO - check # rho = 1.8 # TODO chem_gas = { chem_species_t.SO2 : 200e-12, chem_species_t.O3 : 50e-9, chem_species_t.H2O2 : 500e-12 } # running all three for rhs in [ rhs_blk_2m(dt), rhs_lgrngn(dt, sd_conc, {kappa:lognormal}, chem_gas) ]: parcel(p_d, th_d, r_v, w, dt, nt, rhs) print p_d, arr_t([th_dry2std(th_d[0], r_v[0])]), r_v
def test(RH_formula, step_count, substep_count, exact_substep, constp): print("[RH_formula = ", RH_formula, "]") print("step_count = ", step_count, " substep_count = ", substep_count, "exact substepping = ", exact_substep, "constp = ", constp) opts_init.sstp_cond = substep_count opts_init.exact_sstp_cond = exact_substep opts_init.RH_formula = RH_formula rhod, th, rv, p = initial_state() rhod_ss, th_ss, rv_ss, p_ss = supersat_state() # in constp mode, th_std is expected instead of th_dry if constp == True: # dry/std conversions assume p = rhod (Rd + rv * Rv) T # which in general is not true in constp, but is true at init so we use it here th[0] = common.th_dry2std(th[0], rv[0]) th_ss[0] = common.th_dry2std(th_ss[0], rv_ss[0]) prtcls = lgrngn.factory(backend, opts_init) if constp == False: prtcls.init(th, rv, rhod) else: prtcls.init(th, rv, rhod, p_ss) # go to supersaturated air, density changes to test density substepping too rhod[0] = rhod_ss th[0] = th_ss rv[0] = rv_ss rv_init = rv.copy() th_init = th.copy() exectime = 0 opts.cond = 0 for step in arange(step_count): wrapped = wrapper(prtcls.step_sync, opts, th, rv, rhod) exectime += timeit.timeit(wrapped, number=1) prtcls.step_async(opts) if step == 9: # some parameters are analyzed after 10 steps, before small CCNs evaporate act_conc_post_cond = act_conc(prtcls) mean_r_post_cond = mean_r(prtcls) second_r_post_cond = second_r(prtcls) third_r_post_cond = third_r(prtcls) if step == 0: print("initial supersaturation", supersaturation(prtcls)) opts.cond = 1 # print step, supersaturation(prtcls), th[0], rv[0], mean_r(prtcls), second_r(prtcls), third_r(prtcls), act_conc(prtcls) ss_post_cond = supersaturation(prtcls) print("supersaturation after condensation", ss_post_cond, th[0], rv[0], mean_r(prtcls), second_r(prtcls), third_r(prtcls), act_conc(prtcls)) assert (abs(th[0] - exp_th[constp]) < 1e-4 * exp_th[constp]) assert (abs(rv[0] - exp_rv[constp]) < 1e-3 * exp_rv[constp]) rv_diff = rv_init.copy() - rv[0].copy() th_diff = th_init.copy() - th[0].copy() # change to subsaturated air - test evaporation rhod[0] = 1.1 th[0] = 305 rv[0] = 0.0085 rv_init = rv.copy() th_init = th.copy() for step in arange(step_count): wrapped = wrapper(prtcls.step_sync, opts, th, rv, rhod) exectime += timeit.timeit(wrapped, number=1) prtcls.step_async(opts) # print step, supersaturation(prtcls), th[0], rv[0], mean_r(prtcls), second_r(prtcls), third_r(prtcls), act_conc(prtcls) ss_post_evap = supersaturation(prtcls) print("supersaturation after evaporation", ss_post_evap, th[0], rv[0], mean_r(prtcls), second_r(prtcls), third_r(prtcls), act_conc(prtcls), gccn_conc(prtcls)) # after evaporation, only larger mode particles should have r > 0.5 microns assert (act_conc(prtcls) == gccn_conc(prtcls)) print('execution time: ', exectime) return ss_post_cond, th[0] - th_init[0] - th_diff[0], rv[0] - rv_init[ 0] - rv_diff[ 0], act_conc_post_cond, mean_r_post_cond, second_r_post_cond, third_r_post_cond
def test(RH_formula, step_count, substep_count, exact_substep, constp): print "[RH_formula = ", RH_formula,"]" print "step_count = ", step_count, " substep_count = ", substep_count, "exact substepping = ", exact_substep, "constp = ", constp opts_init.sstp_cond=substep_count opts_init.exact_sstp_cond=exact_substep opts_init.RH_formula = RH_formula rhod, th, rv, p = initial_state() rhod_ss, th_ss, rv_ss, p_ss = supersat_state() # in constp mode, th_std is expected instead of th_dry if constp == True: # dry/std conversions assume p = rhod (Rd + rv * Rv) T # which in general is not true in constp, but is true at init so we use it here th[0] = common.th_dry2std(th[0], rv[0]) th_ss[0] = common.th_dry2std(th_ss[0], rv_ss[0]) prtcls = lgrngn.factory(backend, opts_init) if constp == False: prtcls.init(th, rv, rhod) else: prtcls.init(th, rv, rhod, p_ss) # go to supersaturated air, density changes to test density substepping too rhod[0] = rhod_ss th[0] = th_ss rv[0] = rv_ss rv_init = rv.copy() th_init = th.copy() exectime = 0 opts.cond = 0 for step in arange(step_count): wrapped = wrapper(prtcls.step_sync, opts, th, rv, rhod) exectime += timeit.timeit(wrapped, number=1) prtcls.step_async(opts) if step == 9: # some parameters are analyzed after 10 steps, before small CCNs evaporate act_conc_post_cond = act_conc(prtcls) mean_r_post_cond = mean_r(prtcls) second_r_post_cond = second_r(prtcls) third_r_post_cond = third_r(prtcls) if step == 0: print "initial supersaturation", supersaturation(prtcls) opts.cond = 1 # print step, supersaturation(prtcls), th[0], rv[0], mean_r(prtcls), second_r(prtcls), third_r(prtcls), act_conc(prtcls) ss_post_cond = supersaturation(prtcls) print "supersaturation after condensation", ss_post_cond, th[0], rv[0], mean_r(prtcls), second_r(prtcls), third_r(prtcls), act_conc(prtcls) assert(abs(th[0] - exp_th[constp]) < 1e-4 * exp_th[constp]) assert(abs(rv[0] - exp_rv[constp]) < 1e-3 * exp_rv[constp]) rv_diff = rv_init.copy() - rv[0].copy() th_diff = th_init.copy() - th[0].copy() # change to subsaturated air - test evaporation rhod[0] = 1.1 th[0] = 305 rv[0] = 0.0085 rv_init = rv.copy() th_init = th.copy() for step in arange(step_count): wrapped = wrapper(prtcls.step_sync, opts, th, rv, rhod) exectime += timeit.timeit(wrapped, number=1) prtcls.step_async(opts) # print step, supersaturation(prtcls), th[0], rv[0], mean_r(prtcls), second_r(prtcls), third_r(prtcls), act_conc(prtcls) ss_post_evap = supersaturation(prtcls) print "supersaturation after evaporation", ss_post_evap, th[0], rv[0], mean_r(prtcls), second_r(prtcls), third_r(prtcls), act_conc(prtcls), gccn_conc(prtcls) # after evaporation, only larger mode particles should have r > 0.5 microns assert(act_conc(prtcls) == gccn_conc(prtcls)) print 'execution time: ', exectime return ss_post_cond, th[0] - th_init[0] - th_diff[0], rv[0] - rv_init[0] - rv_diff[0], act_conc_post_cond, mean_r_post_cond, second_r_post_cond, third_r_post_cond
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) # just testing if the density is > 1 kg / m3 assert common.rhod(100000, 300, 0) > 1