PySDM_examples.Grabowski_and_Pawlowska_2023.simulation

  1import numpy as np
  2from PySDM_examples.utils import BasicSimulation
  3
  4from PySDM import Builder
  5from PySDM.backends import CPU
  6from PySDM.backends.impl_numba.test_helpers import scipy_ode_condensation_solver
  7from PySDM.dynamics import AmbientThermodynamics, Condensation
  8from PySDM.environments import Parcel
  9from PySDM.initialisation import equilibrate_wet_radii
 10from PySDM.initialisation.sampling.spectral_sampling import ConstantMultiplicity
 11from PySDM.physics import si
 12
 13
 14class Simulation(BasicSimulation):
 15    def __init__(
 16        self,
 17        settings,
 18        products=None,
 19        scipy_solver=False,
 20        sampling_class=ConstantMultiplicity,
 21    ):
 22        builder = Builder(
 23            n_sd=settings.n_sd,
 24            backend=CPU(
 25                formulae=settings.formulae, override_jit_flags={"parallel": False}
 26            ),
 27            environment=Parcel(
 28                dt=settings.timestep,
 29                p0=settings.initial_pressure,
 30                initial_water_vapour_mixing_ratio=settings.initial_vapour_mixing_ratio,
 31                T0=settings.initial_temperature,
 32                w=settings.vertical_velocity,
 33                mass_of_dry_air=44 * si.kg,
 34            ),
 35        )
 36        builder.add_dynamic(AmbientThermodynamics())
 37        builder.add_dynamic(
 38            Condensation(rtol_thd=settings.rtol_thd, rtol_x=settings.rtol_x)
 39        )
 40        for attribute in (
 41            "critical supersaturation",
 42            "equilibrium supersaturation",
 43            "critical volume",
 44        ):
 45            builder.request_attribute(attribute)
 46
 47        env = builder.particulator.environment
 48        volume = env.mass_of_dry_air / settings.initial_air_density
 49        attributes = {
 50            k: np.empty(0)
 51            for k in ("dry volume", "kappa times dry volume", "multiplicity")
 52        }
 53
 54        assert len(settings.aerosol_modes_by_kappa.keys()) == 1
 55        kappa = tuple(settings.aerosol_modes_by_kappa.keys())[0]
 56        spectrum = settings.aerosol_modes_by_kappa[kappa]
 57
 58        r_dry, n_per_volume = sampling_class(spectrum).sample(settings.n_sd)
 59        v_dry = settings.formulae.trivia.volume(radius=r_dry)
 60        attributes["multiplicity"] = np.append(
 61            attributes["multiplicity"], n_per_volume * volume
 62        )
 63        attributes["dry volume"] = np.append(attributes["dry volume"], v_dry)
 64        attributes["kappa times dry volume"] = np.append(
 65            attributes["kappa times dry volume"], v_dry * kappa
 66        )
 67        r_wet = equilibrate_wet_radii(
 68            r_dry=settings.formulae.trivia.radius(volume=attributes["dry volume"]),
 69            environment=env,
 70            kappa_times_dry_volume=attributes["kappa times dry volume"],
 71        )
 72        attributes["volume"] = settings.formulae.trivia.volume(radius=r_wet)
 73
 74        super().__init__(
 75            particulator=builder.build(attributes=attributes, products=products)
 76        )
 77        if scipy_solver:
 78            scipy_ode_condensation_solver.patch_particulator(self.particulator)
 79
 80        self.output_attributes = {
 81            "volume": tuple([] for _ in range(self.particulator.n_sd)),
 82            "dry volume": tuple([] for _ in range(self.particulator.n_sd)),
 83            "critical supersaturation": tuple(
 84                [] for _ in range(self.particulator.n_sd)
 85            ),
 86            "equilibrium supersaturation": tuple(
 87                [] for _ in range(self.particulator.n_sd)
 88            ),
 89            "critical volume": tuple([] for _ in range(self.particulator.n_sd)),
 90            "multiplicity": tuple([] for _ in range(self.particulator.n_sd)),
 91        }
 92        self.settings = settings
 93
 94        self.__sanity_checks(attributes, volume)
 95
 96    def __sanity_checks(self, attributes, volume):
 97        for attribute in attributes.values():
 98            assert attribute.shape[0] == self.particulator.n_sd
 99        np.testing.assert_approx_equal(
100            sum(attributes["multiplicity"]) / volume,
101            sum(
102                mode.norm_factor
103                for mode in self.settings.aerosol_modes_by_kappa.values()
104            ),
105            significant=4,
106        )
107
108    def _save(self, output):
109        for key, attr in self.output_attributes.items():
110            attr_data = self.particulator.attributes[key].to_ndarray()
111            for drop_id in range(self.particulator.n_sd):
112                attr[drop_id].append(attr_data[drop_id])
113        super()._save(output)
114
115    def run(self):
116        output_products = super()._run(
117            self.settings.nt, self.settings.steps_per_output_interval
118        )
119        return {"products": output_products, "attributes": self.output_attributes}
 15class Simulation(BasicSimulation):
 16    def __init__(
 17        self,
 18        settings,
 19        products=None,
 20        scipy_solver=False,
 21        sampling_class=ConstantMultiplicity,
 22    ):
 23        builder = Builder(
 24            n_sd=settings.n_sd,
 25            backend=CPU(
 26                formulae=settings.formulae, override_jit_flags={"parallel": False}
 27            ),
 28            environment=Parcel(
 29                dt=settings.timestep,
 30                p0=settings.initial_pressure,
 31                initial_water_vapour_mixing_ratio=settings.initial_vapour_mixing_ratio,
 32                T0=settings.initial_temperature,
 33                w=settings.vertical_velocity,
 34                mass_of_dry_air=44 * si.kg,
 35            ),
 36        )
 37        builder.add_dynamic(AmbientThermodynamics())
 38        builder.add_dynamic(
 39            Condensation(rtol_thd=settings.rtol_thd, rtol_x=settings.rtol_x)
 40        )
 41        for attribute in (
 42            "critical supersaturation",
 43            "equilibrium supersaturation",
 44            "critical volume",
 45        ):
 46            builder.request_attribute(attribute)
 47
 48        env = builder.particulator.environment
 49        volume = env.mass_of_dry_air / settings.initial_air_density
 50        attributes = {
 51            k: np.empty(0)
 52            for k in ("dry volume", "kappa times dry volume", "multiplicity")
 53        }
 54
 55        assert len(settings.aerosol_modes_by_kappa.keys()) == 1
 56        kappa = tuple(settings.aerosol_modes_by_kappa.keys())[0]
 57        spectrum = settings.aerosol_modes_by_kappa[kappa]
 58
 59        r_dry, n_per_volume = sampling_class(spectrum).sample(settings.n_sd)
 60        v_dry = settings.formulae.trivia.volume(radius=r_dry)
 61        attributes["multiplicity"] = np.append(
 62            attributes["multiplicity"], n_per_volume * volume
 63        )
 64        attributes["dry volume"] = np.append(attributes["dry volume"], v_dry)
 65        attributes["kappa times dry volume"] = np.append(
 66            attributes["kappa times dry volume"], v_dry * kappa
 67        )
 68        r_wet = equilibrate_wet_radii(
 69            r_dry=settings.formulae.trivia.radius(volume=attributes["dry volume"]),
 70            environment=env,
 71            kappa_times_dry_volume=attributes["kappa times dry volume"],
 72        )
 73        attributes["volume"] = settings.formulae.trivia.volume(radius=r_wet)
 74
 75        super().__init__(
 76            particulator=builder.build(attributes=attributes, products=products)
 77        )
 78        if scipy_solver:
 79            scipy_ode_condensation_solver.patch_particulator(self.particulator)
 80
 81        self.output_attributes = {
 82            "volume": tuple([] for _ in range(self.particulator.n_sd)),
 83            "dry volume": tuple([] for _ in range(self.particulator.n_sd)),
 84            "critical supersaturation": tuple(
 85                [] for _ in range(self.particulator.n_sd)
 86            ),
 87            "equilibrium supersaturation": tuple(
 88                [] for _ in range(self.particulator.n_sd)
 89            ),
 90            "critical volume": tuple([] for _ in range(self.particulator.n_sd)),
 91            "multiplicity": tuple([] for _ in range(self.particulator.n_sd)),
 92        }
 93        self.settings = settings
 94
 95        self.__sanity_checks(attributes, volume)
 96
 97    def __sanity_checks(self, attributes, volume):
 98        for attribute in attributes.values():
 99            assert attribute.shape[0] == self.particulator.n_sd
100        np.testing.assert_approx_equal(
101            sum(attributes["multiplicity"]) / volume,
102            sum(
103                mode.norm_factor
104                for mode in self.settings.aerosol_modes_by_kappa.values()
105            ),
106            significant=4,
107        )
108
109    def _save(self, output):
110        for key, attr in self.output_attributes.items():
111            attr_data = self.particulator.attributes[key].to_ndarray()
112            for drop_id in range(self.particulator.n_sd):
113                attr[drop_id].append(attr_data[drop_id])
114        super()._save(output)
115
116    def run(self):
117        output_products = super()._run(
118            self.settings.nt, self.settings.steps_per_output_interval
119        )
120        return {"products": output_products, "attributes": self.output_attributes}
Simulation( settings, products=None, scipy_solver=False, sampling_class=<class 'PySDM.initialisation.sampling.spectral_sampling.ConstantMultiplicity'>)
16    def __init__(
17        self,
18        settings,
19        products=None,
20        scipy_solver=False,
21        sampling_class=ConstantMultiplicity,
22    ):
23        builder = Builder(
24            n_sd=settings.n_sd,
25            backend=CPU(
26                formulae=settings.formulae, override_jit_flags={"parallel": False}
27            ),
28            environment=Parcel(
29                dt=settings.timestep,
30                p0=settings.initial_pressure,
31                initial_water_vapour_mixing_ratio=settings.initial_vapour_mixing_ratio,
32                T0=settings.initial_temperature,
33                w=settings.vertical_velocity,
34                mass_of_dry_air=44 * si.kg,
35            ),
36        )
37        builder.add_dynamic(AmbientThermodynamics())
38        builder.add_dynamic(
39            Condensation(rtol_thd=settings.rtol_thd, rtol_x=settings.rtol_x)
40        )
41        for attribute in (
42            "critical supersaturation",
43            "equilibrium supersaturation",
44            "critical volume",
45        ):
46            builder.request_attribute(attribute)
47
48        env = builder.particulator.environment
49        volume = env.mass_of_dry_air / settings.initial_air_density
50        attributes = {
51            k: np.empty(0)
52            for k in ("dry volume", "kappa times dry volume", "multiplicity")
53        }
54
55        assert len(settings.aerosol_modes_by_kappa.keys()) == 1
56        kappa = tuple(settings.aerosol_modes_by_kappa.keys())[0]
57        spectrum = settings.aerosol_modes_by_kappa[kappa]
58
59        r_dry, n_per_volume = sampling_class(spectrum).sample(settings.n_sd)
60        v_dry = settings.formulae.trivia.volume(radius=r_dry)
61        attributes["multiplicity"] = np.append(
62            attributes["multiplicity"], n_per_volume * volume
63        )
64        attributes["dry volume"] = np.append(attributes["dry volume"], v_dry)
65        attributes["kappa times dry volume"] = np.append(
66            attributes["kappa times dry volume"], v_dry * kappa
67        )
68        r_wet = equilibrate_wet_radii(
69            r_dry=settings.formulae.trivia.radius(volume=attributes["dry volume"]),
70            environment=env,
71            kappa_times_dry_volume=attributes["kappa times dry volume"],
72        )
73        attributes["volume"] = settings.formulae.trivia.volume(radius=r_wet)
74
75        super().__init__(
76            particulator=builder.build(attributes=attributes, products=products)
77        )
78        if scipy_solver:
79            scipy_ode_condensation_solver.patch_particulator(self.particulator)
80
81        self.output_attributes = {
82            "volume": tuple([] for _ in range(self.particulator.n_sd)),
83            "dry volume": tuple([] for _ in range(self.particulator.n_sd)),
84            "critical supersaturation": tuple(
85                [] for _ in range(self.particulator.n_sd)
86            ),
87            "equilibrium supersaturation": tuple(
88                [] for _ in range(self.particulator.n_sd)
89            ),
90            "critical volume": tuple([] for _ in range(self.particulator.n_sd)),
91            "multiplicity": tuple([] for _ in range(self.particulator.n_sd)),
92        }
93        self.settings = settings
94
95        self.__sanity_checks(attributes, volume)
output_attributes
settings
def run(self):
116    def run(self):
117        output_products = super()._run(
118            self.settings.nt, self.settings.steps_per_output_interval
119        )
120        return {"products": output_products, "attributes": self.output_attributes}