24 from lsstDebug
import getDebugFrame
27 import lsst.pipe.base.connectionTypes
as cT
29 from lsst.meas.astrom import AstrometryTask, displayAstrometry, denormalizeMatches
38 CatalogCalculationTask)
40 from lsst.utils.timer
import timeMethod
42 from .fakes
import BaseFakeSourcesTask
43 from .photoCal
import PhotoCalTask
44 from .computeExposureSummaryStats
import ComputeExposureSummaryStatsTask
47 __all__ = [
"CalibrateConfig",
"CalibrateTask"]
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")
153 class 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 setPrimaryFlags = pexConfig.ConfigurableField(
262 target=SetPrimaryFlagsTask,
263 doc=(
"Set flags for primary source classification in single frame "
264 "processing. True if sources are not sky sources and not a parent.")
266 doApCorr = pexConfig.Field(
269 doc=
"Run subtask to apply aperture correction"
271 applyApCorr = pexConfig.ConfigurableField(
272 target=ApplyApCorrTask,
273 doc=
"Subtask to apply aperture corrections"
278 catalogCalculation = pexConfig.ConfigurableField(
279 target=CatalogCalculationTask,
280 doc=
"Subtask to run catalogCalculation plugins on catalog"
282 doInsertFakes = pexConfig.Field(
285 doc=
"Run fake sources injection task"
287 insertFakes = pexConfig.ConfigurableField(
288 target=BaseFakeSourcesTask,
289 doc=
"Injection of fake sources for testing purposes (must be "
292 doComputeSummaryStats = pexConfig.Field(
295 doc=
"Run subtask to measure exposure summary statistics?"
297 computeSummaryStats = pexConfig.ConfigurableField(
298 target=ComputeExposureSummaryStatsTask,
299 doc=
"Subtask to run computeSummaryStats on exposure"
301 doWriteExposure = pexConfig.Field(
304 doc=
"Write the calexp? If fakes have been added then we do not want to write out the calexp as a "
305 "normal calexp but as a fakes_calexp."
310 self.
detectiondetection.doTempLocalBackground =
False
311 self.
deblenddeblend.maxFootprintSize = 2000
312 self.
measurementmeasurement.plugins.names |= [
"base_LocalPhotoCalib",
"base_LocalWcs"]
316 astromRefCatGen2 = getattr(self.
astromRefObjLoaderastromRefObjLoader,
"ref_dataset_name",
None)
317 if astromRefCatGen2
is not None and astromRefCatGen2 != self.connections.astromRefCat:
319 f
"Gen2 ({astromRefCatGen2}) and Gen3 ({self.connections.astromRefCat}) astrometry reference "
320 f
"catalogs are different. These options must be kept in sync until Gen2 is retired."
322 photoRefCatGen2 = getattr(self.
photoRefObjLoaderphotoRefObjLoader,
"ref_dataset_name",
None)
323 if photoRefCatGen2
is not None and photoRefCatGen2 != self.connections.photoRefCat:
325 f
"Gen2 ({photoRefCatGen2}) and Gen3 ({self.connections.photoRefCat}) photometry reference "
326 f
"catalogs are different. These options must be kept in sync until Gen2 is retired."
338 r"""!Calibrate an exposure: measure sources and perform astrometric and
339 photometric calibration
341 @anchor CalibrateTask_
343 @section pipe_tasks_calibrate_Contents Contents
345 - @ref pipe_tasks_calibrate_Purpose
346 - @ref pipe_tasks_calibrate_Initialize
347 - @ref pipe_tasks_calibrate_IO
348 - @ref pipe_tasks_calibrate_Config
349 - @ref pipe_tasks_calibrate_Metadata
350 - @ref pipe_tasks_calibrate_Debug
353 @section pipe_tasks_calibrate_Purpose Description
355 Given an exposure with a good PSF model and aperture correction map
356 (e.g. as provided by @ref CharacterizeImageTask), perform the following
358 - Run detection and measurement
359 - Run astrometry subtask to fit an improved WCS
360 - Run photoCal subtask to fit the exposure's photometric zero-point
362 @section pipe_tasks_calibrate_Initialize Task initialisation
364 @copydoc \_\_init\_\_
366 @section pipe_tasks_calibrate_IO Invoking the Task
368 If you want this task to unpersist inputs or persist outputs, then call
369 the `runDataRef` method (a wrapper around the `run` method).
371 If you already have the inputs unpersisted and do not want to persist the
372 output then it is more direct to call the `run` method:
374 @section pipe_tasks_calibrate_Config Configuration parameters
376 See @ref CalibrateConfig
378 @section pipe_tasks_calibrate_Metadata Quantities set in exposure Metadata
382 <dt>MAGZERO_RMS <dd>MAGZERO's RMS == sigma reported by photoCal task
383 <dt>MAGZERO_NOBJ <dd>Number of stars used == ngood reported by photoCal
385 <dt>COLORTERM1 <dd>?? (always 0.0)
386 <dt>COLORTERM2 <dd>?? (always 0.0)
387 <dt>COLORTERM3 <dd>?? (always 0.0)
390 @section pipe_tasks_calibrate_Debug Debug variables
392 The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink
393 interface supports a flag
394 `--debug` to import `debug.py` from your `$PYTHONPATH`; see @ref baseDebug
395 for more about `debug.py`.
397 CalibrateTask has a debug dictionary containing one key:
400 <dd>frame (an int; <= 0 to not display) in which to display the exposure,
401 sources and matches. See @ref lsst.meas.astrom.displayAstrometry for
402 the meaning of the various symbols.
405 For example, put something like:
409 di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would
410 # call us recursively
411 if name == "lsst.pipe.tasks.calibrate":
418 lsstDebug.Info = DebugInfo
420 into your `debug.py` file and run `calibrateTask.py` with the `--debug`
423 Some subtasks may have their own debug variables; see individual Task
430 ConfigClass = CalibrateConfig
431 _DefaultName =
"calibrate"
432 RunnerClass = pipeBase.ButlerInitializedTaskRunner
434 def __init__(self, butler=None, astromRefObjLoader=None,
435 photoRefObjLoader=None, icSourceSchema=None,
436 initInputs=None, **kwargs):
437 """!Construct a CalibrateTask
439 @param[in] butler The butler is passed to the refObjLoader constructor
440 in case it is needed. Ignored if the refObjLoader argument
441 provides a loader directly.
442 @param[in] astromRefObjLoader An instance of LoadReferenceObjectsTasks
443 that supplies an external reference catalog for astrometric
444 calibration. May be None if the desired loader can be constructed
445 from the butler argument or all steps requiring a reference catalog
447 @param[in] photoRefObjLoader An instance of LoadReferenceObjectsTasks
448 that supplies an external reference catalog for photometric
449 calibration. May be None if the desired loader can be constructed
450 from the butler argument or all steps requiring a reference catalog
452 @param[in] icSourceSchema schema for icSource catalog, or None.
453 Schema values specified in config.icSourceFieldsToCopy will be
454 taken from this schema. If set to None, no values will be
455 propagated from the icSourceCatalog
456 @param[in,out] kwargs other keyword arguments for
457 lsst.pipe.base.CmdLineTask
461 if icSourceSchema
is None and butler
is not None:
463 icSourceSchema = butler.get(
"icSrc_schema", immediate=
True).schema
465 if icSourceSchema
is None and butler
is None and initInputs
is not None:
466 icSourceSchema = initInputs[
'icSourceSchema'].schema
468 if icSourceSchema
is not None:
471 minimumSchema = afwTable.SourceTable.makeMinimalSchema()
472 self.
schemaMapperschemaMapper.addMinimalSchema(minimumSchema,
False)
481 "Source was detected as an icSource"))
482 missingFieldNames = []
483 for fieldName
in self.config.icSourceFieldsToCopy:
485 schemaItem = icSourceSchema.find(fieldName)
487 missingFieldNames.append(fieldName)
490 self.
schemaMapperschemaMapper.addMapping(schemaItem.getKey())
492 if missingFieldNames:
493 raise RuntimeError(
"isSourceCat is missing fields {} "
494 "specified in icSourceFieldsToCopy"
495 .
format(missingFieldNames))
502 self.
schemaschema = afwTable.SourceTable.makeMinimalSchema()
503 self.makeSubtask(
'detection', schema=self.
schemaschema)
510 if self.config.doInsertFakes:
511 self.makeSubtask(
"insertFakes")
513 if self.config.doDeblend:
514 self.makeSubtask(
"deblend", schema=self.
schemaschema)
515 if self.config.doSkySources:
516 self.makeSubtask(
"skySources")
517 self.
skySourceKeyskySourceKey = self.
schemaschema.addField(
"sky_source", type=
"Flag", doc=
"Sky objects.")
518 self.makeSubtask(
'measurement', schema=self.
schemaschema,
520 self.makeSubtask(
"setPrimaryFlags", schema=self.
schemaschema, isSingleFrame=
True)
521 if self.config.doApCorr:
522 self.makeSubtask(
'applyApCorr', schema=self.
schemaschema)
523 self.makeSubtask(
'catalogCalculation', schema=self.
schemaschema)
525 if self.config.doAstrometry:
526 if astromRefObjLoader
is None and butler
is not None:
527 self.makeSubtask(
'astromRefObjLoader', butler=butler)
528 astromRefObjLoader = self.astromRefObjLoader
529 self.makeSubtask(
"astrometry", refObjLoader=astromRefObjLoader,
531 if self.config.doPhotoCal:
532 if photoRefObjLoader
is None and butler
is not None:
533 self.makeSubtask(
'photoRefObjLoader', butler=butler)
534 photoRefObjLoader = self.photoRefObjLoader
535 self.makeSubtask(
"photoCal", refObjLoader=photoRefObjLoader,
537 if self.config.doComputeSummaryStats:
538 self.makeSubtask(
'computeSummaryStats')
540 if initInputs
is not None and (astromRefObjLoader
is not None or photoRefObjLoader
is not None):
541 raise RuntimeError(
"PipelineTask form of this task should not be initialized with "
542 "reference object loaders.")
547 self.
schemaschema.checkUnits(parse_strict=self.config.checkUnitsParseStrict)
554 def runDataRef(self, dataRef, exposure=None, background=None, icSourceCat=None,
556 """!Calibrate an exposure, optionally unpersisting inputs and
559 This is a wrapper around the `run` method that unpersists inputs
560 (if `doUnpersist` true) and persists outputs (if `config.doWrite` true)
562 @param[in] dataRef butler data reference corresponding to a science
564 @param[in,out] exposure characterized exposure (an
565 lsst.afw.image.ExposureF or similar), or None to unpersist existing
566 icExp and icBackground. See `run` method for details of what is
568 @param[in,out] background initial model of background already
569 subtracted from exposure (an lsst.afw.math.BackgroundList). May be
570 None if no background has been subtracted, though that is unusual
571 for calibration. A refined background model is output. Ignored if
573 @param[in] icSourceCat catalog from which to copy the fields specified
574 by icSourceKeys, or None;
575 @param[in] doUnpersist unpersist data:
576 - if True, exposure, background and icSourceCat are read from
577 dataRef and those three arguments must all be None;
578 - if False the exposure must be provided; background and
579 icSourceCat are optional. True is intended for running as a
580 command-line task, False for running as a subtask
581 @return same data as the calibrate method
583 self.log.
info(
"Processing %s", dataRef.dataId)
586 if any(item
is not None for item
in (exposure, background,
588 raise RuntimeError(
"doUnpersist true; exposure, background "
589 "and icSourceCat must all be None")
590 exposure = dataRef.get(
"icExp", immediate=
True)
591 background = dataRef.get(
"icExpBackground", immediate=
True)
592 icSourceCat = dataRef.get(
"icSrc", immediate=
True)
593 elif exposure
is None:
594 raise RuntimeError(
"doUnpersist false; exposure must be provided")
596 exposureIdInfo = dataRef.get(
"expIdInfo")
598 calRes = self.
runrun(
600 exposureIdInfo=exposureIdInfo,
601 background=background,
602 icSourceCat=icSourceCat,
605 if self.config.doWrite:
608 exposure=calRes.exposure,
609 background=calRes.background,
610 sourceCat=calRes.sourceCat,
611 astromMatches=calRes.astromMatches,
612 matchMeta=calRes.matchMeta,
618 inputs = butlerQC.get(inputRefs)
619 inputs[
'exposureIdInfo'] = ExposureIdInfo.fromDataId(butlerQC.quantum.dataId,
"visit_detector")
621 if self.config.doAstrometry:
623 for ref
in inputRefs.astromRefCat],
624 refCats=inputs.pop(
'astromRefCat'),
625 config=self.config.astromRefObjLoader, log=self.log)
626 self.astrometry.setRefObjLoader(refObjLoader)
628 if self.config.doPhotoCal:
630 for ref
in inputRefs.photoRefCat],
631 refCats=inputs.pop(
'photoRefCat'),
632 config=self.config.photoRefObjLoader,
634 self.photoCal.match.setRefObjLoader(photoRefObjLoader)
636 outputs = self.
runrun(**inputs)
638 if self.config.doWriteMatches
and self.config.doAstrometry:
640 normalizedMatches.table.setMetadata(outputs.matchMeta)
641 if self.config.doWriteMatchesDenormalized:
643 outputs.matchesDenormalized = denormMatches
644 outputs.matches = normalizedMatches
645 butlerQC.put(outputs, outputRefs)
648 def run(self, exposure, exposureIdInfo=None, background=None,
650 """!Calibrate an exposure (science image or coadd)
652 @param[in,out] exposure exposure to calibrate (an
653 lsst.afw.image.ExposureF or similar);
658 - MaskedImage has background subtracted
660 - PhotoCalib is replaced
661 @param[in] exposureIdInfo ID info for exposure (an
662 lsst.obs.base.ExposureIdInfo) If not provided, returned
663 SourceCatalog IDs will not be globally unique.
664 @param[in,out] background background model already subtracted from
665 exposure (an lsst.afw.math.BackgroundList). May be None if no
666 background has been subtracted, though that is unusual for
667 calibration. A refined background model is output.
668 @param[in] icSourceCat A SourceCatalog from CharacterizeImageTask
669 from which we can copy some fields.
671 @return pipe_base Struct containing these fields:
672 - exposure calibrate science exposure with refined WCS and PhotoCalib
673 - background model of background subtracted from exposure (an
674 lsst.afw.math.BackgroundList)
675 - sourceCat catalog of measured sources
676 - astromMatches list of source/refObj matches from the astrometry
680 if exposureIdInfo
is None:
681 exposureIdInfo = ExposureIdInfo()
683 if background
is None:
685 sourceIdFactory = exposureIdInfo.makeSourceIdFactory()
686 table = SourceTable.make(self.
schemaschema, sourceIdFactory)
689 detRes = self.detection.
run(table=table, exposure=exposure,
691 sourceCat = detRes.sources
692 if detRes.fpSets.background:
693 for bg
in detRes.fpSets.background:
694 background.append(bg)
695 if self.config.doSkySources:
696 skySourceFootprints = self.skySources.
run(mask=exposure.mask, seed=exposureIdInfo.expId)
697 if skySourceFootprints:
698 for foot
in skySourceFootprints:
699 s = sourceCat.addNew()
702 if self.config.doDeblend:
703 self.deblend.
run(exposure=exposure, sources=sourceCat)
704 self.measurement.
run(
707 exposureId=exposureIdInfo.expId
709 if self.config.doApCorr:
710 self.applyApCorr.
run(
712 apCorrMap=exposure.getInfo().getApCorrMap()
714 self.catalogCalculation.
run(sourceCat)
716 self.setPrimaryFlags.
run(sourceCat)
718 if icSourceCat
is not None and \
719 len(self.config.icSourceFieldsToCopy) > 0:
727 if not sourceCat.isContiguous():
728 sourceCat = sourceCat.copy(deep=
True)
734 if self.config.doAstrometry:
736 astromRes = self.astrometry.
run(
740 astromMatches = astromRes.matches
741 matchMeta = astromRes.matchMeta
742 except Exception
as e:
743 if self.config.requireAstrometry:
745 self.log.
warning(
"Unable to perform astrometric calibration "
746 "(%s): attempting to proceed", e)
749 if self.config.doPhotoCal:
751 photoRes = self.photoCal.
run(exposure, sourceCat=sourceCat, expId=exposureIdInfo.expId)
752 exposure.setPhotoCalib(photoRes.photoCalib)
754 self.log.
info(
"Photometric zero-point: %f",
755 photoRes.photoCalib.instFluxToMagnitude(1.0))
756 self.
setMetadatasetMetadata(exposure=exposure, photoRes=photoRes)
757 except Exception
as e:
758 if self.config.requirePhotoCal:
760 self.log.
warning(
"Unable to perform photometric calibration "
761 "(%s): attempting to proceed", e)
762 self.
setMetadatasetMetadata(exposure=exposure, photoRes=
None)
764 if self.config.doInsertFakes:
765 self.insertFakes.
run(exposure, background=background)
767 table = SourceTable.make(self.
schemaschema, sourceIdFactory)
770 detRes = self.detection.
run(table=table, exposure=exposure,
772 sourceCat = detRes.sources
773 if detRes.fpSets.background:
774 for bg
in detRes.fpSets.background:
775 background.append(bg)
776 if self.config.doDeblend:
777 self.deblend.
run(exposure=exposure, sources=sourceCat)
778 self.measurement.
run(
781 exposureId=exposureIdInfo.expId
783 if self.config.doApCorr:
784 self.applyApCorr.
run(
786 apCorrMap=exposure.getInfo().getApCorrMap()
788 self.catalogCalculation.
run(sourceCat)
790 if icSourceCat
is not None and len(self.config.icSourceFieldsToCopy) > 0:
794 if self.config.doComputeSummaryStats:
795 summary = self.computeSummaryStats.
run(exposure=exposure,
797 background=background)
798 exposure.getInfo().setSummaryStats(summary)
805 matches=astromMatches,
810 return pipeBase.Struct(
812 background=background,
814 astromMatches=astromMatches,
818 outputExposure=exposure,
820 outputBackground=background,
824 astromMatches, matchMeta):
825 """Write output data to the output repository
827 @param[in] dataRef butler data reference corresponding to a science
829 @param[in] exposure exposure to write
830 @param[in] background background model for exposure
831 @param[in] sourceCat catalog of measured sources
832 @param[in] astromMatches list of source/refObj matches from the
835 dataRef.put(sourceCat,
"src")
836 if self.config.doWriteMatches
and astromMatches
is not None:
838 normalizedMatches.table.setMetadata(matchMeta)
839 dataRef.put(normalizedMatches,
"srcMatch")
840 if self.config.doWriteMatchesDenormalized:
842 dataRef.put(denormMatches,
"srcMatchFull")
843 if self.config.doWriteExposure:
844 dataRef.put(exposure,
"calexp")
845 dataRef.put(background,
"calexpBackground")
848 """Return a dict of empty catalogs for each catalog dataset produced
853 return {
"src": sourceCat}
856 """!Set task and exposure metadata
858 Logs a warning and continues if needed data is missing.
860 @param[in,out] exposure exposure whose metadata is to be set
861 @param[in] photoRes results of running photoCal; if None then it was
867 metadata = exposure.getMetadata()
871 exposureTime = exposure.getInfo().getVisitInfo().getExposureTime()
872 magZero = photoRes.zp - 2.5*math.log10(exposureTime)
874 self.log.
warning(
"Could not set normalized MAGZERO in header: no "
879 metadata.set(
'MAGZERO', magZero)
880 metadata.set(
'MAGZERO_RMS', photoRes.sigma)
881 metadata.set(
'MAGZERO_NOBJ', photoRes.ngood)
882 metadata.set(
'COLORTERM1', 0.0)
883 metadata.set(
'COLORTERM2', 0.0)
884 metadata.set(
'COLORTERM3', 0.0)
885 except Exception
as e:
886 self.log.
warning(
"Could not set exposure metadata: %s", e)
889 """!Match sources in icSourceCat and sourceCat and copy the specified fields
891 @param[in] icSourceCat catalog from which to copy fields
892 @param[in,out] sourceCat catalog to which to copy fields
894 The fields copied are those specified by `config.icSourceFieldsToCopy`
895 that actually exist in the schema. This was set up by the constructor
896 using self.schemaMapper.
899 raise RuntimeError(
"To copy icSource fields you must specify "
900 "icSourceSchema nd icSourceKeys when "
901 "constructing this task")
902 if icSourceCat
is None or sourceCat
is None:
903 raise RuntimeError(
"icSourceCat and sourceCat must both be "
905 if len(self.config.icSourceFieldsToCopy) == 0:
906 self.log.
warning(
"copyIcSourceFields doing nothing because "
907 "icSourceFieldsToCopy is empty")
911 mc.findOnlyClosest =
False
913 self.config.matchRadiusPix, mc)
914 if self.config.doDeblend:
915 deblendKey = sourceCat.schema[
"deblend_nChild"].asKey()
917 matches = [m
for m
in matches
if m[1].get(deblendKey) == 0]
924 for m0, m1, d
in matches:
926 match = bestMatches.get(id0)
927 if match
is None or d <= match[2]:
928 bestMatches[id0] = (m0, m1, d)
929 matches =
list(bestMatches.values())
934 numMatches = len(matches)
935 numUniqueSources = len(
set(m[1].getId()
for m
in matches))
936 if numUniqueSources != numMatches:
937 self.log.
warning(
"%d icSourceCat sources matched only %d sourceCat "
938 "sources", numMatches, numUniqueSources)
940 self.log.
info(
"Copying flags from icSourceCat to sourceCat for "
941 "%d sources", numMatches)
945 for icSrc, src, d
in matches:
951 icSrcFootprint = icSrc.getFootprint()
953 icSrc.setFootprint(src.getFootprint())
956 icSrc.setFootprint(icSrcFootprint)
afw::table::PointKey< int > dimensions
Pass parameters to algorithms that match list of sources.
A mapping between the keys of two Schemas, used to copy data between them.
Class for storing ordered metadata with comments.
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)
daf::base::PropertyList * list
daf::base::PropertySet * set
BaseCatalog packMatches(std::vector< Match< Record1, Record2 > > const &matches)
Return a table representation of a MatchVector that can be used to persist it.
SourceMatchVector matchXy(SourceCatalog const &cat1, SourceCatalog const &cat2, double radius, MatchControl const &mc=MatchControl())
Compute all tuples (s1,s2,d) where s1 belings to cat1, s2 belongs to cat2 and d, the distance between...
bool any(CoordinateExpr< N > const &expr) noexcept
Return true if any elements are true.
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations.
def denormalizeMatches(matches, matchMeta=None)
def displayAstrometry(refCat=None, sourceCat=None, distortedCentroidKey=None, bbox=None, exposure=None, matches=None, frame=1, title="", pause=True)
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
def getDebugFrame(debugDisplay, name)
A description of a field in a table.