LSST Applications g0b6bd0c080+a72a5dd7e6,g1182afd7b4+2a019aa3bb,g17e5ecfddb+2b8207f7de,g1d67935e3f+06cf436103,g38293774b4+ac198e9f13,g396055baef+6a2097e274,g3b44f30a73+6611e0205b,g480783c3b1+98f8679e14,g48ccf36440+89c08d0516,g4b93dc025c+98f8679e14,g5c4744a4d9+a302e8c7f0,g613e996a0d+e1c447f2e0,g6c8d09e9e7+25247a063c,g7271f0639c+98f8679e14,g7a9cd813b8+124095ede6,g9d27549199+a302e8c7f0,ga1cf026fa3+ac198e9f13,ga32aa97882+7403ac30ac,ga786bb30fb+7a139211af,gaa63f70f4e+9994eb9896,gabf319e997+ade567573c,gba47b54d5d+94dc90c3ea,gbec6a3398f+06cf436103,gc6308e37c7+07dd123edb,gc655b1545f+ade567573c,gcc9029db3c+ab229f5caf,gd01420fc67+06cf436103,gd877ba84e5+06cf436103,gdb4cecd868+6f279b5b48,ge2d134c3d5+cc4dbb2e3f,ge448b5faa6+86d1ceac1d,gecc7e12556+98f8679e14,gf3ee170dca+25247a063c,gf4ac96e456+ade567573c,gf9f5ea5b4d+ac198e9f13,gff490e6085+8c2580be5c,w.2022.27
LSST Data Management Base Package
calexpCutout.py
Go to the documentation of this file.
1import lsst.pipe.base as pipeBase
2import lsst.geom as geom
3from lsst.pex.config import Field
4from lsst.meas.algorithms import Stamp, Stamps
5
6__all__ = ['CalexpCutoutTaskConfig', 'CalexpCutoutTask']
7DETECTOR_DIMENSIONS = ('instrument', 'visit', 'detector')
8
9
10class CalexpCutoutTaskConnections(pipeBase.PipelineTaskConnections,
11 dimensions=DETECTOR_DIMENSIONS,
12 defaultTemplates={}):
13 """Connections class for CalexpCutoutTask
14 """
15 in_table = pipeBase.connectionTypes.Input(
16 doc="Locations for cutouts",
17 name="cutout_positions",
18 storageClass="AstropyQTable",
19 dimensions=DETECTOR_DIMENSIONS,
20 )
21 calexp = pipeBase.connectionTypes.Input(
22 doc="Calexp objects",
23 name="calexp",
24 storageClass="ExposureF",
25 dimensions=DETECTOR_DIMENSIONS,
26 )
27 cutouts = pipeBase.connectionTypes.Output(
28 doc="Cutouts",
29 name="calexp_cutouts",
30 storageClass="Stamps",
31 dimensions=DETECTOR_DIMENSIONS,
32 )
33
34
35class CalexpCutoutTaskConfig(pipeBase.PipelineTaskConfig,
36 pipelineConnections=CalexpCutoutTaskConnections):
37 """Configuration for CalexpCutoutTask
38 """
39 max_cutouts = Field(dtype=int, default=100, doc='Maximum number of entries to process. '
40 'The result will be the first N in the input table.')
41 skip_bad = Field(dtype=bool, default=True, doc='Skip cutouts that do not fall completely within'
42 ' the calexp bounding box? If set to False a ValueError'
43 ' is raised instead.')
44
45
46class CalexpCutoutTask(pipeBase.PipelineTask):
47 """Task for computing cutouts on a specific calexp given
48 positions, xspans, and yspans of the stamps.
49 """
50 ConfigClass = CalexpCutoutTaskConfig
51 _DefaultName = "calexpCutoutTask"
52
53 def run(self, in_table, calexp):
54 """Compute and return the cutouts.
55
56 Parameters
57 ----------
58 in_table : `astropy.QTable`
59 A table containing at least the following columns: position, xspan
60 and yspan. The position should be an `astropy.SkyCoord`. The
61 xspan and yspan are the extent of the cutout in x and y in pixels.
62 calexp : `lsst.afw.image.ExposureF`
63 The calibrated exposure from which to extract cutouts
64
65 Returns
66 -------
67 output : `lsst.pipe.base.Struct`
68 A struct containing:
69
70 * cutouts: an `lsst.meas.algorithms.Stamps` object
71 that wraps a list of masked images of the cutouts and a
72 `PropertyList` containing the metadata to be persisted
73 with the cutouts. The exposure metadata is preserved and,
74 in addition, arrays holding the RA and Dec of each stamp
75 in degrees are added to the metadata. Note: the origin
76 of the output stamps is `lsst.afw.image.PARENT`.
77 * skipped_positions: a `list` of `lsst.geom.SpherePoint` objects for
78 stamps that were skiped for being off the image
79 or partially off the image
80
81 Raises
82 ------
83 ValueError
84 If the input catalog doesn't have the required columns,
85 a ValueError is raised
86 """
87 cols = in_table.colnames
88 if 'position' not in cols or 'xspan' not in cols or 'yspan' not in cols:
89 raise ValueError('Required column missing from the input table. '
90 'Required columns are "position", "xspan", and "yspan". '
91 f'The column names are: {in_table.colnames}')
92 max_idx = self.config.max_cutouts
93 cutout_list = []
94 wcs = calexp.getWcs()
95 mim = calexp.getMaskedImage()
96 ras = []
97 decs = []
98 skipped_positions = []
99 for rec in in_table[:max_idx]:
100 ra = rec['position'].ra.degree
101 dec = rec['position'].dec.degree
102 ras.append(ra)
103 decs.append(dec)
104 pt = geom.SpherePoint(geom.Angle(ra, geom.degrees),
105 geom.Angle(dec, geom.degrees))
106 pix = wcs.skyToPixel(pt)
107 xspan = rec['xspan'].value
108 yspan = rec['yspan'].value
109 # Clamp to LL corner of the LL pixel and draw extent from there
110 box = geom.Box2I(geom.Point2I(int(pix.x-xspan/2), int(pix.y-yspan/2)),
111 geom.Extent2I(xspan, yspan))
112 if not mim.getBBox().contains(box):
113 if not self.config.skip_bad:
114 raise ValueError(f'Cutout bounding box is not completely contained in the image: {box}')
115 else:
116 skipped_positions.append(pt)
117 continue
118 sub = mim.Factory(mim, box)
119 stamp = Stamp(stamp_im=sub, position=pt)
120 cutout_list.append(stamp)
121 metadata = calexp.getMetadata()
122 metadata['RA_DEG'] = ras
123 metadata['DEC_DEG'] = decs
124 return pipeBase.Struct(cutouts=Stamps(cutout_list, metadata=metadata),
125 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
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations.