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