Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
484d3a4
Some intial implemementation of new kernel choice logic
tluettm Jun 12, 2026
676b95f
Moved parts of golovin kernel to formulae; setup for other collision …
tluettm Jun 16, 2026
44b8fd9
Modyfing call of golovin kernel
tluettm Jun 17, 2026
a23145f
Updates to new unittest
tluettm Jun 17, 2026
12dd7ce
Removed passing of collision kernel argument to collision dynamic
tluettm Jun 18, 2026
ee28fe5
Updated all collisions kernel to be compatible with new kernel choice…
tluettm Jun 18, 2026
6437192
Merge branch 'main' into new_collision_kernel_logic
tluettm Jun 18, 2026
af89155
Moved analytical solution for golovin kernel
tluettm Jun 19, 2026
f3f5baa
Merge branch 'main' into new_collision_kernel_logic
tluettm Jul 1, 2026
6b7775e
Some intial implemementation of new kernel choice logic
tluettm Jun 12, 2026
1f4bf94
Moved parts of golovin kernel to formulae; setup for other collision …
tluettm Jun 16, 2026
e52c6bc
Modyfing call of golovin kernel
tluettm Jun 17, 2026
9460527
Updates to new unittest
tluettm Jun 17, 2026
59e3edd
Removed passing of collision kernel argument to collision dynamic
tluettm Jun 18, 2026
8ecdc79
Updated all collisions kernel to be compatible with new kernel choice…
tluettm Jun 18, 2026
1d71267
Moved analytical solution for golovin kernel
tluettm Jun 19, 2026
5d098a7
adapt test_collision_rates.py to new API
slayoo Jul 4, 2026
f2b5a3e
adapting test_diffusional_growth_mass_change.py to the new API
slayoo Jul 4, 2026
cb83e33
adapt test_sdm_breakup.py to the new API
slayoo Jul 4, 2026
e826cf7
adapting srivastava_1982/test_eq_10.py to the new API
slayoo Jul 4, 2026
b5a9462
adapr docs code snippets to API changes
slayoo Jul 4, 2026
88f02a1
fix docs codes
slayoo Jul 4, 2026
d47bbb3
syntax fix
slayoo Jul 4, 2026
0538f0e
Merge branch 'new_collision_kernel_logic' of github.com:tluettm/PySDM…
tluettm Jul 14, 2026
80d26e6
fix tutorial code snippets
slayoo Jul 15, 2026
2f3e1a2
one more docs snippet fix
slayoo Jul 15, 2026
798edd4
adapt get_dummy_particulator_and_coalescence
slayoo Jul 15, 2026
521ef14
workarounds... (thanks @Bodzio-2)
slayoo Jul 15, 2026
490827c
one more test adapted
slayoo Jul 15, 2026
eb11c5b
one more test fixed
slayoo Jul 15, 2026
5f29ac0
API adaptation continued
slayoo Jul 15, 2026
5dce6c9
Merge branch 'main' of https://github.com/open-atmos/PySDM into new_c…
tluettm Sep 4, 2026
a4018cd
Draft of reworked collision kernel classes
tluettm Sep 17, 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
13 changes: 7 additions & 6 deletions PySDM/dynamics/collisions/collision.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from PySDM.dynamics.collisions.breakup_efficiencies import ConstEb
from PySDM.dynamics.collisions.breakup_fragmentations import AlwaysN
from PySDM.dynamics.collisions.coalescence_efficiencies import ConstEc
from PySDM.dynamics.collisions import collision_kernels
from PySDM.dynamics.impl.random_generator_optimizer import RandomGeneratorOptimizer
from PySDM.dynamics.impl.random_generator_optimizer_nopair import (
RandomGeneratorOptimizerNoPair,
Expand All @@ -42,7 +43,6 @@ class Collision: # pylint: disable=too-many-instance-attributes
def __init__(
self,
*,
collision_kernel,
coalescence_efficiency,
breakup_efficiency,
fragmentation_function,
Expand All @@ -63,7 +63,6 @@ def __init__(
self.warn_overflows = warn_overflows
self.max_multiplicity = DEFAULTS.max_multiplicity

self.collision_kernel = collision_kernel
self.compute_coalescence_efficiency = coalescence_efficiency
self.compute_breakup_efficiency = breakup_efficiency
self.compute_number_of_fragments = fragmentation_function
Expand Down Expand Up @@ -98,6 +97,8 @@ def __init__(
self.breakup_rate = None
self.breakup_rate_deficit = None

self.collision_kernel = None

def register(self, builder):
self.particulator = builder.particulator
rnd_args = {
Expand Down Expand Up @@ -136,6 +137,10 @@ def register(self, builder):
self.stats_dt_min.fill(np.nan)

self.rnd_opt_coll.register(builder)
self.collision_kernel = getattr(
collision_kernels,
self.particulator.formulae.collision_kernel_liquid_liquid.__name__,
)()
self.collision_kernel.register(builder)

if self.croupier is None:
Expand Down Expand Up @@ -295,7 +300,6 @@ class Coalescence(Collision):
def __init__(
self,
*,
collision_kernel,
coalescence_efficiency=ConstEc(Ec=1),
croupier=None,
optimized_random=False,
Expand All @@ -306,7 +310,6 @@ def __init__(
breakup_efficiency = ConstEb(Eb=0)
fragmentation_function = AlwaysN(n=1)
super().__init__(
collision_kernel=collision_kernel,
coalescence_efficiency=coalescence_efficiency,
breakup_efficiency=breakup_efficiency,
fragmentation_function=fragmentation_function,
Expand All @@ -324,7 +327,6 @@ class Breakup(Collision):
def __init__(
self,
*,
collision_kernel,
fragmentation_function,
croupier=None,
optimized_random=False,
Expand All @@ -336,7 +338,6 @@ def __init__(
coalescence_efficiency = ConstEc(Ec=0.0)
breakup_efficiency = ConstEb(Eb=1.0)
super().__init__(
collision_kernel=collision_kernel,
coalescence_efficiency=coalescence_efficiency,
breakup_efficiency=breakup_efficiency,
fragmentation_function=fragmentation_function,
Expand Down
1 change: 1 addition & 0 deletions PySDM/dynamics/collisions/collision_kernels/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@
from .linear import Linear
from .simple_geometric import SimpleGeometric
from .long1974 import Long1974
from .neglect import Neglect
5 changes: 2 additions & 3 deletions PySDM/dynamics/collisions/collision_kernels/constantK.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@


class ConstantK:
def __init__(self, a):
self.a = a
def __init__(self):
self.particulator = None

def __call__(self, output, is_first_in_pair):
output.fill(self.a)
output.fill(self.particulator.formulae.constants.CONSTANTK_a)

def register(self, builder):
self.particulator = builder.particulator
10 changes: 4 additions & 6 deletions PySDM/dynamics/collisions/collision_kernels/geometric.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,13 @@


class Geometric(Gravitational):
def __init__(self, collection_efficiency=1.0, x="volume"):
super().__init__()
self.collection_efficiency = collection_efficiency
self.x = x

def __call__(self, output, is_first_in_pair):
output.sum(self.particulator.attributes["radius"], is_first_in_pair)
output **= 2
output *= const.PI * self.collection_efficiency
output *= (
const.PI
* self.particulator.formulae.constants.GEOMETRIC_collection_efficiency
)
self.pair_tmp.distance(
self.particulator.attributes["relative fall velocity"], is_first_in_pair
)
Expand Down
32 changes: 2 additions & 30 deletions PySDM/dynamics/collisions/collision_kernels/golovin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,15 @@
[Golovin 1963](http://mi.mathnet.ru/dan27630))
"""

import numpy as np
from scipy import special


class Golovin:
def __init__(self, b):
self.b = b
def __init__(self):
self.particulator = None

def __call__(self, output, is_first_in_pair):
output.sum(self.particulator.attributes["volume"], is_first_in_pair)
output *= self.b
output *= self.particulator.formulae.constants.GOLOVIN_b

def register(self, builder):
self.particulator = builder.particulator
builder.request_attribute("volume")

def analytic_solution(self, x, t, x_0, N_0):
tau = 1 - np.exp(-N_0 * self.b * x_0 * t)

if isinstance(x, np.ndarray):
func = np.vectorize(
lambda i: Golovin.analytic_solution_helper(x[int(i)], tau, x_0)
)
result = np.fromfunction(func, x.shape, dtype=float)
return result

return Golovin.analytic_solution_helper(x, tau, x_0)

@staticmethod
def analytic_solution_helper(x, tau, x_0):
sqrt_tau = np.sqrt(tau)
result = float(
(1 - tau)
* 1
/ (x * np.sqrt(tau))
* special.ive(1, 2 * x / x_0 * sqrt_tau) # pylint: disable=no-member
* np.exp(-(1 + tau - 2 * sqrt_tau) * x / x_0)
)
return result
8 changes: 3 additions & 5 deletions PySDM/dynamics/collisions/collision_kernels/linear.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@


class Linear:
def __init__(self, a, b):
self.a = a
self.b = b
def __init__(self):
self.particulator = None

def __call__(self, output, is_first_in_pair):
output.sum_pair(self.particulator.attributes["volume"], is_first_in_pair)
output *= self.b
output += self.a
output *= self.particulator.formulae.constants.LINEAR_b
output += self.particulator.formulae.constants.LINEAR_a

def register(self, builder):
self.particulator = builder.particulator
Expand Down
14 changes: 14 additions & 0 deletions PySDM/dynamics/collisions/collision_kernels/neglect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""
kernel for disabling collision
"""


class Neglect:
def __init__(self):
self.particulator = None

def __call__(self, output, is_first_in_pair):
output.fill(0)

def register(self, builder):
self.particulator = builder.particulator
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@


class SimpleGeometric:
def __init__(self, C):
def __init__(self):
self.particulator = None
self.pair_tmp = None
self.C = C

def register(self, builder):
self.particulator = builder.particulator
Expand All @@ -18,7 +17,7 @@ def register(self, builder):
)

def __call__(self, output, is_first_in_pair):
output[:] = self.C
output[:] = self.particulator.formulae.constants.SIMPLE_GEOMETRIC_c
self.pair_tmp.sum(self.particulator.attributes["radius"], is_first_in_pair)
self.pair_tmp **= 2
output *= self.pair_tmp
Expand Down
4 changes: 4 additions & 0 deletions PySDM/formulae.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ def __init__( # pylint: disable=too-many-locals,too-many-arguments
freezing_temperature_spectrum: str = "Null",
heterogeneous_ice_nucleation_rate: str = "Null",
homogeneous_ice_nucleation_rate: str = "Null",
collision_kernel: str = "Neglect+Neglect+Neglect",
fragmentation_function: str = "AlwaysN",
isotope_equilibrium_fractionation_factors: str = "Null",
isotope_kinetic_fractionation_factors: str = "Null",
Expand Down Expand Up @@ -96,6 +97,9 @@ def __init__( # pylint: disable=too-many-locals,too-many-arguments
self.freezing_temperature_spectrum = freezing_temperature_spectrum
self.heterogeneous_ice_nucleation_rate = heterogeneous_ice_nucleation_rate
self.homogeneous_ice_nucleation_rate = homogeneous_ice_nucleation_rate
self.collision_kernel_liquid_liquid = collision_kernel.split("+")[0]
self.collision_kernel_liquid_ice = collision_kernel.split("+")[1]
self.collision_kernel_ice_ice = collision_kernel.split("+")[2]
self.fragmentation_function = fragmentation_function
self.isotope_equilibrium_fractionation_factors = (
isotope_equilibrium_fractionation_factors
Expand Down
1 change: 1 addition & 0 deletions PySDM/physics/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,6 @@
terminal_velocity,
terminal_velocity_ice,
bulk_phase_partitioning,
collision_kernel,
)
from .constants import convert_to, in_unit, si
13 changes: 13 additions & 0 deletions PySDM/physics/collision_kernel/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""
Collision kernels physics
"""

from .neglect import Neglect
from .constantK import ConstantK
from .electric import Electric
from .geometric import Geometric
from .golovin import Golovin
from .hydrodynamic import Hydrodynamic
from .linear import Linear
from .simple_geometric import SimpleGeometric
from .long1974 import Long1974
8 changes: 8 additions & 0 deletions PySDM/physics/collision_kernel/constantK.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""
Formulae supporting `PySDM.dynamics.collisions.collision_kernels.ConstantK`
"""


class ConstantK:
def __init__(self, _):
pass
8 changes: 8 additions & 0 deletions PySDM/physics/collision_kernel/electric.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""
Formulae supporting `PySDM.dynamics.collisions.collision_kernels.Electric`
"""


class Electric:
def __init__(self, _):
pass
8 changes: 8 additions & 0 deletions PySDM/physics/collision_kernel/geometric.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""
Formulae supporting `PySDM.dynamics.collisions.collision_kernels.Geometric`
"""


class Geometric:
def __init__(self, _):
pass
36 changes: 36 additions & 0 deletions PySDM/physics/collision_kernel/golovin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""
Formulae supporting `PySDM.dynamics.collisions.collision_kernels.golovin`
"""

import numpy as np
from scipy import special


class Golovin:
def __init__(self, _):
pass


@staticmethod
def analytic_solution(b, x, t, x_0, N_0):

def analytic_solution_helper(x, tau, x_0):
sqrt_tau = np.sqrt(tau)
result = float(
(1 - tau)
* 1
/ (x * np.sqrt(tau))
* special.ive(1, 2 * x / x_0 * sqrt_tau) # pylint: disable=no-member
* np.exp(-(1 + tau - 2 * sqrt_tau) * x / x_0)
)
return result

tau = 1 - np.exp(-N_0 * b * x_0 * t)

if isinstance(x, np.ndarray):
func = np.vectorize(lambda i: analytic_solution_helper(x[int(i)], tau, x_0))
result = np.fromfunction(func, x.shape, dtype=float)
else:
result = analytic_solution_helper(x, tau, x_0)

return result
8 changes: 8 additions & 0 deletions PySDM/physics/collision_kernel/hydrodynamic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""
Formulae supporting `PySDM.dynamics.collisions.collision_kernels.Hydrodynamic`
"""


class Hydrodynamic:
def __init__(self, _):
pass
8 changes: 8 additions & 0 deletions PySDM/physics/collision_kernel/linear.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""
Formulae supporting `PySDM.dynamics.collisions.collision_kernels.Linear`
"""


class Linear:
def __init__(self, _):
pass
8 changes: 8 additions & 0 deletions PySDM/physics/collision_kernel/long1974.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""
Formulae supporting `PySDM.dynamics.collisions.collision_kernels.Long1974`
"""


class Long1974:
def __init__(self, _):
pass
12 changes: 12 additions & 0 deletions PySDM/physics/collision_kernel/neglect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"""
disable liquid liquid collisions
"""


class Neglect:
def __init__(self, _):
pass

@staticmethod
def collision_kernel(const, output, is_first_in_pair):
pass
8 changes: 8 additions & 0 deletions PySDM/physics/collision_kernel/simple_geometric.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""
Formulae supporting `PySDM.dynamics.collisions.collision_kernels.SimpleGeometric`
"""


class SimpleGeometric:
def __init__(self, _):
pass
16 changes: 16 additions & 0 deletions PySDM/physics/constants_defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,22 @@
J_HOM = np.nan
""" constant ice nucleation rates """

GOLOVIN_b = 5e3 * si.s
""" Golovin collision kernel constant """

CONSTANTK_a = np.nan
""" CONSTANTK collision kernel constant """

LINEAR_a = np.nan
LINEAR_b = np.nan
""" LINEAR collision kernel constants """

GEOMETRIC_collection_efficiency = 1
""" GEOMETRIC collision kernel constants """

SIMPLE_GEOMETRIC_c = 1
""" SIMPLE_GEOMETRIC collision kernel constants """

STRAUB_E_D1 = 0.04 * si.cm
""" [Straub et al. 2010](https://doi.org/10.1175/2009JAS3175.1) """
STRAUB_MU2 = 0.095 * si.cm
Expand Down
Loading
Loading