PySDM_examples.featured.pyrcel_docs_testcase.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        *,
 19        products=None,
 20        scipy_solver=False,
 21        rtol_thd=1e-10,
 22        rtol_x=1e-10,
 23        mass_of_dry_air=44 * si.kg,
 24        additional_attributes=None,
 25    ):
 26        environment = Parcel(
 27            dt=settings.timestep,
 28            p0=settings.initial_pressure,
 29            initial_water_vapour_mixing_ratio=settings.initial_vapour_mixing_ratio,
 30            T0=settings.initial_temperature,
 31            w=settings.vertical_velocity,
 32            mass_of_dry_air=mass_of_dry_air,
 33            backend=CPU(formulae=settings.formulae),
 34        )
 35        n_sd = sum(settings.n_sd_per_mode)
 36        volume = environment.mass_of_dry_air / settings.initial_air_density
 37        attributes = {
 38            k: np.empty(0)
 39            for k in ("dry volume", "kappa times dry volume", "multiplicity")
 40        }
 41        for i, (kappa, spectrum) in enumerate(settings.aerosol_modes_by_kappa.items()):
 42            sampling = ConstantMultiplicity(spectrum)
 43            r_dry, n_per_volume = sampling.sample_deterministic(
 44                settings.n_sd_per_mode[i]
 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_kwargs = {
 62            "n_sd": n_sd,
 63            "environment": environment,
 64            "dynamics": (
 65                AmbientThermodynamics(),
 66                Condensation(rtol_thd=rtol_thd, rtol_x=rtol_x),
 67            ),
 68            "attributes": attributes,
 69            "products": products,
 70        }
 71
 72        if additional_attributes is not None:
 73            particulator_kwargs["requested_attributes"] = additional_attributes
 74
 75        super().__init__(particulator=Particulator(**particulator_kwargs))
 76
 77        if scipy_solver:
 78            scipy_ode_condensation_solver.patch_particulator(self.particulator)
 79
 80        self.output_attributes = {
 81            attr: tuple([] for _ in range(self.particulator.n_sd))
 82            for attr in ["volume"]
 83            + (list(additional_attributes) if additional_attributes is not None else [])
 84        }
 85        self.settings = settings
 86
 87        self.__sanity_checks(attributes, volume)
 88
 89    def __sanity_checks(self, attributes, volume):
 90        for attribute in attributes.values():
 91            assert attribute.shape[0] == self.particulator.n_sd
 92        np.testing.assert_approx_equal(
 93            sum(attributes["multiplicity"]) / volume,
 94            sum(
 95                mode.norm_factor
 96                for mode in self.settings.aerosol_modes_by_kappa.values()
 97            ),
 98            significant=4,
 99        )
100
101    def _save(self, output):
102        for key, attr in self.output_attributes.items():
103            attr_data = self.particulator.attributes[key].to_ndarray()
104            for drop_id in range(self.particulator.n_sd):
105                attr[drop_id].append(attr_data[drop_id])
106        super()._save(output)
107
108    def run(self, observers=()):
109        for observer in observers:
110            self.particulator.observers.append(observer)
111        output_products = super()._run(
112            self.settings.nt, self.settings.steps_per_output_interval
113        )
114        return {"products": output_products, "attributes": self.output_attributes}
 15class Simulation(BasicSimulation):
 16    def __init__(
 17        self,
 18        settings,
 19        *,
 20        products=None,
 21        scipy_solver=False,
 22        rtol_thd=1e-10,
 23        rtol_x=1e-10,
 24        mass_of_dry_air=44 * si.kg,
 25        additional_attributes=None,
 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=mass_of_dry_air,
 34            backend=CPU(formulae=settings.formulae),
 35        )
 36        n_sd = sum(settings.n_sd_per_mode)
 37        volume = environment.mass_of_dry_air / settings.initial_air_density
 38        attributes = {
 39            k: np.empty(0)
 40            for k in ("dry volume", "kappa times dry volume", "multiplicity")
 41        }
 42        for i, (kappa, spectrum) in enumerate(settings.aerosol_modes_by_kappa.items()):
 43            sampling = ConstantMultiplicity(spectrum)
 44            r_dry, n_per_volume = sampling.sample_deterministic(
 45                settings.n_sd_per_mode[i]
 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_kwargs = {
 63            "n_sd": n_sd,
 64            "environment": environment,
 65            "dynamics": (
 66                AmbientThermodynamics(),
 67                Condensation(rtol_thd=rtol_thd, rtol_x=rtol_x),
 68            ),
 69            "attributes": attributes,
 70            "products": products,
 71        }
 72
 73        if additional_attributes is not None:
 74            particulator_kwargs["requested_attributes"] = additional_attributes
 75
 76        super().__init__(particulator=Particulator(**particulator_kwargs))
 77
 78        if scipy_solver:
 79            scipy_ode_condensation_solver.patch_particulator(self.particulator)
 80
 81        self.output_attributes = {
 82            attr: tuple([] for _ in range(self.particulator.n_sd))
 83            for attr in ["volume"]
 84            + (list(additional_attributes) if additional_attributes is not None else [])
 85        }
 86        self.settings = settings
 87
 88        self.__sanity_checks(attributes, volume)
 89
 90    def __sanity_checks(self, attributes, volume):
 91        for attribute in attributes.values():
 92            assert attribute.shape[0] == self.particulator.n_sd
 93        np.testing.assert_approx_equal(
 94            sum(attributes["multiplicity"]) / volume,
 95            sum(
 96                mode.norm_factor
 97                for mode in self.settings.aerosol_modes_by_kappa.values()
 98            ),
 99            significant=4,
100        )
101
102    def _save(self, output):
103        for key, attr in self.output_attributes.items():
104            attr_data = self.particulator.attributes[key].to_ndarray()
105            for drop_id in range(self.particulator.n_sd):
106                attr[drop_id].append(attr_data[drop_id])
107        super()._save(output)
108
109    def run(self, observers=()):
110        for observer in observers:
111            self.particulator.observers.append(observer)
112        output_products = super()._run(
113            self.settings.nt, self.settings.steps_per_output_interval
114        )
115        return {"products": output_products, "attributes": self.output_attributes}
Simulation( settings, *, products=None, scipy_solver=False, rtol_thd=1e-10, rtol_x=1e-10, mass_of_dry_air=44.0, additional_attributes=None)
16    def __init__(
17        self,
18        settings,
19        *,
20        products=None,
21        scipy_solver=False,
22        rtol_thd=1e-10,
23        rtol_x=1e-10,
24        mass_of_dry_air=44 * si.kg,
25        additional_attributes=None,
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=mass_of_dry_air,
34            backend=CPU(formulae=settings.formulae),
35        )
36        n_sd = sum(settings.n_sd_per_mode)
37        volume = environment.mass_of_dry_air / settings.initial_air_density
38        attributes = {
39            k: np.empty(0)
40            for k in ("dry volume", "kappa times dry volume", "multiplicity")
41        }
42        for i, (kappa, spectrum) in enumerate(settings.aerosol_modes_by_kappa.items()):
43            sampling = ConstantMultiplicity(spectrum)
44            r_dry, n_per_volume = sampling.sample_deterministic(
45                settings.n_sd_per_mode[i]
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_kwargs = {
63            "n_sd": n_sd,
64            "environment": environment,
65            "dynamics": (
66                AmbientThermodynamics(),
67                Condensation(rtol_thd=rtol_thd, rtol_x=rtol_x),
68            ),
69            "attributes": attributes,
70            "products": products,
71        }
72
73        if additional_attributes is not None:
74            particulator_kwargs["requested_attributes"] = additional_attributes
75
76        super().__init__(particulator=Particulator(**particulator_kwargs))
77
78        if scipy_solver:
79            scipy_ode_condensation_solver.patch_particulator(self.particulator)
80
81        self.output_attributes = {
82            attr: tuple([] for _ in range(self.particulator.n_sd))
83            for attr in ["volume"]
84            + (list(additional_attributes) if additional_attributes is not None else [])
85        }
86        self.settings = settings
87
88        self.__sanity_checks(attributes, volume)
output_attributes
settings
def run(self, observers=()):
109    def run(self, observers=()):
110        for observer in observers:
111            self.particulator.observers.append(observer)
112        output_products = super()._run(
113            self.settings.nt, self.settings.steps_per_output_interval
114        )
115        return {"products": output_products, "attributes": self.output_attributes}