PySDM_examples.Abdul_Razzak_Ghan_2000.run_ARG_parcel
1from collections import namedtuple 2 3import numpy as np 4from PySDM_examples.Abdul_Razzak_Ghan_2000.aerosol import CONSTANTS_ARG, AerosolARG 5 6from PySDM import Builder, Formulae 7from PySDM import products as PySDM_products 8from PySDM.backends import CPU 9from PySDM.dynamics import AmbientThermodynamics, Condensation 10from PySDM.environments import Parcel 11from PySDM.initialisation.hygroscopic_equilibrium import equilibrate_wet_radii 12from PySDM.initialisation.sampling.spectral_sampling import ConstantMultiplicity 13from PySDM.physics import si 14 15 16def run_parcel( 17 w, 18 sol2, 19 N2, 20 rad2, 21 n_sd_per_mode, 22 RH0=1.0, 23 T0=294 * si.K, 24 p0=1e5 * si.Pa, 25 n_steps=50, 26 mass_of_dry_air=1e3 * si.kg, 27 dt=2 * si.s, 28): 29 products = ( 30 PySDM_products.WaterMixingRatio(unit="g/kg", name="liquid water mixing ratio"), 31 PySDM_products.PeakSaturation(name="S max"), 32 PySDM_products.AmbientRelativeHumidity(name="RH"), 33 PySDM_products.ParcelDisplacement(name="z"), 34 ) 35 36 formulae = Formulae(constants=CONSTANTS_ARG) 37 const = formulae.constants 38 pv0 = RH0 * formulae.saturation_vapour_pressure.pvs_water(T0) 39 40 env = Parcel( 41 dt=dt, 42 mass_of_dry_air=mass_of_dry_air, 43 p0=p0, 44 initial_water_vapour_mixing_ratio=const.eps * pv0 / (p0 - pv0), 45 w=w, 46 T0=T0, 47 ) 48 49 aerosol = AerosolARG( 50 M2_sol=sol2, M2_N=N2, M2_rad=rad2, water_molar_volume=const.Mv / const.rho_w 51 ) 52 n_sd = n_sd_per_mode * len(aerosol.modes) 53 54 builder = Builder(backend=CPU(formulae), n_sd=n_sd, environment=env) 55 builder.add_dynamic(AmbientThermodynamics()) 56 builder.add_dynamic(Condensation()) 57 builder.request_attribute("critical saturation") 58 59 attributes = { 60 k: np.empty(0) for k in ("dry volume", "kappa times dry volume", "multiplicity") 61 } 62 for i, mode in enumerate(aerosol.modes): 63 kappa, spectrum = mode["kappa"]["CompressedFilmOvadnevaite"], mode["spectrum"] 64 r_dry, concentration = ConstantMultiplicity(spectrum).sample_deterministic( 65 n_sd_per_mode 66 ) 67 v_dry = builder.formulae.trivia.volume(radius=r_dry) 68 specific_concentration = concentration / builder.formulae.constants.rho_STP 69 attributes["multiplicity"] = np.append( 70 attributes["multiplicity"], 71 specific_concentration * builder.particulator.environment.mass_of_dry_air, 72 ) 73 attributes["dry volume"] = np.append(attributes["dry volume"], v_dry) 74 attributes["kappa times dry volume"] = np.append( 75 attributes["kappa times dry volume"], v_dry * kappa 76 ) 77 78 r_wet = equilibrate_wet_radii( 79 r_dry=builder.formulae.trivia.radius(volume=attributes["dry volume"]), 80 environment=builder.particulator.environment, 81 kappa_times_dry_volume=attributes["kappa times dry volume"], 82 ) 83 attributes["volume"] = builder.formulae.trivia.volume(radius=r_wet) 84 85 particulator = builder.build(attributes, products=products) 86 87 output = {product.name: [] for product in particulator.products.values()} 88 output_attributes = { 89 "multiplicity": tuple([] for _ in range(particulator.n_sd)), 90 "volume": tuple([] for _ in range(particulator.n_sd)), 91 "critical volume": tuple([] for _ in range(particulator.n_sd)), 92 "critical saturation": tuple([] for _ in range(particulator.n_sd)), 93 } 94 95 for _ in range(n_steps): 96 particulator.run(steps=1) 97 for product in particulator.products.values(): 98 value = product.get() 99 output[product.name].append(value[0]) 100 for key, attr in output_attributes.items(): 101 attr_data = particulator.attributes[key].to_ndarray() 102 for drop_id in range(particulator.n_sd): 103 attr[drop_id].append(attr_data[drop_id]) 104 105 error = np.zeros(len(aerosol.modes)) 106 activated_fraction_S = np.zeros(len(aerosol.modes)) 107 activated_fraction_V = np.zeros(len(aerosol.modes)) 108 for j, mode in enumerate(aerosol.modes): 109 activated_drops_j_S = 0 110 activated_drops_j_V = 0 111 RHmax = np.nanmax(np.asarray(output["RH"])) 112 for i, volume in enumerate(output_attributes["volume"]): 113 if j * n_sd_per_mode <= i < (j + 1) * n_sd_per_mode: 114 if output_attributes["critical saturation"][i][-1] < RHmax: 115 activated_drops_j_S += output_attributes["multiplicity"][i][-1] 116 if output_attributes["critical volume"][i][-1] < volume[-1]: 117 activated_drops_j_V += output_attributes["multiplicity"][i][-1] 118 Nj = np.asarray(output_attributes["multiplicity"])[ 119 j * n_sd_per_mode : (j + 1) * n_sd_per_mode, -1 120 ] 121 max_multiplicity_j = np.max(Nj) 122 sum_multiplicity_j = np.sum(Nj) 123 error[j] = max_multiplicity_j / sum_multiplicity_j 124 activated_fraction_S[j] = activated_drops_j_S / sum_multiplicity_j 125 activated_fraction_V[j] = activated_drops_j_V / sum_multiplicity_j 126 127 Output = namedtuple( 128 "Output", 129 [ 130 "profile", 131 "attributes", 132 "aerosol", 133 "activated_fraction_S", 134 "activated_fraction_V", 135 "error", 136 ], 137 ) 138 return Output( 139 profile=output, 140 attributes=output_attributes, 141 aerosol=aerosol, 142 activated_fraction_S=activated_fraction_S, 143 activated_fraction_V=activated_fraction_V, 144 error=error, 145 )
def
run_parcel( w, sol2, N2, rad2, n_sd_per_mode, RH0=1.0, T0=294.0, p0=100000.0, n_steps=50, mass_of_dry_air=1000.0, dt=2.0):
17def run_parcel( 18 w, 19 sol2, 20 N2, 21 rad2, 22 n_sd_per_mode, 23 RH0=1.0, 24 T0=294 * si.K, 25 p0=1e5 * si.Pa, 26 n_steps=50, 27 mass_of_dry_air=1e3 * si.kg, 28 dt=2 * si.s, 29): 30 products = ( 31 PySDM_products.WaterMixingRatio(unit="g/kg", name="liquid water mixing ratio"), 32 PySDM_products.PeakSaturation(name="S max"), 33 PySDM_products.AmbientRelativeHumidity(name="RH"), 34 PySDM_products.ParcelDisplacement(name="z"), 35 ) 36 37 formulae = Formulae(constants=CONSTANTS_ARG) 38 const = formulae.constants 39 pv0 = RH0 * formulae.saturation_vapour_pressure.pvs_water(T0) 40 41 env = Parcel( 42 dt=dt, 43 mass_of_dry_air=mass_of_dry_air, 44 p0=p0, 45 initial_water_vapour_mixing_ratio=const.eps * pv0 / (p0 - pv0), 46 w=w, 47 T0=T0, 48 ) 49 50 aerosol = AerosolARG( 51 M2_sol=sol2, M2_N=N2, M2_rad=rad2, water_molar_volume=const.Mv / const.rho_w 52 ) 53 n_sd = n_sd_per_mode * len(aerosol.modes) 54 55 builder = Builder(backend=CPU(formulae), n_sd=n_sd, environment=env) 56 builder.add_dynamic(AmbientThermodynamics()) 57 builder.add_dynamic(Condensation()) 58 builder.request_attribute("critical saturation") 59 60 attributes = { 61 k: np.empty(0) for k in ("dry volume", "kappa times dry volume", "multiplicity") 62 } 63 for i, mode in enumerate(aerosol.modes): 64 kappa, spectrum = mode["kappa"]["CompressedFilmOvadnevaite"], mode["spectrum"] 65 r_dry, concentration = ConstantMultiplicity(spectrum).sample_deterministic( 66 n_sd_per_mode 67 ) 68 v_dry = builder.formulae.trivia.volume(radius=r_dry) 69 specific_concentration = concentration / builder.formulae.constants.rho_STP 70 attributes["multiplicity"] = np.append( 71 attributes["multiplicity"], 72 specific_concentration * builder.particulator.environment.mass_of_dry_air, 73 ) 74 attributes["dry volume"] = np.append(attributes["dry volume"], v_dry) 75 attributes["kappa times dry volume"] = np.append( 76 attributes["kappa times dry volume"], v_dry * kappa 77 ) 78 79 r_wet = equilibrate_wet_radii( 80 r_dry=builder.formulae.trivia.radius(volume=attributes["dry volume"]), 81 environment=builder.particulator.environment, 82 kappa_times_dry_volume=attributes["kappa times dry volume"], 83 ) 84 attributes["volume"] = builder.formulae.trivia.volume(radius=r_wet) 85 86 particulator = builder.build(attributes, products=products) 87 88 output = {product.name: [] for product in particulator.products.values()} 89 output_attributes = { 90 "multiplicity": tuple([] for _ in range(particulator.n_sd)), 91 "volume": tuple([] for _ in range(particulator.n_sd)), 92 "critical volume": tuple([] for _ in range(particulator.n_sd)), 93 "critical saturation": tuple([] for _ in range(particulator.n_sd)), 94 } 95 96 for _ in range(n_steps): 97 particulator.run(steps=1) 98 for product in particulator.products.values(): 99 value = product.get() 100 output[product.name].append(value[0]) 101 for key, attr in output_attributes.items(): 102 attr_data = particulator.attributes[key].to_ndarray() 103 for drop_id in range(particulator.n_sd): 104 attr[drop_id].append(attr_data[drop_id]) 105 106 error = np.zeros(len(aerosol.modes)) 107 activated_fraction_S = np.zeros(len(aerosol.modes)) 108 activated_fraction_V = np.zeros(len(aerosol.modes)) 109 for j, mode in enumerate(aerosol.modes): 110 activated_drops_j_S = 0 111 activated_drops_j_V = 0 112 RHmax = np.nanmax(np.asarray(output["RH"])) 113 for i, volume in enumerate(output_attributes["volume"]): 114 if j * n_sd_per_mode <= i < (j + 1) * n_sd_per_mode: 115 if output_attributes["critical saturation"][i][-1] < RHmax: 116 activated_drops_j_S += output_attributes["multiplicity"][i][-1] 117 if output_attributes["critical volume"][i][-1] < volume[-1]: 118 activated_drops_j_V += output_attributes["multiplicity"][i][-1] 119 Nj = np.asarray(output_attributes["multiplicity"])[ 120 j * n_sd_per_mode : (j + 1) * n_sd_per_mode, -1 121 ] 122 max_multiplicity_j = np.max(Nj) 123 sum_multiplicity_j = np.sum(Nj) 124 error[j] = max_multiplicity_j / sum_multiplicity_j 125 activated_fraction_S[j] = activated_drops_j_S / sum_multiplicity_j 126 activated_fraction_V[j] = activated_drops_j_V / sum_multiplicity_j 127 128 Output = namedtuple( 129 "Output", 130 [ 131 "profile", 132 "attributes", 133 "aerosol", 134 "activated_fraction_S", 135 "activated_fraction_V", 136 "error", 137 ], 138 ) 139 return Output( 140 profile=output, 141 attributes=output_attributes, 142 aerosol=aerosol, 143 activated_fraction_S=activated_fraction_S, 144 activated_fraction_V=activated_fraction_V, 145 error=error, 146 )