Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
120 commits
Select commit Hold shift + click to select a range
121ed92
added new homogeneous freezing example
tluettm Jul 8, 2025
b23b733
expanded freezing temperature unit test, and notebook
tluettm Jul 8, 2025
7f269b1
fix mark_updated calls for freezing
slayoo Jul 8, 2025
fc604f9
Merge pull request #3 from slayoo/tim/new_hom_freezing_example
tluettm Jul 8, 2025
22aa786
finished example setup for threshold homogeneous freezing
tluettm Jul 8, 2025
4b56496
expanded hom freezing example
tluettm Jul 9, 2025
0345a1a
Changed plot function
tluettm Jul 10, 2025
2e65c9f
added back freezing temperature histogram plots
tluettm Jul 10, 2025
87cd676
added ensemble of realisations
tluettm Jul 11, 2025
03529b1
draft of a smoke test + avoiding relative imports in the notebook to …
slayoo Jul 11, 2025
a53d448
note in the noteboo
slayoo Jul 11, 2025
5215b77
added ensemble for numer of super droplets
tluettm Jul 11, 2025
823cbaf
added vertical updraft ensemble
tluettm Jul 14, 2025
3d53216
Merge remote-tracking branch 'upstream' into new_hom_freezing_example
tluettm Jul 14, 2025
e11348e
added updraft ensemble and notebook cleanup
tluettm Jul 16, 2025
c8b7d28
added ensemble for ccn concentration / droplet size
tluettm Jul 17, 2025
2403fa3
new unit test for homogeneous nucleation rate and changed saturation …
tluettm Jul 19, 2025
b4c49ad
addressing pylint
tluettm Jul 21, 2025
21e4d88
added vapour deposition on ice to notebook example
tluettm Jul 23, 2025
3096742
further tinkering with simulation setups
tluettm Jul 27, 2025
83c6659
work done on the example notebook
tluettm Aug 5, 2025
aca1e86
Merge branch 'main' into new_hom_freezing_example
tluettm Aug 6, 2025
90da071
'signed water mass' changes applied to scipy solver. scipy solver too…
tluettm Sep 1, 2025
e12ed99
addressing pylint
tluettm Sep 2, 2025
7d8f046
additions to __init__.py
tluettm Sep 2, 2025
2964499
improvements to hom_freezing_example
tluettm Sep 9, 2025
8b46b6a
splitted hom_freezing.ipynb intwo two parts, improvements to simulati…
tluettm Sep 11, 2025
7a56320
precommit check for newly added files
tluettm Sep 11, 2025
ac5fc4c
added hom. freezing example with coalescence
tluettm Sep 12, 2025
0a053cb
extended hom. freezing example with coalescence
tluettm Sep 12, 2025
6306564
Added plot names to show_plot()
tluettm Sep 17, 2025
223147b
Refresh notebook
tluettm Sep 20, 2025
40c782e
Update to the plots and (temporary) change to module imports
tluettm Sep 22, 2025
65aad6a
added_new_plot_type
tluettm Sep 23, 2025
0e2acaa
added_new_plot variable
tluettm Sep 23, 2025
9cffb9a
added plots for updraft ensemble
tluettm Sep 24, 2025
6ea8681
updated notebooks
tluettm Sep 29, 2025
f66516f
Merge branch 'main' into new_hom_freezing_example
tluettm Sep 29, 2025
843620c
changed dry to wet radius initialisation and added lucky droplet meth…
tluettm Sep 30, 2025
95df379
worked at new example for smoke test
tluettm Oct 22, 2025
0560c50
Finished simple hom. freezing notebook
tluettm Oct 22, 2025
69f2f0c
Updated smoke test for hom. freezing
tluettm Oct 22, 2025
99ceb62
Simplifaction of output function and addressing pylint
tluettm Oct 22, 2025
fadccd8
addressing pylint
tluettm Oct 23, 2025
32690a7
addressing pylint
tluettm Oct 23, 2025
6417c80
New plots types and cleanup
tluettm Oct 30, 2025
2041f9c
Cleanup and gathered plots
tluettm Oct 31, 2025
42888bb
Added the new plot variants to deposition notebook
tluettm Nov 5, 2025
7c3148c
Addressing pylint
tluettm Nov 5, 2025
968e3ae
precommit
tluettm Nov 5, 2025
39abf76
Merge branch 'main' into new_hom_freezing_example
slayoo Nov 7, 2025
9520776
Added new nucleation rates plot
tluettm Nov 11, 2025
11c7520
Merge branch 'new_hom_freezing_example' of github.com:tluettm/PySDM i…
tluettm Nov 11, 2025
eb04c53
New figure 1 and 2 plots
tluettm Nov 12, 2025
fd50a41
small fixes and pylint
tluettm Nov 12, 2025
6022646
Changes to Fig 1
tluettm Nov 21, 2025
706b95c
Changes to Fig 3 and 4
tluettm Nov 25, 2025
7a40615
Changes to Fig 5
tluettm Dec 3, 2025
f266d3b
New figures 6 and 7
tluettm Dec 10, 2025
ba93ab6
Redistributed plots between notebooks
tluettm Dec 12, 2025
fead737
Adressing pylint and refresh notebooks
tluettm Dec 17, 2025
fa530a4
fix docstring includes
slayoo Dec 17, 2025
1b57a77
Added markdown
tluettm Dec 18, 2025
be6aeb1
Merge remote changes
tluettm Dec 18, 2025
a37da10
removed title from fig 3
tluettm Dec 18, 2025
dc0e942
Merge remote-tracking branch 'upstream/main' into HEAD
slayoo Dec 27, 2025
c5c826c
merge with upstream/main, fix pre-commit issues
slayoo Dec 27, 2025
c6530a9
workarounbd pylint hints
slayoo Dec 27, 2025
8576a7f
adapt to new sampling API
slayoo Dec 27, 2025
1c60875
Merge branch 'main' into new_hom_freezing_example
tluettm Jan 27, 2026
30f4c85
New J_hom formulae (K&M2016 adapted for water activity)
tluettm Jan 28, 2026
8c81a93
added new j_hom file
tluettm Jan 28, 2026
1500056
Addressing pylint and pdoc
tluettm Jan 28, 2026
5ccb7ac
added daw adapted KM16 formulation to simple hom. freezing example
tluettm Jan 28, 2026
2ae8b3f
bump scipy dependency version in setup.py to allow using scipy.optimi…
slayoo Jan 28, 2026
5eb188d
pre-commit run
slayoo Jan 29, 2026
79d729a
updated plots
tluettm Feb 2, 2026
be052ef
Merge branch 'main' into new_hom_freezing_example
tluettm Feb 2, 2026
3f7301f
pdoc fix and change to fig 3
tluettm Feb 3, 2026
d0b864f
mark Rozanski_Sonntag test as xfail due to the bug with new version o…
AgnieszkaZaba Feb 6, 2026
71c3c81
set xfail to be strict for bug #1207
AgnieszkaZaba Feb 6, 2026
3aebc2f
New Murray_et_al_2010 example added
tluettm Mar 12, 2026
2eec7ac
pdoc, code cleanup and plot improvements
tluettm Mar 12, 2026
d0c6564
change to temperature instead of time step, expanded example for diff…
tluettm Mar 12, 2026
83df43a
Updaded plots
tluettm Mar 26, 2026
d83fce3
Merge branch 'main' into new_hom_freezing_example
slayoo Apr 8, 2026
9c22d83
updated figure 1
tluettm Apr 10, 2026
b1564a0
Update xfail condition for tests on non-Windows platforms
slayoo Apr 20, 2026
aedf4a5
Merge remote-tracking branch 'upstream/slayoo-patch-21' into HEAD
slayoo Apr 20, 2026
5c35fdf
addressing pylint hints
slayoo Apr 20, 2026
3246dc8
few lines less
slayoo Apr 20, 2026
69844aa
add new example forlders to TEST_SUITES
slayoo Apr 20, 2026
a21e94c
Merge remote-tracking branch 'upstream/main' into HEAD
slayoo Apr 20, 2026
e253ce9
Fix for simple hom. freezing notebook
tluettm Apr 21, 2026
7b74780
workaround NumPy warning
slayoo Apr 21, 2026
2642aa7
Merge remote-tracking branch 'tim/new_hom_freezing_example' into HEAD
slayoo Apr 21, 2026
76fbe8d
making the workaround work also with JIT compilation disabled
slayoo Apr 21, 2026
787577c
fix pylint false warning
slayoo Apr 21, 2026
ac7951f
reduce number of realisations only for CI to speed up notebook execution
slayoo Apr 22, 2026
e940a8b
remove seed=time.time_ns() setting, which is anyhow what is done by d…
slayoo Apr 23, 2026
02ac47d
Changed termination condition for simulations
tluettm Apr 24, 2026
66a83b6
pylint
tluettm Apr 24, 2026
52f447b
addressing pylint
tluettm Apr 24, 2026
cb1b5f3
changed timestep
tluettm May 1, 2026
b1409cc
Change to plots and CI statements
tluettm May 8, 2026
b47878c
plot module changes
tluettm May 8, 2026
7b8f62b
Added more CI statements
tluettm May 13, 2026
737ec83
fix for notebook run with CI=1
tluettm May 13, 2026
035b185
add override_jit_flags to backend instantiations to force disabling N…
slayoo May 14, 2026
139baf0
typo fix
slayoo May 14, 2026
8bad268
lower vertical resolution for CI in the simple_homogeneous_freezing n…
slayoo May 15, 2026
5f6bcaf
increase timeout for Windows to 1200s, det fail-fast to false
slayoo May 17, 2026
cd9a747
CI smoke-tests-with-jit: increase timeout for non-Windows platforms t…
slayoo May 18, 2026
4918f82
CI fix for fig_S1_S2.ipynb
tluettm May 19, 2026
cadae49
Merge remote-tracking branch 'upstream/main' into new_hom_freezing_ex…
slayoo May 19, 2026
562698f
rearrange test suites
slayoo May 19, 2026
793ab32
another try
slayoo May 19, 2026
9765061
syntax fix
slayoo May 19, 2026
bb662f1
Update number_of_nsd for CI environment
slayoo May 20, 2026
6cc68a2
temporarily disable homogeneous freezing test suite for Ubuntu and Wi…
slayoo May 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions PySDM/particulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,7 @@ def homogeneous_freezing_time_dependent(self, *, rand: Storage):
temperature=self.environment["T"],
relative_humidity_ice=self.environment["RH_ice"],
)
self.attributes.mark_updated("signed water mass")

def homogeneous_freezing_threshold(self):
self.backend.homogeneous_freezing_threshold(
Expand All @@ -560,6 +561,7 @@ def homogeneous_freezing_threshold(self):
temperature=self.environment["T"],
relative_humidity_ice=self.environment["RH_ice"],
)
self.attributes.mark_updated("signed water mass")

def thaw_instantaneous(self):
self.backend.thaw_instantaneous(
Expand All @@ -569,3 +571,4 @@ def thaw_instantaneous(self):
cell=self.attributes["cell id"],
temperature=self.environment["T"],
)
self.attributes.mark_updated("signed water mass")
5 changes: 5 additions & 0 deletions examples/PySDM_examples/homogeneous_freezing/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""
Homogeneous freezing example
"""

from .settings import Settings
Comment thread
slayoo marked this conversation as resolved.
Outdated

Large diffs are not rendered by default.

107 changes: 107 additions & 0 deletions examples/PySDM_examples/homogeneous_freezing/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import time

import numpy as np
from pystrict import strict

from PySDM import Formulae
from PySDM.physics.constants import si
from PySDM.initialisation.spectra import Lognormal
from PySDM.initialisation.sampling import spectral_sampling
from tests.unit_tests.backends.test_oxidation import formulae


class Settings:
def __init__(
self,
*,
n_sd: int,
w_updraft: float,
T0: float,
dt: float,
N_dv_droplet_distribution: float,
r_mean_droplet_distribution: float,
sigma_droplet_distribution: float = None,
type_droplet_distribution: str,
p0: float = 200 * si.hectopascals,
RH_0: float = 1.0,
kappa: float = 0.64,
condensation_enable: bool=True,
deposition_enable: bool=True,
hom_freezing: str=None,
):

print("Setting up simulation with " + hom_freezing)
self.n_sd = n_sd
self.w_updraft = w_updraft
self.N_dv_droplet_distribution = N_dv_droplet_distribution
self.r_mean_droplet_distribution = r_mean_droplet_distribution
self.sigma_droplet_distribution = sigma_droplet_distribution
self.type_droplet_distribution = type_droplet_distribution

self.mass_of_dry_air = 1000 * si.kilogram
self.initial_pressure = p0
self.initial_water_supersaturation = RH_0
# self.initial_ice_supersaturation = RHi_0
self.kappa = kappa
self.initial_temperature = T0

self.condensation_enable = condensation_enable
self.deposition_enable = deposition_enable



if hom_freezing == "threshold":
hom_nucleation_rate = "Null"
self.hom_freezing_type = "threshold"
else:
hom_nucleation_rate = hom_freezing
self.hom_freezing_type = "time-dependent"

formulae = Formulae(
particle_shape_and_density="MixedPhaseSpheres",
homogeneous_ice_nucleation_rate=hom_nucleation_rate,
seed=time.time_ns()
)

self.formulae = formulae

const = self.formulae.constants
# pvs_i = self.formulae.saturation_vapour_pressure.pvs_ice(self.initial_temperature)
pvs_w = self.formulae.saturation_vapour_pressure.pvs_water(
self.initial_temperature
)
self.initial_water_vapour_mixing_ratio = const.eps / (
self.initial_pressure / self.initial_water_supersaturation / pvs_w - 1
)

dry_air_density = (
self.formulae.trivia.p_d(
self.initial_pressure, self.initial_water_vapour_mixing_ratio
)
/ self.initial_temperature
/ const.Rd
)

if self.type_droplet_distribution == ("monodisperse"):
self.r_dry = np.ones(self.n_sd) * r_mean_droplet_distribution
self.specific_concentration = (
np.ones(self.n_sd)
* N_dv_droplet_distribution
/ self.n_sd
/ dry_air_density
)

elif self.type_droplet_distribution == ("lognormal"):
spectrum = Lognormal(
norm_factor=N_dv_droplet_distribution / dry_air_density,
m_mode=r_mean_droplet_distribution,
s_geom=sigma_droplet_distribution,
)

self.r_dry, self.specific_concentration = spectral_sampling.Linear(
spectrum
).sample(n_sd)

self.t_max_duration = 7200 # 3600 * 1.5 # total duration of simulation
self.dt = dt
self.n_output = 10 # int(self.t_duration / 100) #100 # number of output steps
174 changes: 174 additions & 0 deletions examples/PySDM_examples/homogeneous_freezing/simulation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import numpy as np

import PySDM.products as PySDM_products
from PySDM.backends import CPU
from PySDM.builder import Builder
from PySDM.dynamics import (
AmbientThermodynamics,
Condensation,
Freezing,
VapourDepositionOnIce,
)
from PySDM.environments import Parcel
from PySDM.physics import constants as const
from PySDM.initialisation import discretise_multiplicities, equilibrate_wet_radii


class Simulation:
def __init__(self, settings, backend=CPU):

dt = settings.dt

formulae = settings.formulae

env = Parcel(
mixed_phase=True,
dt=dt,
mass_of_dry_air=settings.mass_of_dry_air,
p0=settings.initial_pressure,
initial_water_vapour_mixing_ratio=settings.initial_water_vapour_mixing_ratio,
T0=settings.initial_temperature,
w=settings.w_updraft,
)

builder = Builder(
backend=backend(
formulae=settings.formulae,
**(
{"override_jit_flags": {"parallel": False}}
if backend == CPU
else {}
),
),
n_sd=settings.n_sd,
environment=env,
)

builder.add_dynamic(AmbientThermodynamics())
if settings.condensation_enable:
builder.add_dynamic(Condensation())
if settings.deposition_enable:
builder.add_dynamic(VapourDepositionOnIce())
builder.add_dynamic(
Freezing(
homogeneous_freezing=settings.hom_freezing_type, immersion_freezing=None
)
)

self.n_sd = settings.n_sd
self.multiplicities = discretise_multiplicities(
settings.specific_concentration * env.mass_of_dry_air
)
self.r_dry = settings.r_dry
v_dry = settings.formulae.trivia.volume(radius=self.r_dry)
kappa = settings.kappa

self.r_wet = equilibrate_wet_radii(
r_dry=self.r_dry,
environment=builder.particulator.environment,
kappa_times_dry_volume=kappa * v_dry,
)
attributes = {
"multiplicity": self.multiplicities,
"dry volume": v_dry,
"kappa times dry volume": kappa * v_dry,
"signed water mass": formulae.particle_shape_and_density.radius_to_mass(
self.r_wet
),
}
builder.request_attribute("temperature of last freezing")

products = [
PySDM_products.ParcelDisplacement(name="z"),
PySDM_products.Time(name="t"),
PySDM_products.AmbientRelativeHumidity(name="RH", unit="%"),
PySDM_products.AmbientRelativeHumidity(name="RH_ice", unit="%"),
PySDM_products.AmbientTemperature(name="T"),
PySDM_products.AmbientPressure(name="p", unit="hPa"),
PySDM_products.WaterMixingRatio(name="water", radius_range=(0, np.inf)),
PySDM_products.WaterMixingRatio(name="ice", radius_range=(-np.inf, 0)),
PySDM_products.WaterMixingRatio(
name="total", radius_range=(-np.inf, np.inf)
),
PySDM_products.AmbientWaterVapourMixingRatio(
name="vapour", var="water_vapour_mixing_ratio"
),
PySDM_products.ParticleConcentration(
name="n_s", unit="1/cm**3", radius_range=(0, np.inf)
),
PySDM_products.ParticleConcentration(
name="n_i", unit="1/cm**3", radius_range=(-np.inf, 0)
),
PySDM_products.MeanRadius(name="r_s", unit="µm", radius_range=(0, np.inf)),
PySDM_products.MeanRadius(name="r_i", unit="µm", radius_range=(-np.inf, 0)),
]

self.particulator = builder.build(attributes, products)

self.n_output = settings.n_output
self.n_substeps = int(self.n_output / dt)
self.t_max_duration = settings.t_max_duration

def save(self, output):
cell_id = 0

output["z"].append(self.particulator.products["z"].get()[cell_id])
output["t"].append(self.particulator.products["t"].get())
output["RH"].append(self.particulator.products["RH"].get()[cell_id])
output["RHi"].append(self.particulator.products["RH_ice"].get()[cell_id])
output["T"].append(self.particulator.products["T"].get()[cell_id])
output["P"].append(self.particulator.products["p"].get()[cell_id])
output["LWC"].append(self.particulator.products["water"].get()[cell_id])
output["IWC"].append(self.particulator.products["ice"].get()[cell_id])
# output["TWC"].append(self.particulator.products["total"].get()[cell_id])
output["qv"].append(self.particulator.products["vapour"].get()[cell_id])
output["ns"].append(self.particulator.products["n_s"].get()[cell_id])
output["ni"].append(self.particulator.products["n_i"].get()[cell_id])
output["rs"].append(self.particulator.products["r_s"].get()[cell_id])
output["ri"].append(self.particulator.products["r_i"].get()[cell_id])
output["water_mass"].append(
self.particulator.attributes["signed water mass"].data.tolist()
)
output["T_frz"].append(
self.particulator.attributes["temperature of last freezing"].data.tolist()
)

def run(self):

print( "Starting simulation..." )

output = {
"t": [],
"z": [],
"RH": [],
"RHi": [],
"T": [],
"P": [],
"LWC": [],
"IWC": [],
"qv": [],
"ns": [],
"ni": [],
"rs": [],
"ri": [],
"water_mass": [],
"T_frz": [],
}

self.save(output)

while True:

self.particulator.run(self.n_substeps)
self.save(output)

# print( output["t"][-1], output["T"][-1], output["LWC"][-1], output["IWC"][-1] )

if output["LWC"][-1] == 0:
print("break due to LWC")
break
if output["t"][-1] >= self.t_max_duration:
print("time exceeded")
break

return output
Loading