Skip to content

torchsky.sphere.healpix

Stability: core. Names on this page follow the deprecation policy in contributing.

The torch-native HEALPix kernels: indexing, neighbors, interpolation, queries, reordering, and map sampling. These functions accept and return PyTorch tensors.

Guides: healpix


This page is generated from the module source. Import these names from torchsky.sphere.healpix.

Module

torchsky.sphere.healpix

UNSEEN module-attribute

UNSEEN = -1.6375e+30

__all__ module-attribute

__all__ = [
    "UNSEEN",
    "ang2pix",
    "ang2pix_nested",
    "ang2pix_ring",
    "ang2vec",
    "angular_distance_deg",
    "boundaries",
    "compact_bits",
    "degrade_pixels",
    "degrade_pixel_ranges",
    "get_all_neighbours",
    "get_interp_val",
    "get_interp_weights",
    "get_map_size",
    "get_nside",
    "isnpixok",
    "isnsideok",
    "lonlat_to_xyz",
    "mask_bad",
    "max_pixel_radius",
    "neighbors",
    "nest2ring",
    "nest_children",
    "nest_parent",
    "npix2nside",
    "nside2npix",
    "nside2order",
    "nside2pixarea",
    "nside2resol",
    "order2nside",
    "pixel_ranges_to_pixels",
    "pixel_resolution_to_nside",
    "pixels_to_pixel_ranges",
    "pix2ang",
    "pix2ang_nested",
    "pix2ang_ring",
    "pix2vec",
    "query_box",
    "query_circle",
    "query_circle_vec",
    "query_disc",
    "query_polygon",
    "query_polygon_vec",
    "query_strip",
    "reorder",
    "ring2nest",
    "spread_bits",
    "ud_grade",
    "upgrade_pixels",
    "upgrade_pixel_ranges",
    "vec2ang",
    "vec2pix",
    "xyz_to_lonlat",
]

_ud_grade_core_nested

_ud_grade_core_nested(
    m_nest: Tensor,
    nside_out: int,
    *,
    pess: bool = False,
    power: float | None = None,
    badval: float = UNSEEN,
) -> Tensor

ang2pix

ang2pix(
    nside: int,
    theta: Tensor | float,
    phi: Tensor | float,
    nest: bool = False,
    lonlat: bool = False,
) -> Tensor

Convert angles to pixel indices.

If lonlat is False, inputs are (theta, phi) in radians with theta=colatitude. If lonlat is True, inputs are (lon, lat) in degrees.

Parameters:

Name Type Description Default
nside int

HEALPix resolution parameter.

required
theta Tensor | float

Colatitude in radians, or longitude in degrees with lonlat=True.

required
phi Tensor | float

Longitude in radians, or latitude in degrees with lonlat=True.

required
nest bool

Use nested rather than ring ordering.

False
lonlat bool

Interpret inputs as longitude and latitude in degrees.

False

Returns:

Type Description
Tensor

Integer HEALPix indices with the broadcast input shape.

Examples:

>>> import torch
>>> from torchsky.sphere import ang2pix
>>> ang2pix(1, torch.tensor([0.0]), torch.tensor([0.0]), lonlat=True).shape
torch.Size([1])

ang2pix_nested

ang2pix_nested(
    nside: int, ra: Tensor, dec: Tensor
) -> Tensor

Convert RA/Dec (degrees) to HEALPix NESTED indices.

ang2pix_ring

ang2pix_ring(nside: int, ra: Tensor, dec: Tensor) -> Tensor

Convert RA/Dec (degrees) to HEALPix RING indices.

ang2vec

ang2vec(
    theta: Tensor | float,
    phi: Tensor | float,
    lonlat: bool = False,
) -> Tensor

Convert angles to unit vectors.

If lonlat=False, input is (theta, phi) in radians with theta=colatitude. If lonlat=True, input is (lon, lat) in degrees. Returns vectors with last dimension 3.

angular_distance_deg

angular_distance_deg(
    ra1: Tensor, dec1: Tensor, ra2: Tensor, dec2: Tensor
) -> Tensor

Great-circle angular distance between two lon/lat points in degrees.

boundaries

boundaries(
    nside: int,
    pix: Tensor,
    step: int = 1,
    nest: bool = False,
) -> Tensor

Return pixel boundary points as Cartesian vectors.

Output shape: - scalar pix: (3, 4step) - 1D pix: (Npix, 3, 4step)

compact_bits

compact_bits(x: Tensor) -> Tensor

Extract interleaved bits from Morton code.

degrade_pixel_ranges

degrade_pixel_ranges(
    nside: int,
    pixel_ranges: Tensor | Sequence[Sequence[int]],
    nside_degrade: int,
) -> Tensor

Degrade NESTED pixel ranges from nside to nside_degrade.

Half-open child ranges [start, stop) map to every parent pixel touched by at least one child. Output ranges are sorted, disjoint, and half-open.

degrade_pixels

degrade_pixels(
    nside: int,
    pixels: Tensor | Sequence[int],
    nside_degrade: int,
    *,
    nest: bool = False,
) -> Tensor

Degrade explicit HEALPix pixel ids to a coarser resolution.

Every parent pixel touched by at least one input child is returned. Duplicates are removed and output is sorted in the requested output ordering.

get_all_neighbours

get_all_neighbours(
    nside: int,
    theta: Tensor | float | int,
    phi: Tensor | float | None = None,
    nest: bool = False,
    lonlat: bool = False,
) -> Tensor

Healpy-compatible neighbors API.

If phi is None, theta is interpreted as pixel index. Otherwise, (theta, phi) are interpreted as angular coordinates.

get_interp_val

get_interp_val(
    m: Tensor | list[float],
    theta: Tensor | float,
    phi: Tensor | float,
    nest: bool = False,
    lonlat: bool = False,
) -> Tensor

Healpy-compatible bilinear interpolation of map values.

m can be shape (npix,) or (nmaps, npix).

get_interp_weights

get_interp_weights(
    nside: int,
    theta: Tensor | float | int,
    phi: Tensor | float | None = None,
    nest: bool = False,
    lonlat: bool = False,
) -> tuple[Tensor, Tensor]

Healpy-compatible bilinear interpolation neighbors and weights.

Returns (pixels, weights) with shape (4, ...).

get_map_size

get_map_size(
    m: Tensor | Sequence[float] | Sequence[Sequence[float]],
) -> int

Return map size (npix) for a map input.

get_nside

get_nside(
    m: Tensor | Sequence[float] | Sequence[Sequence[float]],
) -> int

Return NSIDE from a map (shape (npix,) or (nmaps, npix)).

isnpixok

isnpixok(npix: Tensor | int | list[int]) -> bool | Tensor

Check whether NPIX values are valid HEALPix sizes.

Returns bool for scalar input and bool tensor for array-like input.

isnsideok

isnsideok(
    nside: Tensor | int | list[int], nest: bool = False
) -> bool | Tensor

Check whether NSIDE values are valid.

Returns bool for scalar input and bool tensor for array-like input.

lonlat_to_xyz

lonlat_to_xyz(
    ra: Tensor, dec: Tensor
) -> Tuple[Tensor, Tensor, Tensor]

Convert spherical lon/lat in degrees to unit Cartesian coordinates.

mask_bad

mask_bad(
    m: Tensor | float,
    badval: float = UNSEEN,
    rtol: float = 1e-05,
    atol: float = 1e-08,
) -> Tensor

Boolean mask for bad (UNSEEN/non-finite) map values.

max_pixel_radius

max_pixel_radius(
    nside: int, degrees: bool = False
) -> float

Return a conservative maximum center-to-corner radius for pixels at nside.

Uses representative polar/equatorial/southern pixels and caches result.

neighbors

neighbors(
    nside: int, ipix: Tensor | int, nest: bool = False
) -> Tensor

Return 8 neighbors (SW, W, NW, N, NE, E, SE, S) for input pixels.

Output shape is ipix.shape + (8,) for array inputs and (8,) for scalars. Missing neighbors are set to -1.

nest2ring

nest2ring(nside: int, pix_nest: Tensor) -> Tensor

Convert NESTED pixel indices to RING.

nest_children

nest_children(pix_nest: Tensor, levels: int = 1) -> Tensor

Return all NESTED children after increasing resolution by levels.

nest_parent

nest_parent(pix_nest: Tensor, levels: int = 1) -> Tensor

Return NESTED parent index after reducing resolution by levels.

npix2nside

npix2nside(npix: int) -> int

Return NSIDE for a given number of pixels.

nside2npix

nside2npix(nside: int) -> int

Return number of pixels for a given NSIDE.

nside2order

nside2order(nside: int) -> int

Return HEALPix order for a given NSIDE (order = log2(nside)).

nside2pixarea

nside2pixarea(nside: int, degrees: bool = False) -> float

Return pixel area for a given NSIDE.

nside2resol

nside2resol(nside: int, arcmin: bool = False) -> float

Return approximate resolution (sqrt pixel area).

order2nside

order2nside(order: int) -> int

Return NSIDE for a given HEALPix order (nside = 2**order).

pix2ang

pix2ang(
    nside: int,
    ipix: Tensor,
    nest: bool = False,
    lonlat: bool = False,
) -> Tuple[Tensor, Tensor]

Convert pixel indices to angles.

If lonlat is False, returns (theta, phi) in radians with theta=colatitude. If lonlat is True, returns (lon, lat) in degrees.

Parameters:

Name Type Description Default
nside int

HEALPix resolution parameter.

required
ipix Tensor

Integer pixel indices.

required
nest bool

Use nested rather than ring ordering.

False
lonlat bool

Return longitude and latitude in degrees.

False

Returns:

Type Description
Tuple[Tensor, Tensor]

Two tensors containing angular coordinates.

Examples:

>>> import torch
>>> from torchsky.sphere import pix2ang
>>> lon, lat = pix2ang(1, torch.tensor([0]), lonlat=True)
>>> lon.shape == lat.shape
True

pix2ang_nested

pix2ang_nested(
    nside: int, pix: Tensor
) -> Tuple[Tensor, Tensor]

Convert HEALPix NESTED indices to RA/Dec (degrees).

pix2ang_ring

pix2ang_ring(
    nside: int, pix: Tensor
) -> Tuple[Tensor, Tensor]

Convert HEALPix RING indices to RA/Dec (degrees).

pix2vec

pix2vec(
    nside: int, ipix: Tensor, nest: bool = False
) -> Tuple[Tensor, Tensor, Tensor]

Convert pixel indices to Cartesian vectors.

pixel_ranges_to_pixels

pixel_ranges_to_pixels(
    pixel_ranges: Tensor | Sequence[Sequence[int]],
    *,
    inclusive: bool = False,
) -> Tensor

Expand pixel ranges into explicit pixels.

Range semantics match hpgeom.pixel_ranges_to_pixels: - inclusive=False: each row is [start, stop) (half-open) - inclusive=True: each row is [start, stop] (closed)

pixel_resolution_to_nside

pixel_resolution_to_nside(
    resolution: float,
    *,
    degrees: bool = False,
    arcmin: bool = False,
    round_to_power_of_two: bool = True,
) -> int

Approximate NSIDE from angular resolution.

pixels_to_pixel_ranges

pixels_to_pixel_ranges(
    pixels: Tensor | Sequence[int],
) -> Tensor

Compress explicit pixels into sorted disjoint half-open ranges [start, stop).

Unlike hpgeom, this helper is torchsky-native and canonicalizes by sorting + deduplicating input pixels before range construction.

query_box

query_box(
    nside: int,
    lon_min: float,
    lat_min: float,
    lon_max: float,
    lat_max: float,
    *,
    nest: bool = False,
    inclusive: bool = False,
    chunk_size: int = 1000000,
) -> Tensor

Return pixels whose centers lie in lon/lat box (degrees). Handles longitude wrap-around.

Uses a latitude (colatitude) ring preselect via query_strip, then applies the longitude filter only on that band — typically far cheaper than scanning all npix pixels when the declination range is narrow.

query_circle

query_circle(
    nside: int,
    lon: Tensor | float,
    lat: Tensor | float,
    radius: float,
    *,
    degrees: bool = True,
    inclusive: bool = False,
    fact: int = 4,
    nest: bool = False,
    chunk_size: int = 1000000,
) -> Tensor

Lon/lat convenience wrapper around query_disc.

query_circle_vec

query_circle_vec(
    nside: int,
    vec: Tensor | Sequence[float],
    radius: float,
    *,
    inclusive: bool = False,
    fact: int = 4,
    nest: bool = False,
    chunk_size: int = 1000000,
) -> Tensor

Cartesian-vector convenience wrapper around query_disc.

query_disc

query_disc(
    nside: int,
    vec: Tensor | Sequence[float],
    radius: float,
    *,
    inclusive: bool = False,
    fact: int = 4,
    nest: bool = False,
    chunk_size: int = 1000000,
) -> Tensor

Return pixels whose centers fall in a spherical disc.

vec is a 3-vector (x, y, z); radius is in radians. If inclusive=True and fact==4 (healpy default), pad the radius by the maximum pixel radius. If inclusive=True and fact!=4, supersample at nside * fact (pad at the fine nside), then degrade to parent pixels — healpy-shaped inclusive overlap. fact is ignored when inclusive=False.

Performance: when the C++ extension is available on CPU (or CUDA via a host copy of vec), queries use ring pruning (O(nside + output)). Without the extension, and on MPS, a torch quadtree descent selects the same pixel centres in O(boundary cells x depth + output), never O(npix). CUDA copies a length-3 vec to host; that copy is O(1) and far below 10% of nside≥512 wall, so the query stays on the CPU kernel.

Parameters:

Name Type Description Default
nside int

HEALPix resolution parameter.

required
vec Tensor | Sequence[float]

Cartesian unit vector at the disc center.

required
radius float

Angular radius in radians.

required
inclusive bool

Include pixels overlapping the disc boundary.

False
fact int

Oversampling factor for inclusive queries.

4
nest bool

Return nested rather than ring indices.

False
chunk_size int

Accepted for API compatibility; unused.

1000000

Returns:

Type Description
Tensor

One-dimensional integer tensor of matching pixels.

Examples:

>>> from torchsky.sphere import query_disc
>>> query_disc(1, [1.0, 0.0, 0.0], 0.1).ndim
1

query_polygon

query_polygon(
    nside: int,
    vertices: Tensor
    | Sequence[Sequence[float]]
    | Sequence[float],
    lat_deg: Tensor | Sequence[float] | None = None,
    *,
    inclusive: bool = False,
    nest: bool = False,
    lonlat: bool = False,
    chunk_size: int = 1000000,
) -> Tensor

Return pixels with centers inside a spherical polygon.

Convex polygons use the direct half-space query. Concave simple polygons are triangulated by :func:torchsky.sphere.geom.query_polygon_general.

Accepts either: - query_polygon(nside, lon_deg, lat_deg, ...) (1D degree sequences/tensors) - query_polygon(nside, vertices, lonlat=True, ...) with shape (N, 2) or (2, N) - query_polygon(nside, vertices, lonlat=False, ...) with Cartesian shape (N, 3) or (3, N)

Parameters:

Name Type Description Default
nside int

HEALPix resolution parameter.

required
vertices Tensor | Sequence[Sequence[float]] | Sequence[float]

Longitude samples or two-/three-dimensional polygon vertices.

required
lat_deg Tensor | Sequence[float] | None

Latitude samples for the separate longitude/latitude form.

None
inclusive bool

Include pixels overlapping the polygon boundary.

False
nest bool

Return nested rather than ring indices.

False
lonlat bool

Interpret paired vertices as degrees rather than Cartesian vectors.

False
chunk_size int

Pixel chunk size for the tensor fallback.

1000000

Returns:

Type Description
Tensor

One-dimensional integer tensor of matching pixels.

Examples:

>>> from torchsky.sphere import query_polygon
>>> callable(query_polygon)
True

query_polygon_vec

query_polygon_vec(
    nside: int,
    vertices: Tensor | Sequence[Sequence[float]],
    *,
    inclusive: bool = False,
    nest: bool = False,
    chunk_size: int = 1000000,
) -> Tensor

Cartesian-vector convenience wrapper around query_polygon.

query_strip

query_strip(
    nside: int,
    theta1: float,
    theta2: float,
    *,
    nest: bool = False,
    inclusive: bool = False,
) -> Tensor

Return pixels with center colatitude in [theta1, theta2] (radians).

Uses ring pruning (O(nside + output)), not a full O(npix) map scan.

reorder

reorder(
    m: Tensor, *, r2n: bool = False, n2r: bool = False
) -> Tensor

Reorder HEALPix maps between RING and NESTED layouts along the last axis.

ring2nest

ring2nest(nside: int, pix_ring: Tensor) -> Tensor

Convert RING pixel indices to NESTED.

spherical_fourier_features

spherical_fourier_features(
    ra: Tensor,
    dec: Tensor,
    num_frequencies: int = 6,
    min_frequency: float = 1.0,
    base: float = 2.0,
    include_xyz: bool = True,
    include_lonlat: bool = True,
) -> Tensor

Build multi-scale periodic features for spherical positional encoders.

Output shape is ra.shape + (D,), where: - xyz block contributes 3 channels if include_xyz=True - each frequency contributes 12 channels for xyz sin/cos (if enabled) - each frequency contributes 4 channels for lon/lat sin/cos (if enabled)

spread_bits

spread_bits(x: Tensor) -> Tensor

Interleave bits for Morton code (x -> x0x1x2...).

ud_grade

ud_grade(
    map_in: Tensor
    | Sequence[float]
    | Sequence[Sequence[float]],
    nside_out: int,
    pess: bool = False,
    badval: float = UNSEEN,
    order_in: str = "RING",
    order_out: str | None = None,
    power: float | None = None,
    dtype: object | None = None,
) -> Tensor

Upgrade or degrade resolution of HEALPix map(s), healpy-compatible shape semantics.

Supports map input shapes (npix,) and (nmaps, npix).

upgrade_pixel_ranges

upgrade_pixel_ranges(
    nside: int,
    pixel_ranges: Tensor | Sequence[Sequence[int]],
    nside_upgrade: int,
) -> Tensor

Upgrade NESTED pixel ranges from nside to nside_upgrade.

Semantics match hpgeom.upgrade_pixel_ranges, where half-open ranges [start, stop) scale by 4**levels.

upgrade_pixels

upgrade_pixels(
    nside: int,
    pixels: Tensor | Sequence[int],
    nside_upgrade: int,
    *,
    nest: bool = False,
) -> Tensor

Upgrade explicit HEALPix pixel ids to a finer resolution.

Each input pixel expands to all child pixels at nside_upgrade. Duplicates are removed and output is sorted in the requested output ordering.

vec2ang

vec2ang(
    vectors: Tensor | Sequence[Sequence[float]],
    lonlat: bool = False,
) -> Tuple[Tensor, Tensor]

Convert vectors to angles.

Accepts shape (..., 3) or (3, ...). If lonlat=False returns (theta, phi) in radians, otherwise returns (lon, lat) in degrees.

vec2pix

vec2pix(
    nside: int,
    x: Tensor,
    y: Tensor,
    z: Tensor,
    nest: bool = False,
) -> Tensor

Convert Cartesian vectors to pixel indices.

xyz_to_lonlat

xyz_to_lonlat(
    x: Tensor, y: Tensor, z: Tensor, eps: float = 1e-15
) -> Tuple[Tensor, Tensor]

Convert Cartesian coordinates to lon/lat in degrees.