LSST Applications g180d380827+0f66a164bb,g2079a07aa2+86d27d4dc4,g2305ad1205+7d304bc7a0,g29320951ab+500695df56,g2bbee38e9b+0e5473021a,g337abbeb29+0e5473021a,g33d1c0ed96+0e5473021a,g3a166c0a6a+0e5473021a,g3ddfee87b4+e42ea45bea,g48712c4677+36a86eeaa5,g487adcacf7+2dd8f347ac,g50ff169b8f+96c6868917,g52b1c1532d+585e252eca,g591dd9f2cf+c70619cc9d,g5a732f18d5+53520f316c,g5ea96fc03c+341ea1ce94,g64a986408d+f7cd9c7162,g858d7b2824+f7cd9c7162,g8a8a8dda67+585e252eca,g99cad8db69+469ab8c039,g9ddcbc5298+9a081db1e4,ga1e77700b3+15fc3df1f7,gb0e22166c9+60f28cb32d,gba4ed39666+c2a2e4ac27,gbb8dafda3b+c92fc63c7e,gbd866b1f37+f7cd9c7162,gc120e1dc64+02c66aa596,gc28159a63d+0e5473021a,gc3e9b769f7+b0068a2d9f,gcf0d15dbbd+e42ea45bea,gdaeeff99f8+f9a426f77a,ge6526c86ff+84383d05b3,ge79ae78c31+0e5473021a,gee10cc3b42+585e252eca,gff1a9f87cc+f7cd9c7162,w.2024.17
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