Source code for spotter.utils
"""
Utility functions for spherical harmonics, HEALPix, and conversions.
This module provides helper functions for working with spherical harmonics,
converting between representations, and mapping to HEALPix.
"""
from collections import defaultdict
import healpy as hp
import jax
import jax.numpy as jnp
import numpy as np
[docs]
def sigmoid(x, scale=1000):
"""
Numerically stable sigmoid function.
Parameters
----------
x : float or array_like
Input value(s).
scale : float, optional
Scaling factor (default 1000).
Returns
-------
y : float or array_like
Output value(s) in [0, 1].
"""
return (jnp.tanh(x * scale / 2) + 1) / 2
[docs]
def y1d_to_2d(ydeg: int, flm_1d: np.ndarray) -> np.ndarray:
"""
Convert 1D starry Ylm to 2D s2fft format.
Parameters
----------
ydeg : int
Maximum degree.
flm_1d : ndarray
1D array of coefficients.
Returns
-------
flm_2d : ndarray
2D array of coefficients.
"""
new_flm = jnp.zeros((ydeg + 1, 2 * ydeg + 1), dtype=flm_1d.dtype)
i = 0
for l in range(ydeg + 1):
for m in range(-l, l + 1):
new_flm = new_flm.at[l, m + ydeg].set(flm_1d[i])
i += 1
return new_flm
[docs]
def y2d_to_1d(ydeg: int, flm_2d: np.ndarray) -> np.ndarray:
"""
Convert 2D s2fft Ylm to 1D starry format.
Parameters
----------
ydeg : int
Maximum degree.
flm_2d : ndarray
2D array of coefficients.
Returns
-------
flm_1d : ndarray
1D array of coefficients.
"""
new_flm = jnp.zeros((ydeg + 1) ** 2, dtype=flm_2d.dtype)
i = 0
for l in range(ydeg + 1):
for m in range(-l, l + 1):
new_flm = new_flm.at[i].set(flm_2d[l, m + ydeg])
i += 1
return new_flm
[docs]
def C(l):
"""
Complex to real spherical harmonics conversion matrix.
Parameters
----------
l : int
Degree.
Returns
-------
C : ndarray
Conversion matrix.
"""
# See https://doi.org/10.1016/s0166-1280(97)00185-1 (Blanco 1997, Eq. 19)
A = np.eye(l, l)[:, ::-1]
B = np.zeros(l)[:, None]
C = np.diag((-1) ** np.arange(1, l + 1))
ABC = np.hstack([A, B, C])
jABC = np.hstack([1j * A, B, -1j * C])[::-1, :]
one = np.zeros(2 * l + 1)
one[l] = np.sqrt(2)
return np.vstack([jABC, one, ABC]) / np.sqrt(2)
[docs]
def ylm_to_hp(y, N):
"""
Convert a ylm array (starry-like) to healpy coefficients and map.
Parameters
----------
y : ndarray
Spherical harmonic coefficients.
N : int
HEALPix nside.
Returns
-------
mh : ndarray
HEALPix map.
"""
from jaxoplanet.starry.core import rotation
deg = int(np.floor(np.sqrt(len(y)))) - 1
ry = rotation.dot_rotation_matrix(deg, None, None, 1.0, -np.pi / 2)(y)
ry = rotation.dot_rotation_matrix(deg, 0.0, 1.0, None, -np.pi / 2)(ry)
y2d = y1d_to_2d(deg, ry)
c = C(deg)
cy = y2d_to_1d(deg, (c.T.conj() @ y2d.T).T)
_hy = defaultdict(lambda: 0 + 0j)
i = 0
for l in range(0, deg + 1):
for m in range(-l, l + 1):
j = hp.sphtfunc.Alm.getidx(deg, l, np.abs(m))
_hy[j] = cy[i]
i += 1
hn = hp.sphtfunc.Alm.getsize(deg)
hy = np.zeros(hn, dtype=np.complex128)
for i in range(hn):
hy[i] = _hy[i]
mh = hp.alm2map(hy, nside=N)
return mh