PySDM_examples.Murray_et_al_2010.simulation

  1import numpy as np
  2from matplotlib import pyplot
  3from matplotlib.ticker import MultipleLocator
  4
  5from PySDM import Builder, Formulae
  6from PySDM.backends import CPU
  7from PySDM.dynamics import Freezing
  8from PySDM.environments import Box
  9from PySDM.physics import si
 10
 11
 12class Simulation:
 13    def __init__(
 14        self,
 15        *,
 16        cases,
 17        n_sd=1000,
 18        n_runs_per_case=1,
 19        temperature_step=0.01 * si.K,
 20        droplet_radius=10 * si.um,
 21        homogeneous_ice_nucleation_rate="KoopMurray2016",
 22        temperature_range=None,
 23    ):
 24        self.cases = cases
 25        self.n_sd = n_sd
 26        self.n_runs_per_case = n_runs_per_case
 27        self.temperature_step = temperature_step
 28        self.droplet_radius = droplet_radius
 29        self.homogeneous_ice_nucleation_rate = homogeneous_ice_nucleation_rate
 30        if temperature_range is None:
 31            temperature_range = [234.5 * si.K, 238 * si.K]
 32        self.temperature_range = temperature_range
 33        self.multiplicity = 1
 34        self.volume = 1 * si.cm**3
 35        self.output = None
 36
 37    def run(self, keys):
 38        self.output = {}
 39        for key in keys:
 40            case = self.cases[key]
 41            assert case["cooling_rate"] != 0
 42            total_time = (
 43                np.diff(np.asarray(self.temperature_range)) / case["cooling_rate"]
 44            )
 45            time_step = self.temperature_step / case["cooling_rate"]
 46
 47            self.output[key] = []
 48            for i in range(self.n_runs_per_case):
 49                T_frz = simulation(
 50                    seed=i,
 51                    n_sd=self.n_sd,
 52                    time_step=time_step,
 53                    volume=self.volume,
 54                    droplet_radius=self.droplet_radius,
 55                    cooling_rate=case["cooling_rate"],
 56                    multiplicity=self.multiplicity,
 57                    total_time=total_time,
 58                    homogeneous_ice_nucleation_rate=self.homogeneous_ice_nucleation_rate,
 59                    initial_temperature=self.temperature_range[1],
 60                )
 61                self.output[key].append({"T_frz": T_frz})
 62
 63    def plot_histogram(self, title=None):
 64
 65        pyplot.rc("font", size=12)
 66        T_bins = np.arange(self.temperature_range[0], self.temperature_range[1], 0.1)
 67
 68        for key in self.output:
 69            for run in range(self.n_runs_per_case):
 70                if run == 0:
 71                    cooling_rate = self.cases[key]["cooling_rate"]
 72                    label = (
 73                        "-"
 74                        + f"{cooling_rate*si.minute:.1f}"
 75                        + r" $\mathrm{K \, min^{-1}}$"
 76                    )
 77                else:
 78                    label = None
 79
 80                pyplot.hist(
 81                    self.output[key][run]["T_frz"],
 82                    bins=T_bins,
 83                    cumulative=-1,
 84                    density=True,
 85                    alpha=1.0,
 86                    histtype="step",
 87                    linewidth=1.5,
 88                    color=self.cases[key]["color"],
 89                    label=label,
 90                )
 91
 92        if title is None:
 93            title = (
 94                r"$r_\mathrm{drop}:$ "
 95                + f"{self.droplet_radius/si.micrometer:.2f}"
 96                + "µm"
 97                + r"   $\mathrm{N_{sd}}:$ "
 98                + str(self.n_sd)
 99                + "   dT: "
100                + f"{self.temperature_step:.2f}"
101                + "K"
102            )
103        pyplot.title(title, pad=15)
104        pyplot.xlim(*self.temperature_range)
105        pyplot.ylim(-0.05, 1.05)
106        pyplot.xlabel("Temperature / K")
107        pyplot.ylabel("Fraction of droplets frozen")
108        pyplot.minorticks_on()
109        pyplot.tick_params(axis="both", which="both", top=True, right=True)
110        pyplot.gca().yaxis.set_minor_locator(MultipleLocator(0.1))
111        pyplot.tick_params(which="minor", length=3)
112        pyplot.tick_params(which="major", length=6)
113        pyplot.legend()
114
115
116def simulation(
117    *,
118    seed,
119    n_sd,
120    time_step,
121    volume,
122    droplet_radius,
123    cooling_rate,
124    multiplicity,
125    total_time,
126    homogeneous_ice_nucleation_rate="KoopMurray2016",
127    initial_temperature=None,
128):
129    formulae = Formulae(
130        seed=seed,
131        homogeneous_ice_nucleation_rate=homogeneous_ice_nucleation_rate,
132        particle_shape_and_density="MixedPhaseSpheres",
133        saturation_vapour_pressure="MurphyKoop2005",
134    )
135    builder = Builder(
136        n_sd=n_sd,
137        backend=CPU(formulae=formulae),
138        environment=Box(dt=time_step, dv=volume),
139        dynamics=(
140            Freezing(homogeneous_freezing="time-dependent", immersion_freezing=None),
141        ),
142    )
143
144    builder.request_attribute("temperature of last freezing")
145    builder.request_attribute("volume")
146    droplet_volume = formulae.trivia.volume(radius=droplet_radius)
147
148    attributes = {
149        "multiplicity": np.full(n_sd, multiplicity),
150        "signed water mass": np.full(n_sd, droplet_volume * formulae.constants.rho_w),
151    }
152    particulator = builder.build(attributes=attributes)
153    env = particulator.environment
154
155    env["T"] = initial_temperature
156    env["a_w_ice"] = np.nan
157    env["RH"] = 1 + np.finfo(float).eps
158    svp = particulator.formulae.saturation_vapour_pressure
159
160    cell_id = 0
161    for i in range(int(total_time / time_step) + 1):
162        env["RH_ice"] = svp.pvs_water(env["T"][cell_id]) / svp.pvs_ice(
163            env["T"][cell_id]
164        )
165        env["a_w_ice"] = svp.pvs_ice(env["T"][cell_id]) / svp.pvs_water(
166            env["T"][cell_id]
167        )
168        env["T"] -= np.full((1,), cooling_rate * time_step)
169        particulator.run(0 if i == 0 else 1)
170
171    assert all(particulator.attributes["signed water mass"].data < 0)
172    T_frz = particulator.attributes["temperature of last freezing"].data.tolist()
173    return T_frz
class Simulation:
 13class Simulation:
 14    def __init__(
 15        self,
 16        *,
 17        cases,
 18        n_sd=1000,
 19        n_runs_per_case=1,
 20        temperature_step=0.01 * si.K,
 21        droplet_radius=10 * si.um,
 22        homogeneous_ice_nucleation_rate="KoopMurray2016",
 23        temperature_range=None,
 24    ):
 25        self.cases = cases
 26        self.n_sd = n_sd
 27        self.n_runs_per_case = n_runs_per_case
 28        self.temperature_step = temperature_step
 29        self.droplet_radius = droplet_radius
 30        self.homogeneous_ice_nucleation_rate = homogeneous_ice_nucleation_rate
 31        if temperature_range is None:
 32            temperature_range = [234.5 * si.K, 238 * si.K]
 33        self.temperature_range = temperature_range
 34        self.multiplicity = 1
 35        self.volume = 1 * si.cm**3
 36        self.output = None
 37
 38    def run(self, keys):
 39        self.output = {}
 40        for key in keys:
 41            case = self.cases[key]
 42            assert case["cooling_rate"] != 0
 43            total_time = (
 44                np.diff(np.asarray(self.temperature_range)) / case["cooling_rate"]
 45            )
 46            time_step = self.temperature_step / case["cooling_rate"]
 47
 48            self.output[key] = []
 49            for i in range(self.n_runs_per_case):
 50                T_frz = simulation(
 51                    seed=i,
 52                    n_sd=self.n_sd,
 53                    time_step=time_step,
 54                    volume=self.volume,
 55                    droplet_radius=self.droplet_radius,
 56                    cooling_rate=case["cooling_rate"],
 57                    multiplicity=self.multiplicity,
 58                    total_time=total_time,
 59                    homogeneous_ice_nucleation_rate=self.homogeneous_ice_nucleation_rate,
 60                    initial_temperature=self.temperature_range[1],
 61                )
 62                self.output[key].append({"T_frz": T_frz})
 63
 64    def plot_histogram(self, title=None):
 65
 66        pyplot.rc("font", size=12)
 67        T_bins = np.arange(self.temperature_range[0], self.temperature_range[1], 0.1)
 68
 69        for key in self.output:
 70            for run in range(self.n_runs_per_case):
 71                if run == 0:
 72                    cooling_rate = self.cases[key]["cooling_rate"]
 73                    label = (
 74                        "-"
 75                        + f"{cooling_rate*si.minute:.1f}"
 76                        + r" $\mathrm{K \, min^{-1}}$"
 77                    )
 78                else:
 79                    label = None
 80
 81                pyplot.hist(
 82                    self.output[key][run]["T_frz"],
 83                    bins=T_bins,
 84                    cumulative=-1,
 85                    density=True,
 86                    alpha=1.0,
 87                    histtype="step",
 88                    linewidth=1.5,
 89                    color=self.cases[key]["color"],
 90                    label=label,
 91                )
 92
 93        if title is None:
 94            title = (
 95                r"$r_\mathrm{drop}:$ "
 96                + f"{self.droplet_radius/si.micrometer:.2f}"
 97                + "µm"
 98                + r"   $\mathrm{N_{sd}}:$ "
 99                + str(self.n_sd)
100                + "   dT: "
101                + f"{self.temperature_step:.2f}"
102                + "K"
103            )
104        pyplot.title(title, pad=15)
105        pyplot.xlim(*self.temperature_range)
106        pyplot.ylim(-0.05, 1.05)
107        pyplot.xlabel("Temperature / K")
108        pyplot.ylabel("Fraction of droplets frozen")
109        pyplot.minorticks_on()
110        pyplot.tick_params(axis="both", which="both", top=True, right=True)
111        pyplot.gca().yaxis.set_minor_locator(MultipleLocator(0.1))
112        pyplot.tick_params(which="minor", length=3)
113        pyplot.tick_params(which="major", length=6)
114        pyplot.legend()
Simulation( *, cases, n_sd=1000, n_runs_per_case=1, temperature_step=0.01, droplet_radius=9.999999999999999e-06, homogeneous_ice_nucleation_rate='KoopMurray2016', temperature_range=None)
14    def __init__(
15        self,
16        *,
17        cases,
18        n_sd=1000,
19        n_runs_per_case=1,
20        temperature_step=0.01 * si.K,
21        droplet_radius=10 * si.um,
22        homogeneous_ice_nucleation_rate="KoopMurray2016",
23        temperature_range=None,
24    ):
25        self.cases = cases
26        self.n_sd = n_sd
27        self.n_runs_per_case = n_runs_per_case
28        self.temperature_step = temperature_step
29        self.droplet_radius = droplet_radius
30        self.homogeneous_ice_nucleation_rate = homogeneous_ice_nucleation_rate
31        if temperature_range is None:
32            temperature_range = [234.5 * si.K, 238 * si.K]
33        self.temperature_range = temperature_range
34        self.multiplicity = 1
35        self.volume = 1 * si.cm**3
36        self.output = None
cases
n_sd
n_runs_per_case
temperature_step
droplet_radius
homogeneous_ice_nucleation_rate
temperature_range
multiplicity
volume
output
def run(self, keys):
38    def run(self, keys):
39        self.output = {}
40        for key in keys:
41            case = self.cases[key]
42            assert case["cooling_rate"] != 0
43            total_time = (
44                np.diff(np.asarray(self.temperature_range)) / case["cooling_rate"]
45            )
46            time_step = self.temperature_step / case["cooling_rate"]
47
48            self.output[key] = []
49            for i in range(self.n_runs_per_case):
50                T_frz = simulation(
51                    seed=i,
52                    n_sd=self.n_sd,
53                    time_step=time_step,
54                    volume=self.volume,
55                    droplet_radius=self.droplet_radius,
56                    cooling_rate=case["cooling_rate"],
57                    multiplicity=self.multiplicity,
58                    total_time=total_time,
59                    homogeneous_ice_nucleation_rate=self.homogeneous_ice_nucleation_rate,
60                    initial_temperature=self.temperature_range[1],
61                )
62                self.output[key].append({"T_frz": T_frz})
def plot_histogram(self, title=None):
 64    def plot_histogram(self, title=None):
 65
 66        pyplot.rc("font", size=12)
 67        T_bins = np.arange(self.temperature_range[0], self.temperature_range[1], 0.1)
 68
 69        for key in self.output:
 70            for run in range(self.n_runs_per_case):
 71                if run == 0:
 72                    cooling_rate = self.cases[key]["cooling_rate"]
 73                    label = (
 74                        "-"
 75                        + f"{cooling_rate*si.minute:.1f}"
 76                        + r" $\mathrm{K \, min^{-1}}$"
 77                    )
 78                else:
 79                    label = None
 80
 81                pyplot.hist(
 82                    self.output[key][run]["T_frz"],
 83                    bins=T_bins,
 84                    cumulative=-1,
 85                    density=True,
 86                    alpha=1.0,
 87                    histtype="step",
 88                    linewidth=1.5,
 89                    color=self.cases[key]["color"],
 90                    label=label,
 91                )
 92
 93        if title is None:
 94            title = (
 95                r"$r_\mathrm{drop}:$ "
 96                + f"{self.droplet_radius/si.micrometer:.2f}"
 97                + "µm"
 98                + r"   $\mathrm{N_{sd}}:$ "
 99                + str(self.n_sd)
100                + "   dT: "
101                + f"{self.temperature_step:.2f}"
102                + "K"
103            )
104        pyplot.title(title, pad=15)
105        pyplot.xlim(*self.temperature_range)
106        pyplot.ylim(-0.05, 1.05)
107        pyplot.xlabel("Temperature / K")
108        pyplot.ylabel("Fraction of droplets frozen")
109        pyplot.minorticks_on()
110        pyplot.tick_params(axis="both", which="both", top=True, right=True)
111        pyplot.gca().yaxis.set_minor_locator(MultipleLocator(0.1))
112        pyplot.tick_params(which="minor", length=3)
113        pyplot.tick_params(which="major", length=6)
114        pyplot.legend()
def simulation( *, seed, n_sd, time_step, volume, droplet_radius, cooling_rate, multiplicity, total_time, homogeneous_ice_nucleation_rate='KoopMurray2016', initial_temperature=None):
117def simulation(
118    *,
119    seed,
120    n_sd,
121    time_step,
122    volume,
123    droplet_radius,
124    cooling_rate,
125    multiplicity,
126    total_time,
127    homogeneous_ice_nucleation_rate="KoopMurray2016",
128    initial_temperature=None,
129):
130    formulae = Formulae(
131        seed=seed,
132        homogeneous_ice_nucleation_rate=homogeneous_ice_nucleation_rate,
133        particle_shape_and_density="MixedPhaseSpheres",
134        saturation_vapour_pressure="MurphyKoop2005",
135    )
136    builder = Builder(
137        n_sd=n_sd,
138        backend=CPU(formulae=formulae),
139        environment=Box(dt=time_step, dv=volume),
140        dynamics=(
141            Freezing(homogeneous_freezing="time-dependent", immersion_freezing=None),
142        ),
143    )
144
145    builder.request_attribute("temperature of last freezing")
146    builder.request_attribute("volume")
147    droplet_volume = formulae.trivia.volume(radius=droplet_radius)
148
149    attributes = {
150        "multiplicity": np.full(n_sd, multiplicity),
151        "signed water mass": np.full(n_sd, droplet_volume * formulae.constants.rho_w),
152    }
153    particulator = builder.build(attributes=attributes)
154    env = particulator.environment
155
156    env["T"] = initial_temperature
157    env["a_w_ice"] = np.nan
158    env["RH"] = 1 + np.finfo(float).eps
159    svp = particulator.formulae.saturation_vapour_pressure
160
161    cell_id = 0
162    for i in range(int(total_time / time_step) + 1):
163        env["RH_ice"] = svp.pvs_water(env["T"][cell_id]) / svp.pvs_ice(
164            env["T"][cell_id]
165        )
166        env["a_w_ice"] = svp.pvs_ice(env["T"][cell_id]) / svp.pvs_water(
167            env["T"][cell_id]
168        )
169        env["T"] -= np.full((1,), cooling_rate * time_step)
170        particulator.run(0 if i == 0 else 1)
171
172    assert all(particulator.attributes["signed water mass"].data < 0)
173    T_frz = particulator.attributes["temperature of last freezing"].data.tolist()
174    return T_frz