PySDM_examples.Spichtinger_et_al_2023.simulation

  1import numpy as np
  2
  3from PySDM_examples.utils import BasicSimulation
  4
  5import PySDM.products as PySDM_products
  6from PySDM.backends import CPU
  7from PySDM.builder import Builder
  8from PySDM.dynamics import (
  9    AmbientThermodynamics,
 10    Condensation,
 11    Freezing,
 12    VapourDepositionOnIce,
 13)
 14from PySDM.environments import Parcel
 15from PySDM.initialisation import discretise_multiplicities
 16from PySDM.initialisation.hygroscopic_equilibrium import equilibrate_wet_radii
 17
 18
 19class Simulation(BasicSimulation):
 20    def __init__(self, settings, backend=CPU):
 21
 22        dt = settings.dt
 23
 24        formulae = settings.formulae
 25
 26        env = Parcel(
 27            mixed_phase=True,
 28            dt=dt,
 29            mass_of_dry_air=settings.mass_of_dry_air,
 30            p0=settings.initial_pressure,
 31            initial_water_vapour_mixing_ratio=settings.initial_water_vapour_mixing_ratio,
 32            T0=settings.initial_temperature,
 33            w=settings.w_updraft,
 34        )
 35
 36        builder = Builder(
 37            backend=backend(
 38                formulae=settings.formulae,
 39                **(
 40                    {"override_jit_flags": {"parallel": False}}
 41                    if backend == CPU
 42                    else {}
 43                ),
 44            ),
 45            n_sd=settings.n_sd,
 46            environment=env,
 47        )
 48
 49        builder.add_dynamic(AmbientThermodynamics())
 50        builder.add_dynamic(Condensation())
 51        builder.add_dynamic(VapourDepositionOnIce())
 52        builder.add_dynamic(
 53            Freezing(homogeneous_freezing="time-dependent", immersion_freezing=None)
 54        )
 55
 56        self.n_sd = settings.n_sd
 57        self.multiplicities = discretise_multiplicities(
 58            settings.specific_concentration * env.mass_of_dry_air
 59        )
 60        self.r_dry = settings.r_dry
 61        v_dry = settings.formulae.trivia.volume(radius=self.r_dry)
 62        kappa = settings.kappa
 63
 64        self.r_wet = equilibrate_wet_radii(
 65            r_dry=self.r_dry,
 66            environment=builder.particulator.environment,
 67            kappa_times_dry_volume=kappa * v_dry,
 68        )
 69
 70        attributes = {
 71            "multiplicity": self.multiplicities,
 72            "dry volume": v_dry,
 73            "kappa times dry volume": kappa * v_dry,
 74            "signed water mass": formulae.particle_shape_and_density.radius_to_mass(
 75                self.r_wet
 76            ),
 77        }
 78
 79        products = [
 80            PySDM_products.Time(name="t"),
 81            PySDM_products.AmbientRelativeHumidity(name="RH_ice", unit="%"),
 82            PySDM_products.ParticleConcentration(
 83                name="n_i", unit="1/m**3", radius_range=(-np.inf, 0)
 84            ),
 85        ]
 86
 87        self.n_output = settings.n_output
 88        self.n_substeps = int(settings.t_duration / dt / self.n_output)
 89        super().__init__(builder.build(attributes, products))
 90
 91    def save(self, output):
 92        cell_id = 0
 93        output["t"].append(self.particulator.products["t"].get())
 94        output["ni"].append(self.particulator.products["n_i"].get()[cell_id])
 95        output["RHi"].append(self.particulator.products["RH_ice"].get()[cell_id])
 96
 97    def run(self):
 98        output = {
 99            "t": [],
100            "ni": [],
101            "RHi": [],
102        }
103
104        self.save(output)
105
106        RHi_old = self.particulator.products["RH_ice"].get()[0].copy()
107        for _ in range(self.n_output):
108
109            self.particulator.run(self.n_substeps)
110
111            self.save(output)
112
113            RHi = self.particulator.products["RH_ice"].get()[0].copy()
114            dRHi = (RHi_old - RHi) / RHi_old
115            if dRHi > 0.0 and RHi < 130.0:
116                print("break")
117                break
118            RHi_old = RHi
119
120        return output["ni"][-1]
 20class Simulation(BasicSimulation):
 21    def __init__(self, settings, backend=CPU):
 22
 23        dt = settings.dt
 24
 25        formulae = settings.formulae
 26
 27        env = Parcel(
 28            mixed_phase=True,
 29            dt=dt,
 30            mass_of_dry_air=settings.mass_of_dry_air,
 31            p0=settings.initial_pressure,
 32            initial_water_vapour_mixing_ratio=settings.initial_water_vapour_mixing_ratio,
 33            T0=settings.initial_temperature,
 34            w=settings.w_updraft,
 35        )
 36
 37        builder = Builder(
 38            backend=backend(
 39                formulae=settings.formulae,
 40                **(
 41                    {"override_jit_flags": {"parallel": False}}
 42                    if backend == CPU
 43                    else {}
 44                ),
 45            ),
 46            n_sd=settings.n_sd,
 47            environment=env,
 48        )
 49
 50        builder.add_dynamic(AmbientThermodynamics())
 51        builder.add_dynamic(Condensation())
 52        builder.add_dynamic(VapourDepositionOnIce())
 53        builder.add_dynamic(
 54            Freezing(homogeneous_freezing="time-dependent", immersion_freezing=None)
 55        )
 56
 57        self.n_sd = settings.n_sd
 58        self.multiplicities = discretise_multiplicities(
 59            settings.specific_concentration * env.mass_of_dry_air
 60        )
 61        self.r_dry = settings.r_dry
 62        v_dry = settings.formulae.trivia.volume(radius=self.r_dry)
 63        kappa = settings.kappa
 64
 65        self.r_wet = equilibrate_wet_radii(
 66            r_dry=self.r_dry,
 67            environment=builder.particulator.environment,
 68            kappa_times_dry_volume=kappa * v_dry,
 69        )
 70
 71        attributes = {
 72            "multiplicity": self.multiplicities,
 73            "dry volume": v_dry,
 74            "kappa times dry volume": kappa * v_dry,
 75            "signed water mass": formulae.particle_shape_and_density.radius_to_mass(
 76                self.r_wet
 77            ),
 78        }
 79
 80        products = [
 81            PySDM_products.Time(name="t"),
 82            PySDM_products.AmbientRelativeHumidity(name="RH_ice", unit="%"),
 83            PySDM_products.ParticleConcentration(
 84                name="n_i", unit="1/m**3", radius_range=(-np.inf, 0)
 85            ),
 86        ]
 87
 88        self.n_output = settings.n_output
 89        self.n_substeps = int(settings.t_duration / dt / self.n_output)
 90        super().__init__(builder.build(attributes, products))
 91
 92    def save(self, output):
 93        cell_id = 0
 94        output["t"].append(self.particulator.products["t"].get())
 95        output["ni"].append(self.particulator.products["n_i"].get()[cell_id])
 96        output["RHi"].append(self.particulator.products["RH_ice"].get()[cell_id])
 97
 98    def run(self):
 99        output = {
100            "t": [],
101            "ni": [],
102            "RHi": [],
103        }
104
105        self.save(output)
106
107        RHi_old = self.particulator.products["RH_ice"].get()[0].copy()
108        for _ in range(self.n_output):
109
110            self.particulator.run(self.n_substeps)
111
112            self.save(output)
113
114            RHi = self.particulator.products["RH_ice"].get()[0].copy()
115            dRHi = (RHi_old - RHi) / RHi_old
116            if dRHi > 0.0 and RHi < 130.0:
117                print("break")
118                break
119            RHi_old = RHi
120
121        return output["ni"][-1]
Simulation(settings, backend=<class 'PySDM.backends.numba.Numba'>)
21    def __init__(self, settings, backend=CPU):
22
23        dt = settings.dt
24
25        formulae = settings.formulae
26
27        env = Parcel(
28            mixed_phase=True,
29            dt=dt,
30            mass_of_dry_air=settings.mass_of_dry_air,
31            p0=settings.initial_pressure,
32            initial_water_vapour_mixing_ratio=settings.initial_water_vapour_mixing_ratio,
33            T0=settings.initial_temperature,
34            w=settings.w_updraft,
35        )
36
37        builder = Builder(
38            backend=backend(
39                formulae=settings.formulae,
40                **(
41                    {"override_jit_flags": {"parallel": False}}
42                    if backend == CPU
43                    else {}
44                ),
45            ),
46            n_sd=settings.n_sd,
47            environment=env,
48        )
49
50        builder.add_dynamic(AmbientThermodynamics())
51        builder.add_dynamic(Condensation())
52        builder.add_dynamic(VapourDepositionOnIce())
53        builder.add_dynamic(
54            Freezing(homogeneous_freezing="time-dependent", immersion_freezing=None)
55        )
56
57        self.n_sd = settings.n_sd
58        self.multiplicities = discretise_multiplicities(
59            settings.specific_concentration * env.mass_of_dry_air
60        )
61        self.r_dry = settings.r_dry
62        v_dry = settings.formulae.trivia.volume(radius=self.r_dry)
63        kappa = settings.kappa
64
65        self.r_wet = equilibrate_wet_radii(
66            r_dry=self.r_dry,
67            environment=builder.particulator.environment,
68            kappa_times_dry_volume=kappa * v_dry,
69        )
70
71        attributes = {
72            "multiplicity": self.multiplicities,
73            "dry volume": v_dry,
74            "kappa times dry volume": kappa * v_dry,
75            "signed water mass": formulae.particle_shape_and_density.radius_to_mass(
76                self.r_wet
77            ),
78        }
79
80        products = [
81            PySDM_products.Time(name="t"),
82            PySDM_products.AmbientRelativeHumidity(name="RH_ice", unit="%"),
83            PySDM_products.ParticleConcentration(
84                name="n_i", unit="1/m**3", radius_range=(-np.inf, 0)
85            ),
86        ]
87
88        self.n_output = settings.n_output
89        self.n_substeps = int(settings.t_duration / dt / self.n_output)
90        super().__init__(builder.build(attributes, products))
n_sd
multiplicities
r_dry
r_wet
n_output
n_substeps
def save(self, output):
92    def save(self, output):
93        cell_id = 0
94        output["t"].append(self.particulator.products["t"].get())
95        output["ni"].append(self.particulator.products["n_i"].get()[cell_id])
96        output["RHi"].append(self.particulator.products["RH_ice"].get()[cell_id])
def run(self):
 98    def run(self):
 99        output = {
100            "t": [],
101            "ni": [],
102            "RHi": [],
103        }
104
105        self.save(output)
106
107        RHi_old = self.particulator.products["RH_ice"].get()[0].copy()
108        for _ in range(self.n_output):
109
110            self.particulator.run(self.n_substeps)
111
112            self.save(output)
113
114            RHi = self.particulator.products["RH_ice"].get()[0].copy()
115            dRHi = (RHi_old - RHi) / RHi_old
116            if dRHi > 0.0 and RHi < 130.0:
117                print("break")
118                break
119            RHi_old = RHi
120
121        return output["ni"][-1]