22from __future__
import annotations
24__all__ = (
"RewriteCellCoaddConnections",
"RewriteCellCoaddTask",
"RewriteCellCoaddConfig")
26from typing
import Any, ClassVar
30import lsst.pipe.base.connectionTypes
as cT
34from lsst.cell_coadds
import MultipleCellCoadd
as LegacyMultipleCellCoadd
35from lsst.images
import Box, Mask, get_legacy_deep_coadd_mask_planes
36from lsst.images.cells
import CellCoadd
37from lsst.images.fields
import field_from_legacy_background
40from lsst.pipe.base
import (
44 PipelineTaskConnections,
51 PipelineTaskConnections,
52 dimensions={
"patch",
"band"},
53 defaultTemplates={
"legacy_prefix":
"legacy_",
"future_prefix":
""},
55 legacy_cell_coadd = cT.Input(
56 "deep_coadd_cell_predetection",
57 storageClass=
"MultipleCellCoadd",
58 dimensions={
"patch",
"band"},
59 doc=
"The pre-detection cell coadd to convert.",
61 object_background = cT.Input(
62 "deep_coadd_background",
63 storageClass=
"Background",
64 dimensions={
"patch",
"band"},
65 doc=
"The background model used to generate the object catalog, to be subtracted from the coadd.",
68 object_mask = cT.Input(
69 "{legacy_prefix}deep_coadd.mask",
71 dimensions={
"patch",
"band"},
72 doc=
"The mask to use for the coadd, including the final DETECTED mask plane.",
75 alternate_background_coadd = cT.Input(
76 "pretty_coadd_extra_bg_subtracted",
77 storageClass=
"ExposureF",
78 dimensions={
"patch",
"band"},
79 doc=
"A coadd to subtract from ``legacy_cell_coadd`` and fit a background to.",
83 doc=
"Description of the skymap's tracts and patches.",
84 name=BaseSkyMap.SKYMAP_DATASET_TYPE_NAME,
85 storageClass=
"SkyMap",
86 dimensions=(
"skymap",),
88 future_cell_coadd = cT.Output(
89 "{future_prefix}deep_coadd",
90 storageClass=
"CellCoadd",
91 dimensions={
"patch",
"band"},
92 doc=
"The output CellCoadd.",
95 config: RewriteCellCoaddConfig
97 def __init__(self, config: RewriteCellCoaddConfig |
None):
98 super().__init__(config=config)
99 if not self.config.do_alternate_background_fit:
100 del self.alternate_background_coadd
103class RewriteCellCoaddConfig(
105 pipelineConnections=RewriteCellCoaddConnections,
107 object_background_description = Field(
108 "Description of the object background, to be stored with the image.",
111 "Background subtracted from the image when generating the Object catalog. "
112 "This intentionally oversubtracts the background to reduce blending and ensure "
113 "scattered light is subtracted. "
114 "Restoring this background does not restore all original backgrounds, "
115 "as the coadd was built from background-subtracted visit images; in most "
116 "cases this background term is actually quite small."
119 do_alternate_background_fit = Field(
120 "Whether to fit an alternate background to the difference between "
121 "the alternate_background_coadd and the main coadd.",
125 alternate_background_fit = ConfigurableField(
126 target=SubtractBackgroundTask,
128 "Configuration for fitting the alternate background. "
129 "Ignored if do_alternate_background_fit is False"
132 alternate_background_name = Field(
133 "Name for the alternate background attached to the image. "
134 "ignored if do_alternate_background_fit is False.",
138 alternate_background_description = Field(
139 "Description for the alternate background attached to the image. "
140 "Ignored if do_alternate_background_fit is False.",
143 "An alternate background optimized for visually attractive RGB images. "
144 "'Subtracting' this background will generally *add* flux, correcting "
145 "for most oversubtraction problems, but leaving in scattered light and "
146 "some instrumental backgrounds in some cases. "
147 "Because this background is fit to a difference of two wholly different "
148 "coadds that may have different input images, it can also be pulled "
149 "up or down by bright variable or transient objects."
153 def setDefaults(self) -> None:
154 super().setDefaults()
155 self.alternate_background_fit.useApprox =
False
156 self.alternate_background_fit.binSize = 64
157 self.alternate_background_fit.ignoredPixelMask = [
"NO_DATA",
"SAT"]
160class RewriteCellCoaddTask(PipelineTask):
161 ConfigClass: ClassVar[type[RewriteCellCoaddConfig]] = RewriteCellCoaddConfig
162 config: RewriteCellCoaddConfig
163 _DefaultName =
"rewriteCellCoadd"
165 def __init__(self, *args: Any, **kwargs: Any) ->
None:
166 super().__init__(*args, **kwargs)
167 self.makeSubtask(
"alternate_background_fit")
171 legacy_cell_coadd: LegacyMultipleCellCoadd,
174 object_background: BackgroundList |
None =
None,
175 object_mask: LegacyMask |
None =
None,
176 alternate_background_coadd: LegacyExposure |
None =
None,
178 tract_info = sky_map[legacy_cell_coadd.identifiers.tract]
179 patch_bbox = tract_info[legacy_cell_coadd.identifiers.patch].getOuterBBox()
180 future_cell_coadd = CellCoadd.from_legacy(
182 tract_info=tract_info,
183 bbox=Box.from_legacy(patch_bbox),
185 if object_mask
is not None:
186 future_cell_coadd.mask.clear()
187 future_cell_coadd.mask.update(
188 Mask.from_legacy(object_mask, plane_map=get_legacy_deep_coadd_mask_planes())
195 "No object mask found; clearing DETECTED and using other predetection mask planes."
197 future_cell_coadd.mask.clear(
"DETECTED")
199 if self.config.do_alternate_background_fit:
200 if alternate_background_coadd
is not None:
201 alt_bg_diff = future_cell_coadd.to_legacy_exposure(copy=
True)
202 alt_bg_diff.maskedImage -= alternate_background_coadd.getMaskedImage()
204 alt_bg_result = self.alternate_background_fit.run(alt_bg_diff, stats=
False)
205 except AlgorithmError:
206 self.log.exception(
"Could not fit alternate background to diff; rewriting without it.")
208 alt_bg = field_from_legacy_background(alt_bg_result.background, unit=astropy.units.nJy)
209 future_cell_coadd.backgrounds.add(
210 self.config.alternate_background_name,
212 self.config.alternate_background_description,
215 self.log.warning(
"No alternate background coadd found; rewriting without it.")
216 elif alternate_background_coadd
is not None:
218 "alternate_background_coadd provided but config.do_alternate_background_fit=False"
220 if object_background
is not None:
226 future_cell_coadd.image.array -= object_background.getImage().array
227 future_cell_coadd.backgrounds.add(
229 field_from_legacy_background(object_background, unit=astropy.units.nJy),
230 self.config.object_background_description,
235 "No object background model found; rewriting coadd without subtracting background."
237 return Struct(future_cell_coadd=future_cell_coadd)