LSST Applications g063fba187b+cac8b7c890,g0f08755f38+6aee506743,g1653933729+a8ce1bb630,g168dd56ebc+a8ce1bb630,g1a2382251a+b4475c5878,g1dcb35cd9c+8f9bc1652e,g20f6ffc8e0+6aee506743,g217e2c1bcf+73dee94bd0,g28da252d5a+1f19c529b9,g2bbee38e9b+3f2625acfc,g2bc492864f+3f2625acfc,g3156d2b45e+6e55a43351,g32e5bea42b+1bb94961c2,g347aa1857d+3f2625acfc,g35bb328faa+a8ce1bb630,g3a166c0a6a+3f2625acfc,g3e281a1b8c+c5dd892a6c,g3e8969e208+a8ce1bb630,g414038480c+5927e1bc1e,g41af890bb2+8a9e676b2a,g7af13505b9+809c143d88,g80478fca09+6ef8b1810f,g82479be7b0+f568feb641,g858d7b2824+6aee506743,g89c8672015+f4add4ffd5,g9125e01d80+a8ce1bb630,ga5288a1d22+2903d499ea,gb58c049af0+d64f4d3760,gc28159a63d+3f2625acfc,gcab2d0539d+b12535109e,gcf0d15dbbd+46a3f46ba9,gda6a2b7d83+46a3f46ba9,gdaeeff99f8+1711a396fd,ge79ae78c31+3f2625acfc,gef2f8181fd+0a71e47438,gf0baf85859+c1f95f4921,gfa517265be+6aee506743,gfa999e8aa5+17cd334064,w.2024.51
LSST Data Management Base Package
Loading...
Searching...
No Matches
coaddBase.py
Go to the documentation of this file.
1# This file is part of pipe_tasks.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://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 <https://www.gnu.org/licenses/>.
21
22__all__ = ["CoaddBaseTask", "makeSkyInfo"]
23
24import lsst.pex.config as pexConfig
25import lsst.afw.image as afwImage
26import lsst.pipe.base as pipeBase
27import lsst.geom as geom
28
29from lsst.afw.geom import Polygon
30from .selectImages import PsfWcsSelectImagesTask
31from .coaddInputRecorder import CoaddInputRecorderTask
32
33
34class CoaddBaseConfig(pexConfig.Config):
35 """Configuration parameters for CoaddBaseTask
36
37 Configuration parameters shared between MakeCoaddTempExp and AssembleCoadd
38 """
39
40 coaddName = pexConfig.Field(
41 doc="Coadd name: typically one of deep or goodSeeing.",
42 dtype=str,
43 default="deep",
44 )
45 select = pexConfig.ConfigurableField(
46 doc="Image selection subtask.",
47 target=PsfWcsSelectImagesTask,
48 )
49 badMaskPlanes = pexConfig.ListField(
50 dtype=str,
51 doc="Mask planes that, if set, the associated pixel should not be included in the coaddTempExp.",
52 default=("NO_DATA",),
53 )
54 inputRecorder = pexConfig.ConfigurableField(
55 doc="Subtask that helps fill CoaddInputs catalogs added to the final Exposure",
56 target=CoaddInputRecorderTask
57 )
58 includeCalibVar = pexConfig.Field(
59 dtype=bool,
60 doc="Add photometric calibration variance to warp variance plane.",
61 default=False
62 )
63 # TODO: Remove this field in DM-44792.
64 matchingKernelSize = pexConfig.Field(
65 dtype=int,
66 doc="Size in pixels of matching kernel. Must be odd.",
67 default=None,
68 optional=True,
69 check=lambda x: x % 2 == 1,
70 deprecated=("This field is deprecated without a replacement. Its value has no effect. "
71 "Will be removed after v29."
72 ),
73 )
74
75
76class CoaddBaseTask(pipeBase.PipelineTask):
77 """Base class for coaddition.
78
79 Subclasses must specify _DefaultName
80 """
81
82 ConfigClass = CoaddBaseConfig
83
84 def __init__(self, **kwargs):
85 super().__init__(**kwargs)
86 self.makeSubtask("select")
87 self.makeSubtask("inputRecorder")
88
89 def getTempExpDatasetName(self, warpType="direct"):
90 """Return warp name for given warpType and task config
91
92 Parameters
93 ----------
94 warpType : `str`
95 Either 'direct' or 'psfMatched'.
96
97 Returns
98 -------
99 WarpDatasetName : `str`
100 """
101 return self.config.coaddName + "Coadd_" + warpType + "Warp"
102
104 """Convenience method to provide the bitmask from the mask plane names
105 """
106 return afwImage.Mask.getPlaneBitMask(self.config.badMaskPlanes)
107
108
109def makeSkyInfo(skyMap, tractId, patchId):
110 """Constructs SkyInfo used by coaddition tasks for multiple
111 patchId formats.
112
113 Parameters
114 ----------
115 skyMap : `lsst.skyMap.SkyMap`
116 Sky map.
117 tractId : `int`
118 The ID of the tract.
119 patchId : `str` or `int` or `tuple` of `int`
120 Either Gen2-style comma delimited string (e.g. '4,5'),
121 tuple of integers (e.g (4, 5), Gen3-style integer.
122
123 Returns
124 -------
125 makeSkyInfo : `lsst.pipe.base.Struct`
126 pipe_base Struct with attributes:
127
128 ``skyMap``
129 Sky map (`lsst.skyMap.SkyMap`).
130 ``tractInfo``
131 Information for chosen tract of sky map (`lsst.skyMap.TractInfo`).
132 ``patchInfo``
133 Information about chosen patch of tract (`lsst.skyMap.PatchInfo`).
134 ``wcs``
135 WCS of tract (`lsst.afw.image.SkyWcs`).
136 ``bbox``
137 Outer bbox of patch, as an geom Box2I (`lsst.afw.geom.Box2I`).
138 """
139 tractInfo = skyMap[tractId]
140
141 if isinstance(patchId, str) and ',' in patchId:
142 # patch format is "xIndex,yIndex"
143 patchIndex = tuple(int(i) for i in patchId.split(","))
144 else:
145 patchIndex = patchId
146
147 patchInfo = tractInfo.getPatchInfo(patchIndex)
148
149 return pipeBase.Struct(
150 skyMap=skyMap,
151 tractInfo=tractInfo,
152 patchInfo=patchInfo,
153 wcs=tractInfo.getWcs(),
154 bbox=patchInfo.getOuterBBox(),
155 )
156
157
158def reorderAndPadList(inputList, inputKeys, outputKeys, padWith=None):
159 """Match the order of one list to another, padding if necessary
160
161 Parameters
162 ----------
163 inputList : `list`
164 List to be reordered and padded. Elements can be any type.
165 inputKeys : `iterable`
166 Iterable of values to be compared with outputKeys. Length must match `inputList`.
167 outputKeys : `iterable`
168 Iterable of values to be compared with inputKeys.
169 padWith : `Unknown`
170 Any value to be inserted where inputKey not in outputKeys.
171
172 Returns
173 -------
174 outputList : `list`
175 Copy of inputList reordered per outputKeys and padded with `padWith`
176 so that the length matches length of outputKeys.
177 """
178 outputList = []
179 for d in outputKeys:
180 if d in inputKeys:
181 outputList.append(inputList[inputKeys.index(d)])
182 else:
183 outputList.append(padWith)
184 return outputList
185
186
187def subBBoxIter(bbox, subregionSize):
188 """Iterate over subregions of a bbox.
189
190 Parameters
191 ----------
192 bbox : `lsst.geom.Box2I`
193 Bounding box over which to iterate.
194 subregionSize : `lsst.geom.Extent2I`
195 Size of sub-bboxes.
196
197 Yields
198 ------
199 subBBox : `lsst.geom.Box2I`
200 Next sub-bounding box of size ``subregionSize`` or smaller; each ``subBBox``
201 is contained within ``bbox``, so it may be smaller than ``subregionSize`` at
202 the edges of ``bbox``, but it will never be empty.
203
204 Raises
205 ------
206 RuntimeError
207 Raised if any of the following occur:
208 - The given bbox is empty.
209 - The subregionSize is 0.
210 """
211 if bbox.isEmpty():
212 raise RuntimeError("bbox %s is empty" % (bbox,))
213 if subregionSize[0] < 1 or subregionSize[1] < 1:
214 raise RuntimeError("subregionSize %s must be nonzero" % (subregionSize,))
215
216 for rowShift in range(0, bbox.getHeight(), subregionSize[1]):
217 for colShift in range(0, bbox.getWidth(), subregionSize[0]):
218 subBBox = geom.Box2I(bbox.getMin() + geom.Extent2I(colShift, rowShift), subregionSize)
219 subBBox.clip(bbox)
220 if subBBox.isEmpty():
221 raise RuntimeError("Bug: empty bbox! bbox=%s, subregionSize=%s, "
222 "colShift=%s, rowShift=%s" %
223 (bbox, subregionSize, colShift, rowShift))
224 yield subBBox
225
226
227# Note that this is implemented as a free-floating function to enable reuse in
228# lsst.pipe.tasks.makeWarp and in lsst.drp.tasks.make_psf_matched_warp
229# without creating any relationships between the two classes.
230# This may be converted to a method after makeWarp.py is removed altogether in
231# DM-47916.
232def growValidPolygons(coaddInputs, growBy: int) -> None:
233 """Grow coaddInputs' ccds' ValidPolygons in place.
234
235 Either modify each ccd's validPolygon in place, or if CoaddInputs
236 does not have a validPolygon, create one from its bbox.
237
238 Parameters
239 ----------
240 coaddInputs : `lsst.afw.image.coaddInputs`
241 CoaddInputs object containing the ccds to grow the valid polygons of.
242 growBy : `int`
243 The value to grow the valid polygons by.
244
245 Notes
246 -----
247 Negative values for ``growBy`` can shrink the polygons.
248 """
249 for ccd in coaddInputs.ccds:
250 polyOrig = ccd.getValidPolygon()
251 validPolyBBox = polyOrig.getBBox() if polyOrig else ccd.getBBox()
252 validPolyBBox.grow(growBy)
253 if polyOrig:
254 validPolygon = polyOrig.intersectionSingle(validPolyBBox)
255 else:
256 validPolygon = Polygon(geom.Box2D(validPolyBBox))
257
258 ccd.validPolygon = validPolygon
Cartesian polygons.
Definition Polygon.h:59
A floating-point coordinate rectangle geometry.
Definition Box.h:413
An integer coordinate rectangle.
Definition Box.h:55
getTempExpDatasetName(self, warpType="direct")
Definition coaddBase.py:89
reorderAndPadList(inputList, inputKeys, outputKeys, padWith=None)
Definition coaddBase.py:158
makeSkyInfo(skyMap, tractId, patchId)
Definition coaddBase.py:109
None growValidPolygons(coaddInputs, int growBy)
Definition coaddBase.py:232
subBBoxIter(bbox, subregionSize)
Definition coaddBase.py:187