ultrasphere_harmonics package¶
- class ultrasphere_harmonics.Phase(*values)[source]¶
Bases:
FlagAdjust phase (±) of the spherical harmonics, mainly to match conventions.
- CONDON_SHORTLEY = 1¶
Whether to apply the Condon-Shortley phase.
It just multiplies the result by \((-1)^m\).
By using this phase, in quantum mechanics, spherical harmonics with ladder operator applied become spherical harmonics times always positive real numbers.
scipy.special.sph_harm_y uses the Condon-Shortley phase.
- NEGATIVE_LEGENDRE = 2¶
Whether to use \(P_l^m\) or \(P_{l}^{\left\|m\right\|}\) for negative m.
If False, \(Y^{-m}_{l} = \overline{Y^{m}_{l}}\). If True, \(Y^{-m}_{l} = (-1)^m \overline{Y^{m}_{l}}\).
scipy.special.sph_harm_y uses P_l^m.
- ultrasphere_harmonics.assume_n_end_and_include_negative_m_from_harmonics(c: SphericalCoordinates, expansion: Mapping[TSpherical, Array] | Array | tuple[int, ...], /, *, flatten: bool = True) tuple[int, bool][source]¶
Assume n_end and include_negative_m from the expansion coefficients.
- Parameters:
c (SphericalCoordinates[TSpherical, TCartesian]) – The spherical coordinates.
expansion (Mapping[TSpherical, Array] | Array | tuple[int, ...]) – The expansion coefficients. If mapping, assume that the expansion is not expanded.
flatten (bool, optional) – Whether the expansion is flattened.
- Returns:
n_end, include_negative_m
- Return type:
tuple[int, bool]
Example
>>> from array_api_compat import numpy as np >>> from ultrasphere import create_spherical >>> from ultrasphere_harmonics import harmonics >>> c = create_spherical() >>> harm = harmonics( ... c, ... {"theta": np.asarray(0.5), "phi": np.asarray(1.0)}, ... n_end=3, ... phase=0 ... ) >>> assume_n_end_and_include_negative_m_from_harmonics(c, harm) (3, True)
- ultrasphere_harmonics.concat_harmonics(c: SphericalCoordinates, harmonics: Mapping[TSpherical, Array]) Array[source]¶
Concatenate the mapping of expanded harmonics.
- Parameters:
c (SphericalCoordinates[TSpherical, TCartesian]) – The spherical coordinates.
harmonics (Mapping[TSpherical, Array]) – The expanded harmonics.
- Returns:
The concatenated harmonics.
- Return type:
Array
Example
>>> from array_api_compat import numpy as np >>> from ultrasphere import create_spherical >>> from ultrasphere_harmonics import harmonics >>> c = create_spherical() >>> harm = harmonics( ... c, ... {"theta": np.asarray(0.5), "phi": np.asarray(1.0)}, ... n_end=2, ... phase=0, ... concat=False, ... ) >>> {k: np.round(harm[k], 2) for k in c.s_nodes} {'theta': array([[0.71, 0. , 0. ], [1.07, 0.42, 0.42]]), 'phi': array([[0.4 +0.j , 0.22+0.34j, 0.22-0.34j]])}
>>> np.round(concat_harmonics(c, harm), 2) array([[0.28+0.j , 0. +0.j , 0. +0.j ], [0.43+0.j , 0.09+0.14j, 0.09-0.14j]])
- ultrasphere_harmonics.expand(c: SphericalCoordinates, f: Callable[[Mapping[TSpherical, Array]], Mapping[TSpherical, Array] | Array] | Mapping[TSpherical, Array] | Array, does_f_support_separation_of_variables: bool, n_end: int, n: int, *, phase: Phase, xp: ArrayNamespaceFull, device: Any | None = None, dtype: Any | None = None) Array | Mapping[TSpherical, Array][source]¶
Calculate the expansion coefficients of the function over the hypersphere.
- Parameters:
c (SphericalCoordinates[TSpherical, TCartesian]) – The spherical coordinates.
f (Callable[ [Mapping[TSpherical, Array]],) –
Mapping[TSpherical, Array] | Array, ] | Mapping[TSpherical, Array] | Array
The function to integrate or the values of the function. In case of vectorized function, the function should add extra axis to the last dimension, not the first dimension.
does_f_support_separation_of_variables (bool) – Whether the function supports separation of variables. This could significantly reduce the computational cost.
n (int) –
The number of integration points.
Must be equal to or larger than n_end.
Must be large enough AGAINST f, as this method does not use adaptive integration. For example, consider expanding
\[ f(θ) = e^{2Nθ} \]with \(n=N\).
>>> from ultrasphere import create_polar >>> from array_api_compat import numpy as np >>> n = 3 >>> expansion = expand( ... create_polar(), ... lambda x: np.exp(1j * (2 * n) * x["phi"]) / np.sqrt(2 * np.pi), ... does_f_support_separation_of_variables=False, ... n=n, ... n_end=n, ... phase=False, ... xp=np, ... ) >>> np.round(expansion, 2) array([ 1.-0.j, 0.+0.j, 0.+0.j, 0.+0.j, -0.+0.j])
This result claims that
\[ f(\phi) = 1 + \sum_{\|m\|\geq3} a_m e^{im\phi}, a_m \in \mathbb{C} \], which is incorrect.
n_end (int) – The maximum degree of the harmonic.
phase (Phase) – Adjust phase (±) of the spherical harmonics, mainly to match conventions. See Phase for details.
xp (ArrayNamespaceFull) – The array namespace.
device (Any, optional) – The device, by default None
dtype (Any, optional) – The data type, by default None
- Returns:
The expanded value of shape (…, ndim)
- Return type:
Array | Mapping[TSpherical, Array]
Example
>>> from array_api_compat import numpy as np >>> from ultrasphere import create_spherical >>> c = create_spherical() >>> coef = expand( ... c, ... lambda spherical: np.sin(spherical["theta"]) * np.sin(spherical["phi"]), ... n_end=2, ... n=3, ... does_f_support_separation_of_variables=False, ... phase=0, ... xp=np, ... ) >>> np.round(coef, 2) + 0.0 array([0.+0.j , 0.+0.j , 0.-1.45j, 0.+1.45j])
>>> coef_fast = expand( ... c, ... lambda spherical: { ... "theta": np.sin(spherical["theta"]), ... "phi": np.sin(spherical["phi"]) ... }, ... n_end=2, ... n=3, ... does_f_support_separation_of_variables=True, ... phase=0, ... xp=np, ... ) >>> {k: np.round(coef_fast[k], 2) for k in c.s_nodes} {'theta': array([[1.13, 0. ], [0. , 1.15], [0. , 1.15]]), 'phi': array([0.+0.j , 0.-1.25j, 0.+1.25j])}
>>> from ultrasphere import create_polar >>> expansion = expand( ... create_polar(), ... lambda x: np.exp(1j * (n - 1) * x["phi"]) / np.sqrt(2 * np.pi), ... does_f_support_separation_of_variables=False, ... n=n, ... n_end=n, ... phase=False, ... xp=np, ... ) >>> np.round(expansion, 2) + 0.0 array([0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j])
>>> expansion = expand( ... create_polar(), ... lambda x: np.exp(1j * n * x["phi"]) / np.sqrt(2 * np.pi), ... does_f_support_separation_of_variables=False, ... n=n, ... n_end=n, ... phase=False, ... xp=np, ... ) >>> np.round(expansion, 2) + 0.0 array([0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j])
- ultrasphere_harmonics.expand_cut(c: SphericalCoordinates, expansion: Mapping[TSpherical, Array] | Array, n_end: int) Mapping[TSpherical, Array] | Array[source]¶
Cut the expansion coefficients to the maximum degree.
- Parameters:
c (SphericalCoordinates[TSpherical, TCartesian]) – The spherical coordinates.
expansion (Mapping[TSpherical, Array] | Array) – The expansion coefficients. If mapping, assume that the expansion is not expanded.
n_end (int) – The maximum degree to cut.
- Returns:
The cut expansion coefficients.
- Return type:
Mapping[TSpherical, Array] | Array
Example
>>> from array_api_compat import numpy as np >>> from ultrasphere import create_spherical >>> from ultrasphere_harmonics import harmonics >>> c = create_spherical() >>> harm = harmonics( ... c, ... {"theta": np.asarray(0.5), "phi": np.asarray(1.0)}, ... n_end=3, ... phase=0 ... ) >>> harm.shape (9,)
>>> harm_cut = expand_cut(c, harm, n_end=2) >>> harm_cut.shape (4,)
- ultrasphere_harmonics.expand_dims_harmonics(c: SphericalCoordinates, harmonics: Mapping[TSpherical, Array]) Mapping[TSpherical, Array][source]¶
Expand dimensions of the harmonics.
Expand dimensions so that all values of the harmonics() result dictionary are commomly indexed by the same s_nodes, by default False
For example, if spherical coordinates, - if True, the result will be indexed {“phi”: [m], “theta”: [m, n]} - if False, the result will be indexed {“phi”: [m, n], “theta”: [m, n]}
Note that the values will not be repeated therefore the computational cost will be the same
- Parameters:
c (SphericalCoordinates[TSpherical, TCartesian]) – The spherical coordinates.
harmonics (Mapping[TSpherical, Array]) – The dictionary of harmonics (eigenfunctions).
- Returns:
The expanded harmonics. The shapes does not need to be either same or broadcastable.
- Return type:
Mapping[TSpherical, Array]
Example
>>> from array_api_compat import numpy as np >>> from ultrasphere import create_spherical >>> from ultrasphere_harmonics import harmonics >>> c = create_spherical() >>> harm = harmonics( ... c, ... {"theta": np.asarray(0.5), "phi": np.asarray(1.0)}, ... n_end=2, ... phase=0, ... concat=False, ... expand_dims=False, ... ) >>> {k: harm[k].shape for k in c.s_nodes} # not broadcastable {'theta': (3, 2), 'phi': (3,)}
>>> harm = expand_dims_harmonics(c, harm) >>> {k: harm[k].shape for k in c.s_nodes} # broadcastable {'theta': (2, 3), 'phi': (1, 3)}
- ultrasphere_harmonics.expand_evaluate(c: SphericalCoordinates, expansion: Mapping[TSpherical, Array] | Array, spherical: Mapping[TSpherical, Array], *, phase: Phase) Array | Mapping[TSpherical, Array][source]¶
Evaluate the expansion at the spherical coordinates.
Make sure to compare with values on the SPHERE, not in the ball.
- Parameters:
c (SphericalCoordinates[TSpherical, TCartesian]) – The spherical coordinates.
expansion (Mapping[TSpherical, Array] | Array) – The expansion coefficients of shape (*shape_e, ndim). If not mapping, assume that the expansion is flatten. If mapping, assume that the expansion is not expanded.
spherical (Mapping[TSpherical, Array]) – The spherical coordinates of shape (*shape_s, c.s_ndim).
phase (Phase) – Adjust phase (±) of the spherical harmonics, mainly to match conventions. See Phase for details.
- Returns:
- Return type:
Array | Mapping[TSpherical, Array]
- ultrasphere_harmonics.flatten_harmonics(c: SphericalCoordinates, harmonics: Array, n_end: int | None = None, include_negative_m: bool | None = None, axis_end: int = -1) Array[source]¶
Flatten the harmonics.
- Parameters:
c (SphericalCoordinates[TSpherical, TCartesian]) – The spherical coordinates.
harmonics (Array) – The (unflattend) harmonics.
n_end (int | None, optional) – The maximum degree of the harmonic, by default None If None, assume from the shape of harmonics.
include_negative_m (bool | None, optional) – Whether to include negative m values, by default None If None, assume from the shape of harmonics.
axis_end (int, optional) – The axis to flatten, by default -1 Must be negative.
- Returns:
The flattened harmonics of shape (…, n_harmonics).
- Return type:
Array
Example
>>> from array_api_compat import numpy as np >>> from ultrasphere import create_spherical >>> from ultrasphere_harmonics import harmonics >>> c = create_spherical() >>> harm = harmonics( ... c, ... {"theta": np.asarray(0.5), "phi": np.asarray(1.0)}, ... n_end=2, ... phase=0, ... flatten=False, ... ) >>> np.round(harm, 2) array([[0.28+0.j , 0. +0.j , 0. +0.j ], [0.43+0.j , 0.09+0.14j, 0.09-0.14j]])
>>> harm_flat = flatten_harmonics(c, harm) >>> np.round(harm_flat, 2) array([0.28+0.j , 0.43+0.j , 0.09+0.14j, 0.09-0.14j])
- ultrasphere_harmonics.harm_n_ndim_eq(n: int | Array, *, c_ndim: int) int | Array[source]¶
The dimension of the spherical harmonics of degree equals to n.
\[\begin{split} N(n, d) = \dim(\mathcal{H}_n (\mathbb{R}^{d})) = \begin{cases} \begin{cases} 1 & (n = 0) \\ 0 & (n \geq 1) \\ \end{cases} & (d = 1) \\ \begin{cases} 1 & (n = 0) \\ 2 & (n \geq 1) \\ \end{cases} & (d = 2) \\ \frac{2 n + d - 2}{d - 2} \binom{n + d - 3}{d - 3} & (d \geq 3) \\ \end{cases} \end{split}\]- Parameters:
n (int | Array) – The degree.
c_ndim (int) – The dimension of the Cartesian space.
- Returns:
The dimension.
- Return type:
int | Array
References
McLean, W. (2000). Strongly Elliptic Systems and Boundary Integral Equations. p.251 (8.13)
Example
>>> harm_n_ndim_eq(3, c_ndim=3) array(7)
- ultrasphere_harmonics.harm_n_ndim_le(n_end: int | Array, *, c_ndim: int) int | Array[source]¶
The dimension of the spherical harmonics of degree below n_end.
\[\begin{split} \dim(\mathcal{H}_{< n} (\mathbb{R}^{d})) = \sum_{k=0}^{n-1} \dim(\mathcal{H}_k (\mathbb{R}^{d})) = \begin{cases} 0 & (n < 1) \\ N(0, d) & (n = 1) \\ N(n - 1, d + 1) &(\text{otherwise}) \\ \end{cases} \end{split}\]- Parameters:
n_end (int | Array) – The degree.
c_ndim (int) – The dimension of the Cartesian space.
- Returns:
The dimension.
- Return type:
int | Array
References
McLean, W. (2000). Strongly Elliptic Systems and Boundary Integral Equations. p.251 (8.12)
Example
>>> harm_n_ndim_le(3, c_ndim=3) array(9)
- ultrasphere_harmonics.harmonics(c: SphericalCoordinates[TSpherical, TCartesian], spherical: Mapping[TSpherical, Array], /, *, n_end: int, phase: Phase, include_negative_m: bool = True, index_with_surrogate_quantum_number: bool = False, expand_dims: bool = True, flatten: bool | None = None, concat: bool = True) Mapping[TSpherical, Array] | Array[source]¶
Calculate the spherical harmonics.
- Parameters:
c (SphericalCoordinates[TSpherical, TCartesian]) – The spherical coordinates.
spherical (Mapping[TSpherical, Array]) – The spherical coordinates.
n_end (int) – The maximum degree of the harmonic.
phase (Phase) – Adjust phase (±) of the spherical harmonics, mainly to match conventions. See Phase for details.
include_negative_m (bool, optional) – Whether to include negative m values, by default True If True, the m values are [0, 1, …, n_end-1, -n_end+1, …, -1], and starts from 0, not -n_end+1.
index_with_surrogate_quantum_number (bool, optional) – Whether to index with surrogate quantum number, by default False
expand_dims (bool, optional) –
Whether to expand dimensions so that all values of the result dictionary are commomly indexed by the same s_nodes, by default False
For example, if spherical coordinates, - if True, the result will be indexed {“phi”: [m], “theta”: [m, n]} - if False, the result will be indexed {“phi”: [m, n], “theta”: [m, n]}
Note that the values will not be repeated therefore the computational cost will be the same
flatten (bool, optional) – Whether to flatten the result, by default None If None, True iff concat is True.
concat (bool, optional) – Whether to concatenate the results, by default True
- Returns:
The spherical harmonics.
- Return type:
Array
Example
Basic usage¶
>>> from array_api_compat import numpy as np >>> from ultrasphere import create_spherical >>> c = create_spherical() >>> harm = harmonics( # flattened output ... c, ... {"theta": np.asarray(0.5), "phi": np.asarray(1.0)}, ... n_end=2, ... phase=0 ... ) >>> np.round(harm, 2) array([0.28+0.j , 0.43+0.j , 0.09+0.14j, 0.09-0.14j])
Unflattened output¶
>>> harm = harmonics( ... c, ... {"theta": np.asarray(0.5), "phi": np.asarray(1.0)}, ... n_end=2, ... phase=0, ... flatten=False, ... ) >>> np.round(harm, 2) array([[0.28+0.j , 0. +0.j , 0. +0.j ], [0.43+0.j , 0.09+0.14j, 0.09-0.14j]])
Unflattened mapping output¶
>>> harm = harmonics( ... c, ... {"theta": np.asarray(0.5), "phi": np.asarray(1.0)}, ... n_end=2, ... phase=0, ... concat=False ... ) >>> {k: np.round(harm[k], 2) for k in c.s_nodes} {'theta': array([[0.71, 0. , 0. ], [1.07, 0.42, 0.42]]), 'phi': array([[0.4 +0.j , 0.22+0.34j, 0.22-0.34j]])}
Using different phase convention to match scipy.special.sph_harm¶
Call harmonics with phase=3 (negative legendre + Condon-Shortley phase)
>>> harm = harmonics( ... c, ... {"theta": np.asarray(0.5), "phi": np.asarray(1.0)}, ... n_end=2, ... phase=3 # negative legendre + Condon-Shortley phase ... ) >>> np.round(harm, 2) array([ 0.28+0.j , 0.43+0.j , -0.09-0.14j, 0.09-0.14j])
Call scipy.special.sph_harm_y_all
>>> from scipy.special import sph_harm_y_all >>> harm_scipy = sph_harm_y_all(1, 1, np.asarray(0.5), np.asarray(1.0)) >>> np.round(harm_scipy, 2) array([[ 0.28+0.j , 0. +0.j , 0. +0.j ], [ 0.43+0.j , -0.09-0.14j, 0.09-0.14j]])
Flatten the scipy output to compare with harmonics
>>> from ultrasphere_harmonics import flatten_harmonics >>> harm_scipy_flatten = flatten_harmonics(c, harm_scipy) >>> np.round(harm_scipy_flatten, 2) array([ 0.28+0.j , 0.43+0.j , -0.09-0.14j, 0.09-0.14j])
Check if they are close
>>> import array_api_extra as xpx >>> np.all(xpx.isclose(harm, harm_scipy_flatten)) np.True_
- ultrasphere_harmonics.harmonics_regular_singular(c: SphericalCoordinates, spherical: Mapping[TSpherical | Literal['r'], Array] | Mapping[Literal['r'], Array], /, *, n_end: int, k: Array, phase: Phase, type: Literal['regular', 'singular', 'j', 'y', 'h1', 'h2'], derivative: bool = False, expand_dims: bool = True, flatten: bool | None = None, concat: bool = True) Array | Mapping[TSpherical, Array][source]¶
Regular or singular harmonics.
\[\begin{split} R_n (x) &:= j_n \left(\|x\|\right) Y_n^m \left(\frac{x}{\|x\|}\right) \\ S_n (x) &:= h_n^{(1)} \left(\|x\|\right) Y_n^m \left(\frac{x}{\|x\|}\right) \end{split}\]- Parameters:
c (SphericalCoordinates[TSpherical, TCartesian]) – The spherical coordinates.
spherical (Mapping[TSpherical | Literal['r'],) – Array] | Mapping[Literal[‘r’], Array] The spherical coordinates.
n_end (int) – The maximum degree of the harmonic.
k (Array) – The wavenumber. Must be positive.
phase (Phase) – Adjust phase (±) of the spherical harmonics, mainly to match conventions. See Phase for details.
type (Literal['regular', 'singular', 'j', 'y', 'h1', 'h2']) – The type of the spherical Bessel/Hankel function.
derivative (bool, optional) – Whether to return the directional derivative to r, in other words whether to return the derivative with respect to r, by default False
expand_dims (bool, optional) –
Whether to expand dimensions so that all values of the result dictionary are commomly indexed by the same s_nodes, by default False
For example, if spherical coordinates, if True, the result will be indexed {“phi”: [m], “theta”: [m, n]} if False, the result will be indexed {“phi”: [m, n], “theta”: [m, n]}
Note that the values will not be repeated therefore the computational cost will be the same
flatten (bool, optional) – Whether to flatten the result, by default None If None, True iff concat is True.
concat (bool, optional) – Whether to concatenate the results, by default True
- Returns:
The regular or singular harmonics.
- Return type:
Array | Mapping[TSpherical, Array]
- Raises:
ValueError – If the wavenumber is not positive.
Example
>>> from array_api_compat import numpy as np >>> from ultrasphere import create_spherical >>> c = create_spherical() >>> R = harmonics_regular_singular( ... c, ... {"r": np.asarray(1.0), "theta": np.asarray(0.5), "phi": np.asarray(1.0)}, ... n_end=2, ... phase=0, ... k=np.asarray(1.0), ... type="regular", ... ) >>> np.round(R, 2) array([0.24+0.j , 0.13+0.j , 0.03+0.04j, 0.03-0.04j])
- ultrasphere_harmonics.harmonics_regular_singular_component(c: SphericalCoordinates, spherical: Mapping[TSpherical | Literal['r'], Array] | Mapping[Literal['r'], Array], /, *, n_end: int, k: Array, type: Literal['regular', 'singular', 'j', 'y', 'h1', 'h2'], derivative: bool = False, expand_dims: bool = True, flatten: bool | None = None, concat: bool = True) Array | Mapping[TSpherical, Array][source]¶
Regular or singular COMPONENT of harmonics (does not include \(Y_n\)).
\[\begin{split} R_n (x) &:= j_n \left(\|x\|\right) Y_n^m \left(\frac{x}{\|x\|}\right) \\ S_n (x) &:= h_n^{(1)} \left(\|x\|\right) Y_n^m \left(\frac{x}{\|x\|}\right) \end{split}\]- Parameters:
c (SphericalCoordinates[TSpherical, TCartesian]) – The spherical coordinates.
spherical (Mapping[TSpherical | Literal['r'],) – Array] | Mapping[Literal[‘r’], Array] The spherical coordinates.
k (Array) – The wavenumber. Must be positive.
n_end (int) – The maximum degree of the harmonic.
type (Literal['regular', 'singular', 'j', 'y', 'h1', 'h2']) – The type of the spherical Bessel/Hankel function.
derivative (bool, optional) – Whether to return the directional derivative to r, in other words whether to return the derivative with respect to r, by default False
expand_dims (bool, optional) –
Whether to expand dimensions so that all values of the result dictionary are commomly indexed by the same s_nodes, by default False
For example, if spherical coordinates, if True, the result will be indexed {“phi”: [m], “theta”: [m, n]} if False, the result will be indexed {“phi”: [m, n], “theta”: [m, n]}
Note that the values will not be repeated therefore the computational cost will be the same
flatten (bool, optional) – Whether to flatten the result, by default None If None, True iff concat is True.
concat (bool, optional) – Whether to concatenate the results, by default True
- Returns:
The regular or singular harmonics.
- Return type:
Array | Mapping[TSpherical, Array]
- Raises:
ValueError – If the wavenumber is not positive.
Example
>>> from array_api_compat import numpy as np >>> from ultrasphere import create_spherical >>> c = create_spherical() >>> Y = harmonics( ... c, ... {"theta": np.asarray(0.5), "phi": np.asarray(1.0)}, ... n_end=2, ... phase=0, ... ) >>> j = harmonics_regular_singular_component( ... c, ... {"r": np.asarray(1.0)}, ... n_end=2, ... k=np.asarray(1.0), ... type="regular", ... ) >>> R = j * Y >>> np.round(R, 2) array([0.24+0.j , 0.13+0.j , 0.03+0.04j, 0.03-0.04j])
- ultrasphere_harmonics.harmonics_translation_coef(c: SphericalCoordinates, spherical: Mapping[TSpherical | Literal['r'], Array], *, n_end: int, n_end_add: int, phase: Phase, k: Array, is_type_same: bool, method: Literal['gumerov', 'plane_wave', 'triplet'] | None = None) Array[source]¶
Translation coefficients between same or different type of elementary solutions.
If is_type_same is True, returns \((R|R) = (S|S)\). If is_type_same is False, returns \((S|R)\).
\[\begin{split}R(x + t) = \sum_n (R|R)_n(t) R(x) \\ S(x + t) = \sum_n (S|S)_n(t) S(x) \\ S(x + t) = \sum_n (S|R)_n(t) R(x)\end{split}\]- Parameters:
c (SphericalCoordinates[TSpherical, TCartesian]) – The spherical coordinates.
spherical (Mapping[TSpherical, Array]) – The translation vector in spherical coordinates.
n_end (int) – The maximum degree of the harmonic.
n_end_add (int) – The maximum degree of the harmonic to be summed over.
phase (Phase) – Adjust phase (±) of the spherical harmonics, mainly to match conventions. See Phase for details.
k (Array) – The wavenumber.
is_type_same (bool) – Whether the type of the elementary solutions is same.
method (Literal["gumerov", "plane_wave", "triplet"] | None) – The method to compute the translation coefficients. If None, the fastest method is chosen automatically. “gumerov” is only available for branching type “ba”. “plane_wave” is only available when is_type_same is True.
- Returns:
The translation coefficients of shape (…, ndim, ndim). The last axis are to be summed over with the elementary solutions to get translated elementary solution which quantum number corresponds to the second last axis indices.
- Return type:
Array
Example
>>> from array_api_compat import numpy as np >>> from ultrasphere import create_spherical >>> c = create_spherical() >>> t = np.asarray([2, -7, 1]) >>> coef = harmonics_translation_coef( ... c, ... c.from_cartesian(t), ... n_end=2, ... n_end_add=2, ... phase=0, ... k=np.asarray(1.0), ... is_type_same=True, ... ) >>> np.round(coef, 2) array([[ 0.12+0.j , 0.01+0.j , 0.02+0.06j, 0.02-0.06j], [-0.01+0.j , -0.01+0.j , 0.01+0.04j, 0.01-0.04j], [-0.02+0.06j, 0.01-0.04j, 0.18+0.j , -0.17-0.11j], [-0.02-0.06j, 0.01+0.04j, -0.17+0.11j, 0.18+0.j ]])
>>> x = np.asarray([-1.0, 1.0, 0.0]) >>> y = x + t >>> coef = harmonics_translation_coef( ... c, ... c.from_cartesian(t), ... n_end=2, ... n_end_add=6, ... phase=0, ... k=np.asarray(1.0), ... is_type_same=True, ... ) >>> R_x = harmonics_regular_singular( ... c, ... c.from_cartesian(x), ... n_end=6, ... phase=0, ... k=np.asarray(1.0), ... type="regular", ... concat=True, ... ) >>> R_y_approx = np.sum(coef * R_x[..., None, :], axis=-1) >>> R_y = harmonics_regular_singular( ... c, ... c.from_cartesian(y), ... n_end=2, ... phase=0, ... k=np.asarray(1.0), ... type="regular", ... concat=True, ... ) >>> np.round(R_y_approx, 8) array([-0.00541026-0.j , -0.01301699-0.j , -0.00919779+0.05521981j, -0.00919779-0.05521981j]) >>> np.round(R_y, 8) array([-0.00542242+0.j , -0.01301453+0.j , -0.00920266+0.05521598j, -0.00920266-0.05521598j])
- ultrasphere_harmonics.harmonics_twins_expansion(c: SphericalCoordinates, *, n_end_1: int, n_end_2: int, phase: Phase, xp: ArrayNamespaceFull, dtype: Any | None = None, device: Any | None = None, conj_1: bool = False, conj_2: bool = False) Array[source]¶
Expansion coefficients of the twins of the harmonics.
- Parameters:
c (SphericalCoordinates[TSpherical, TCartesian]) – The spherical coordinates.
n_end_1 (int) – The maximum degree of the harmonic for the first harmonics.
n_end_2 (int) – The maximum degree of the harmonic for the second harmonics.
phase (Phase) – Adjust phase (±) of the spherical harmonics, mainly to match conventions. See Phase for details.
xp (ArrayNamespaceFull) – The array namespace.
dtype (Any | None) – The dtype, by default None
device (Any | None) – The device, by default None
conj_1 (bool) – Whether to conjugate the first harmonics. by default False
conj_2 (bool) – Whether to conjugate the second harmonics. by default False
- Returns:
The expansion coefficients of the twins of shape [*1st quantum number, *2nd quantum number, *3rd quantum number] and dim 3 * c.s_ndim and of dtype float, not complex. The n_end for 1st quantum number is n_end_1, The n_end for 2nd quantum number is n_end_2, The n_end for 3rd quantum number is n_end_1 + n_end_2 - 1. (not n_end_1 or n_end_2)
- Return type:
Array
Notes
To get ∫Y_{n1}(x)Y_{n2}(x)Y_{n3}(x)dx (integral involving three harmonics), one may use harmonics_twins_expansion(conj_1=True, conj_2=True)
- ultrasphere_harmonics.homogeneous_ndim_eq(n: int | Array, *, c_ndim: int) int | Array[source]¶
The dimension of the homogeneous polynomials of degree equals to n.
\[ M(n, d) = \dim(\mathcal{P}_n (\mathbb{R}^{d})) = \binom{n + d - 1}{d - 1} \]- Parameters:
n (int | Array) – The degree.
c_ndim (int) – The dimension of the Cartesian space.
- Returns:
The dimension.
- Return type:
int | Array
References
McLean, W. (2000). Strongly Elliptic Systems and Boundary Integral Equations. p.250 (8.7)
Example
>>> homogeneous_ndim_eq(3, c_ndim=3) array(10)
- ultrasphere_harmonics.homogeneous_ndim_le(n_end: int | Array, *, c_ndim: int) int | Array[source]¶
The dimension of the homogeneous polynomials of degree below n_end.
\[\begin{split} \dim(\mathcal{P}_{< n} (\mathbb{R}^{d})) = \sum_{k=0}^{n-1} \dim(\mathcal{P}_k (\mathbb{R}^{d})) = \begin{cases} 0 & (n < 1) \\ M(n, 0) & (n = 1) \\ M(n - 1, d + 1) &(\text{otherwise}) \\ \end{cases} \end{split}\]where
\[ M(n, d) = \dim(\mathcal{P}_n (\mathbb{R}^{d})) = \binom{n + d - 1}{d - 1} \]- Parameters:
n_end (int | Array) – The degree.
c_ndim (int) – The dimension of the Cartesian space.
- Returns:
The dimension.
- Return type:
int | Array
References
McLean, W. (2000). Strongly Elliptic Systems and Boundary Integral Equations. p.250 (8.9)
Example
>>> homogeneous_ndim_le(3, c_ndim=3) array(10)
- ultrasphere_harmonics.index_array_harmonics(c: SphericalCoordinates, node: TSpherical, /, *, n_end: int, xp: ArrayNamespaceFull, expand_dims: bool = True, include_negative_m: bool = True, flatten: bool = False, dtype: Any = None, device: Any = None) Array[source]¶
The index of the eigenfunction corresponding to the node.
- Parameters:
c (SphericalCoordinates[TSpherical, TCartesian]) – The spherical coordinates.
node (TSpherical) – The node of the spherical coordinates.
n_end (int) – The maximum degree of the harmonic.
expand_dims (bool, optional) – Whether to expand dimensions, by default True
include_negative_m (bool, optional) – Whether to include negative m values, by default True If None, True iff concat is True.
flatten (bool, optional) – Whether to flatten the result, by default False
xp (ArrayNamespaceFull) – The array namespace.
dtype (Any, optional) – The dtype, by default None
device (Any, optional) – The device, by default None
- Returns:
The index.
- Return type:
Array
Example
>>> from array_api_compat import numpy as np >>> from ultrasphere import create_spherical >>> c = create_spherical()
>>> index_array_harmonics( ... c, ... "theta", ... n_end=3, ... xp=np, ... ) array([[0], [1], [2]])
>>> index_array_harmonics( ... c, ... "phi", ... n_end=3, ... xp=np, ... ) array([[ 0, 1, 2, -2, -1]])
- ultrasphere_harmonics.index_array_harmonics_all(c: SphericalCoordinates, *, n_end: int, xp: ArrayNamespaceFull, include_negative_m: bool = True, expand_dims: bool = True, as_array: bool, mask: bool = False, flatten: bool | None = None, dtype: Any = None, device: Any = None) Array | Mapping[TSpherical, Array][source]¶
The all indices of the eigenfunction corresponding to the spherical coordinates.
- Parameters:
c (SphericalCoordinates[TSpherical, TCartesian]) – The spherical coordinates.
n_end (int) – The maximum degree of the harmonic.
include_negative_m (bool, optional) – Whether to include negative m values, by default True
expand_dims (bool, optional) – Whether to expand dimensions, by default True Must be True if as_array is True.
as_array (bool, optional) – Whether to return as an array, by default False
mask (bool, optional) – Whether to fill invalid quantum numbers with NaN, by default False Must be False if as_array is False.
flatten (bool, optional) – Whether to flatten the result, by default None If None, True iff as_array is True.
xp (ArrayNamespaceFull) – The array namespace.
dtype (Any, optional) – The dtype, by default None
device (Any, optional) – The device, by default None
- Returns:
If as_array is True, the indices of shape [c.s_ndim, len(index_array_harmonics(c, node1)), …, len(index_array_harmonics(c, node(c.s_ndim)))]. If as_array is False, the dictionary of indices.
- Return type:
Array | Mapping[TSpherical, Array]
Notes
To check the indices where all quantum numbers match, (numbers1 == numbers2).all(axis=0) can be used.
- Raises:
ValueError – If expand_dims is False and as_array is True. If mask is True and as_array is False.
Example
>>> from array_api_compat import numpy as np >>> from ultrasphere import create_spherical >>> c = create_spherical()
>>> index_array_harmonics_all( ... c, ... n_end=3, ... xp=np, ... as_array=True, ... ) array([[ 0, 1, 1, 1, 2, 2, 2, 2, 2], [ 0, 0, 1, -1, 0, 1, 2, -2, -1]])
>>> index_array_harmonics_all( ... c, ... n_end=3, ... xp=np, ... as_array=False, ... ) {'theta': array([[0], [1], [2]]), 'phi': array([[ 0, 1, 2, -2, -1]])}