PySDM_examples.Grabowski_and_Pawlowska_2023.simulation

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