LSSTApplications  18.1.0
LSSTDataManagementBasePackage
processFakes.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 # (http://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 <http://www.gnu.org/licenses/>.
21 
22 """
23 Insert fake sources into calexps
24 """
25 from astropy.table import Table
26 
27 import lsst.pex.config as pexConfig
28 import lsst.pipe.base as pipeBase
29 import lsst.daf.base as dafBase
30 
31 from .insertFakes import InsertFakesTask
32 from lsst.meas.algorithms import SourceDetectionTask
33 from lsst.meas.base import (SingleFrameMeasurementTask, ApplyApCorrTask, CatalogCalculationTask,
34  PerTractCcdDataIdContainer)
35 from lsst.meas.deblender import SourceDeblendTask
36 from lsst.afw.table import SourceTable, IdFactory
37 from lsst.obs.base import ExposureIdInfo
38 from lsst.pipe.base import PipelineTask, PipelineTaskConfig, CmdLineTask
39 
40 
41 __all__ = ["ProcessCcdWithFakesConfig", "ProcessCcdWithFakesTask"]
42 
43 
45  """Config for inserting fake sources
46 
47  Notes
48  -----
49  The default column names are those from the UW sims database.
50  """
51 
52  useUpdatedCalibs = pexConfig.Field(
53  doc="Use updated calibs and wcs from jointcal?",
54  dtype=bool,
55  default=False,
56  )
57 
58  exposure = pipeBase.InputDatasetField(
59  doc="Exposure into which fakes are to be added.",
60  name="calexp",
61  scalar=True,
62  storageClass="ExposureF",
63  dimensions=("Instrument", "Visit", "Detector")
64  )
65 
66  fakeCat = pipeBase.InputDatasetField(
67  doc="Catalog of fake sources to draw inputs from.",
68  nameTemplate="{CoaddName}Coadd_fakeSourceCat",
69  scalar=True,
70  storageClass="Parquet",
71  dimensions=("Tract", "SkyMap")
72  )
73 
74  wcs = pipeBase.InputDatasetField(
75  doc="WCS information for the input exposure.",
76  name="jointcal_wcs",
77  scalar=True,
78  storageClass="TablePersistableWcs",
79  dimensions=("Tract", "SkyMap", "Instrument", "Visit", "Detector")
80  )
81 
82  photoCalib = pipeBase.InputDatasetField(
83  doc="Calib information for the input exposure.",
84  name="jointcal_photoCalib",
85  scalar=True,
86  storageClass="TablePersistablePhotoCalib",
87  dimensions=("Tract", "SkyMap", "Instrument", "Visit", "Detector")
88  )
89 
90  outputExposure = pipeBase.OutputDatasetField(
91  doc="Exposure with fake sources added.",
92  name="fakes_calexp",
93  scalar=True,
94  storageClass="ExposureF",
95  dimensions=("Instrument", "Visit", "Detector")
96  )
97 
98  outputCat = pipeBase.OutputDatasetField(
99  doc="Source catalog produced in calibrate task with fakes also measured.",
100  name="src",
101  storageClass="SourceCatalog",
102  dimensions=("Instrument", "Visit", "Detector"),
103  scalar=True
104  )
105 
106  coaddName = pexConfig.Field(
107  doc="The name of the type of coadd used",
108  dtype=str,
109  default="deep",
110  )
111 
112  insertFakes = pexConfig.ConfigurableField(target=InsertFakesTask,
113  doc="Configuration for the fake sources")
114 
115  detection = pexConfig.ConfigurableField(target=SourceDetectionTask,
116  doc="The detection task to use.")
117 
118  deblend = pexConfig.ConfigurableField(target=SourceDeblendTask, doc="The deblending task to use.")
119 
120  measurement = pexConfig.ConfigurableField(target=SingleFrameMeasurementTask,
121  doc="The measurement task to use")
122 
123  applyApCorr = pexConfig.ConfigurableField(target=ApplyApCorrTask,
124  doc="The apply aperture correction task to use.")
125 
126  catalogCalculation = pexConfig.ConfigurableField(target=CatalogCalculationTask,
127  doc="The catalog calculation ask to use.")
128 
129  def setDefaults(self):
130  self.detection.reEstimateBackground = False
131  super().setDefaults()
132  self.quantum.dimensions = ("Instrument", "Visit", "Detector")
133  self.measurement.plugins["base_PixelFlags"].masksFpAnywhere.append("FAKE")
134  self.measurement.plugins["base_PixelFlags"].masksFpCenter.append("FAKE")
135 
136 
138  """Insert fake objects into calexps.
139 
140  Add fake stars and galaxies to the given calexp, specified in the dataRef. Galaxy parameters are read in
141  from the specified file and then modelled using galsim. Re-runs characterize image and calibrate image to
142  give a new background estimation and measurement of the calexp.
143 
144  `ProcessFakeSourcesTask` inherits six functions from insertFakesTask that make images of the fake
145  sources and then add them to the calexp.
146 
147  `addPixCoords`
148  Use the WCS information to add the pixel coordinates of each source
149  Adds an ``x`` and ``y`` column to the catalog of fake sources.
150  `trimFakeCat`
151  Trim the fake cat to about the size of the input image.
152  `mkFakeGalsimGalaxies`
153  Use Galsim to make fake double sersic galaxies for each set of galaxy parameters in the input file.
154  `mkFakeStars`
155  Use the PSF information from the calexp to make a fake star using the magnitude information from the
156  input file.
157  `cleanCat`
158  Remove rows of the input fake catalog which have half light radius, of either the bulge or the disk,
159  that are 0.
160  `addFakeSources`
161  Add the fake sources to the calexp.
162 
163  Notes
164  -----
165  The ``calexp`` with fake souces added to it is written out as the datatype ``calexp_fakes``.
166  """
167 
168  _DefaultName = "processCcdWithFakes"
169  ConfigClass = ProcessCcdWithFakesConfig
170 
171  def __init__(self, schema=None, **kwargs):
172  """Initalize tings! This should go above in the class docstring
173  """
174 
175  super().__init__(**kwargs)
176 
177  if schema is None:
178  schema = SourceTable.makeMinimalSchema()
179  self.schema = schema
180  self.makeSubtask("insertFakes")
182  self.makeSubtask("detection", schema=self.schema)
183  self.makeSubtask("deblend", schema=self.schema)
184  self.makeSubtask("measurement", schema=self.schema, algMetadata=self.algMetadata)
185  self.makeSubtask("applyApCorr", schema=self.schema)
186  self.makeSubtask("catalogCalculation", schema=self.schema)
187 
188  def runDataRef(self, dataRef):
189  """Read in/write out the required data products and add fake sources to the calexp.
190 
191  Parameters
192  ----------
193  dataRef : `lsst.daf.persistence.butlerSubset.ButlerDataRef`
194  Data reference defining the ccd to have fakes added to it.
195  Used to access the following data products:
196  calexp
197  jointcal_wcs
198  jointcal_photoCalib
199 
200  Notes
201  -----
202  Uses the calibration and WCS information attached to the calexp for the posistioning and calibration
203  of the sources unless the config option config.useUpdatedCalibs is set then it uses the
204  meas_mosaic/jointCal outputs. The config defualts for the column names in the catalog of fakes are
205  taken from the University of Washington simulations database. Operates on one ccd at a time.
206  """
207  exposureIdInfo = dataRef.get("expIdInfo")
208 
209  if self.config.insertFakes.fakeType == "snapshot":
210  fakeCat = dataRef.get("fakeSourceCat").toDataFrame()
211  elif self.config.insertFakes.fakeType == "static":
212  fakeCat = dataRef.get("deepCoadd_fakeSourceCat").toDataFrame()
213  else:
214  fakeCat = Table.read(self.config.insertFakes.fakeType).to_pandas()
215 
216  calexp = dataRef.get("calexp")
217  if self.config.useUpdatedCalibs:
218  self.log.info("Using updated calibs from meas_mosaic/jointCal")
219  wcs = dataRef.get("jointcal_wcs")
220  photoCalib = dataRef.get("jointcal_photoCalib")
221  else:
222  wcs = calexp.getWcs()
223  photoCalib = calexp.getCalib()
224 
225  resultStruct = self.run(fakeCat, calexp, wcs=wcs, photoCalib=photoCalib,
226  exposureIdInfo=exposureIdInfo)
227 
228  dataRef.put(resultStruct.outputExposure, "fakes_calexp")
229  dataRef.put(resultStruct.outputCat, "fakes_src")
230 
231  def adaptArgsAndRun(self, inputData, inputDataIds, outputDataIds, butler):
232  if 'exposureIdInfo' not in inputData.keys():
233  packer = butler.registry.makeDataIdPacker("VisitDetector", inputDataIds['exposure'])
234  exposureIdInfo = ExposureIdInfo()
235  exposureIdInfo.expId = packer.pack(inputDataIds['exposure'])
236  exposureIdInfo.expBits = packer.maxBits
237  inputData['exposureIdInfo'] = exposureIdInfo
238 
239  if inputData["wcs"] is None:
240  inputData["wcs"] = inputData["image"].getWcs()
241  if inputData["photoCalib"] is None:
242  inputData["photoCalib"] = inputData["image"].getCalib()
243 
244  return self.run(**inputData)
245 
246  @classmethod
247  def _makeArgumentParser(cls):
248  parser = pipeBase.ArgumentParser(name=cls._DefaultName)
249  parser.add_id_argument("--id", "fakes_calexp", help="data ID with raw CCD keys [+ tract optionally], "
250  "e.g. --id visit=12345 ccd=1,2 [tract=0]",
251  ContainerClass=PerTractCcdDataIdContainer)
252  return parser
253 
254  def run(self, fakeCat, exposure, wcs=None, photoCalib=None, exposureIdInfo=None):
255  """Add fake sources to a calexp and then run detection, deblending and measurement.
256 
257  Parameters
258  ----------
259  fakeCat : `pandas.core.frame.DataFrame`
260  The catalog of fake sources to add to the exposure
261  exposure : `lsst.afw.image.exposure.exposure.ExposureF`
262  The exposure to add the fake sources to
263  wcs : `lsst.afw.geom.skyWcs.skyWcs.SkyWcs`
264  WCS to use to add fake sources
265  photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
266  Photometric calibration to be used to calibrate the fake sources
267  exposureIdInfo : `lsst.obs.base.ExposureIdInfo`
268 
269  Returns
270  -------
271  resultStruct : `lsst.pipe.base.struct.Struct`
272  contains : outputExposure : `lsst.afw.image.exposure.exposure.ExposureF`
273  outputCat : `lsst.afw.table.source.source.SourceCatalog`
274 
275  Notes
276  -----
277  Adds pixel coordinates for each source to the fakeCat and removes objects with bulge or disk half
278  light radius = 0 (if ``config.cleanCat = True``). These columns are called ``x`` and ``y`` and are in
279  pixels.
280 
281  Adds the ``Fake`` mask plane to the exposure which is then set by `addFakeSources` to mark where fake
282  sources have been added. Uses the information in the ``fakeCat`` to make fake galaxies (using galsim)
283  and fake stars, using the PSF models from the PSF information for the calexp. These are then added to
284  the calexp and the calexp with fakes included returned.
285 
286  The galsim galaxies are made using a double sersic profile, one for the bulge and one for the disk,
287  this is then convolved with the PSF at that point.
288 
289  If exposureIdInfo is not provided then the SourceCatalog IDs will not be globally unique.
290  """
291 
292  if wcs is None:
293  wcs = exposure.getWcs()
294 
295  if photoCalib is None:
296  photoCalib = exposure.getCalib()
297 
298  self.insertFakes.run(fakeCat, exposure, wcs, photoCalib)
299 
300  # detect, deblend and measure sources
301  if exposureIdInfo is None:
302  exposureIdInfo = ExposureIdInfo()
303 
304  sourceIdFactory = IdFactory.makeSource(exposureIdInfo.expId, exposureIdInfo.unusedBits)
305  table = SourceTable.make(self.schema, sourceIdFactory)
306  table.setMetadata(self.algMetadata)
307 
308  detRes = self.detection.run(table=table, exposure=exposure, doSmooth=True)
309  sourceCat = detRes.sources
310  self.deblend.run(exposure=exposure, sources=sourceCat)
311  self.measurement.run(measCat=sourceCat, exposure=exposure, exposureId=exposureIdInfo.expId)
312  self.applyApCorr.run(catalog=sourceCat, apCorrMap=exposure.getInfo().getApCorrMap())
313  self.catalogCalculation.run(sourceCat)
314 
315  resultStruct = pipeBase.Struct(outputExposure=exposure, outputCat=sourceCat)
316  return resultStruct
def makeSubtask(self, name, keyArgs)
Definition: task.py:275
Class for storing ordered metadata with comments.
Definition: PropertyList.h:68
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations...
def run(self, fakeCat, exposure, wcs=None, photoCalib=None, exposureIdInfo=None)
def adaptArgsAndRun(self, inputData, inputDataIds, outputDataIds, butler)