24from lsstDebug
import getDebugFrame
27import lsst.pipe.base.connectionTypes
as cT
29from lsst.meas.astrom import AstrometryTask, displayAstrometry, denormalizeMatches
31from lsst.obs.base
import ExposureIdInfo
38 CatalogCalculationTask)
40from lsst.utils.timer
import timeMethod
42from .fakes
import BaseFakeSourcesTask
43from .photoCal
import PhotoCalTask
44from .computeExposureSummaryStats
import ComputeExposureSummaryStatsTask
47__all__ = [
"CalibrateConfig",
"CalibrateTask"]
50class CalibrateConnections(pipeBase.PipelineTaskConnections, dimensions=(
"instrument",
"visit",
"detector"),
53 icSourceSchema = cT.InitInput(
54 doc=
"Schema produced by characterize image task, used to initialize this task",
56 storageClass=
"SourceCatalog",
59 outputSchema = cT.InitOutput(
60 doc=
"Schema after CalibrateTask has been initialized",
62 storageClass=
"SourceCatalog",
66 doc=
"Input image to calibrate",
68 storageClass=
"ExposureF",
69 dimensions=(
"instrument",
"visit",
"detector"),
72 background = cT.Input(
73 doc=
"Backgrounds determined by characterize task",
74 name=
"icExpBackground",
75 storageClass=
"Background",
76 dimensions=(
"instrument",
"visit",
"detector"),
79 icSourceCat = cT.Input(
80 doc=
"Source catalog created by characterize task",
82 storageClass=
"SourceCatalog",
83 dimensions=(
"instrument",
"visit",
"detector"),
86 astromRefCat = cT.PrerequisiteInput(
87 doc=
"Reference catalog to use for astrometry",
89 storageClass=
"SimpleCatalog",
90 dimensions=(
"skypix",),
95 photoRefCat = cT.PrerequisiteInput(
96 doc=
"Reference catalog to use for photometric calibration",
98 storageClass=
"SimpleCatalog",
99 dimensions=(
"skypix",),
104 outputExposure = cT.Output(
105 doc=
"Exposure after running calibration task",
107 storageClass=
"ExposureF",
108 dimensions=(
"instrument",
"visit",
"detector"),
111 outputCat = cT.Output(
112 doc=
"Source catalog produced in calibrate task",
114 storageClass=
"SourceCatalog",
115 dimensions=(
"instrument",
"visit",
"detector"),
118 outputBackground = cT.Output(
119 doc=
"Background models estimated in calibration task",
120 name=
"calexpBackground",
121 storageClass=
"Background",
122 dimensions=(
"instrument",
"visit",
"detector"),
126 doc=
"Source/refObj matches from the astrometry solver",
128 storageClass=
"Catalog",
129 dimensions=(
"instrument",
"visit",
"detector"),
132 matchesDenormalized = cT.Output(
133 doc=
"Denormalized matches from astrometry solver",
135 storageClass=
"Catalog",
136 dimensions=(
"instrument",
"visit",
"detector"),
142 if config.doAstrometry
is False:
143 self.prerequisiteInputs.remove(
"astromRefCat")
144 if config.doPhotoCal
is False:
145 self.prerequisiteInputs.remove(
"photoRefCat")
147 if config.doWriteMatches
is False or config.doAstrometry
is False:
148 self.outputs.remove(
"matches")
149 if config.doWriteMatchesDenormalized
is False or config.doAstrometry
is False:
150 self.outputs.remove(
"matchesDenormalized")
153class CalibrateConfig(pipeBase.PipelineTaskConfig, pipelineConnections=CalibrateConnections):
154 """Config for CalibrateTask"""
155 doWrite = pexConfig.Field(
158 doc=
"Save calibration results?",
160 doWriteHeavyFootprintsInSources = pexConfig.Field(
163 doc=
"Include HeavyFootprint data in source table? If false then heavy "
164 "footprints are saved as normal footprints, which saves some space"
166 doWriteMatches = pexConfig.Field(
169 doc=
"Write reference matches (ignored if doWrite or doAstrometry false)?",
171 doWriteMatchesDenormalized = pexConfig.Field(
174 doc=(
"Write reference matches in denormalized format? "
175 "This format uses more disk space, but is more convenient to "
176 "read. Ignored if doWriteMatches=False or doWrite=False."),
178 doAstrometry = pexConfig.Field(
181 doc=
"Perform astrometric calibration?",
183 astromRefObjLoader = pexConfig.ConfigurableField(
184 target=LoadIndexedReferenceObjectsTask,
185 doc=
"reference object loader for astrometric calibration",
187 photoRefObjLoader = pexConfig.ConfigurableField(
188 target=LoadIndexedReferenceObjectsTask,
189 doc=
"reference object loader for photometric calibration",
191 astrometry = pexConfig.ConfigurableField(
192 target=AstrometryTask,
193 doc=
"Perform astrometric calibration to refine the WCS",
195 requireAstrometry = pexConfig.Field(
198 doc=(
"Raise an exception if astrometry fails? Ignored if doAstrometry "
201 doPhotoCal = pexConfig.Field(
204 doc=
"Perform phometric calibration?",
206 requirePhotoCal = pexConfig.Field(
209 doc=(
"Raise an exception if photoCal fails? Ignored if doPhotoCal "
212 photoCal = pexConfig.ConfigurableField(
214 doc=
"Perform photometric calibration",
216 icSourceFieldsToCopy = pexConfig.ListField(
218 default=(
"calib_psf_candidate",
"calib_psf_used",
"calib_psf_reserved"),
219 doc=(
"Fields to copy from the icSource catalog to the output catalog "
220 "for matching sources Any missing fields will trigger a "
221 "RuntimeError exception. Ignored if icSourceCat is not provided.")
223 matchRadiusPix = pexConfig.Field(
226 doc=(
"Match radius for matching icSourceCat objects to sourceCat "
229 checkUnitsParseStrict = pexConfig.Field(
230 doc=(
"Strictness of Astropy unit compatibility check, can be 'raise', "
231 "'warn' or 'silent'"),
235 detection = pexConfig.ConfigurableField(
236 target=SourceDetectionTask,
239 doDeblend = pexConfig.Field(
242 doc=
"Run deblender input exposure"
244 deblend = pexConfig.ConfigurableField(
245 target=SourceDeblendTask,
246 doc=
"Split blended sources into their components"
248 doSkySources = pexConfig.Field(
251 doc=
"Generate sky sources?",
253 skySources = pexConfig.ConfigurableField(
254 target=SkyObjectsTask,
255 doc=
"Generate sky sources",
257 measurement = pexConfig.ConfigurableField(
258 target=SingleFrameMeasurementTask,
259 doc=
"Measure sources"
261 postCalibrationMeasurement = pexConfig.ConfigurableField(
262 target=SingleFrameMeasurementTask,
263 doc=
"Second round of measurement for plugins that need to be run after photocal"
265 setPrimaryFlags = pexConfig.ConfigurableField(
266 target=SetPrimaryFlagsTask,
267 doc=(
"Set flags for primary source classification in single frame "
268 "processing. True if sources are not sky sources and not a parent.")
270 doApCorr = pexConfig.Field(
273 doc=
"Run subtask to apply aperture correction"
275 applyApCorr = pexConfig.ConfigurableField(
276 target=ApplyApCorrTask,
277 doc=
"Subtask to apply aperture corrections"
282 catalogCalculation = pexConfig.ConfigurableField(
283 target=CatalogCalculationTask,
284 doc=
"Subtask to run catalogCalculation plugins on catalog"
286 doInsertFakes = pexConfig.Field(
289 doc=
"Run fake sources injection task",
290 deprecated=(
"doInsertFakes is no longer supported. This config will be removed after v24. "
291 "Please use ProcessCcdWithFakesTask instead.")
293 insertFakes = pexConfig.ConfigurableField(
294 target=BaseFakeSourcesTask,
295 doc=
"Injection of fake sources for testing purposes (must be "
297 deprecated=(
"insertFakes is no longer supported. This config will be removed after v24. "
298 "Please use ProcessCcdWithFakesTask instead.")
300 doComputeSummaryStats = pexConfig.Field(
303 doc=
"Run subtask to measure exposure summary statistics?"
305 computeSummaryStats = pexConfig.ConfigurableField(
306 target=ComputeExposureSummaryStatsTask,
307 doc=
"Subtask to run computeSummaryStats on exposure"
309 doWriteExposure = pexConfig.Field(
312 doc=
"Write the calexp? If fakes have been added then we do not want to write out the calexp as a "
313 "normal calexp but as a fakes_calexp."
318 self.
detectiondetection.doTempLocalBackground =
False
319 self.
deblenddeblend.maxFootprintSize = 2000
327 astromRefCatGen2 = getattr(self.
astromRefObjLoaderastromRefObjLoader,
"ref_dataset_name",
None)
328 if astromRefCatGen2
is not None and astromRefCatGen2 != self.connections.astromRefCat:
330 f
"Gen2 ({astromRefCatGen2}) and Gen3 ({self.connections.astromRefCat}) astrometry reference "
331 f
"catalogs are different. These options must be kept in sync until Gen2 is retired."
333 photoRefCatGen2 = getattr(self.
photoRefObjLoaderphotoRefObjLoader,
"ref_dataset_name",
None)
334 if photoRefCatGen2
is not None and photoRefCatGen2 != self.connections.photoRefCat:
336 f
"Gen2 ({photoRefCatGen2}) and Gen3 ({self.connections.photoRefCat}) photometry reference "
337 f
"catalogs are different. These options must be kept in sync until Gen2 is retired."
349 r"""!Calibrate an exposure: measure sources and perform astrometric and
350 photometric calibration
352 @anchor CalibrateTask_
354 @section pipe_tasks_calibrate_Contents Contents
356 -
@ref pipe_tasks_calibrate_Purpose
357 -
@ref pipe_tasks_calibrate_Initialize
358 -
@ref pipe_tasks_calibrate_IO
359 -
@ref pipe_tasks_calibrate_Config
360 -
@ref pipe_tasks_calibrate_Metadata
361 -
@ref pipe_tasks_calibrate_Debug
363 @section pipe_tasks_calibrate_Purpose Description
365 Given an exposure
with a good PSF model
and aperture correction map
366 (e.g.
as provided by
@ref characterizeImage::CharacterizeImageTask
"CharacterizeImageTask"),
367 perform the following operations:
368 - Run detection
and measurement
369 - Run astrometry subtask to fit an improved WCS
370 - Run photoCal subtask to fit the exposure
's photometric zero-point
372 @section pipe_tasks_calibrate_Initialize Task initialisation
374 @copydoc \_\_init\_\_
376 @section pipe_tasks_calibrate_IO Invoking the Task
378 If you want this task to unpersist inputs
or persist outputs, then call
379 the `runDataRef` method (a wrapper around the `run` method).
381 If you already have the inputs unpersisted
and do
not want to persist the
382 output then it
is more direct to call the `run` method:
384 @section pipe_tasks_calibrate_Config Configuration parameters
386 See
@ref CalibrateConfig
388 @section pipe_tasks_calibrate_Metadata Quantities set
in exposure Metadata
392 <dt>MAGZERO_RMS <dd>MAGZERO
's RMS == sigma reported by photoCal task
393 <dt>MAGZERO_NOBJ <dd>Number of stars used == ngood reported by photoCal
395 <dt>COLORTERM1 <dd>?? (always 0.0)
396 <dt>COLORTERM2 <dd>?? (always 0.0)
397 <dt>COLORTERM3 <dd>?? (always 0.0)
400 @section pipe_tasks_calibrate_Debug Debug variables
402 The command line task
403 interface supports a flag
404 `--debug` to
import `debug.py`
from your `$PYTHONPATH`; see
405 <a href=
"https://pipelines.lsst.io/modules/lsstDebug/">the lsstDebug documentation</a>
406 for more about `debug.py`.
408 CalibrateTask has a debug dictionary containing one key:
411 <dd>frame (an int; <= 0 to
not display)
in which to display the exposure,
412 sources
and matches. See
@ref lsst.meas.astrom.displayAstrometry
for
413 the meaning of the various symbols.
416 For example, put something like:
422 if name ==
"lsst.pipe.tasks.calibrate":
431 into your `debug.py` file
and run `calibrateTask.py`
with the `--debug`
434 Some subtasks may have their own debug variables; see individual Task
441 ConfigClass = CalibrateConfig
442 _DefaultName =
"calibrate"
443 RunnerClass = pipeBase.ButlerInitializedTaskRunner
445 def __init__(self, butler=None, astromRefObjLoader=None,
446 photoRefObjLoader=None, icSourceSchema=None,
447 initInputs=None, **kwargs):
448 """!Construct a CalibrateTask
450 @param[
in] butler The butler
is passed to the refObjLoader constructor
451 in case it
is needed. Ignored
if the refObjLoader argument
452 provides a loader directly.
453 @param[
in] astromRefObjLoader An instance of LoadReferenceObjectsTasks
454 that supplies an external reference catalog
for astrometric
455 calibration. May be
None if the desired loader can be constructed
456 from the butler argument
or all steps requiring a reference catalog
458 @param[
in] photoRefObjLoader An instance of LoadReferenceObjectsTasks
459 that supplies an external reference catalog
for photometric
460 calibration. May be
None if the desired loader can be constructed
461 from the butler argument
or all steps requiring a reference catalog
463 @param[
in] icSourceSchema schema
for icSource catalog,
or None.
464 Schema values specified
in config.icSourceFieldsToCopy will be
465 taken
from this schema. If set to
None, no values will be
466 propagated
from the icSourceCatalog
467 @param[
in,out] kwargs other keyword arguments
for
468 lsst.pipe.base.CmdLineTask
472 if icSourceSchema
is None and butler
is not None:
474 icSourceSchema = butler.get(
"icSrc_schema", immediate=
True).schema
476 if icSourceSchema
is None and butler
is None and initInputs
is not None:
477 icSourceSchema = initInputs[
'icSourceSchema'].schema
479 if icSourceSchema
is not None:
482 minimumSchema = afwTable.SourceTable.makeMinimalSchema()
483 self.
schemaMapperschemaMapper.addMinimalSchema(minimumSchema,
False)
491 afwTable.Field[
"Flag"](
"calib_detected",
492 "Source was detected as an icSource"))
493 missingFieldNames = []
494 for fieldName
in self.config.icSourceFieldsToCopy:
496 schemaItem = icSourceSchema.find(fieldName)
498 missingFieldNames.append(fieldName)
501 self.
schemaMapperschemaMapper.addMapping(schemaItem.getKey())
503 if missingFieldNames:
504 raise RuntimeError(
"isSourceCat is missing fields {} "
505 "specified in icSourceFieldsToCopy"
506 .format(missingFieldNames))
513 self.
schemaschema = afwTable.SourceTable.makeMinimalSchema()
514 self.makeSubtask(
'detection', schema=self.
schemaschema)
518 if self.config.doDeblend:
519 self.makeSubtask(
"deblend", schema=self.
schemaschema)
520 if self.config.doSkySources:
521 self.makeSubtask(
"skySources")
522 self.
skySourceKeyskySourceKey = self.
schemaschema.addField(
"sky_source", type=
"Flag", doc=
"Sky objects.")
523 self.makeSubtask(
'measurement', schema=self.
schemaschema,
525 self.makeSubtask(
'postCalibrationMeasurement', schema=self.
schemaschema,
527 self.makeSubtask(
"setPrimaryFlags", schema=self.
schemaschema, isSingleFrame=
True)
528 if self.config.doApCorr:
529 self.makeSubtask(
'applyApCorr', schema=self.
schemaschema)
530 self.makeSubtask(
'catalogCalculation', schema=self.
schemaschema)
532 if self.config.doAstrometry:
533 if astromRefObjLoader
is None and butler
is not None:
534 self.makeSubtask(
'astromRefObjLoader', butler=butler)
535 astromRefObjLoader = self.astromRefObjLoader
536 self.makeSubtask(
"astrometry", refObjLoader=astromRefObjLoader,
538 if self.config.doPhotoCal:
539 if photoRefObjLoader
is None and butler
is not None:
540 self.makeSubtask(
'photoRefObjLoader', butler=butler)
541 photoRefObjLoader = self.photoRefObjLoader
542 self.makeSubtask(
"photoCal", refObjLoader=photoRefObjLoader,
544 if self.config.doComputeSummaryStats:
545 self.makeSubtask(
'computeSummaryStats')
547 if initInputs
is not None and (astromRefObjLoader
is not None or photoRefObjLoader
is not None):
548 raise RuntimeError(
"PipelineTask form of this task should not be initialized with "
549 "reference object loaders.")
554 self.
schemaschema.checkUnits(parse_strict=self.config.checkUnitsParseStrict)
556 sourceCatSchema = afwTable.SourceCatalog(self.
schemaschema)
561 def runDataRef(self, dataRef, exposure=None, background=None, icSourceCat=None,
563 """!Calibrate an exposure, optionally unpersisting inputs and
566 This is a wrapper around the `run` method that unpersists inputs
567 (
if `doUnpersist` true)
and persists outputs (
if `config.doWrite` true)
569 @param[
in] dataRef butler data reference corresponding to a science
571 @param[
in,out] exposure characterized exposure (an
572 lsst.afw.image.ExposureF
or similar),
or None to unpersist existing
573 icExp
and icBackground. See `run` method
for details of what
is
575 @param[
in,out] background initial model of background already
576 subtracted
from exposure (an lsst.afw.math.BackgroundList). May be
577 None if no background has been subtracted, though that
is unusual
578 for calibration. A refined background model
is output. Ignored
if
580 @param[
in] icSourceCat catalog
from which to copy the fields specified
581 by icSourceKeys,
or None;
582 @param[
in] doUnpersist unpersist data:
583 -
if True, exposure, background
and icSourceCat are read
from
584 dataRef
and those three arguments must all be
None;
585 -
if False the exposure must be provided; background
and
586 icSourceCat are optional.
True is intended
for running
as a
587 command-line task,
False for running
as a subtask
588 @return same data
as the calibrate method
590 self.log.info("Processing %s", dataRef.dataId)
593 if any(item
is not None for item
in (exposure, background,
595 raise RuntimeError(
"doUnpersist true; exposure, background "
596 "and icSourceCat must all be None")
597 exposure = dataRef.get(
"icExp", immediate=
True)
598 background = dataRef.get(
"icExpBackground", immediate=
True)
599 icSourceCat = dataRef.get(
"icSrc", immediate=
True)
600 elif exposure
is None:
601 raise RuntimeError(
"doUnpersist false; exposure must be provided")
603 exposureIdInfo = dataRef.get(
"expIdInfo")
605 calRes = self.
runrun(
607 exposureIdInfo=exposureIdInfo,
608 background=background,
609 icSourceCat=icSourceCat,
612 if self.config.doWrite:
615 exposure=calRes.exposure,
616 background=calRes.background,
617 sourceCat=calRes.sourceCat,
618 astromMatches=calRes.astromMatches,
619 matchMeta=calRes.matchMeta,
625 inputs = butlerQC.get(inputRefs)
626 inputs[
'exposureIdInfo'] = ExposureIdInfo.fromDataId(butlerQC.quantum.dataId,
"visit_detector")
628 if self.config.doAstrometry:
629 refObjLoader = ReferenceObjectLoader(dataIds=[ref.datasetRef.dataId
630 for ref
in inputRefs.astromRefCat],
631 refCats=inputs.pop(
'astromRefCat'),
632 config=self.config.astromRefObjLoader, log=self.log)
633 self.astrometry.setRefObjLoader(refObjLoader)
635 if self.config.doPhotoCal:
636 photoRefObjLoader = ReferenceObjectLoader(dataIds=[ref.datasetRef.dataId
637 for ref
in inputRefs.photoRefCat],
638 refCats=inputs.pop(
'photoRefCat'),
639 config=self.config.photoRefObjLoader,
641 self.photoCal.match.setRefObjLoader(photoRefObjLoader)
643 outputs = self.
runrun(**inputs)
645 if self.config.doWriteMatches
and self.config.doAstrometry:
646 normalizedMatches = afwTable.packMatches(outputs.astromMatches)
647 normalizedMatches.table.setMetadata(outputs.matchMeta)
648 if self.config.doWriteMatchesDenormalized:
649 denormMatches = denormalizeMatches(outputs.astromMatches, outputs.matchMeta)
650 outputs.matchesDenormalized = denormMatches
651 outputs.matches = normalizedMatches
652 butlerQC.put(outputs, outputRefs)
655 def run(self, exposure, exposureIdInfo=None, background=None,
657 """!Calibrate an exposure (science image or coadd)
659 @param[
in,out] exposure exposure to calibrate (an
660 lsst.afw.image.ExposureF
or similar);
665 - MaskedImage has background subtracted
667 - PhotoCalib
is replaced
668 @param[
in] exposureIdInfo ID info
for exposure (an
669 lsst.obs.base.ExposureIdInfo) If
not provided, returned
670 SourceCatalog IDs will
not be globally unique.
671 @param[
in,out] background background model already subtracted
from
672 exposure (an lsst.afw.math.BackgroundList). May be
None if no
673 background has been subtracted, though that
is unusual
for
674 calibration. A refined background model
is output.
675 @param[
in] icSourceCat A SourceCatalog
from CharacterizeImageTask
676 from which we can copy some fields.
678 @return pipe_base Struct containing these fields:
679 - exposure calibrate science exposure
with refined WCS
and PhotoCalib
680 - background model of background subtracted
from exposure (an
681 lsst.afw.math.BackgroundList)
682 - sourceCat catalog of measured sources
683 - astromMatches list of source/refObj matches
from the astrometry
687 if exposureIdInfo
is None:
688 exposureIdInfo = ExposureIdInfo()
690 if background
is None:
691 background = BackgroundList()
692 sourceIdFactory = exposureIdInfo.makeSourceIdFactory()
693 table = SourceTable.make(self.
schemaschema, sourceIdFactory)
696 detRes = self.detection.
run(table=table, exposure=exposure,
698 sourceCat = detRes.sources
699 if detRes.fpSets.background:
700 for bg
in detRes.fpSets.background:
701 background.append(bg)
702 if self.config.doSkySources:
703 skySourceFootprints = self.skySources.
run(mask=exposure.mask, seed=exposureIdInfo.expId)
704 if skySourceFootprints:
705 for foot
in skySourceFootprints:
706 s = sourceCat.addNew()
709 if self.config.doDeblend:
710 self.deblend.
run(exposure=exposure, sources=sourceCat)
711 self.measurement.
run(
714 exposureId=exposureIdInfo.expId
716 if self.config.doApCorr:
717 self.applyApCorr.
run(
719 apCorrMap=exposure.getInfo().getApCorrMap()
721 self.catalogCalculation.
run(sourceCat)
723 self.setPrimaryFlags.
run(sourceCat)
725 if icSourceCat
is not None and \
726 len(self.config.icSourceFieldsToCopy) > 0:
734 if not sourceCat.isContiguous():
735 sourceCat = sourceCat.copy(deep=
True)
741 if self.config.doAstrometry:
743 astromRes = self.astrometry.
run(
747 astromMatches = astromRes.matches
748 matchMeta = astromRes.matchMeta
749 except Exception
as e:
750 if self.config.requireAstrometry:
752 self.log.warning(
"Unable to perform astrometric calibration "
753 "(%s): attempting to proceed", e)
756 if self.config.doPhotoCal:
758 photoRes = self.photoCal.
run(exposure, sourceCat=sourceCat, expId=exposureIdInfo.expId)
759 exposure.setPhotoCalib(photoRes.photoCalib)
761 self.log.info(
"Photometric zero-point: %f",
762 photoRes.photoCalib.instFluxToMagnitude(1.0))
763 self.
setMetadatasetMetadata(exposure=exposure, photoRes=photoRes)
764 except Exception
as e:
765 if self.config.requirePhotoCal:
767 self.log.warning(
"Unable to perform photometric calibration "
768 "(%s): attempting to proceed", e)
769 self.
setMetadatasetMetadata(exposure=exposure, photoRes=
None)
771 self.postCalibrationMeasurement.
run(
774 exposureId=exposureIdInfo.expId
777 if self.config.doComputeSummaryStats:
778 summary = self.computeSummaryStats.
run(exposure=exposure,
780 background=background)
781 exposure.getInfo().setSummaryStats(summary)
783 frame = getDebugFrame(self._display,
"calibrate")
788 matches=astromMatches,
793 return pipeBase.Struct(
795 background=background,
797 astromMatches=astromMatches,
801 outputExposure=exposure,
803 outputBackground=background,
807 astromMatches, matchMeta):
808 """Write output data to the output repository
810 @param[
in] dataRef butler data reference corresponding to a science
812 @param[
in] exposure exposure to write
813 @param[
in] background background model
for exposure
814 @param[
in] sourceCat catalog of measured sources
815 @param[
in] astromMatches list of source/refObj matches
from the
818 dataRef.put(sourceCat, "src")
819 if self.config.doWriteMatches
and astromMatches
is not None:
820 normalizedMatches = afwTable.packMatches(astromMatches)
821 normalizedMatches.table.setMetadata(matchMeta)
822 dataRef.put(normalizedMatches,
"srcMatch")
823 if self.config.doWriteMatchesDenormalized:
824 denormMatches = denormalizeMatches(astromMatches, matchMeta)
825 dataRef.put(denormMatches,
"srcMatchFull")
826 if self.config.doWriteExposure:
827 dataRef.put(exposure,
"calexp")
828 dataRef.put(background,
"calexpBackground")
831 """Return a dict of empty catalogs for each catalog dataset produced
834 sourceCat = afwTable.SourceCatalog(self.schemaschema)
836 return {
"src": sourceCat}
839 """!Set task and exposure metadata
841 Logs a warning and continues
if needed data
is missing.
843 @param[
in,out] exposure exposure whose metadata
is to be set
844 @param[
in] photoRes results of running photoCal;
if None then it was
850 metadata = exposure.getMetadata()
854 exposureTime = exposure.getInfo().getVisitInfo().getExposureTime()
855 magZero = photoRes.zp - 2.5*math.log10(exposureTime)
857 self.log.warning(
"Could not set normalized MAGZERO in header: no "
862 metadata.set(
'MAGZERO', magZero)
863 metadata.set(
'MAGZERO_RMS', photoRes.sigma)
864 metadata.set(
'MAGZERO_NOBJ', photoRes.ngood)
865 metadata.set(
'COLORTERM1', 0.0)
866 metadata.set(
'COLORTERM2', 0.0)
867 metadata.set(
'COLORTERM3', 0.0)
868 except Exception
as e:
869 self.log.warning(
"Could not set exposure metadata: %s", e)
872 """!Match sources in icSourceCat and sourceCat and copy the specified fields
874 @param[
in] icSourceCat catalog
from which to copy fields
875 @param[
in,out] sourceCat catalog to which to copy fields
877 The fields copied are those specified by `config.icSourceFieldsToCopy`
878 that actually exist
in the schema. This was set up by the constructor
882 raise RuntimeError(
"To copy icSource fields you must specify "
883 "icSourceSchema nd icSourceKeys when "
884 "constructing this task")
885 if icSourceCat
is None or sourceCat
is None:
886 raise RuntimeError(
"icSourceCat and sourceCat must both be "
888 if len(self.config.icSourceFieldsToCopy) == 0:
889 self.log.warning(
"copyIcSourceFields doing nothing because "
890 "icSourceFieldsToCopy is empty")
893 mc = afwTable.MatchControl()
894 mc.findOnlyClosest =
False
895 matches = afwTable.matchXy(icSourceCat, sourceCat,
896 self.config.matchRadiusPix, mc)
897 if self.config.doDeblend:
898 deblendKey = sourceCat.schema[
"deblend_nChild"].asKey()
900 matches = [m
for m
in matches
if m[1].get(deblendKey) == 0]
907 for m0, m1, d
in matches:
909 match = bestMatches.get(id0)
910 if match
is None or d <= match[2]:
911 bestMatches[id0] = (m0, m1, d)
912 matches = list(bestMatches.values())
917 numMatches = len(matches)
918 numUniqueSources = len(set(m[1].getId()
for m
in matches))
919 if numUniqueSources != numMatches:
920 self.log.warning(
"%d icSourceCat sources matched only %d sourceCat "
921 "sources", numMatches, numUniqueSources)
923 self.log.info(
"Copying flags from icSourceCat to sourceCat for "
924 "%d sources", numMatches)
928 for icSrc, src, d
in matches:
934 icSrcFootprint = icSrc.getFootprint()
936 icSrc.setFootprint(src.getFootprint())
939 icSrc.setFootprint(icSrcFootprint)
postCalibrationMeasurement
def __init__(self, *config=None)
Calibrate an exposure: measure sources and perform astrometric and photometric calibration.
def writeOutputs(self, dataRef, exposure, background, sourceCat, astromMatches, matchMeta)
def runDataRef(self, dataRef, exposure=None, background=None, icSourceCat=None, doUnpersist=True)
Calibrate an exposure, optionally unpersisting inputs and persisting outputs.
def __init__(self, butler=None, astromRefObjLoader=None, photoRefObjLoader=None, icSourceSchema=None, initInputs=None, **kwargs)
Construct a CalibrateTask.
def setMetadata(self, exposure, photoRes=None)
Set task and exposure metadata.
def runQuantum(self, butlerQC, inputRefs, outputRefs)
def getSchemaCatalogs(self)
def copyIcSourceFields(self, icSourceCat, sourceCat)
Match sources in icSourceCat and sourceCat and copy the specified fields.
def run(self, exposure, exposureIdInfo=None, background=None, icSourceCat=None)
Calibrate an exposure (science image or coadd)