PySDM_examples.Pyrcel.tutorial_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, settings, products=None, scipy_solver=False, rtol_thd=1e-10, rtol_x=1e-10
17    ):
18        env = Parcel(
19            dt=settings.timestep,
20            p0=settings.initial_pressure,
21            initial_water_vapour_mixing_ratio=settings.initial_vapour_mixing_ratio,
22            T0=settings.initial_temperature,
23            w=settings.vertical_velocity,
24            mass_of_dry_air=44 * si.kg,
25        )
26        n_sd = sum(settings.n_sd_per_mode)
27        builder = Builder(n_sd=n_sd, backend=CPU(formulae=settings.formulae))
28        builder.set_environment(env)
29        builder.add_dynamic(AmbientThermodynamics())
30        builder.add_dynamic(Condensation(rtol_thd=rtol_thd, rtol_x=rtol_x))
31
32        volume = env.mass_of_dry_air / settings.initial_air_density
33        attributes = {
34            k: np.empty(0) for k in ("dry volume", "kappa times dry volume", "n")
35        }
36        for i, (kappa, spectrum) in enumerate(settings.aerosol_modes_by_kappa.items()):
37            sampling = ConstantMultiplicity(spectrum)
38            r_dry, n_per_volume = sampling.sample(settings.n_sd_per_mode[i])
39            v_dry = settings.formulae.trivia.volume(radius=r_dry)
40            attributes["n"] = np.append(attributes["n"], n_per_volume * volume)
41            attributes["dry volume"] = np.append(attributes["dry volume"], v_dry)
42            attributes["kappa times dry volume"] = np.append(
43                attributes["kappa times dry volume"], v_dry * kappa
44            )
45        r_wet = equilibrate_wet_radii(
46            r_dry=settings.formulae.trivia.radius(volume=attributes["dry volume"]),
47            environment=env,
48            kappa_times_dry_volume=attributes["kappa times dry volume"],
49        )
50        attributes["volume"] = settings.formulae.trivia.volume(radius=r_wet)
51
52        super().__init__(
53            particulator=builder.build(attributes=attributes, products=products)
54        )
55        if scipy_solver:
56            scipy_ode_condensation_solver.patch_particulator(self.particulator)
57
58        self.output_attributes = {
59            "volume": tuple([] for _ in range(self.particulator.n_sd))
60        }
61        self.settings = settings
62
63        self.__sanity_checks(attributes, volume)
64
65    def __sanity_checks(self, attributes, volume):
66        for attribute in attributes.values():
67            assert attribute.shape[0] == self.particulator.n_sd
68        np.testing.assert_approx_equal(
69            sum(attributes["multiplicity"]) / volume,
70            sum(
71                mode.norm_factor
72                for mode in self.settings.aerosol_modes_by_kappa.values()
73            ),
74            significant=4,
75        )
76
77    def _save(self, output):
78        for key, attr in self.output_attributes.items():
79            attr_data = self.particulator.attributes[key].to_ndarray()
80            for drop_id in range(self.particulator.n_sd):
81                attr[drop_id].append(attr_data[drop_id])
82        super()._save(output)
83
84    def run(self, observers=()):
85        for observer in observers:
86            self.particulator.observers.append(observer)
87        output_products = super()._run(
88            self.settings.nt, self.settings.steps_per_output_interval
89        )
90        return {"products": output_products, "attributes": self.output_attributes}
15class Simulation(BasicSimulation):
16    def __init__(
17        self, settings, products=None, scipy_solver=False, rtol_thd=1e-10, rtol_x=1e-10
18    ):
19        env = Parcel(
20            dt=settings.timestep,
21            p0=settings.initial_pressure,
22            initial_water_vapour_mixing_ratio=settings.initial_vapour_mixing_ratio,
23            T0=settings.initial_temperature,
24            w=settings.vertical_velocity,
25            mass_of_dry_air=44 * si.kg,
26        )
27        n_sd = sum(settings.n_sd_per_mode)
28        builder = Builder(n_sd=n_sd, backend=CPU(formulae=settings.formulae))
29        builder.set_environment(env)
30        builder.add_dynamic(AmbientThermodynamics())
31        builder.add_dynamic(Condensation(rtol_thd=rtol_thd, rtol_x=rtol_x))
32
33        volume = env.mass_of_dry_air / settings.initial_air_density
34        attributes = {
35            k: np.empty(0) for k in ("dry volume", "kappa times dry volume", "n")
36        }
37        for i, (kappa, spectrum) in enumerate(settings.aerosol_modes_by_kappa.items()):
38            sampling = ConstantMultiplicity(spectrum)
39            r_dry, n_per_volume = sampling.sample(settings.n_sd_per_mode[i])
40            v_dry = settings.formulae.trivia.volume(radius=r_dry)
41            attributes["n"] = np.append(attributes["n"], n_per_volume * volume)
42            attributes["dry volume"] = np.append(attributes["dry volume"], v_dry)
43            attributes["kappa times dry volume"] = np.append(
44                attributes["kappa times dry volume"], v_dry * kappa
45            )
46        r_wet = equilibrate_wet_radii(
47            r_dry=settings.formulae.trivia.radius(volume=attributes["dry volume"]),
48            environment=env,
49            kappa_times_dry_volume=attributes["kappa times dry volume"],
50        )
51        attributes["volume"] = settings.formulae.trivia.volume(radius=r_wet)
52
53        super().__init__(
54            particulator=builder.build(attributes=attributes, products=products)
55        )
56        if scipy_solver:
57            scipy_ode_condensation_solver.patch_particulator(self.particulator)
58
59        self.output_attributes = {
60            "volume": tuple([] for _ in range(self.particulator.n_sd))
61        }
62        self.settings = settings
63
64        self.__sanity_checks(attributes, volume)
65
66    def __sanity_checks(self, attributes, volume):
67        for attribute in attributes.values():
68            assert attribute.shape[0] == self.particulator.n_sd
69        np.testing.assert_approx_equal(
70            sum(attributes["multiplicity"]) / volume,
71            sum(
72                mode.norm_factor
73                for mode in self.settings.aerosol_modes_by_kappa.values()
74            ),
75            significant=4,
76        )
77
78    def _save(self, output):
79        for key, attr in self.output_attributes.items():
80            attr_data = self.particulator.attributes[key].to_ndarray()
81            for drop_id in range(self.particulator.n_sd):
82                attr[drop_id].append(attr_data[drop_id])
83        super()._save(output)
84
85    def run(self, observers=()):
86        for observer in observers:
87            self.particulator.observers.append(observer)
88        output_products = super()._run(
89            self.settings.nt, self.settings.steps_per_output_interval
90        )
91        return {"products": output_products, "attributes": self.output_attributes}
Simulation( settings, products=None, scipy_solver=False, rtol_thd=1e-10, rtol_x=1e-10)
16    def __init__(
17        self, settings, products=None, scipy_solver=False, rtol_thd=1e-10, rtol_x=1e-10
18    ):
19        env = Parcel(
20            dt=settings.timestep,
21            p0=settings.initial_pressure,
22            initial_water_vapour_mixing_ratio=settings.initial_vapour_mixing_ratio,
23            T0=settings.initial_temperature,
24            w=settings.vertical_velocity,
25            mass_of_dry_air=44 * si.kg,
26        )
27        n_sd = sum(settings.n_sd_per_mode)
28        builder = Builder(n_sd=n_sd, backend=CPU(formulae=settings.formulae))
29        builder.set_environment(env)
30        builder.add_dynamic(AmbientThermodynamics())
31        builder.add_dynamic(Condensation(rtol_thd=rtol_thd, rtol_x=rtol_x))
32
33        volume = env.mass_of_dry_air / settings.initial_air_density
34        attributes = {
35            k: np.empty(0) for k in ("dry volume", "kappa times dry volume", "n")
36        }
37        for i, (kappa, spectrum) in enumerate(settings.aerosol_modes_by_kappa.items()):
38            sampling = ConstantMultiplicity(spectrum)
39            r_dry, n_per_volume = sampling.sample(settings.n_sd_per_mode[i])
40            v_dry = settings.formulae.trivia.volume(radius=r_dry)
41            attributes["n"] = np.append(attributes["n"], n_per_volume * volume)
42            attributes["dry volume"] = np.append(attributes["dry volume"], v_dry)
43            attributes["kappa times dry volume"] = np.append(
44                attributes["kappa times dry volume"], v_dry * kappa
45            )
46        r_wet = equilibrate_wet_radii(
47            r_dry=settings.formulae.trivia.radius(volume=attributes["dry volume"]),
48            environment=env,
49            kappa_times_dry_volume=attributes["kappa times dry volume"],
50        )
51        attributes["volume"] = settings.formulae.trivia.volume(radius=r_wet)
52
53        super().__init__(
54            particulator=builder.build(attributes=attributes, products=products)
55        )
56        if scipy_solver:
57            scipy_ode_condensation_solver.patch_particulator(self.particulator)
58
59        self.output_attributes = {
60            "volume": tuple([] for _ in range(self.particulator.n_sd))
61        }
62        self.settings = settings
63
64        self.__sanity_checks(attributes, volume)
output_attributes
settings
def run(self, observers=()):
85    def run(self, observers=()):
86        for observer in observers:
87            self.particulator.observers.append(observer)
88        output_products = super()._run(
89            self.settings.nt, self.settings.steps_per_output_interval
90        )
91        return {"products": output_products, "attributes": self.output_attributes}