33 from .astrometry
import AstrometryTask
34 from .repair
import RepairTask
35 from .measurePsf
import MeasurePsfTask
38 """!Describes the initial PSF used for detection and measurement before we do PSF determination."""
40 model = pexConfig.ChoiceField(
42 doc =
"PSF model type",
43 default =
"SingleGaussian",
45 "SingleGaussian":
"Single Gaussian model",
46 "DoubleGaussian":
"Double Gaussian model",
49 pixelScale = pexConfig.Field(
51 doc =
"Pixel size (arcsec). Only needed if no Wcs is provided",
54 fwhm = pexConfig.Field(
56 doc =
"FWHM of PSF model (arcsec)",
59 size = pexConfig.Field(
61 doc =
"Size of PSF model (pixels)",
66 initialPsf = pexConfig.ConfigField(dtype=InitialPsfConfig, doc=InitialPsfConfig.__doc__)
67 doBackground = pexConfig.Field(
69 doc =
"Subtract background (after computing it, if not supplied)?",
72 doPsf = pexConfig.Field(
74 doc =
"Perform PSF fitting?",
77 doAstrometry = pexConfig.Field(
79 doc =
"Compute astrometric solution?",
82 doPhotoCal = pexConfig.Field(
84 doc =
"Compute photometric zeropoint?",
87 background = pexConfig.ConfigField(
88 dtype = measAlg.estimateBackground.ConfigClass,
89 doc =
"Background estimation configuration"
91 repair = pexConfig.ConfigurableField(target = RepairTask, doc =
"")
92 detection = pexConfig.ConfigurableField(
93 target = measAlg.SourceDetectionTask,
94 doc =
"Initial (high-threshold) detection phase for calibration",
96 initialMeasurement = pexConfig.ConfigurableField(
97 target = lsst.meas.base.SingleFrameMeasurementTask,
98 doc =
"Initial measurements used to feed PSF determination and aperture correction determination",
100 measurePsf = pexConfig.ConfigurableField(target = MeasurePsfTask, doc =
"")
101 measurement = pexConfig.ConfigurableField(
102 target = lsst.meas.base.SingleFrameMeasurementTask,
103 doc =
"Post-PSF-determination measurements used to feed other calibrations",
105 astrometry = pexConfig.ConfigurableField(target = AstrometryTask, doc =
"")
106 photocal = pexConfig.ConfigurableField(target = PhotoCalTask, doc=
"")
109 pexConfig.Config.validate(self)
111 raise ValueError(
"Cannot do photometric calibration without doing astrometric matching")
112 if self.measurement.target.tableVersion != self.initialMeasurement.target.tableVersion:
113 raise ValueError(
"measurement and initialMeasurement subtasks must have the same tableVersion")
116 self.detection.includeThresholdMultiplier = 10.0
117 self.initialMeasurement.algorithms.names -= [
"correctfluxes",
"classification.extendedness"]
118 initflags = [x
for x
in self.measurePsf.starSelector[
"catalog"].badStarPixelFlags]
119 self.measurePsf.starSelector[
"catalog"].badStarPixelFlags.extend(initflags)
120 self.background.binSize = 1024
131 \anchor CalibrateTask_
133 \brief Calibrate an exposure: measure PSF, subtract background, measure astrometry and photometry
135 \section pipe_tasks_calibrate_Contents Contents
137 - \ref pipe_tasks_calibrate_Purpose
138 - \ref pipe_tasks_calibrate_Initialize
139 - \ref pipe_tasks_calibrate_IO
140 - \ref pipe_tasks_calibrate_Config
141 - \ref pipe_tasks_calibrate_Metadata
142 - \ref pipe_tasks_calibrate_Debug
143 - \ref pipe_tasks_calibrate_Example
145 \section pipe_tasks_calibrate_Purpose Description
147 \copybrief CalibrateTask
149 Calculate an Exposure's zero-point given a set of flux measurements of stars matched to an input catalogue.
150 The type of flux to use is specified by CalibrateConfig.fluxField.
152 The algorithm clips outliers iteratively, with parameters set in the configuration.
154 \note This task can adds fields to the schema, so any code calling this task must ensure that
155 these columns are indeed present in the input match list; see \ref pipe_tasks_calibrate_Example
157 \section pipe_tasks_calibrate_Initialize Task initialisation
159 \copydoc \_\_init\_\_
161 CalibrateTask delegates most of its work to a set of sub-Tasks:
163 <DT> repair \ref RepairTask_ "RepairTask"
164 <DD> Interpolate over defects such as bad columns and cosmic rays. This task is called twice; once
165 before the %measurePsf step and again after the PSF has been measured.
166 <DT> detection \ref SourceDetectionTask_ "SourceDetectionTask"
167 <DD> Initial (high-threshold) detection phase for calibration
168 <DT> initialMeasurement \ref SourceMeasurementTask_ "SourceMeasurementTask"
169 <DD> Make the initial measurements used to feed PSF determination and aperture correction determination
170 <DT> astrometry \ref AstrometryTask_ "AstrometryTask"
171 <DD> Solve the astrometry. May be disabled by setting CalibrateTaskConfig.doAstrometry to be False.
172 This task is called twice; once before the %measurePsf step and again after the PSF has been measured.
173 <DT> %measurePsf \ref MeasurePsfTask_ "MeasurePsfTask"
174 <DD> Estimate the PSF. May be disabled by setting CalibrateTaskConfig.doPsf to be False. If requested
175 the astrometry is solved before this is called, so if you disable the astrometry the %measurePsf
176 task won't have access to objects positions.
177 <DT> measurement \ref SourceMeasurementTask_ "SourceMeasurementTask"
178 <DD> Post-PSF-determination measurements used to feed other calibrations
179 <DT> photocal \ref PhotoCalTask_ "PhotoCalTask"
180 <DD> Solve for the photometric zeropoint.
181 May be disabled by setting CalibrateTaskConfig.doPhotoCal to be False.
182 \em N.b. Requires that \c astrometry was successfully run.
185 You can replace any of these subtasks if you wish, see \ref calibrate_MyAstrometryTask.
186 \note These task APIs are not well controlled, so replacing a task is a matter of matching
187 a poorly specified interface. We will be working on this over the first year of construction.
189 \section pipe_tasks_calibrate_IO Invoking the Task
193 \section pipe_tasks_calibrate_Config Configuration parameters
195 See \ref CalibrateConfig
197 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
199 \section pipe_tasks_calibrate_Metadata Quantities set in Metadata
205 <DT> MAGZERO <DD> Measured zeropoint (DN per second)
208 <DT> Exposure metadata
211 <DT> MAGZERO_RMS <DD> MAGZERO's RMS == return.sigma
212 <DT> MAGZERO_NOBJ <DD> Number of stars used == return.ngood
213 <DT> COLORTERM1 <DD> ?? (always 0.0)
214 <DT> COLORTERM2 <DD> ?? (always 0.0)
215 <DT> COLORTERM3 <DD> ?? (always 0.0)
219 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
221 \section pipe_tasks_calibrate_Debug Debug variables
223 The \link lsst.pipe.base.cmdLineTask.CmdLineTask command line task\endlink interface supports a
224 flag \c -d to import \b debug.py from your \c PYTHONPATH; see \ref baseDebug for more about \b debug.py files.
226 The calibrate task has a debug dictionary with keys which correspond to stages of the CalibrationTask
230 <DD> Fixed defects and masked cosmic rays with a guessed PSF. Action: show the exposure.
232 <DD> Subtracted background (no sources masked). Action: show the exposure
234 <DD> Fixed defects and removed cosmic rays with an estimated PSF. Action: show the exposure
236 <DD> Subtracted background (calibration sources masked). Action: show the exposure
238 <DD> Just before astro/photo calibration. Action: show the exposure, and
239 - sources as smallish green o
240 - matches (if exposure has a Wcs).
241 - catalog position as a largish yellow +
242 - source position as a largish red x
244 The values are the \c ds9 frame to display in (if >= 1); if <= 0, nothing's displayed.
245 There's an example \ref pipe_tasks_calibrate_Debug_example "here".
247 Some subtasks may also have their own debug information; see individual Task documentation.
249 \section pipe_tasks_calibrate_Example A complete example of using CalibrateTask
251 This code is in \link calibrateTask.py\endlink in the examples directory, and can be run as \em e.g.
253 examples/calibrateTask.py --ds9
255 \dontinclude calibrateTask.py
257 Import the task (there are some other standard imports; read the file if you're curious)
258 \skipline CalibrateTask
260 Create the detection task
261 \skip CalibrateTask.ConfigClass
263 Note that we're using a custom AstrometryTask (because we don't have a valid astrometric catalogue handy);
264 see \ref calibrate_MyAstrometryTask.
266 We're now ready to process the data (we could loop over multiple exposures/catalogues using the same
267 task objects) and unpack the results
271 We then might plot the results (\em e.g. if you set \c --ds9 on the command line)
275 \subsection calibrate_MyAstrometryTask Using a Custom Astrometry Task
277 The first thing to do is define my own task:
278 \dontinclude calibrateTask.py
279 \skip MyAstrometryTask
280 \skip MyAstrometryTask
283 Then we need our own \c run method. First unpack the filtername and wcs
286 Then build a "reference catalog" by shamelessly copying the catalog of detected sources
288 \until get("photometric")
289 (you need to set "flux" as well as \c filterName due to a bug in the photometric calibration code;
290 <A HREF=https://jira.lsstcorp.org/browse/DM-933>DM-933</A>).
292 Then "match" by zipping up the two catalogs,
295 and finally return the desired results.
300 \anchor pipe_tasks_calibrate_Debug_example
301 To investigate the \ref pipe_tasks_calibrate_Debug, put something like
305 di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively
306 if name == "lsst.pipe.tasks.calibrate":
314 lsstDebug.Info = DebugInfo
316 into your debug.py file and run calibrateTask.py with the \c --debug flag.
318 ConfigClass = CalibrateConfig
319 _DefaultName =
"calibrate"
323 Create the calibration task
325 \param **kwargs keyword arguments to be passed to lsst.pipe.base.task.Task.__init__
327 pipeBase.Task.__init__(self, **kwargs)
333 self.
schema1 = afwTable.SourceTable.makeMinimalSchema()
334 minimalCount = self.schema1.getFieldCount()
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)
356 field = item.getField()
357 name = field.getName()
358 if count > beginInitial
and count <= endInitial:
359 name =
"initial" + separator + name
360 self.schemaMapper.addMapping(item.key, name)
363 schema = self.schemaMapper.editOutputSchema()
364 self.makeSubtask(
"measurement", schema=schema, algMetadata=self.
algMetadata)
367 self.
schema = self.schemaMapper.getOutputSchema()
371 Return a sequence of schema keys that represent fields that should be propagated from
372 icSrc to src by ProcessCcdTask.
374 if self.config.doPsf:
375 return (self.measurePsf.candidateKey, self.measurePsf.usedKey)
380 def run(self, exposure, defects=None, idFactory=None):
381 """!Run the calibration task on an exposure
383 \param[in,out] exposure Exposure to calibrate; measured PSF will be installed there as well
384 \param[in] defects List of defects on exposure
385 \param[in] idFactory afw.table.IdFactory to use for source catalog.
386 \return a pipeBase.Struct with fields:
387 - exposure: Repaired exposure
388 - backgrounds: A list of background models applied in the calibration phase
389 - psf: Point spread function
390 - sources: Sources used in calibration
391 - matches: Astrometric matches
392 - matchMeta: Metadata for astrometric matches
393 - photocal: Output of photocal subtask
395 It is moderately important to provide a decent initial guess for the seeing if you want to
396 deal with cosmic rays. If there's a PSF in the exposure it'll be used; failing that the
397 CalibrateConfig.initialPsf is consulted (although the pixel scale will be taken from the
400 If the exposure contains an lsst.afw.image.Calib object with the exposure time set, MAGZERO
401 will be set in the task metadata.
403 assert exposure
is not None,
"No exposure provided"
405 if not exposure.hasPsf():
407 if idFactory
is None:
408 idFactory = afwTable.IdFactory.makeSimple()
409 backgrounds = afwMath.BackgroundList()
411 self.repair.run(exposure, defects=defects, keepCRs=keepCRs)
412 self.display(
'repair', exposure=exposure)
413 if self.config.doBackground:
414 with self.timer(
"background"):
415 bg, exposure = measAlg.estimateBackground(exposure, self.config.background, subtract=
True)
416 backgrounds.append(bg)
417 self.display(
'background', exposure=exposure)
420 table1 = afwTable.SourceTable.make(self.
schema1, idFactory)
422 detRet = self.detection.makeSourceCatalog(table1, exposure)
423 sources1 = detRet.sources
426 if detRet.fpSets.background:
427 backgrounds.append(detRet.fpSets.background)
431 self.initialMeasurement.measure(exposure, sources1)
433 if self.config.doPsf:
434 if self.config.doAstrometry:
435 astromRet = self.astrometry.run(exposure, sources1)
436 matches = astromRet.matches
441 psfRet = self.measurePsf.run(exposure, sources1, matches=matches)
442 cellSet = psfRet.cellSet
444 elif exposure.hasPsf():
445 psf = exposure.getPsf()
448 psf, cellSet =
None,
None
452 if self.config.doPsf:
453 self.repair.run(exposure, defects=defects, keepCRs=
None)
454 self.display(
'PSF_repair', exposure=exposure)
456 if self.config.doBackground:
460 with self.timer(
"background"):
462 bg, exposure = measAlg.estimateBackground(
463 exposure, self.config.background, subtract=
True,
464 statsKeys=(
'BGMEAN2',
'BGVAR2'))
465 self.log.info(
"Fit and subtracted background")
466 backgrounds.append(bg)
468 self.display(
'PSF_background', exposure=exposure)
472 table2 = afwTable.SourceTable.make(self.
schema, idFactory)
478 self.measurement.run(exposure, sources)
480 if self.config.doAstrometry:
481 astromRet = self.astrometry.run(exposure, sources)
482 matches = astromRet.matches
483 matchMeta = astromRet.matchMeta
485 matches, matchMeta =
None,
None
487 if self.config.doPhotoCal:
488 assert(matches
is not None)
490 photocalRet = self.photocal.run(exposure, matches)
493 self.log.warn(
"Failed to determine photometric zero-point: %s" % e)
495 self.metadata.set(
'MAGZERO', float(
"NaN"))
498 self.log.info(
"Photometric zero-point: %f" % photocalRet.calib.getMagnitude(1.0))
499 exposure.getCalib().setFluxMag0(photocalRet.calib.getFluxMag0())
500 metadata = exposure.getMetadata()
503 magZero = photocalRet.zp - 2.5 * math.log10(exposure.getCalib().getExptime() )
504 metadata.set(
'MAGZERO', magZero)
506 self.log.warn(
"Could not set normalized MAGZERO in header: no exposure time")
507 metadata.set(
'MAGZERO_RMS', photocalRet.sigma)
508 metadata.set(
'MAGZERO_NOBJ', photocalRet.ngood)
509 metadata.set(
'COLORTERM1', 0.0)
510 metadata.set(
'COLORTERM2', 0.0)
511 metadata.set(
'COLORTERM3', 0.0)
514 self.display(
'calibrate', exposure=exposure, sources=sources, matches=matches)
515 return pipeBase.Struct(
517 backgrounds = backgrounds,
521 matchMeta = matchMeta,
522 photocal = photocalRet,
526 """!Initialise the calibration procedure by setting the PSF to a configuration-defined guess.
528 \param[in,out] exposure Exposure to process; fake PSF will be installed here.
529 \throws AssertionError If exposure or exposure.getWcs() are None
531 assert exposure,
"No exposure provided"
533 wcs = exposure.getWcs()
535 pixelScale = wcs.pixelScale().asArcseconds()
537 pixelScale = self.config.initialPsf.pixelScale
539 cls = getattr(measAlg, self.config.initialPsf.model +
"Psf")
541 fwhm = self.config.initialPsf.fwhm/pixelScale
542 size = self.config.initialPsf.size
543 self.log.info(
"installInitialPsf fwhm=%s pixels; size=%s pixels" % (fwhm, size))
544 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.