Source code for hipscat.pixel_tree.pixel_tree

from __future__ import annotations

from typing import List, Sequence

import numpy as np
from mocpy import MOC

from hipscat.pixel_math import HealpixInputTypes, HealpixPixel
from hipscat.pixel_math.healpix_pixel_convertor import get_healpix_tuple
from hipscat.pixel_math.healpix_pixel_function import get_pixels_from_intervals


[docs] class PixelTree: """Sparse Quadtree of HEALPix pixels that make up the HiPSCat catalog This class stores each node in the tree, with leaf nodes corresponding to pixels with data files. There are a number of methods in this class which allow for quickly navigating through the tree and performing operations to filter the pixels in the catalog. Attributes: pixels: Nested dictionary of pixel nodes stored in the tree. Indexed by HEALPix order then pixel number """ def __init__(self, tree: np.ndarray, order: int) -> None: """Initialises a tree object from the nodes in the tree Args: tree (np.ndarray): sorted array of intervals that represent each pixel in the tree order (int): HEALPix order of the pixel numbers in the intervals """ self.tree_order = order self.tree = tree if not np.all((self.tree.T[0, 1:] - self.tree.T[1, :-1]) >= 0): raise ValueError("Invalid Catalog: Tree contains overlapping pixels") self.pixels = get_pixels_from_intervals(self.tree, self.tree_order)
[docs] def __len__(self): """Gets the number of nodes in the tree Returns: The number of nodes in the tree """ return len(self.tree)
[docs] def contains(self, pixel: HealpixInputTypes) -> bool: """Check if tree contains a node at a given order and pixel Args: pixel: HEALPix pixel to check. Either of type `HealpixPixel` or a tuple of (order, pixel) Returns: True if the tree contains the pixel, False if not """ (order, pixel) = get_healpix_tuple(pixel) if order > self.tree_order: return False d_order = self.tree_order - order pixel_at_tree_order = pixel << 2 * d_order index = np.searchsorted(self.tree.T[1], pixel_at_tree_order, side="right") if index >= len(self.pixels): return False is_same_order = self.pixels[index][0] == order return pixel_at_tree_order == self.tree[index][0] and is_same_order
[docs] def __contains__(self, item): return self.contains(item)
[docs] def get_max_depth(self) -> int: """Get the max depth (or highest healpix order) represented in the list of pixels. Returns: max depth (or highest healpix order) of the pixels in the tree """ return np.max(self.pixels.T[0])
[docs] def get_healpix_pixels(self) -> List[HealpixPixel]: """Creates a list of HealpixPixels in the tree Returns (List[HealpixPixel]): A list of the HEALPix pixels in the tree """ return [HealpixPixel(p[0], p[1]) for p in self.pixels]
[docs] def to_moc(self) -> MOC: """Returns the MOC object that covers the same pixels as the tree""" return MOC.from_healpix_cells(self.pixels.T[1], self.pixels.T[0], self.tree_order)
@classmethod
[docs] def from_healpix(cls, healpix_pixels: Sequence[HealpixInputTypes], tree_order=None) -> PixelTree: """Build a tree from a list of constituent healpix pixels Args: healpix_pixels: list of healpix pixels tree_order (int): (Default = None) order to generate the tree at. If None, will use the highest order from input pixels Returns: The pixel tree with the leaf pixels specified in the list """ if len(healpix_pixels) == 0: return PixelTree(np.empty((0, 2), dtype=np.int64), 0) pixel_tuples = [get_healpix_tuple(p) for p in healpix_pixels] pixel_array = np.array(pixel_tuples).T orders = pixel_array[0] pixels = pixel_array[1] max_order = np.max(orders) if tree_order is None else tree_order starts = pixels * 4 ** (max_order - orders) ends = (pixels + 1) * 4 ** (max_order - orders) result = np.vstack((starts, ends)).T result.sort(axis=0) return cls(result, max_order)