4SPH Kernel related constants, coefficients, and functions.
6All constants and kernel coefficients are taken from table 1 of
7Dehnen & Aly, MNRAS, 425, pp. 1062-1082 (2012).
11from typing
import Union
24sph_vectorized_kernel_list = [
25 "quartic_spline_vectorized",
31 Modify the default dict to raise an error if a user tries to
32 access kernels which aren't defined. Undefined kernels are
33 specified via blocked_keys kwarg during initialization.
35 Also limit the available kernels to those specified in the
39 def __init__(self, *args, blocked_keys=(), ndim=0, **kwargs):
41 for key
in blocked_keys:
42 if key
not in sph_kernel_list
and key
not in sph_vectorized_kernel_list:
44 f
"Invalid kernel key {key}. Only {sph_kernel_list} are permitted"
50 if key
not in sph_kernel_list
and key
not in sph_vectorized_kernel_list:
52 f
"Invalid kernel key {key}. Only {sph_kernel_list} are permitted"
58 raise ValueError(f
"SPH kernel {key} is not defined for ndim={self.ndim}")
66sph_kernel_H_over_h = [
74sph_kernel_normalization = [
89sph_kernel_macro_name[
"cubic_spline"] =
"CUBIC_SPLINE_KERNEL"
90sph_kernel_macro_name[
"quartic_spline"] =
"QUARTIC_SPLINE_KERNEL"
91sph_kernel_macro_name[
"quintic_spline"] =
"QUINTIC_SPLINE_KERNEL"
92sph_kernel_macro_name[
"wendland_C2"] =
"WENDLAND_C2_KERNEL"
93sph_kernel_macro_name[
"wendland_C4"] =
"WENDLAND_C4_KERNEL"
94sph_kernel_macro_name[
"wendland_C6"] =
"WENDLAND_C6_KERNEL"
95sph_kernel_macro_name[
"quartic_spline_vectorized"] = sph_kernel_macro_name[
101sph_kernel_H_over_h[2][
"cubic_spline"] = 1.825742
102sph_kernel_H_over_h[2][
"quartic_spline"] = 2.018932
103sph_kernel_H_over_h[2][
"quintic_spline"] = 2.195775
104sph_kernel_H_over_h[2][
"wendland_C2"] = 1.936492
105sph_kernel_H_over_h[2][
"wendland_C4"] = 2.207940
106sph_kernel_H_over_h[2][
"wendland_C6"] = 2.449490
107sph_kernel_H_over_h[2][
"quartic_spline_vectorized"] = sph_kernel_H_over_h[2][
112sph_kernel_H_over_h[1][
"cubic_spline"] = 1.778002
113sph_kernel_H_over_h[1][
"quartic_spline"] = 1.977173
114sph_kernel_H_over_h[1][
"quintic_spline"] = 2.158131
115sph_kernel_H_over_h[1][
"wendland_C2"] = 1.897367
116sph_kernel_H_over_h[1][
"wendland_C4"] = 2.171239
117sph_kernel_H_over_h[1][
"wendland_C6"] = 2.415230
118sph_kernel_H_over_h[1][
"quartic_spline_vectorized"] = sph_kernel_H_over_h[1][
123sph_kernel_H_over_h[0][
"cubic_spline"] = 1.732051
124sph_kernel_H_over_h[0][
"quartic_spline"] = 1.936492
125sph_kernel_H_over_h[0][
"quintic_spline"] = 2.121321
126sph_kernel_H_over_h[0][
"wendland_C2"] = 1.620185
127sph_kernel_H_over_h[0][
"wendland_C4"] =
None
128sph_kernel_H_over_h[0][
"wendland_C6"] =
None
129sph_kernel_H_over_h[0][
"quartic_spline_vectorized"] = sph_kernel_H_over_h[0][
136sph_kernel_normalization[2][
"cubic_spline"] = 16.0 / np.pi
137sph_kernel_normalization[2][
"quartic_spline"] = 15625.0 / (np.pi * 512.0)
138sph_kernel_normalization[2][
"quintic_spline"] = 2187.0 / (np.pi * 40.0)
139sph_kernel_normalization[2][
"wendland_C2"] = 21.0 / (np.pi * 2.0)
140sph_kernel_normalization[2][
"wendland_C4"] = 495.0 / (np.pi * 32.0)
141sph_kernel_normalization[2][
"wendland_C6"] = 1365.0 / (np.pi * 64.0)
142sph_kernel_normalization[2][
"quartic_spline_vectorized"] = sph_kernel_normalization[2][
147sph_kernel_normalization[1][
"cubic_spline"] = 80.0 / (np.pi * 7.0)
148sph_kernel_normalization[1][
"quartic_spline"] = 46875.0 / (np.pi * 2398.0)
149sph_kernel_normalization[1][
"quintic_spline"] = 15309.0 / (np.pi * 478.0)
150sph_kernel_normalization[1][
"wendland_C2"] = 7.0 / np.pi
151sph_kernel_normalization[1][
"wendland_C4"] = 9.0 / np.pi
152sph_kernel_normalization[1][
"wendland_C6"] = 78.0 / (np.pi * 7.0)
153sph_kernel_normalization[1][
"quartic_spline_vectorized"] = sph_kernel_normalization[1][
158sph_kernel_normalization[0][
"cubic_spline"] = 8.0 / 3.0
159sph_kernel_normalization[0][
"quartic_spline"] = 3125.0 / 768.0
160sph_kernel_normalization[0][
"quintic_spline"] = 243.0 / 40.0
161sph_kernel_normalization[0][
"wendland_C2"] = 5.0 / 4.0
162sph_kernel_normalization[0][
"wendland_C4"] =
None
163sph_kernel_normalization[0][
"wendland_C6"] =
None
164sph_kernel_normalization[0][
"quartic_spline_vectorized"] = sph_kernel_normalization[0][
171 Evaluates the cubic spline kernel
174 res = 3.0 * q**2.0 * (q - 1.0) + 0.5
177 res = -(q**3.0) + 3.0 * q**2.0 - 3.0 * q + 1.0
185 Evaluates the quartic spline kernel
188 res = 6 * q**4 - 2.4 * q**2 + 46 / 125
190 res = -4 * q**4 + 8 * q**3 - 4.8 * q**2 + 8 / 25 * q + 44.0 / 125
192 res = q**4 - 4 * q**3 + 6 * q**2 - 4 * q + 1
200 Evaluates the quartic spline kernel
203 res = np.zeros(q.shape)
205 mask2 = np.logical_and(q > 0.2, q <= 0.6)
206 mask3 = np.logical_and(q > 0.6, q <= 1.0)
210 res[mask1] = 6.0 * qa2**2 - 2.4 * qa2 + 46.0 / 125.0
215 -4.0 * qb2**2 + 8.0 * qb2 * qb - 4.8 * qb2 + 8.0 / 25.0 * qb + 44.0 / 125.0
220 res[mask3] = qc2**2 - 4.0 * qc2 * qc + 6.0 * qc2 - 4.0 * qc + 1.0
227 Evaluates the quintic spline kernel
230 res = 10.0 * (q**4 * (1.0 - q) - 0.2222222222 * q**2) + 0.2716049382716049
231 elif q < 0.666666666666:
238 + qsq * (3.333333333333333 * q - 1.5555555555555)
239 + 0.18518518518518517 * q
241 + 0.20987654320987653
245 res = qsq * (qsq * (5 - q) + 10 * (1 - q)) - 5 * q + 1
253 Evaluates the quintic spline kernel
256 res = np.zeros(q.shape)
257 mask1 = q <= 1.0 / 3.0
258 mask2 = np.logical_and(q > 1.0 / 3.0, q <= 2.0 / 3)
259 mask3 = np.logical_and(q > 2.0 / 3, q <= 1.0)
263 10.0 * (qa**4 * (1.0 - qa) - 0.2222222222 * qa**2) + 0.2716049382716049
274 + qb2 * (3.333333333333333 * qb - 1.5555555555555)
275 + 0.18518518518518517 * qb
277 + 0.20987654320987653
282 res[mask3] = qc2 * (qc2 * (5.0 - qc) + 10.0 * (1.0 - qc)) - 5.0 * qc + 1.0
289 Evaluates the Wendland C2 kernel
293 res = qsq * (qsq * (4.0 * q - 15.0) + 10.0 * (2.0 * q - 1.0)) + 1.0
301 Evaluates the Wendland C4 kernel
308 11.666666666666666 * q4 * q4
309 - 64.0 * q4 * qsq * q
311 - 149.3333333333333 * q4 * q
313 - 9.33333333333333 * qsq
323 Evaluates the Wendland C6 kernel
344 Evaluates the cubic spline kernel derivative
347 res = 9 * q**2 - 6 * q
349 res = 6 * q - 3 * q**2 - 3
358 Evaluates the quartic spline kernel derivative
361 res = 24 * q**3 - 4.8 * q
363 res = -16 * q**3 + 24 * q**2 - 9.6 * q + 8 / 25
365 res = 4 * q**3 - 12 * q**2 + 12 * q - 4
373 Evaluates the quartic spline kernel derivative
376 res = np.zeros(q.shape)
378 mask2 = np.logical_and(q > 0.2, q <= 0.6)
379 mask3 = np.logical_and(q > 0.6, q <= 1.0)
383 res[mask1] = 24.0 * qa**3 - 4.8 * qa
387 res[mask2] = -16.0 * qb2 * qb + 24.0 * qb2 - 9.6 * qb + 8.0 / 25.0
391 res[mask3] = 4.0 * qc2 * qc - 12.0 * qc2 + 12.0 * qc - 4.0
398 Evaluates the quintic spline kernel derivative
400 if q < 0.333333333333:
401 res = 40 * q**3 - 50 * q**4 - 4.44444444444 * q
402 elif q < 0.666666666666:
407 - 15.555555555555 * q
411 res = 20 * q**3 - 5 * q**4 + 20 * q - 30 * q**2 - 5
419 Evaluates the Wendland C2 kernel derivative
422 res = 20.0 * q**4 - 60.0 * q**3 + 60.0 * q**2 - 20.0 * q
430 Evaluates the Wendland C4 kernel derivative
437 - 746.6666666666 * q**4
439 - 18.66666666666666 * q
448 Evaluates the Wendland C6 kernel derivative
466sph_kernel_eval_function[
"cubic_spline"] = _sph_kernel_eval_cubic_spline
467sph_kernel_eval_function[
"quartic_spline"] = _sph_kernel_eval_quartic_spline
468sph_kernel_eval_function[
"quintic_spline"] = _sph_kernel_eval_quintic_spline
469sph_kernel_eval_function[
"wendland_C2"] = _sph_kernel_eval_wendland_C2
470sph_kernel_eval_function[
"wendland_C4"] = _sph_kernel_eval_wendland_C4
471sph_kernel_eval_function[
"wendland_C6"] = _sph_kernel_eval_wendland_C6
472sph_kernel_eval_function[
473 "quartic_spline_vectorized"
474] = _sph_kernel_eval_quartic_spline_vectorized
476sph_kernel_deval_function[
"cubic_spline"] = _sph_kernel_deval_cubic_spline
477sph_kernel_deval_function[
"quartic_spline"] = _sph_kernel_deval_quartic_spline
478sph_kernel_deval_function[
"quintic_spline"] = _sph_kernel_deval_quintic_spline
479sph_kernel_deval_function[
"wendland_C2"] = _sph_kernel_deval_wendland_C2
480sph_kernel_deval_function[
"wendland_C4"] = _sph_kernel_deval_wendland_C4
481sph_kernel_deval_function[
"wendland_C6"] = _sph_kernel_deval_wendland_C6
482sph_kernel_deval_function[
483 "quartic_spline_vectorized"
484] = _sph_kernel_deval_quartic_spline_vectorized
488 r: Union[float, np.ndarray], h: Union[float, np.ndarray], kernel: str, ndim: int
491 Evaluates various kernels.
492 The kernels are scaled such that W(q > 1) = 0.
493 Currently implemented:
498 wendland_C4, [not with ndim=1]
499 wendland_C6, [not with ndim=1]
515 what dimension to use. [1-3]
526 sigma = sph_kernel_normalization[ndim - 1][kernel]
527 H = sph_kernel_get_H(h, kernel, ndim)
528 kernel_W = sph_kernel_eval_function[kernel]
530 W = sigma * kernel_W(q) / H**ndim
536 r: Union[float, np.ndarray], h: Union[float, np.ndarray], kernel: str, ndim: int
539 Evaluates kernel derivatives for various kernels:
540 returns dW/dr = dW/dq dq/dr = 1/H * dW/dq
542 The kernels are scaled such that W(q > 1) = 0.
543 Currently implemented:
548 wendland_C4, [not with ndim=1]
549 wendland_C6, [not with ndim=1]
565 what dimension to use. [1-3]
570 dWdr: float or ndarray
571 evaluated kernel derivative
575 sigma = sph_kernel_normalization[ndim - 1][kernel]
576 kernel_dWdr = sph_kernel_deval_function[kernel]
577 H = sph_kernel_get_H(h, kernel, ndim)
579 dWdr = sigma * kernel_dWdr(q) / H ** (ndim + 1)
585 h: Union[float, np.ndarray], kernel: str, ndim: int
588 Computes the interaction radius (compact support radius) for a given smoothing length h,
589 SPH kernel `kernel`, and kernel dimension `ndim`.
591 return sph_kernel_get_H(h, kernel, ndim)
594def sph_kernel_get_H(h: Union[float, np.ndarray], kernel: str, ndim: int):
596 Compute the compact support radius of a given kernel and given smoothing length.
597 The kernels defined above are defined and scaled to support a region <= H.
602 h: float or np.ndarray
609 how many dimensions we're working with
615 H: float or np.dnarray
616 compact support radii.
620 return h * sph_kernel_H_over_h[ndim - 1][kernel]
624 H: Union[float, np.ndarray], kernel: str, ndim: int
627 Compute the smoothing length given the compact support length of a given kernel.
628 The kernels defined above are defined and scaled to support a region <= H.
634 H: float or np.ndarray
635 compact support radii.
641 how many dimensions we're working with
647 h: float or np.dnarray
652 return H / sph_kernel_H_over_h[ndim - 1][kernel]
655def sph_kernel_root(kernel: str, ndim: int):
657 Evaluate kernel root, i.e. W(0, h).
658 We don't actually need `h` here, because the quantity used in the kernels,
659 `q = r/h` is also zero by construction.
668 what dimension to use. [1-3]
678 kernel_novector = kernel
679 if kernel.endswith(
"vectorized"):
680 kernel_novector = kernel[:-11]
682 return sph_kernel_W(0.0, 1.0, kernel_novector, ndim)