PySDM.products.size_spectral.effective_radius

effective radius of particles within a grid cell (ratio of third to second moments, optionally restricted to a given size range)

 1"""
 2effective radius of particles within a grid cell (ratio of third to second moments,
 3 optionally restricted to a given size range)
 4"""
 5
 6import numba
 7import numpy as np
 8
 9from PySDM.backends.impl_numba.conf import JIT_FLAGS
10from PySDM.physics import constants as const
11from PySDM.products.impl import MomentProduct, register_product
12
13GEOM_FACTOR = const.PI_4_3 ** (-1 / 3)
14
15
16@register_product()
17class EffectiveRadius(MomentProduct):
18    def __init__(self, *, radius_range=None, unit="m", name=None):
19        super().__init__(name=name, unit=unit)
20        self.volume_range = None
21        self.radius_range = radius_range or (0, np.inf)
22
23    def register(self, builder):
24        super().register(builder)
25        self.volume_range = self.formulae.trivia.volume(np.asarray(self.radius_range))
26
27    @staticmethod
28    @numba.njit(**JIT_FLAGS)
29    def nan_aware_reff_impl(input_volume_output_reff, volume_2_3):
30        """computes the effective radius (<r^3>/<r^2>) based on <v^(2/3)> and <v>"""
31        input_volume_output_reff[:] = np.where(
32            volume_2_3[:] > 0,
33            input_volume_output_reff[:]
34            * GEOM_FACTOR
35            / (
36                volume_2_3[:] + (volume_2_3[:] == 0)
37            ),  # (+ x==0) to avoid div-by-zero warnings
38            np.nan,
39        )
40
41    def _impl(self, **kwargs):
42        tmp = np.empty_like(self.buffer)
43        self._download_moment_to_buffer(
44            attr="volume",
45            rank=2 / 3,
46            filter_range=self.volume_range,
47            filter_attr="volume",
48        )
49        tmp[:] = self.buffer[:]
50        self._download_moment_to_buffer(
51            attr="volume",
52            rank=1,
53            filter_range=self.volume_range,
54            filter_attr="volume",
55        )
56        EffectiveRadius.nan_aware_reff_impl(
57            input_volume_output_reff=self.buffer, volume_2_3=tmp
58        )
59        return self.buffer
GEOM_FACTOR = 0.6203504908994001
@register_product()
class EffectiveRadius(PySDM.products.impl.moment_product.MomentProduct):
17@register_product()
18class EffectiveRadius(MomentProduct):
19    def __init__(self, *, radius_range=None, unit="m", name=None):
20        super().__init__(name=name, unit=unit)
21        self.volume_range = None
22        self.radius_range = radius_range or (0, np.inf)
23
24    def register(self, builder):
25        super().register(builder)
26        self.volume_range = self.formulae.trivia.volume(np.asarray(self.radius_range))
27
28    @staticmethod
29    @numba.njit(**JIT_FLAGS)
30    def nan_aware_reff_impl(input_volume_output_reff, volume_2_3):
31        """computes the effective radius (<r^3>/<r^2>) based on <v^(2/3)> and <v>"""
32        input_volume_output_reff[:] = np.where(
33            volume_2_3[:] > 0,
34            input_volume_output_reff[:]
35            * GEOM_FACTOR
36            / (
37                volume_2_3[:] + (volume_2_3[:] == 0)
38            ),  # (+ x==0) to avoid div-by-zero warnings
39            np.nan,
40        )
41
42    def _impl(self, **kwargs):
43        tmp = np.empty_like(self.buffer)
44        self._download_moment_to_buffer(
45            attr="volume",
46            rank=2 / 3,
47            filter_range=self.volume_range,
48            filter_attr="volume",
49        )
50        tmp[:] = self.buffer[:]
51        self._download_moment_to_buffer(
52            attr="volume",
53            rank=1,
54            filter_range=self.volume_range,
55            filter_attr="volume",
56        )
57        EffectiveRadius.nan_aware_reff_impl(
58            input_volume_output_reff=self.buffer, volume_2_3=tmp
59        )
60        return self.buffer

Helper class that provides a standard way to create an ABC using inheritance.

EffectiveRadius(*, radius_range=None, unit='m', name=None)
19    def __init__(self, *, radius_range=None, unit="m", name=None):
20        super().__init__(name=name, unit=unit)
21        self.volume_range = None
22        self.radius_range = radius_range or (0, np.inf)
volume_range
radius_range
def register(self, builder):
24    def register(self, builder):
25        super().register(builder)
26        self.volume_range = self.formulae.trivia.volume(np.asarray(self.radius_range))

Register a virtual subclass of an ABC.

Returns the subclass, to allow usage as a class decorator.

@staticmethod
@numba.njit(**JIT_FLAGS)
def nan_aware_reff_impl(input_volume_output_reff, volume_2_3):
28    @staticmethod
29    @numba.njit(**JIT_FLAGS)
30    def nan_aware_reff_impl(input_volume_output_reff, volume_2_3):
31        """computes the effective radius (<r^3>/<r^2>) based on <v^(2/3)> and <v>"""
32        input_volume_output_reff[:] = np.where(
33            volume_2_3[:] > 0,
34            input_volume_output_reff[:]
35            * GEOM_FACTOR
36            / (
37                volume_2_3[:] + (volume_2_3[:] == 0)
38            ),  # (+ x==0) to avoid div-by-zero warnings
39            np.nan,
40        )

computes the effective radius (/) based on

def instantiate(self, *, builder, buffer):
 8def _instantiate(self, *, builder, buffer):
 9    copy = deepcopy(self)
10    copy.set_buffer(buffer)
11    copy.register(builder)
12    return copy