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 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.PeakSupersaturation(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 supersaturation") 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(n_sd_per_mode) 65 v_dry = builder.formulae.trivia.volume(radius=r_dry) 66 specific_concentration = concentration / builder.formulae.constants.rho_STP 67 attributes["multiplicity"] = np.append( 68 attributes["multiplicity"], 69 specific_concentration * builder.particulator.environment.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=builder.formulae.trivia.radius(volume=attributes["dry volume"]), 78 environment=builder.particulator.environment, 79 kappa_times_dry_volume=attributes["kappa times dry volume"], 80 ) 81 attributes["volume"] = builder.formulae.trivia.volume(radius=r_wet) 82 83 particulator = builder.build(attributes, products=products) 84 85 output = {product.name: [] for product in particulator.products.values()} 86 output_attributes = { 87 "multiplicity": tuple([] for _ in range(particulator.n_sd)), 88 "volume": tuple([] for _ in range(particulator.n_sd)), 89 "critical volume": tuple([] for _ in range(particulator.n_sd)), 90 "critical supersaturation": tuple([] for _ in range(particulator.n_sd)), 91 } 92 93 for _ in range(n_steps): 94 particulator.run(steps=1) 95 for product in particulator.products.values(): 96 value = product.get() 97 output[product.name].append(value[0]) 98 for key, attr in output_attributes.items(): 99 attr_data = particulator.attributes[key].to_ndarray() 100 for drop_id in range(particulator.n_sd): 101 attr[drop_id].append(attr_data[drop_id]) 102 103 error = np.zeros(len(aerosol.modes)) 104 activated_fraction_S = np.zeros(len(aerosol.modes)) 105 activated_fraction_V = np.zeros(len(aerosol.modes)) 106 for j, mode in enumerate(aerosol.modes): 107 activated_drops_j_S = 0 108 activated_drops_j_V = 0 109 RHmax = np.nanmax(np.asarray(output["RH"])) 110 for i, volume in enumerate(output_attributes["volume"]): 111 if j * n_sd_per_mode <= i < (j + 1) * n_sd_per_mode: 112 if output_attributes["critical supersaturation"][i][-1] < RHmax: 113 activated_drops_j_S += output_attributes["multiplicity"][i][-1] 114 if output_attributes["critical volume"][i][-1] < volume[-1]: 115 activated_drops_j_V += output_attributes["multiplicity"][i][-1] 116 Nj = np.asarray(output_attributes["multiplicity"])[ 117 j * n_sd_per_mode : (j + 1) * n_sd_per_mode, -1 118 ] 119 max_multiplicity_j = np.max(Nj) 120 sum_multiplicity_j = np.sum(Nj) 121 error[j] = max_multiplicity_j / sum_multiplicity_j 122 activated_fraction_S[j] = activated_drops_j_S / sum_multiplicity_j 123 activated_fraction_V[j] = activated_drops_j_V / sum_multiplicity_j 124 125 Output = namedtuple( 126 "Output", 127 [ 128 "profile", 129 "attributes", 130 "aerosol", 131 "activated_fraction_S", 132 "activated_fraction_V", 133 "error", 134 ], 135 ) 136 return Output( 137 profile=output, 138 attributes=output_attributes, 139 aerosol=aerosol, 140 activated_fraction_S=activated_fraction_S, 141 activated_fraction_V=activated_fraction_V, 142 error=error, 143 )
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.PeakSupersaturation(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 supersaturation") 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(n_sd_per_mode) 66 v_dry = builder.formulae.trivia.volume(radius=r_dry) 67 specific_concentration = concentration / builder.formulae.constants.rho_STP 68 attributes["multiplicity"] = np.append( 69 attributes["multiplicity"], 70 specific_concentration * builder.particulator.environment.mass_of_dry_air, 71 ) 72 attributes["dry volume"] = np.append(attributes["dry volume"], v_dry) 73 attributes["kappa times dry volume"] = np.append( 74 attributes["kappa times dry volume"], v_dry * kappa 75 ) 76 77 r_wet = equilibrate_wet_radii( 78 r_dry=builder.formulae.trivia.radius(volume=attributes["dry volume"]), 79 environment=builder.particulator.environment, 80 kappa_times_dry_volume=attributes["kappa times dry volume"], 81 ) 82 attributes["volume"] = builder.formulae.trivia.volume(radius=r_wet) 83 84 particulator = builder.build(attributes, products=products) 85 86 output = {product.name: [] for product in particulator.products.values()} 87 output_attributes = { 88 "multiplicity": tuple([] for _ in range(particulator.n_sd)), 89 "volume": tuple([] for _ in range(particulator.n_sd)), 90 "critical volume": tuple([] for _ in range(particulator.n_sd)), 91 "critical supersaturation": tuple([] for _ in range(particulator.n_sd)), 92 } 93 94 for _ in range(n_steps): 95 particulator.run(steps=1) 96 for product in particulator.products.values(): 97 value = product.get() 98 output[product.name].append(value[0]) 99 for key, attr in output_attributes.items(): 100 attr_data = particulator.attributes[key].to_ndarray() 101 for drop_id in range(particulator.n_sd): 102 attr[drop_id].append(attr_data[drop_id]) 103 104 error = np.zeros(len(aerosol.modes)) 105 activated_fraction_S = np.zeros(len(aerosol.modes)) 106 activated_fraction_V = np.zeros(len(aerosol.modes)) 107 for j, mode in enumerate(aerosol.modes): 108 activated_drops_j_S = 0 109 activated_drops_j_V = 0 110 RHmax = np.nanmax(np.asarray(output["RH"])) 111 for i, volume in enumerate(output_attributes["volume"]): 112 if j * n_sd_per_mode <= i < (j + 1) * n_sd_per_mode: 113 if output_attributes["critical supersaturation"][i][-1] < RHmax: 114 activated_drops_j_S += output_attributes["multiplicity"][i][-1] 115 if output_attributes["critical volume"][i][-1] < volume[-1]: 116 activated_drops_j_V += output_attributes["multiplicity"][i][-1] 117 Nj = np.asarray(output_attributes["multiplicity"])[ 118 j * n_sd_per_mode : (j + 1) * n_sd_per_mode, -1 119 ] 120 max_multiplicity_j = np.max(Nj) 121 sum_multiplicity_j = np.sum(Nj) 122 error[j] = max_multiplicity_j / sum_multiplicity_j 123 activated_fraction_S[j] = activated_drops_j_S / sum_multiplicity_j 124 activated_fraction_V[j] = activated_drops_j_V / sum_multiplicity_j 125 126 Output = namedtuple( 127 "Output", 128 [ 129 "profile", 130 "attributes", 131 "aerosol", 132 "activated_fraction_S", 133 "activated_fraction_V", 134 "error", 135 ], 136 ) 137 return Output( 138 profile=output, 139 attributes=output_attributes, 140 aerosol=aerosol, 141 activated_fraction_S=activated_fraction_S, 142 activated_fraction_V=activated_fraction_V, 143 error=error, 144 )