LSST Applications g0f08755f38+82efc23009,g12f32b3c4e+e7bdf1200e,g1653933729+a8ce1bb630,g1a0ca8cf93+50eff2b06f,g28da252d5a+52db39f6a5,g2bbee38e9b+37c5a29d61,g2bc492864f+37c5a29d61,g2cdde0e794+c05ff076ad,g3156d2b45e+41e33cbcdc,g347aa1857d+37c5a29d61,g35bb328faa+a8ce1bb630,g3a166c0a6a+37c5a29d61,g3e281a1b8c+fb992f5633,g414038480c+7f03dfc1b0,g41af890bb2+11b950c980,g5fbc88fb19+17cd334064,g6b1c1869cb+12dd639c9a,g781aacb6e4+a8ce1bb630,g80478fca09+72e9651da0,g82479be7b0+04c31367b4,g858d7b2824+82efc23009,g9125e01d80+a8ce1bb630,g9726552aa6+8047e3811d,ga5288a1d22+e532dc0a0b,gae0086650b+a8ce1bb630,gb58c049af0+d64f4d3760,gc28159a63d+37c5a29d61,gcf0d15dbbd+2acd6d4d48,gd7358e8bfb+778a810b6e,gda3e153d99+82efc23009,gda6a2b7d83+2acd6d4d48,gdaeeff99f8+1711a396fd,ge2409df99d+6b12de1076,ge79ae78c31+37c5a29d61,gf0baf85859+d0a5978c5a,gf3967379c6+4954f8c433,gfb92a5be7c+82efc23009,gfec2e1e490+2aaed99252,w.2024.46
LSST Data Management Base Package
Loading...
Searching...
No Matches
patchInfo.py
Go to the documentation of this file.
2# LSST Data Management System
3# Copyright 2008, 2009, 2010 LSST Corporation.
4#
5# This product includes software developed by the
6# LSST Project (http://www.lsst.org/).
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the LSST License Statement and
19# the GNU General Public License along with this program. If not,
20# see <http://www.lsstcorp.org/LegalNotices/>.
21#
22
23__all__ = ["PatchInfo"]
24
25import numbers
26from collections.abc import Iterable
27
28from lsst.geom import Extent2I, Point2I, Box2I
29from .detail import makeSkyPolygonFromBBox, Index2D
30from .cellInfo import CellInfo
31
32
34 """Information about a patch within a tract of a sky map.
35
36 If cellInnerDimensions and cellBorder are set then the patch
37 will be gridded with cells.
38
39 See `TractInfo` for more information.
40
41 Parameters
42 ----------
43 index : `lsst.skymap.Index2D`
44 x,y index of patch (a pair of ints)
45 innerBBox : `lsst.geom.Box2I`
46 inner bounding box
47 outerBBox : `lsst.geom.Box2I`
48 inner bounding box
49 sequentialIndex : `int`
50 Patch sequential index
51 tractWcs : `lsst.afw.geom.SkyWcs`
52 Tract WCS object.
53 cellInnerDimensions : `~collections.abc.Iterable` of 2 `int` or \
54 `lsst.geom.Extent2I`, optional
55 Inner dimensions of each cell (x,y pixels).
56 cellBorder : `int`, optional
57 Cell border size (pixels).
58 numCellsPerPatchInner : `int`, optional
59 Number of cells per inner patch region.
60 numCellsInPatchBorder : `int`, optional
61 Number of cells in the patch border.
62 """
63
64 def __init__(self, index, innerBBox, outerBBox, sequentialIndex,
65 tractWcs,
66 cellInnerDimensions=(0, 0), cellBorder=0,
67 numCellsPerPatchInner=0, numCellsInPatchBorder=0):
68 self._index = index
69 self._sequentialIndex = sequentialIndex
70 self._innerBBox = innerBBox
71 self._outerBBox = outerBBox
72 self._wcs = tractWcs
73 if not outerBBox.contains(innerBBox):
74 raise RuntimeError("outerBBox=%s does not contain innerBBox=%s" % (outerBBox, innerBBox))
75 if not isinstance(cellInnerDimensions, (Iterable, Extent2I)):
76 raise ValueError("Input cellInnerDimensions is not an iterable.")
77 if len(cellInnerDimensions) != 2:
78 raise ValueError("Input cellInnerDimensions does not have two values.")
79 self._cellInnerDimensions = Extent2I(*cellInnerDimensions)
80 self._cellBorder = cellBorder
81 self._numCellsInPatchBorder = numCellsInPatchBorder
82 if numCellsPerPatchInner == 0:
83 self._numCells = Index2D(x=0, y=0)
84 else:
85 # There are numCellsInPatchBorder extra boundary cell on each side
86 self._numCells = Index2D(x=numCellsPerPatchInner + 2*numCellsInPatchBorder,
87 y=numCellsPerPatchInner + 2*numCellsInPatchBorder)
88
89 def getIndex(self):
90 """Return patch index: a tuple of (x, y)
91
92 Returns
93 -------
94 result : `lsst.skymap.Index2D`
95 Patch index (x, y).
96 """
97 return self._index
98
99 index = property(getIndex)
100
102 """Return patch sequential index.
103
104 Returns
105 -------
106 result : `int`
107 Sequential patch index.
108 """
109 return self._sequentialIndex
110
111 sequential_index = property(getSequentialIndex)
112
113 def getWcs(self):
114 """Return the associated tract wcs
115
116 Returns
117 -------
118 wcs : `lsst.afw.geom.SkyWcs`
119 Tract WCS.
120 """
121 return self._wcs
122
123 wcs = property(getWcs)
124
125 def getInnerBBox(self):
126 """Get inner bounding box.
127
128 Returns
129 -------
130 bbox : `lsst.geom.Box2I`
131 The inner bounding Box.
132 """
133 return self._innerBBox
134
135 inner_bbox = property(getInnerBBox)
136
137 def getOuterBBox(self):
138 """Get outer bounding box.
139
140 Returns
141 -------
142 bbox : `lsst.geom.Box2I`
143 The outer bounding Box.
144 """
145 return self._outerBBox
146
147 outer_bbox = property(getOuterBBox)
148
149 def getInnerSkyPolygon(self, tractWcs=None):
150 """Get the inner on-sky region.
151
152 Parameters
153 ----------
154 tractWcs : `lsst.afw.image.SkyWcs`, optional
155 WCS for the associated tract.
156
157 Returns
158 -------
159 result : `lsst.sphgeom.ConvexPolygon`
160 The inner sky region.
161 """
162 _tractWcs = tractWcs if tractWcs is not None else self._wcs
163 return makeSkyPolygonFromBBox(bbox=self.getInnerBBox(), wcs=_tractWcs)
164
165 @property
167 return self.getInnerSkyPolygon()
168
169 def getOuterSkyPolygon(self, tractWcs=None):
170 """Get the outer on-sky region.
171
172 Parameters
173 ----------
174 tractWcs : `lsst.afw.image.SkyWcs`, optional
175 WCS for the associated tract.
176
177 Returns
178 -------
179 result : `lsst.sphgeom.ConvexPolygon`
180 The outer sky region.
181 """
182 _tractWcs = tractWcs if tractWcs is not None else self._wcs
183 return makeSkyPolygonFromBBox(bbox=self.getOuterBBox(), wcs=_tractWcs)
184
185 @property
187 return self.getOuterSkyPolygon()
188
189 def getNumCells(self):
190 """Get the number of cells in x, y.
191
192 May return (0, 0) if no cells are defined.
193
194 Returns
195 -------
196 result : `lsst.skymap.Index2D`
197 The number of cells in x, y.
198 """
199 return self._numCells
200
201 num_cells = property(getNumCells)
202
203 def getCellBorder(self):
204 return self._cellBorder
205
206 cell_border = property(getCellBorder)
207
208 def getCellInfo(self, index):
209 """Return information for the specified cell.
210
211 Parameters
212 ----------
213 index : `lsst.skymap.Index2D` or `~collections.abc.Iterable` of 2 `int`
214 Index of cell, as `Index2D` ,or two integers,
215 or a sequential index as returned by getSequentialCellIndex;
216 negative values are not supported.
217
218 Returns
219 -------
220 result : `lsst.skymap.CellInfo`
221 The cell info for that index.
222
223 Raises
224 ------
225 IndexError
226 Raised if index is out of range.
227 """
228 if self._numCells.x == 0 or self._numCells.y == 0:
229 raise IndexError("Patch does not contain cells.")
230 if isinstance(index, Index2D):
231 _index = index
232 else:
233 if isinstance(index, numbers.Number):
234 _index = self.getCellIndexPair(index)
235 else:
236 _index = Index2D(*index)
237 if (not 0 <= _index.x < self._numCells.x) \
238 or (not 0 <= _index.y < self._numCells.y):
239 raise IndexError("Cell index %s is not in range [0-%d, 0-%d]" %
240 (_index, self._numCells.x - 1, self._numCells.y - 1))
241 # We offset the index by numCellsInPatchBorder because the cells
242 # start outside the inner dimensions.
243 # The cells are defined relative to the patch bounding box (within the
244 # tract).
245 patchInnerBBox = self.getInnerBBox()
246 innerMin = Point2I(*[(_index[i] - self._numCellsInPatchBorder)*self._cellInnerDimensions[i]
247 + patchInnerBBox.getBegin()[i]
248 for i in range(2)])
249
250 innerBBox = Box2I(innerMin, self._cellInnerDimensions)
251 outerBBox = Box2I(innerBBox)
252 outerBBox.grow(self._cellBorder)
253
254 return CellInfo(
255 index=_index,
256 innerBBox=innerBBox,
257 outerBBox=outerBBox,
258 sequentialIndex=self.getSequentialCellIndexFromPair(_index),
259 tractWcs=self._wcs
260 )
261
263 """Get dimensions of inner region of the cells (all are the same)
264 """
265 return self._cellInnerDimensions
266
267 cell_inner_dimensions = property(getCellInnerDimensions)
268
269 def getSequentialCellIndex(self, cellInfo):
270 """Return a single integer that uniquely identifies
271 the given cell within this patch.
272
273 Parameters
274 ----------
275 cellInfo : `lsst.skymap.CellInfo`
276
277 Returns
278 -------
279 sequentialIndex : `int`
280
281 Raises
282 ------
283 IndexError
284 Raised if index is out of range.
285 """
286 index = cellInfo.getIndex()
287 return self.getSequentialCellIndexFromPair(index)
288
290 """Return a single integer that uniquely identifies
291 the given cell within this patch.
292
293 Parameters
294 ----------
295 index : `lsst.skymap.Index2D`
296
297 Returns
298 -------
299 sequentialIndex : `int`
300
301 Raises
302 ------
303 IndexError
304 Raised if index is out of range.
305 """
306 if isinstance(index, Index2D):
307 _index = index
308 else:
309 _index = Index2D(*index)
310 nx, ny = self.getNumCells()
311 return nx*_index.y + _index.x
312
313 def getCellIndexPair(self, sequentialIndex):
314 """Convert a sequential index into an index pair.
315
316 Parameters
317 ----------
318 sequentialIndex : `int`
319
320 Returns
321 -------
322 x, y : `lsst.skymap.Index2D`
323
324 Raises
325 ------
326 IndexError
327 Raised if index is out of range.
328 """
329 if self._numCells.x == 0 or self._numCells.y == 0:
330 raise IndexError("Patch does not contain cells.")
331
332 nx, ny = self.getNumCells()
333 x = sequentialIndex % nx
334 y = sequentialIndex // nx
335 return Index2D(x=x, y=y)
336
337 def __iter__(self):
338 xNum, yNum = self.getNumCells()
339 for y in range(yNum):
340 for x in range(xNum):
341 yield self.getCellInfo(Index2D(x=x, y=y))
342
343 def __len__(self):
344 xNum, yNum = self.getNumCells()
345 return xNum*yNum
346
347 def __getitem__(self, index):
348 return self.getCellInfo(index)
349
350 def __eq__(self, rhs):
351 return (self.getIndex() == rhs.getIndex()) \
352 and (self.getInnerBBox() == rhs.getInnerBBox()) \
353 and (self.getOuterBBox() == rhs.getOuterBBox()) \
354 and (self.getNumCells() == rhs.getNumCells()) \
355 and (self.getCellBorder() == rhs.getCellBorder())
356
357 def __ne__(self, rhs):
358 return not self.__eq__(rhs)
359
360 def __str__(self):
361 return "PatchInfo(index=%s)" % (self.getIndex(),)
362
363 def __repr__(self):
364 if self.getNumCells()[0] > 0:
365 return ("PatchInfo(index=%s, innerBBox=%s, outerBBox=%s, cellInnerDimensions=%s, "
366 "cellBorder=%s, numCellsPerPatchInner=%s)") % \
367 (self.getIndex(), self.getInnerBBox(), self.getOuterBBox(),
369 self.getNumCells()[0])
370 else:
371 return "PatchInfo(index=%s, innerBBox=%s, outerBBox=%s)" % \
372 (self.getIndex(), self.getInnerBBox(), self.getOuterBBox())
An integer coordinate rectangle.
Definition Box.h:55
getOuterSkyPolygon(self, tractWcs=None)
Definition patchInfo.py:169
getSequentialCellIndexFromPair(self, index)
Definition patchInfo.py:289
getSequentialCellIndex(self, cellInfo)
Definition patchInfo.py:269
__init__(self, index, innerBBox, outerBBox, sequentialIndex, tractWcs, cellInnerDimensions=(0, 0), cellBorder=0, numCellsPerPatchInner=0, numCellsInPatchBorder=0)
Definition patchInfo.py:67
getInnerSkyPolygon(self, tractWcs=None)
Definition patchInfo.py:149
getCellIndexPair(self, sequentialIndex)
Definition patchInfo.py:313