LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
_healpixPixelization.py
Go to the documentation of this file.
1 # This file is part of sphgeom.
2 #
3 # Developed for the LSST Data Management System.
4 # This product includes software developed by the LSST Project
5 # (http://www.lsst.org).
6 # See the COPYRIGHT file at the top-level directory of this distribution
7 # for details of code ownership.
8 #
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 __all__ = ["HealpixPixelization"]
22 
23 import numpy as np
24 import healpy as hp
25 
26 from ._sphgeom import RangeSet, Region, UnitVector3d
27 from ._sphgeom import Box, Circle, ConvexPolygon, Ellipse
28 from .pixelization_abc import PixelizationABC
29 
30 
32  """HEALPix pixelization class.
33 
34  Parameters
35  ----------
36  level : `int`
37  Pixelization level. HEALPix nside = 2**level
38  """
39  MAX_LEVEL = 17
40 
41  def __init__(self, level: int):
42 
43  if level < 0:
44  raise ValueError("HealPix level must be >= 0.")
45 
46  self._level_level = level
47  self._nside_nside = 2**level
48 
49  self._npix_npix = hp.nside2npix(self._nside_nside)
50 
51  # Values used to do pixel/region intersections
52  self._bit_shift_bit_shift = 8
53  self._nside_highres_nside_highres = self._nside_nside*(2**(self._bit_shift_bit_shift//2))
54 
55  @property
56  def nside(self):
57  return self._nside_nside
58 
59  def getLevel(self):
60  return self._level_level
61 
62  level = property(getLevel)
63 
64  def universe(self) -> RangeSet:
65  return RangeSet(0, self._npix_npix)
66 
67  def pixel(self, i) -> Region:
68  # This is arbitrarily returning 4 points on a side
69  # to approximate the pixel shape.
70  varr = hp.boundaries(self._nside_nside, i, step=4, nest=True).T
71  return ConvexPolygon([UnitVector3d(*c) for c in varr])
72 
73  def index(self, v: UnitVector3d) -> int:
74  return hp.vec2pix(self._nside_nside, v.x(), v.y(), v.z(), nest=True)
75 
76  def toString(self, i: int) -> str:
77  return str(i)
78 
79  def envelope(self, region: Region, maxRanges: int = 0):
80  if maxRanges > 0:
81  # If this is important, the rangeset can be consolidated.
82  raise NotImplementedError("HealpixPixelization: maxRanges not implemented")
83  pixels_highres = self._interior_pixels_from_region_interior_pixels_from_region(self._nside_highres_nside_highres, region)
84 
85  # Dilate the high resolution pixels by one to ensure that the full
86  # region is completely covered at high resolution.
87  neighbors = hp.get_all_neighbours(self._nside_highres_nside_highres,
88  pixels_highres,
89  nest=True)
90  # Shift back to the original resolution and uniquify
91  pixels = np.unique(np.right_shift(neighbors, self._bit_shift_bit_shift))
92 
93  return RangeSet(pixels)
94 
95  def interior(self, region: Region, maxRanges: int = 0):
96  if maxRanges > 0:
97  # If this is important, the rangeset can be consolidated.
98  raise NotImplementedError("HealpixPixelization: maxRanges not implemented")
99  pixels = self._interior_pixels_from_region_interior_pixels_from_region(self._nside_nside, region)
100 
101  # Check that the corners of the pixels are entirely enclosed in
102  # the region
103 
104  # Returns array [npixels, 3, ncorners], where ncorners is 4, and
105  # the center index points to x, y, z.
106  corners = hp.boundaries(self._nside_nside, pixels, step=1, nest=True)
107 
108  corners_int = region.contains(corners[:, 0, :].ravel(),
109  corners[:, 1, :].ravel(),
110  corners[:, 2, :].ravel()).reshape((len(pixels), 4))
111  interior = (np.sum(corners_int, axis=1) == 4)
112  pixels = pixels[interior]
113 
114  return RangeSet(pixels)
115 
116  def _interior_pixels_from_region(self, nside: int, region: Region):
117  """Get interior pixels from a region.
118 
119  Parameters
120  ----------
121  nside : `int`
122  Healpix nside to retrieve interior pixels.
123  region : `lsst.sphgeom.Region`
124  Sphgeom region to find interior pixels.
125 
126  Returns
127  -------
128  pixels : `np.ndarray`
129  Array of pixels at resolution nside, nest ordering.
130  """
131  _circle = None
132  _poly = None
133  if isinstance(region, (Box, Ellipse)):
134  _circle = region.getBoundingCircle()
135  elif isinstance(region, Circle):
136  _circle = region
137  elif isinstance(region, ConvexPolygon):
138  _poly = region
139  else:
140  raise ValueError("Invalid region.")
141 
142  # Find all pixels at an arbitrarily higher resolution
143  if _circle is not None:
144  center = _circle.getCenter()
145  vec = np.array([center.x(), center.y(), center.z()]).T
146  pixels = hp.query_disc(nside,
147  vec,
148  _circle.getOpeningAngle().asRadians(),
149  inclusive=False,
150  nest=True)
151  else:
152  vertices = np.array([[v.x(), v.y(), v.z()] for v in _poly.getVertices()])
153  pixels = hp.query_polygon(nside,
154  vertices,
155  inclusive=False,
156  nest=True)
157 
158  return pixels
159 
160  def __eq__(self, other):
161  if isinstance(other, HealpixPixelization):
162  return (self._level_level == other._level)
163 
164  def __repr__(self):
165  return f"HealpixPixelization({self._level})"
166 
167  def __reduce__(self):
168  return (self.__class__, (self._level_level, ))
def envelope(self, Region region, int maxRanges=0)
def interior(self, Region region, int maxRanges=0)
def _interior_pixels_from_region(self, int nside, Region region)