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