33 from .repair
import RepairTask
34 from .measurePsf
import MeasurePsfTask
37 """!Describes the initial PSF used for detection and measurement before we do PSF determination."""
39 model = pexConfig.ChoiceField(
41 doc =
"PSF model type",
42 default =
"SingleGaussian",
44 "SingleGaussian":
"Single Gaussian model",
45 "DoubleGaussian":
"Double Gaussian model",
48 pixelScale = pexConfig.Field(
50 doc =
"Pixel size (arcsec). Only needed if no Wcs is provided",
53 fwhm = pexConfig.Field(
55 doc =
"FWHM of PSF model (arcsec)",
58 size = pexConfig.Field(
60 doc =
"Size of PSF model (pixels)",
65 initialPsf = pexConfig.ConfigField(dtype=InitialPsfConfig, doc=InitialPsfConfig.__doc__)
66 doBackground = pexConfig.Field(
68 doc =
"Subtract background (after computing it, if not supplied)?",
71 doPsf = pexConfig.Field(
73 doc =
"Perform PSF fitting?",
76 doAstrometry = pexConfig.Field(
78 doc =
"Compute astrometric solution?",
81 doPhotoCal = pexConfig.Field(
83 doc =
"Compute photometric zeropoint?",
86 background = pexConfig.ConfigField(
87 dtype = measAlg.estimateBackground.ConfigClass,
88 doc =
"Background estimation configuration"
90 repair = pexConfig.ConfigurableField(target = RepairTask, doc =
"")
91 detection = pexConfig.ConfigurableField(
92 target = measAlg.SourceDetectionTask,
93 doc =
"Initial (high-threshold) detection phase for calibration",
95 initialMeasurement = pexConfig.ConfigurableField(
96 target = lsst.meas.base.SingleFrameMeasurementTask,
97 doc =
"Initial measurements used to feed PSF determination and aperture correction determination",
99 measurePsf = pexConfig.ConfigurableField(target = MeasurePsfTask, doc =
"")
100 measurement = pexConfig.ConfigurableField(
101 target = lsst.meas.base.SingleFrameMeasurementTask,
102 doc =
"Post-PSF-determination measurements used to feed other calibrations",
104 astrometry = pexConfig.ConfigurableField(
105 target = ANetAstrometryTask,
106 doc =
"fit WCS of exposure",
108 photocal = pexConfig.ConfigurableField(
109 target = PhotoCalTask,
110 doc =
"peform photometric calibration",
114 pexConfig.Config.validate(self)
116 raise ValueError(
"Cannot do photometric calibration without doing astrometric matching")
119 self.detection.includeThresholdMultiplier = 10.0
120 self.initialMeasurement.algorithms.names -= [
"correctfluxes",
"classification.extendedness"]
121 initflags = [x
for x
in self.measurePsf.starSelector[
"catalog"].badStarPixelFlags]
122 self.measurePsf.starSelector[
"catalog"].badStarPixelFlags.extend(initflags)
123 self.background.binSize = 1024
134 \anchor CalibrateTask_
136 \brief Calibrate an exposure: measure PSF, subtract background, measure astrometry and photometry
138 \section pipe_tasks_calibrate_Contents Contents
140 - \ref pipe_tasks_calibrate_Purpose
141 - \ref pipe_tasks_calibrate_Initialize
142 - \ref pipe_tasks_calibrate_IO
143 - \ref pipe_tasks_calibrate_Config
144 - \ref pipe_tasks_calibrate_Metadata
145 - \ref pipe_tasks_calibrate_Debug
146 - \ref pipe_tasks_calibrate_Example
148 \section pipe_tasks_calibrate_Purpose Description
150 \copybrief CalibrateTask
152 Calculate an Exposure's zero-point given a set of flux measurements of stars matched to an input catalogue.
153 The type of flux to use is specified by CalibrateConfig.fluxField.
155 The algorithm clips outliers iteratively, with parameters set in the configuration.
157 \note This task can adds fields to the schema, so any code calling this task must ensure that
158 these columns are indeed present in the input match list; see \ref pipe_tasks_calibrate_Example
160 \section pipe_tasks_calibrate_Initialize Task initialisation
162 \copydoc \_\_init\_\_
164 CalibrateTask delegates most of its work to a set of sub-Tasks:
166 <DT> repair \ref RepairTask_ "RepairTask"
167 <DD> Interpolate over defects such as bad columns and cosmic rays. This task is called twice; once
168 before the %measurePsf step and again after the PSF has been measured.
169 <DT> detection \ref SourceDetectionTask_ "SourceDetectionTask"
170 <DD> Initial (high-threshold) detection phase for calibration
171 <DT> initialMeasurement \ref SourceMeasurementTask_ "SourceMeasurementTask"
172 <DD> Make the initial measurements used to feed PSF determination and aperture correction determination
173 <DT> astrometry \ref AstrometryTask_ "AstrometryTask"
174 <DD> Solve the astrometry. May be disabled by setting CalibrateTaskConfig.doAstrometry to be False.
175 This task is called twice; once before the %measurePsf step and again after the PSF has been measured.
176 <DT> %measurePsf \ref MeasurePsfTask_ "MeasurePsfTask"
177 <DD> Estimate the PSF. May be disabled by setting CalibrateTaskConfig.doPsf to be False. If requested
178 the astrometry is solved before this is called, so if you disable the astrometry the %measurePsf
179 task won't have access to objects positions.
180 <DT> measurement \ref SourceMeasurementTask_ "SourceMeasurementTask"
181 <DD> Post-PSF-determination measurements used to feed other calibrations
182 <DT> photocal \ref PhotoCalTask_ "PhotoCalTask"
183 <DD> Solve for the photometric zeropoint.
184 May be disabled by setting CalibrateTaskConfig.doPhotoCal to be False.
185 \em N.b. Requires that \c astrometry was successfully run.
188 You can replace any of these subtasks if you wish, see \ref calibrate_MyAstrometryTask.
189 \note These task APIs are not well controlled, so replacing a task is a matter of matching
190 a poorly specified interface. We will be working on this over the first year of construction.
192 \section pipe_tasks_calibrate_IO Invoking the Task
196 \section pipe_tasks_calibrate_Config Configuration parameters
198 See \ref CalibrateConfig
200 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
202 \section pipe_tasks_calibrate_Metadata Quantities set in Metadata
208 <DT> MAGZERO <DD> Measured zeropoint (DN per second)
211 <DT> Exposure metadata
214 <DT> MAGZERO_RMS <DD> MAGZERO's RMS == return.sigma
215 <DT> MAGZERO_NOBJ <DD> Number of stars used == return.ngood
216 <DT> COLORTERM1 <DD> ?? (always 0.0)
217 <DT> COLORTERM2 <DD> ?? (always 0.0)
218 <DT> COLORTERM3 <DD> ?? (always 0.0)
222 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
224 \section pipe_tasks_calibrate_Debug Debug variables
226 The \link lsst.pipe.base.cmdLineTask.CmdLineTask command line task\endlink interface supports a
227 flag \c -d to import \b debug.py from your \c PYTHONPATH; see \ref baseDebug for more about \b debug.py files.
229 The calibrate task has a debug dictionary with keys which correspond to stages of the CalibrationTask
233 <DD> Fixed defects and masked cosmic rays with a guessed PSF. Action: show the exposure.
235 <DD> Subtracted background (no sources masked). Action: show the exposure
237 <DD> Fixed defects and removed cosmic rays with an estimated PSF. Action: show the exposure
239 <DD> Subtracted background (calibration sources masked). Action: show the exposure
241 <DD> Just before astro/photo calibration. Action: show the exposure, and
242 - sources as smallish green o
243 - matches (if exposure has a Wcs).
244 - catalog position as a largish yellow +
245 - source position as a largish red x
247 The values are the \c ds9 frame to display in (if >= 1); if <= 0, nothing's displayed.
248 There's an example \ref pipe_tasks_calibrate_Debug_example "here".
250 Some subtasks may also have their own debug information; see individual Task documentation.
252 \section pipe_tasks_calibrate_Example A complete example of using CalibrateTask
254 This code is in \link calibrateTask.py\endlink in the examples directory, and can be run as \em e.g.
256 examples/calibrateTask.py --ds9
258 \dontinclude calibrateTask.py
260 Import the task (there are some other standard imports; read the file if you're curious)
261 \skipline CalibrateTask
263 Create the detection task
264 \skip CalibrateTask.ConfigClass
266 Note that we're using a custom AstrometryTask (because we don't have a valid astrometric catalogue handy);
267 see \ref calibrate_MyAstrometryTask.
269 We're now ready to process the data (we could loop over multiple exposures/catalogues using the same
270 task objects) and unpack the results
274 We then might plot the results (\em e.g. if you set \c --ds9 on the command line)
278 \subsection calibrate_MyAstrometryTask Using a Custom Astrometry Task
280 The first thing to do is define my own task:
281 \dontinclude calibrateTask.py
282 \skip MyAstrometryTask
283 \skip MyAstrometryTask
286 Then we need our own \c run method. First unpack the filtername and wcs
289 Then build a "reference catalog" by shamelessly copying the catalog of detected sources
291 \until get("photometric")
292 (you need to set "flux" as well as \c filterName due to a bug in the photometric calibration code;
293 <A HREF=https://jira.lsstcorp.org/browse/DM-933>DM-933</A>).
295 Then "match" by zipping up the two catalogs,
298 and finally return the desired results.
303 \anchor pipe_tasks_calibrate_Debug_example
304 To investigate the \ref pipe_tasks_calibrate_Debug, put something like
308 di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively
309 if name == "lsst.pipe.tasks.calibrate":
317 lsstDebug.Info = DebugInfo
319 into your debug.py file and run calibrateTask.py with the \c --debug flag.
321 ConfigClass = CalibrateConfig
322 _DefaultName =
"calibrate"
326 Create the calibration task
328 \param **kwargs keyword arguments to be passed to lsst.pipe.base.task.Task.__init__
330 pipeBase.Task.__init__(self, **kwargs)
336 self.
schema1 = afwTable.SourceTable.makeMinimalSchema()
338 self.makeSubtask(
"repair")
339 self.makeSubtask(
"detection", schema=self.
schema1)
340 beginInitial = self.schema1.getFieldCount()
341 self.makeSubtask(
"initialMeasurement", schema=self.
schema1, algMetadata=self.
algMetadata)
342 endInitial = self.schema1.getFieldCount()
343 self.makeSubtask(
"measurePsf", schema=self.
schema1)
344 self.makeSubtask(
"astrometry", schema=self.
schema1)
345 self.makeSubtask(
"photocal", schema=self.
schema1)
353 field = item.getField()
354 name = field.getName()
355 if count > beginInitial
and count <= endInitial:
356 name =
"initial" + separator + name
357 self.schemaMapper.addMapping(item.key, name)
360 schema = self.schemaMapper.editOutputSchema()
361 self.makeSubtask(
"measurement", schema=schema, algMetadata=self.
algMetadata)
364 self.
schema = self.schemaMapper.getOutputSchema()
368 Return a sequence of schema keys that represent fields that should be propagated from
369 icSrc to src by ProcessCcdTask.
371 if self.config.doPsf:
372 return (self.measurePsf.candidateKey, self.measurePsf.usedKey)
377 def run(self, exposure, defects=None, idFactory=None):
378 """!Run the calibration task on an exposure
380 \param[in,out] exposure Exposure to calibrate; measured PSF will be installed there as well
381 \param[in] defects List of defects on exposure
382 \param[in] idFactory afw.table.IdFactory to use for source catalog.
383 \return a pipeBase.Struct with fields:
384 - exposure: Repaired exposure
385 - backgrounds: A list of background models applied in the calibration phase
386 - psf: Point spread function
387 - sources: Sources used in calibration
388 - matches: Astrometric matches
389 - matchMeta: Metadata for astrometric matches
390 - photocal: Output of photocal subtask
392 It is moderately important to provide a decent initial guess for the seeing if you want to
393 deal with cosmic rays. If there's a PSF in the exposure it'll be used; failing that the
394 CalibrateConfig.initialPsf is consulted (although the pixel scale will be taken from the
397 If the exposure contains an lsst.afw.image.Calib object with the exposure time set, MAGZERO
398 will be set in the task metadata.
400 assert exposure
is not None,
"No exposure provided"
402 if not exposure.hasPsf():
404 if idFactory
is None:
405 idFactory = afwTable.IdFactory.makeSimple()
406 backgrounds = afwMath.BackgroundList()
408 self.repair.run(exposure, defects=defects, keepCRs=keepCRs)
409 self.display(
'repair', exposure=exposure)
410 if self.config.doBackground:
411 with self.timer(
"background"):
412 bg, exposure = measAlg.estimateBackground(exposure, self.config.background, subtract=
True)
413 backgrounds.append(bg)
414 self.display(
'background', exposure=exposure)
417 table1 = afwTable.SourceTable.make(self.
schema1, idFactory)
419 detRet = self.detection.makeSourceCatalog(table1, exposure)
420 sources1 = detRet.sources
423 if detRet.fpSets.background:
424 backgrounds.append(detRet.fpSets.background)
428 self.initialMeasurement.measure(exposure, sources1)
430 if self.config.doPsf:
431 if self.config.doAstrometry:
432 astromRet = self.astrometry.run(exposure, sources1)
433 matches = astromRet.matches
438 psfRet = self.measurePsf.run(exposure, sources1, matches=matches)
440 elif exposure.hasPsf():
441 psf = exposure.getPsf()
447 if self.config.doPsf:
448 self.repair.run(exposure, defects=defects, keepCRs=
None)
449 self.display(
'PSF_repair', exposure=exposure)
451 if self.config.doBackground:
455 with self.timer(
"background"):
457 bg, exposure = measAlg.estimateBackground(
458 exposure, self.config.background, subtract=
True,
459 statsKeys=(
'BGMEAN2',
'BGVAR2'))
460 self.log.info(
"Fit and subtracted background")
461 backgrounds.append(bg)
463 self.display(
'PSF_background', exposure=exposure)
467 table2 = afwTable.SourceTable.make(self.
schema, idFactory)
473 self.measurement.run(exposure, sources)
475 if self.config.doAstrometry:
476 astromRet = self.astrometry.run(exposure, sources)
477 matches = astromRet.matches
478 matchMeta = astromRet.matchMeta
480 matches, matchMeta =
None,
None
482 if self.config.doPhotoCal:
483 assert(matches
is not None)
485 photocalRet = self.photocal.run(exposure, matches)
488 self.log.warn(
"Failed to determine photometric zero-point: %s" % e)
490 self.metadata.set(
'MAGZERO', float(
"NaN"))
493 self.log.info(
"Photometric zero-point: %f" % photocalRet.calib.getMagnitude(1.0))
494 exposure.getCalib().setFluxMag0(photocalRet.calib.getFluxMag0())
495 metadata = exposure.getMetadata()
498 magZero = photocalRet.zp - 2.5 * math.log10(exposure.getCalib().getExptime() )
499 metadata.set(
'MAGZERO', magZero)
501 self.log.warn(
"Could not set normalized MAGZERO in header: no exposure time")
502 metadata.set(
'MAGZERO_RMS', photocalRet.sigma)
503 metadata.set(
'MAGZERO_NOBJ', photocalRet.ngood)
504 metadata.set(
'COLORTERM1', 0.0)
505 metadata.set(
'COLORTERM2', 0.0)
506 metadata.set(
'COLORTERM3', 0.0)
509 self.display(
'calibrate', exposure=exposure, sources=sources, matches=matches)
510 return pipeBase.Struct(
512 backgrounds = backgrounds,
516 matchMeta = matchMeta,
517 photocal = photocalRet,
521 """!Initialise the calibration procedure by setting the PSF to a configuration-defined guess.
523 \param[in,out] exposure Exposure to process; fake PSF will be installed here.
524 \throws AssertionError If exposure or exposure.getWcs() are None
526 assert exposure,
"No exposure provided"
528 wcs = exposure.getWcs()
530 pixelScale = wcs.pixelScale().asArcseconds()
532 pixelScale = self.config.initialPsf.pixelScale
534 cls = getattr(measAlg, self.config.initialPsf.model +
"Psf")
536 fwhm = self.config.initialPsf.fwhm/pixelScale
537 size = self.config.initialPsf.size
538 self.log.info(
"installInitialPsf fwhm=%s pixels; size=%s pixels" % (fwhm, size))
539 psf = cls(size, size, fwhm/(2*math.sqrt(2*math.log(2))))
def __init__
Create the calibration task.
def getCalibKeys
Return a sequence of schema keys that represent fields that should be propagated from icSrc to src by...
Class for storing ordered metadata with comments.
A mapping between the keys of two Schemas, used to copy data between them.
Describes the initial PSF used for detection and measurement before we do PSF determination.
def installInitialPsf
Initialise the calibration procedure by setting the PSF to a configuration-defined guess...
Custom catalog class for record/table subclasses that are guaranteed to have an ID, and should generally be sorted by that ID.
def run
Run the calibration task on an exposure.
Calibrate an exposure: measure PSF, subtract background, measure astrometry and photometry.