Skip to content

Commit fe88baf

Browse files
ekdejongslayoo
andauthored
coalescence-only single-column test case ("deJong_Azimi" based on S&H); power-law terminal velocity; initialisation of particles in part of the domain in 1D kinematic env (#1221)
Co-authored-by: Sylwester Arabas <[email protected]> Co-authored-by: Sylwester Arabas <[email protected]>
1 parent d6b0df2 commit fe88baf

File tree

27 files changed

+14083
-127
lines changed

27 files changed

+14083
-127
lines changed

PySDM/backends/impl_numba/methods/terminal_velocity_methods.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,23 @@ def terminal_velocity(self, *, values, radius, k1, k2, k3, r1, r2):
4646
self.terminal_velocity_body(
4747
values=values, radius=radius, k1=k1, k2=k2, k3=k3, r1=r1, r2=r2
4848
)
49+
50+
@cached_property
51+
def power_series_body(self):
52+
@numba.njit(**{**conf.JIT_FLAGS, "fastmath": self.formulae.fastmath})
53+
def power_series_body(*, values, radius, num_terms, prefactors, powers):
54+
for i in numba.prange(len(values)): # pylint: disable=not-an-iterable
55+
values[i] = 0.0
56+
for j in range(num_terms):
57+
values[i] = values[i] + prefactors[j] * radius[i] ** (powers[j] * 3)
58+
59+
return power_series_body
60+
61+
def power_series(self, *, values, radius, num_terms, prefactors, powers):
62+
self.power_series_body(
63+
values=values,
64+
radius=radius,
65+
num_terms=num_terms,
66+
prefactors=prefactors,
67+
powers=powers,
68+
)

PySDM/backends/impl_thrust_rtc/methods/terminal_velocity_methods.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,27 @@ def interpolation(self, *, output, radius, factor, b, c):
131131
self.__interpolation_body.launch_n(
132132
len(radius), (output.data, radius.data, factor_device, b.data, c.data)
133133
)
134+
135+
@cached_property
136+
def __power_series_body(self):
137+
# TODO #599 r<0
138+
return trtc.For(
139+
("output", "radius", "num_terms", "prefactors", "powers"),
140+
"i",
141+
"""
142+
output[i] = 0.0
143+
int kmax = num_terms
144+
for (auto k = 0; k < kmax; k+=1) {
145+
auto sumterm = prefactors[k] * pow(radius[i], 3*powers[k])
146+
output[i] = output[i] + sumterm
147+
""",
148+
)
149+
150+
@nice_thrust(**NICE_THRUST_FLAGS)
151+
def power_series(self, *, values, radius, num_terms, prefactors, powers):
152+
prefactors = self._get_floating_point(prefactors)
153+
powers = self._get_floating_point(powers)
154+
num_terms = self._get_floating_point(num_terms)
155+
self.__power_series_body.launch_n(
156+
values.size(), (values, radius, num_terms, prefactors, powers)
157+
)

PySDM/dynamics/terminal_velocity/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
"""
44

55
from PySDM.dynamics.terminal_velocity.gunn_and_kinzer import GunnKinzer1949
6+
from PySDM.dynamics.terminal_velocity.power_series import PowerSeries
67
from PySDM.dynamics.terminal_velocity.rogers_and_yau import RogersYau
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
"""
2+
Power series expression
3+
"""
4+
5+
import numpy as np
6+
7+
from PySDM.physics import constants as const
8+
9+
10+
class PowerSeries: # pylint: disable=too-few-public-methods
11+
def __init__(self, particulator, *, prefactors=None, powers=None):
12+
si = const.si
13+
self.particulator = particulator
14+
prefactors = prefactors or [2.0e-1 * si.m / si.s / np.sqrt(si.m)]
15+
self.prefactors = np.array(prefactors)
16+
powers = powers or [1 / 6]
17+
self.powers = np.array(powers)
18+
for i, p in enumerate(self.powers):
19+
self.prefactors[i] *= (4 / 3 * const.PI) ** (p)
20+
self.prefactors[i] /= (1 * si.um**3) ** (p)
21+
assert len(self.prefactors) == len(self.powers)
22+
23+
def __call__(self, output, radius):
24+
self.particulator.backend.power_series(
25+
values=output.data,
26+
radius=radius.data,
27+
num_terms=len(self.powers),
28+
prefactors=self.prefactors,
29+
powers=self.powers,
30+
)

PySDM/environments/kinematic_1d.py

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,13 @@ def get_thd(self) -> np.ndarray:
3232
return self.thd0
3333

3434
def init_attributes(
35-
self, *, spatial_discretisation, spectral_discretisation, kappa
35+
self,
36+
*,
37+
spatial_discretisation,
38+
spectral_discretisation,
39+
kappa,
40+
z_part=None,
41+
collisions_only=False
3642
):
3743
super().sync()
3844
self.notify()
@@ -43,31 +49,40 @@ def init_attributes(
4349
backend=self.particulator.backend,
4450
grid=self.mesh.grid,
4551
n_sd=self.particulator.n_sd,
52+
z_part=z_part,
4653
)
4754
(
4855
attributes["cell id"],
4956
attributes["cell origin"],
5057
attributes["position in cell"],
5158
) = self.mesh.cellular_attributes(positions)
5259

53-
r_dry, n_per_kg = spectral_discretisation.sample(
54-
backend=self.particulator.backend, n_sd=self.particulator.n_sd
55-
)
56-
attributes["dry volume"] = self.formulae.trivia.volume(radius=r_dry)
57-
attributes["kappa times dry volume"] = attributes["dry volume"] * kappa
58-
r_wet = equilibrate_wet_radii(
59-
r_dry=r_dry,
60-
environment=self,
61-
cell_id=attributes["cell id"],
62-
kappa_times_dry_volume=attributes["kappa times dry volume"],
63-
)
60+
if collisions_only:
61+
v_wet, n_per_kg = spectral_discretisation.sample(
62+
backend=self.particulator.backend, n_sd=self.particulator.n_sd
63+
)
64+
# attributes["dry volume"] = v_wet
65+
attributes["volume"] = v_wet
66+
# attributes["kappa times dry volume"] = attributes["dry volume"] * kappa
67+
else:
68+
r_dry, n_per_kg = spectral_discretisation.sample(
69+
backend=self.particulator.backend, n_sd=self.particulator.n_sd
70+
)
71+
attributes["dry volume"] = self.formulae.trivia.volume(radius=r_dry)
72+
attributes["kappa times dry volume"] = attributes["dry volume"] * kappa
73+
r_wet = equilibrate_wet_radii(
74+
r_dry=r_dry,
75+
environment=self,
76+
cell_id=attributes["cell id"],
77+
kappa_times_dry_volume=attributes["kappa times dry volume"],
78+
)
79+
attributes["volume"] = self.formulae.trivia.volume(radius=r_wet)
6480

6581
rhod = self["rhod"].to_ndarray()
6682
cell_id = attributes["cell id"]
6783
domain_volume = np.prod(np.array(self.mesh.size))
6884

6985
attributes["multiplicity"] = n_per_kg * rhod[cell_id] * domain_volume
70-
attributes["volume"] = self.formulae.trivia.volume(radius=r_wet)
7186

7287
return attributes
7388

PySDM/formulae.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
from PySDM import physics
2121
from PySDM.backends.impl_numba import conf
22-
from PySDM.dynamics.terminal_velocity import GunnKinzer1949, RogersYau
22+
from PySDM.dynamics.terminal_velocity import GunnKinzer1949, PowerSeries, RogersYau
2323
from PySDM.dynamics.terminal_velocity.gunn_and_kinzer import TpDependent
2424

2525

@@ -124,6 +124,7 @@ def __init__( # pylint: disable=too-many-locals
124124
"GunnKinzer1949": GunnKinzer1949,
125125
"RogersYau": RogersYau,
126126
"TpDependent": TpDependent,
127+
"PowerSeries": PowerSeries,
127128
}[terminal_velocity]
128129

129130
def __str__(self):

PySDM/initialisation/sampling/spatial_sampling.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,23 @@
88

99
class Pseudorandom: # pylint: disable=too-few-public-methods
1010
@staticmethod
11-
def sample(*, backend, grid, n_sd):
11+
def sample(*, backend, grid, n_sd, z_part=None):
1212
dimension = len(grid)
1313
n_elements = dimension * n_sd
1414

1515
storage = backend.Storage.empty(n_elements, dtype=float)
1616
backend.Random(seed=backend.formulae.seed, size=n_elements)(storage)
1717
positions = storage.to_ndarray().reshape(dimension, n_sd)
1818

19-
for dim in range(dimension):
20-
positions[dim, :] *= grid[dim]
19+
if z_part is None:
20+
for dim in range(dimension):
21+
positions[dim, :] *= grid[dim]
22+
else:
23+
assert dimension == 1
24+
iz_min = int(grid[0] * z_part[0])
25+
iz_max = int(grid[0] * z_part[1])
26+
for dim in range(dimension):
27+
positions[dim, :] *= iz_max - iz_min
28+
positions[dim, :] += iz_min
29+
2130
return positions

PySDM/products/size_spectral/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
RadiusFirstMoment,
55
RadiusSixthMoment,
66
VolumeFirstMoment,
7+
VolumeSecondMoment,
78
ZerothMoment,
89
)
910
from .effective_radius import EffectiveRadius

PySDM/products/size_spectral/arbitrary_moment.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ def _impl(self, **kwargs):
3232
rank=1, attr="volume", attr_unit="m^3"
3333
)
3434

35+
VolumeSecondMoment = make_arbitrary_moment_product(
36+
rank=2, attr="volume", attr_unit="m^3"
37+
)
38+
3539
RadiusSixthMoment = make_arbitrary_moment_product(rank=6, attr="radius", attr_unit="m")
3640

3741
RadiusFirstMoment = make_arbitrary_moment_product(rank=1, attr="radius", attr_unit="m")

examples/PySDM_examples/Shipway_and_Hill_2012/fig_1.ipynb

Lines changed: 95 additions & 64 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)