Skip to content

Commit ef3ac83

Browse files
edejong-caltechslayooabulenokde Jong
authored
Fixes to Straub fragmentation function and sampling methods, addition of LowList1982 fragmentation function and coalescence efficiency (#1023)
Co-authored-by: Sylwester Arabas <[email protected]> Co-authored-by: Oleksii Bulenok <[email protected]> Co-authored-by: de Jong <[email protected]> Co-authored-by: Oleksii Bulenok <[email protected]>
1 parent c48269b commit ef3ac83

File tree

29 files changed

+1123
-256
lines changed

29 files changed

+1123
-256
lines changed

PySDM/backends/impl_numba/methods/collisions_methods.py

+261-48
Large diffs are not rendered by default.

PySDM/backends/impl_thrust_rtc/methods/collisions_methods.py

+47-36
Original file line numberDiff line numberDiff line change
@@ -521,23 +521,24 @@ def __init__(self):
521521
param_names=(
522522
"n_fragment",
523523
"frag_size",
524-
"v_max",
525524
"x_plus_y",
526525
"vmin",
527526
"nfmax",
528527
"nfmax_is_not_none",
529528
),
530529
name_iter="i",
531530
body="""
532-
frag_size[i] = min(frag_size[i], v_max[i]);
533-
frag_size[i] = max(frag_size[i], vmin);
531+
frag_size[i] = min(frag_size[i], x_plus_y[i])
534532
535533
if (nfmax_is_not_none) {
536534
if (x_plus_y[i] / frag_size[i] > nfmax) {
537535
frag_size[i] = x_plus_y[i] / nfmax;
538536
}
539537
}
540-
if (frag_size[i] == 0.0) {
538+
else if (frag_size[i] < vmin) {
539+
frag_size[i] = x_plus_y[i];
540+
}
541+
else if (frag_size[i] == 0.0) {
541542
frag_size[i] = x_plus_y[i];
542543
}
543544
n_fragment[i] = x_plus_y[i] / frag_size[i];
@@ -549,10 +550,8 @@ def __init__(self):
549550
param_names=("mu", "sigma", "frag_size", "rand"),
550551
name_iter="i",
551552
body=f"""
552-
frag_size[i] = {self.formulae.fragmentation_function.frag_size.c_inline(
553-
mu="mu",
554-
sigma="sigma",
555-
rand="rand[i]"
553+
frag_size[i] = mu + sigma * {self.formulae.trivia.erfinv_approx.c_inline(
554+
c="rand[i]"
556555
)};
557556
""".replace(
558557
"real_type", self._get_c_type()
@@ -610,6 +609,20 @@ def __init__(self):
610609
Nrt[i] = Nr1[i] + Nr2[i] + Nr3[i] + Nr4[i];
611610
"""
612611

612+
self.__straub_mass_remainder = """
613+
Nr1[i] = Nr1[i] * exp(3 * mu1 + 9 * pow(sigma1, 2.0) / 2);
614+
Nr2[i] = Nr2[i] * (pow(mu2, 3.0) + 3 * mu2 * pow(sigma2, 2.0));
615+
Nr3[i] = Nr3[i] * (pow(mu3, 3.0) + 3 * mu3 * pow(sigma3, 2.0));
616+
Nr4[i] = v_max[i] * 6.0 / 3.141592654 + pow(ds[i], 3.0) - Nr1[i] - Nr2[i] - Nr3[i];
617+
if Nr4[i] <= 0.0 {
618+
d34[i] = 0;
619+
Nr4[i] = 0;
620+
}
621+
else {
622+
d34[i] = exp(log(Nr4[i]) / 3);
623+
}
624+
"""
625+
613626
if self.formulae.fragmentation_function.__name__ == "Straub2010Nf":
614627
self.__straub_fragmentation_body = trtc.For(
615628
param_names=(
@@ -624,41 +637,44 @@ def __init__(self):
624637
"Nr3",
625638
"Nr4",
626639
"Nrt",
640+
"d34",
627641
),
628642
name_iter="i",
629643
body=f"""
630644
{self.__straub_Nr_body}
645+
auto sigma1 = {self.formulae.fragmentation_function.params_sigma1.c_inline(CW="CW[i]")};
646+
auto mu1 = {self.formulae.fragmentation_function.params_mu1.c_inline(sigma1="sigma1")};
647+
auto sigma2 = {self.formulae.fragmentation_function.params_sigma2.c_inline(CW="CW[i]")};
648+
auto mu2 = {self.formulae.fragmentation_function.params_mu2.c_inline(ds="ds[i]")};
649+
auto sigma3 = {self.formulae.fragmentation_function.params_sigma3.c_inline(CW="CW[i]")};
650+
auto mu3 = {self.formulae.fragmentation_function.params_mu3.c_inline(ds="ds[i]")};
651+
{self.__straub_mass_remainder}
652+
Nrt[i] = Nr1[i] + Nr2[i] + Nr3[i] + Nr4[i]
631653
632654
if (rand[i] < Nr1[i] / Nrt[i]) {{
633-
auto sigma1 = {self.formulae.fragmentation_function.sigma1.c_inline(CW="CW[i]")};
634-
frag_size[i] = {self.formulae.fragmentation_function.p1.c_inline(
635-
sigma1="sigma1",
636-
rand="rand[i] * Nrt[i] / Nr1[i]"
655+
auto X = rand[i] * Nrt[i] / Nr1[i];
656+
auto lnarg = mu1 + sqrt(2.0) * sigma1 * {self.formulae.trivia.erfinv_approx.c_inline(
657+
c="X"
637658
)};
659+
frag_size[i] = exp(lnarg);
638660
}}
639661
else if (rand[i] < (Nr2[i] + Nr1[i]) / Nrt[i]) {{
640-
frag_size[i] = {self.formulae.fragmentation_function.p2.c_inline(
641-
CW="CW[i]",
642-
rand="(rand[i] * Nrt[i] - Nr1[i]) / (Nr2[i] - Nr1[i])"
662+
auto X = (rand[i] * Nrt[i] - Nr1[i]) / Nr2[i];
663+
frag_size[i] = mu2 + sqrt(2.0) * sigma2 * {self.formulae.trivia.erfinv_approx.c_inline(
664+
c="X"
643665
)};
644666
}}
645667
else if (rand[i] < (Nr3[i] + Nr2[i] + Nr1[i]) / Nrt[i]) {{
646-
frag_size[i] = {self.formulae.fragmentation_function.p3.c_inline(
647-
CW="CW[i]",
648-
ds="ds[i]",
649-
rand="(rand[i] * Nrt[i] - Nr2[i]) / (Nr3[i] - Nr2[i])"
668+
auto X = (rand[i] * Nrt[i] - Nr1[i] - Nr2[i]) / Nr3[i];
669+
frag_size[i] = mu3 + sqrt(2.0) * sigma3 * {self.formulae.trivia.erfinv_approx.c_inline(
670+
c="X"
650671
)};
651672
}}
652673
else {{
653-
frag_size[i] = {self.formulae.fragmentation_function.p4.c_inline(
654-
CW="CW[i]",
655-
ds="ds[i]",
656-
v_max="v_max[i]",
657-
Nr1="Nr1[i]",
658-
Nr2="Nr2[i]",
659-
Nr3="Nr3[i]"
660-
)};
674+
frag_size[i] = d34[i];
661675
}}
676+
677+
frag_size[i] = pow(frag_size[i], 3.0) * 3.141592654 / 6.0
662678
""".replace(
663679
"real_type", self._get_c_type()
664680
),
@@ -910,7 +926,6 @@ def exp_fragmentation(
910926
n_fragment,
911927
scale,
912928
frag_size,
913-
v_max,
914929
x_plus_y,
915930
rand,
916931
vmin,
@@ -932,7 +947,6 @@ def exp_fragmentation(
932947
args=(
933948
n_fragment.data,
934949
frag_size.data,
935-
v_max.data,
936950
x_plus_y.data,
937951
self._get_floating_point(vmin),
938952
self._get_floating_point(nfmax if nfmax else -1),
@@ -941,7 +955,7 @@ def exp_fragmentation(
941955
)
942956

943957
def gauss_fragmentation(
944-
self, *, n_fragment, mu, sigma, frag_size, v_max, x_plus_y, rand, vmin, nfmax
958+
self, *, n_fragment, mu, sigma, frag_size, x_plus_y, rand, vmin, nfmax
945959
):
946960
self.__gauss_fragmentation_body.launch_n(
947961
n=len(frag_size),
@@ -958,7 +972,6 @@ def gauss_fragmentation(
958972
args=(
959973
n_fragment.data,
960974
frag_size.data,
961-
v_max.data,
962975
x_plus_y.data,
963976
self._get_floating_point(vmin),
964977
self._get_floating_point(nfmax if nfmax else -1),
@@ -967,7 +980,7 @@ def gauss_fragmentation(
967980
)
968981

969982
def slams_fragmentation(
970-
self, n_fragment, frag_size, v_max, x_plus_y, probs, rand, vmin, nfmax
983+
self, n_fragment, frag_size, x_plus_y, probs, rand, vmin, nfmax
971984
): # pylint: disable=too-many-arguments
972985
self.__slams_fragmentation_body.launch_n(
973986
n=(len(n_fragment)),
@@ -985,7 +998,6 @@ def slams_fragmentation(
985998
args=(
986999
n_fragment.data,
9871000
frag_size.data,
988-
v_max.data,
9891001
x_plus_y.data,
9901002
self._get_floating_point(vmin),
9911003
self._get_floating_point(nfmax if nfmax else -1),
@@ -999,7 +1011,6 @@ def feingold1988_fragmentation(
9991011
n_fragment,
10001012
scale,
10011013
frag_size,
1002-
v_max,
10031014
x_plus_y,
10041015
rand,
10051016
fragtol,
@@ -1022,7 +1033,6 @@ def feingold1988_fragmentation(
10221033
args=(
10231034
n_fragment.data,
10241035
frag_size.data,
1025-
v_max.data,
10261036
x_plus_y.data,
10271037
self._get_floating_point(vmin),
10281038
self._get_floating_point(nfmax if nfmax else -1),
@@ -1049,6 +1059,7 @@ def straub_fragmentation(
10491059
Nr3,
10501060
Nr4,
10511061
Nrt,
1062+
d34,
10521063
):
10531064
self.__straub_fragmentation_body.launch_n(
10541065
n=len(frag_size),
@@ -1064,6 +1075,7 @@ def straub_fragmentation(
10641075
Nr3.data,
10651076
Nr4.data,
10661077
Nrt.data,
1078+
d34.data,
10671079
),
10681080
)
10691081

@@ -1072,7 +1084,6 @@ def straub_fragmentation(
10721084
args=(
10731085
n_fragment.data,
10741086
frag_size.data,
1075-
v_max.data,
10761087
x_plus_y.data,
10771088
self._get_floating_point(vmin),
10781089
self._get_floating_point(nfmax if nfmax else -1),

PySDM/backends/impl_thrust_rtc/test_helpers/cpp2python.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ def to_numba(name, args, iter_var, body):
190190
f"""
191191
def make(self):
192192
import numpy as np
193-
from numpy import floor, ceil, exp, log, power, sqrt, arctanh
193+
from numpy import floor, ceil, exp, log, power, sqrt, arctanh, sinh, arcsinh
194194
import numba
195195
196196
@numba.njit(parallel=False, {JIT_OPTS})

PySDM/dynamics/collisions/breakup_fragmentations/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66
from .exponential import ExponFrag
77
from .feingold1988 import Feingold1988Frag
88
from .gaussian import Gaussian
9+
from .lowlist82 import LowList1982Nf
910
from .slams import SLAMS
1011
from .straub2010 import Straub2010Nf

PySDM/dynamics/collisions/breakup_fragmentations/exponential.py

-6
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,22 @@ def __init__(self, scale, vmin=0.0, nfmax=None):
1010
self.scale = scale
1111
self.vmin = vmin
1212
self.nfmax = nfmax
13-
self.max_size = None
1413
self.sum_of_volumes = None
1514

1615
def register(self, builder):
1716
self.particulator = builder.particulator
18-
self.max_size = self.particulator.PairwiseStorage.empty(
19-
self.particulator.n_sd // 2, dtype=float
20-
)
2117
self.sum_of_volumes = self.particulator.PairwiseStorage.empty(
2218
self.particulator.n_sd // 2, dtype=float
2319
)
2420

2521
def __call__(self, nf, frag_size, u01, is_first_in_pair):
26-
self.max_size.max(self.particulator.attributes["volume"], is_first_in_pair)
2722
self.sum_of_volumes.sum(
2823
self.particulator.attributes["volume"], is_first_in_pair
2924
)
3025
self.particulator.backend.exp_fragmentation(
3126
n_fragment=nf,
3227
scale=self.scale,
3328
frag_size=frag_size,
34-
v_max=self.max_size,
3529
x_plus_y=self.sum_of_volumes,
3630
rand=u01,
3731
vmin=self.vmin,

PySDM/dynamics/collisions/breakup_fragmentations/feingold1988.py

-6
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,23 @@ def __init__(self, scale, fragtol=1e-3, vmin=0.0, nfmax=None):
1111
self.fragtol = fragtol
1212
self.vmin = vmin
1313
self.nfmax = nfmax
14-
self.max_size = None
1514
self.sum_of_volumes = None
1615

1716
def register(self, builder):
1817
self.particulator = builder.particulator
1918
builder.request_attribute("volume")
20-
self.max_size = self.particulator.PairwiseStorage.empty(
21-
self.particulator.n_sd // 2, dtype=float
22-
)
2319
self.sum_of_volumes = self.particulator.PairwiseStorage.empty(
2420
self.particulator.n_sd // 2, dtype=float
2521
)
2622

2723
def __call__(self, nf, frag_size, u01, is_first_in_pair):
28-
self.max_size.max(self.particulator.attributes["volume"], is_first_in_pair)
2924
self.sum_of_volumes.sum(
3025
self.particulator.attributes["volume"], is_first_in_pair
3126
)
3227
self.particulator.backend.feingold1988_fragmentation(
3328
n_fragment=nf,
3429
scale=self.scale,
3530
frag_size=frag_size,
36-
v_max=self.max_size,
3731
x_plus_y=self.sum_of_volumes,
3832
rand=u01,
3933
fragtol=self.fragtol,

PySDM/dynamics/collisions/breakup_fragmentations/gaussian.py

-6
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,15 @@ def __init__(self, mu, sigma, vmin=0.0, nfmax=None):
1010
self.sigma = sigma
1111
self.vmin = vmin
1212
self.nfmax = nfmax
13-
self.max_size = None
1413
self.sum_of_volumes = None
1514

1615
def register(self, builder):
1716
self.particulator = builder.particulator
18-
self.max_size = self.particulator.PairwiseStorage.empty(
19-
self.particulator.n_sd // 2, dtype=float
20-
)
2117
self.sum_of_volumes = self.particulator.PairwiseStorage.empty(
2218
self.particulator.n_sd // 2, dtype=float
2319
)
2420

2521
def __call__(self, nf, frag_size, u01, is_first_in_pair):
26-
self.max_size.max(self.particulator.attributes["volume"], is_first_in_pair)
2722
self.sum_of_volumes.sum(
2823
self.particulator.attributes["volume"], is_first_in_pair
2924
)
@@ -32,7 +27,6 @@ def __call__(self, nf, frag_size, u01, is_first_in_pair):
3227
mu=self.mu,
3328
sigma=self.sigma,
3429
frag_size=frag_size,
35-
v_max=self.max_size,
3630
x_plus_y=self.sum_of_volumes,
3731
rand=u01,
3832
vmin=self.vmin,

0 commit comments

Comments
 (0)