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
calexpCutout.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__ = ['CalexpCutoutTaskConfig', 'CalexpCutoutTask']
23
24import lsst.pipe.base as pipeBase
25import lsst.geom as geom
26from lsst.pex.config import Field
27from lsst.meas.algorithms import Stamp, Stamps
28
29DETECTOR_DIMENSIONS = ('instrument', 'visit', 'detector')
30
31
32class CalexpCutoutTaskConnections(pipeBase.PipelineTaskConnections,
33 dimensions=DETECTOR_DIMENSIONS,
34 defaultTemplates={}):
35 """Connections class for CalexpCutoutTask
36 """
37 in_table = pipeBase.connectionTypes.Input(
38 doc="Locations for cutouts",
39 name="cutout_positions",
40 storageClass="AstropyQTable",
41 dimensions=DETECTOR_DIMENSIONS,
42 )
43 calexp = pipeBase.connectionTypes.Input(
44 doc="Calexp objects",
45 name="calexp",
46 storageClass="ExposureF",
47 dimensions=DETECTOR_DIMENSIONS,
48 )
49 cutouts = pipeBase.connectionTypes.Output(
50 doc="Cutouts",
51 name="calexp_cutouts",
52 storageClass="Stamps",
53 dimensions=DETECTOR_DIMENSIONS,
54 )
55
56
57class CalexpCutoutTaskConfig(pipeBase.PipelineTaskConfig,
58 pipelineConnections=CalexpCutoutTaskConnections):
59 """Configuration for CalexpCutoutTask
60 """
61 max_cutouts = Field(dtype=int, default=100, doc='Maximum number of entries to process. '
62 'The result will be the first N in the input table.')
63 skip_bad = Field(dtype=bool, default=True, doc='Skip cutouts that do not fall completely within'
64 ' the calexp bounding box? If set to False a ValueError'
65 ' is raised instead.')
66
67
68class CalexpCutoutTask(pipeBase.PipelineTask):
69 """Task for computing cutouts on a specific calexp given
70 positions, xspans, and yspans of the stamps.
71 """
72 ConfigClass = CalexpCutoutTaskConfig
73 _DefaultName = "calexpCutoutTask"
74
75 def run(self, in_table, calexp):
76 """Compute and return the cutouts.
77
78 Parameters
79 ----------
80 in_table : `astropy.QTable`
81 A table containing at least the following columns: position, xspan
82 and yspan. The position should be an `astropy.SkyCoord`. The
83 xspan and yspan are the extent of the cutout in x and y in pixels.
84 calexp : `lsst.afw.image.ExposureF`
85 The calibrated exposure from which to extract cutouts
86
87 Returns
88 -------
89 output : `lsst.pipe.base.Struct`
90 A struct containing:
91
92 * cutouts: an `lsst.meas.algorithms.Stamps` object
93 that wraps a list of masked images of the cutouts and a
94 `PropertyList` containing the metadata to be persisted
95 with the cutouts. The exposure metadata is preserved and,
96 in addition, arrays holding the RA and Dec of each stamp
97 in degrees are added to the metadata. Note: the origin
98 of the output stamps is `lsst.afw.image.PARENT`.
99 * skipped_positions: a `list` of `lsst.geom.SpherePoint` objects for
100 stamps that were skiped for being off the image
101 or partially off the image
102
103 Raises
104 ------
105 ValueError
106 If the input catalog doesn't have the required columns,
107 a ValueError is raised
108 """
109 cols = in_table.colnames
110 if 'position' not in cols or 'xspan' not in cols or 'yspan' not in cols:
111 raise ValueError('Required column missing from the input table. '
112 'Required columns are "position", "xspan", and "yspan". '
113 f'The column names are: {in_table.colnames}')
114 wcs = calexp.getWcs()
115 if wcs is None:
116 raise RuntimeError("Calexp has no WCS, so cannot compute sky positions.")
117 max_idx = self.config.max_cutouts
118 cutout_list = []
119 mim = calexp.getMaskedImage()
120 ras = []
121 decs = []
122 skipped_positions = []
123 for rec in in_table[:max_idx]:
124 ra = rec['position'].ra.degree
125 dec = rec['position'].dec.degree
126 ras.append(ra)
127 decs.append(dec)
128 pt = geom.SpherePoint(geom.Angle(ra, geom.degrees),
129 geom.Angle(dec, geom.degrees))
130 pix = wcs.skyToPixel(pt)
131 xspan = rec['xspan'].value
132 yspan = rec['yspan'].value
133 # Clamp to LL corner of the LL pixel and draw extent from there
134 box = geom.Box2I(geom.Point2I(int(pix.x-xspan/2), int(pix.y-yspan/2)),
135 geom.Extent2I(xspan, yspan))
136 if not mim.getBBox().contains(box):
137 if not self.config.skip_bad:
138 raise ValueError(f'Cutout bounding box is not completely contained in the image: {box}')
139 else:
140 skipped_positions.append(pt)
141 continue
142 sub = mim.Factory(mim, box)
143 stamp = Stamp(stamp_im=sub, position=pt)
144 cutout_list.append(stamp)
145 metadata = calexp.getMetadata()
146 metadata['RA_DEG'] = ras
147 metadata['DEC_DEG'] = decs
148 return pipeBase.Struct(cutouts=Stamps(cutout_list, metadata=metadata),
149 skipped_positions=skipped_positions)
A class representing an angle.
Definition Angle.h:128
An integer coordinate rectangle.
Definition Box.h:55
Point in an unspecified spherical coordinate system.
Definition SpherePoint.h:57