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    )