Skip to content

Commit dc19af2

Browse files
authored
Merge pull request #613 from slayoo/freezing
introducing immersed surface area attribute
2 parents 899593e + d4195af commit dc19af2

File tree

9 files changed

+35
-29
lines changed

9 files changed

+35
-29
lines changed

PySDM/attributes/ice/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
from .freezing_temperature import FreezingTemperature
2-
from .nucleation_sites import NucleationSites
2+
from .immersed_surface_area import ImmersedSurfaceArea
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from ..impl import ExtensiveAttribute
2+
3+
class ImmersedSurfaceArea(ExtensiveAttribute):
4+
def __init__(self, particles_builder):
5+
super().__init__(particles_builder, name='immersed surface area')

PySDM/attributes/ice/nucleation_sites.py

Lines changed: 0 additions & 5 deletions
This file was deleted.

PySDM/attributes/impl/mapper.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from PySDM.attributes.physics.hygroscopicity import Kappa, KappaTimesDryVolume
44
from PySDM.attributes.physics import (Multiplicities, Volume, Radius, DryRadius,
55
TerminalVelocity, Temperature, Heat, CriticalVolume)
6-
from PySDM.attributes.ice import FreezingTemperature, NucleationSites
6+
from PySDM.attributes.ice import FreezingTemperature, ImmersedSurfaceArea
77
from PySDM.attributes.numerics import CellID, CellOrigin, PositionInCell
88
from PySDM.attributes.chemistry import MoleAmount, Concentration, pH, HydrogenIonConcentration
99
from PySDM.physics.aqueous_chemistry.support import AQUEOUS_COMPOUNDS
@@ -41,7 +41,7 @@
4141
'pH': lambda _: pH,
4242
'conc_H': lambda _: HydrogenIonConcentration,
4343
'freezing temperature': lambda _: FreezingTemperature,
44-
'nucleation sites': lambda _: NucleationSites
44+
'immersed surface area': lambda _: ImmersedSurfaceArea
4545
}
4646

4747

PySDM/backends/numba/impl/freezing_methods.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,17 @@ def freeze_singular_body(T_fz, v_wet, T, RH, cell):
2424
self.freeze_singular_body = freeze_singular_body
2525

2626
@numba.njit(**{**conf.JIT_FLAGS, 'fastmath': self.formulae.fastmath})
27-
def freeze_time_dependent_body(rand, nucleation_sites, volume, r, dt):
28-
p = 1 - np.exp(-r * dt)
29-
# TODO #599: assert if > 1?
30-
for i in numba.prange(len(nucleation_sites)):
27+
def freeze_time_dependent_body(rand, immersed_surface_area, volume, J_het, dt):
28+
n_sd = len(volume)
29+
for i in numba.prange(n_sd):
3130
if _unfrozen(volume, i):
31+
p = 1 - np.exp(-J_het * immersed_surface_area[i] * dt) # TODO #599: assert if > 1?
3232
if rand[i] < p:
3333
_freeze(volume, i)
3434
self.freeze_time_dependent_body = freeze_time_dependent_body
3535

3636
def freeze_singular(self, T_fz, v_wet, T, RH, cell):
3737
self.freeze_singular_body(T_fz.data, v_wet.data, T.data, RH.data, cell.data)
3838

39-
def freeze_time_dependent(self, rand, nucleation_sites, volume, r, dt):
40-
self.freeze_time_dependent_body(rand.data, nucleation_sites.data, volume.data, r, dt)
39+
def freeze_time_dependent(self, rand, immersed_surface_area, volume, J_het, dt):
40+
self.freeze_time_dependent_body(rand.data, immersed_surface_area.data, volume.data, J_het, dt)

PySDM/dynamics/freezing.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
class Freezing:
2-
def __init__(self, *, singular=True, r=None):
2+
def __init__(self, *, singular=True, J_het=None):
33
self.singular = singular
44
self.enable = True
5-
self.r = r
5+
self.J_het = J_het
66
self.rand = None
77
self.rng = None
88

@@ -11,9 +11,11 @@ def register(self, builder):
1111

1212
builder.request_attribute("volume")
1313
if self.singular:
14+
assert self.J_het is None
1415
builder.request_attribute("freezing temperature")
1516
else:
16-
builder.request_attribute("nucleation sites")
17+
assert self.J_het is not None
18+
builder.request_attribute("immersed surface area")
1719
self.rand = self.core.Storage.empty(self.core.n_sd, dtype=float)
1820
self.rng = self.core.Random(self.core.n_sd, self.core.bck.formulae.seed)
1921

@@ -36,9 +38,9 @@ def __call__(self):
3638
self.rand.urand(self.rng)
3739
self.core.bck.freeze_time_dependent(
3840
rand=self.rand,
39-
nucleation_sites=self.core.particles['nucleation sites'],
41+
immersed_surface_area=self.core.particles['immersed surface area'],
4042
volume=self.core.particles['volume'],
41-
r=self.r,
43+
J_het=self.J_het,
4244
dt=self.core.dt
4345
)
4446

PySDM/physics/spectra.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ class Lognormal(Spectrum):
4949
def __init__(self, norm_factor: float, m_mode: float, s_geom: float):
5050
super().__init__(lognorm, (math.log(s_geom), 0, m_mode), norm_factor)
5151

52+
@property
53+
def s_geom(self):
54+
return math.exp(self.distribution_params[0])
5255

5356
class Sum:
5457

PySDM_tests/unit_tests/backends/test_freezing_methods.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class TestFreezingMethods:
1919
# pass
2020

2121
@staticmethod
22-
def test_freeze_time_dependent(plot=False):
22+
def test_freeze_time_dependent(plot=True):
2323
# Arrange
2424
cases = (
2525
{'dt': 5e5, 'N': 1},
@@ -29,17 +29,18 @@ def test_freeze_time_dependent(plot=False):
2929
{'dt': 5e5, 'N': 32},
3030
{'dt': 1e6, 'N': 32},
3131
)
32-
r = 1e-9
32+
rate = 1e-9
33+
immersed_surface_area = 1
34+
J_het = rate / immersed_surface_area
3335
number_of_real_droplets = 1024
34-
nucleation_sites_per_particle = 1024
3536
total_time = 2e9 # effectively interpretted here as seconds, i.e. cycle = 1 * si.s
3637

3738
# dummy (but must-be-set) values
3839
vol = 44 # just to enable sign flipping (ice water uses negative volumes), actual value does not matter
3940
dv = 666 # products use concentration, just dividing there and multiplying back here, actual value does not matter
4041

41-
hgh = lambda t: np.exp(-0.8 * r * (t - total_time / 10))
42-
low = lambda t: np.exp(-1.2 * r * (t + total_time / 10))
42+
hgh = lambda t: np.exp(-0.8 * rate * (t - total_time / 10))
43+
low = lambda t: np.exp(-1.2 * rate * (t + total_time / 10))
4344

4445
# Act
4546
output = {}
@@ -54,10 +55,10 @@ def test_freeze_time_dependent(plot=False):
5455

5556
builder = Builder(n_sd=n_sd, backend=CPU)
5657
builder.set_environment(Box(dt=case['dt'], dv=dv))
57-
builder.add_dynamic(Freezing(singular=False, r=r))
58+
builder.add_dynamic(Freezing(singular=False, J_het=J_het))
5859
attributes = {
5960
'n': np.full(n_sd, int(case['N'])),
60-
'nucleation sites': np.full(n_sd, nucleation_sites_per_particle),
61+
'immersed surface area': np.full(n_sd, immersed_surface_area),
6162
'volume': np.full(n_sd, vol)
6263
}
6364
products = (IceWaterContent(specific=False),)
@@ -76,7 +77,7 @@ def test_freeze_time_dependent(plot=False):
7677
# Plot
7778
if plot:
7879
fit_x = np.linspace(0, total_time, num=100)
79-
fit_y = np.exp(-r * fit_x)
80+
fit_y = np.exp(-rate * fit_x)
8081

8182
for key in output.keys():
8283
pylab.step(

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ beyond the latest release).
7575
For development purposes, we suggest cloning the repository and installing it using ``pip -e``.
7676
Test-time dependencies are listed in the ``test-time-requirements.txt`` file.
7777

78-
PySDM examples listed below are hosted in a separate repository and constitute
78+
PySDM examples are hosted in a separate repository and constitute
7979
the [``PySDM_examples``](https://github.com/atmos-cloud-sim-uj/PySDM-examples) package.
8080
The examples have additional dependencies listed in [``PySDM_examples`` package ``setup.py``](https://github.com/atmos-cloud-sim-uj/PySDM-examples/blob/main/setup.py) file.
8181
Running the examples requires the ``PySDM_examples`` package to be installed.
@@ -87,7 +87,7 @@ pip install -e .
8787
jupyter-notebook
8888
```
8989
Alternatively, one can also install the examples package from pypi.org by
90-
using `pip install PySDM-examples``.
90+
using ``pip install PySDM-examples``.
9191

9292
## PySDM examples (Jupyter notebooks reproducing results from literature):
9393

0 commit comments

Comments
 (0)