24 from lsstDebug
import getDebugFrame
27 import lsst.pipe.base.connectionTypes
as cT
29 from lsst.meas.astrom import AstrometryTask, displayAstrometry, denormalizeMatches
38 CatalogCalculationTask)
41 from .fakes
import BaseFakeSourcesTask
42 from .photoCal
import PhotoCalTask
43 from .computeExposureSummaryStats
import ComputeExposureSummaryStatsTask
46 __all__ = [
"CalibrateConfig",
"CalibrateTask"]
52 icSourceSchema = cT.InitInput(
53 doc=
"Schema produced by characterize image task, used to initialize this task",
55 storageClass=
"SourceCatalog",
58 outputSchema = cT.InitOutput(
59 doc=
"Schema after CalibrateTask has been initialized",
61 storageClass=
"SourceCatalog",
65 doc=
"Input image to calibrate",
67 storageClass=
"ExposureF",
68 dimensions=(
"instrument",
"visit",
"detector"),
71 background = cT.Input(
72 doc=
"Backgrounds determined by characterize task",
73 name=
"icExpBackground",
74 storageClass=
"Background",
75 dimensions=(
"instrument",
"visit",
"detector"),
78 icSourceCat = cT.Input(
79 doc=
"Source catalog created by characterize task",
81 storageClass=
"SourceCatalog",
82 dimensions=(
"instrument",
"visit",
"detector"),
85 astromRefCat = cT.PrerequisiteInput(
86 doc=
"Reference catalog to use for astrometry",
88 storageClass=
"SimpleCatalog",
89 dimensions=(
"skypix",),
94 photoRefCat = cT.PrerequisiteInput(
95 doc=
"Reference catalog to use for photometric calibration",
97 storageClass=
"SimpleCatalog",
98 dimensions=(
"skypix",),
103 outputExposure = cT.Output(
104 doc=
"Exposure after running calibration task",
106 storageClass=
"ExposureF",
107 dimensions=(
"instrument",
"visit",
"detector"),
110 outputCat = cT.Output(
111 doc=
"Source catalog produced in calibrate task",
113 storageClass=
"SourceCatalog",
114 dimensions=(
"instrument",
"visit",
"detector"),
117 outputBackground = cT.Output(
118 doc=
"Background models estimated in calibration task",
119 name=
"calexpBackground",
120 storageClass=
"Background",
121 dimensions=(
"instrument",
"visit",
"detector"),
125 doc=
"Source/refObj matches from the astrometry solver",
127 storageClass=
"Catalog",
128 dimensions=(
"instrument",
"visit",
"detector"),
131 matchesDenormalized = cT.Output(
132 doc=
"Denormalized matches from astrometry solver",
134 storageClass=
"Catalog",
135 dimensions=(
"instrument",
"visit",
"detector"),
141 if config.doAstrometry
is False:
142 self.prerequisiteInputs.remove(
"astromRefCat")
143 if config.doPhotoCal
is False:
144 self.prerequisiteInputs.remove(
"photoRefCat")
146 if config.doWriteMatches
is False or config.doAstrometry
is False:
147 self.outputs.remove(
"matches")
148 if config.doWriteMatchesDenormalized
is False or config.doAstrometry
is False:
149 self.outputs.remove(
"matchesDenormalized")
152 class CalibrateConfig(pipeBase.PipelineTaskConfig, pipelineConnections=CalibrateConnections):
153 """Config for CalibrateTask"""
154 doWrite = pexConfig.Field(
157 doc=
"Save calibration results?",
159 doWriteHeavyFootprintsInSources = pexConfig.Field(
162 doc=
"Include HeavyFootprint data in source table? If false then heavy "
163 "footprints are saved as normal footprints, which saves some space"
165 doWriteMatches = pexConfig.Field(
168 doc=
"Write reference matches (ignored if doWrite or doAstrometry false)?",
170 doWriteMatchesDenormalized = pexConfig.Field(
173 doc=(
"Write reference matches in denormalized format? "
174 "This format uses more disk space, but is more convenient to "
175 "read. Ignored if doWriteMatches=False or doWrite=False."),
177 doAstrometry = pexConfig.Field(
180 doc=
"Perform astrometric calibration?",
182 astromRefObjLoader = pexConfig.ConfigurableField(
183 target=LoadIndexedReferenceObjectsTask,
184 doc=
"reference object loader for astrometric calibration",
186 photoRefObjLoader = pexConfig.ConfigurableField(
187 target=LoadIndexedReferenceObjectsTask,
188 doc=
"reference object loader for photometric calibration",
190 astrometry = pexConfig.ConfigurableField(
191 target=AstrometryTask,
192 doc=
"Perform astrometric calibration to refine the WCS",
194 requireAstrometry = pexConfig.Field(
197 doc=(
"Raise an exception if astrometry fails? Ignored if doAstrometry "
200 doPhotoCal = pexConfig.Field(
203 doc=
"Perform phometric calibration?",
205 requirePhotoCal = pexConfig.Field(
208 doc=(
"Raise an exception if photoCal fails? Ignored if doPhotoCal "
211 photoCal = pexConfig.ConfigurableField(
213 doc=
"Perform photometric calibration",
215 icSourceFieldsToCopy = pexConfig.ListField(
217 default=(
"calib_psf_candidate",
"calib_psf_used",
"calib_psf_reserved"),
218 doc=(
"Fields to copy from the icSource catalog to the output catalog "
219 "for matching sources Any missing fields will trigger a "
220 "RuntimeError exception. Ignored if icSourceCat is not provided.")
222 matchRadiusPix = pexConfig.Field(
225 doc=(
"Match radius for matching icSourceCat objects to sourceCat "
228 checkUnitsParseStrict = pexConfig.Field(
229 doc=(
"Strictness of Astropy unit compatibility check, can be 'raise', "
230 "'warn' or 'silent'"),
234 detection = pexConfig.ConfigurableField(
235 target=SourceDetectionTask,
238 doDeblend = pexConfig.Field(
241 doc=
"Run deblender input exposure"
243 deblend = pexConfig.ConfigurableField(
244 target=SourceDeblendTask,
245 doc=
"Split blended sources into their components"
247 doSkySources = pexConfig.Field(
250 doc=
"Generate sky sources?",
252 skySources = pexConfig.ConfigurableField(
253 target=SkyObjectsTask,
254 doc=
"Generate sky sources",
256 measurement = pexConfig.ConfigurableField(
257 target=SingleFrameMeasurementTask,
258 doc=
"Measure sources"
260 setPrimaryFlags = pexConfig.ConfigurableField(
261 target=SetPrimaryFlagsTask,
262 doc=(
"Set flags for primary source classification in single frame "
263 "processing. True if sources are not sky sources and not a parent.")
265 doApCorr = pexConfig.Field(
268 doc=
"Run subtask to apply aperture correction"
270 applyApCorr = pexConfig.ConfigurableField(
271 target=ApplyApCorrTask,
272 doc=
"Subtask to apply aperture corrections"
277 catalogCalculation = pexConfig.ConfigurableField(
278 target=CatalogCalculationTask,
279 doc=
"Subtask to run catalogCalculation plugins on catalog"
281 doInsertFakes = pexConfig.Field(
284 doc=
"Run fake sources injection task"
286 insertFakes = pexConfig.ConfigurableField(
287 target=BaseFakeSourcesTask,
288 doc=
"Injection of fake sources for testing purposes (must be "
291 doComputeSummaryStats = pexConfig.Field(
294 doc=
"Run subtask to measure exposure summary statistics?"
296 computeSummaryStats = pexConfig.ConfigurableField(
297 target=ComputeExposureSummaryStatsTask,
298 doc=
"Subtask to run computeSummaryStats on exposure"
300 doWriteExposure = pexConfig.Field(
303 doc=
"Write the calexp? If fakes have been added then we do not want to write out the calexp as a "
304 "normal calexp but as a fakes_calexp."
309 self.
detectiondetection.doTempLocalBackground =
False
310 self.
deblenddeblend.maxFootprintSize = 2000
311 self.
measurementmeasurement.plugins.names |= [
"base_LocalPhotoCalib",
"base_LocalWcs"]
315 astromRefCatGen2 = getattr(self.
astromRefObjLoaderastromRefObjLoader,
"ref_dataset_name",
None)
316 if astromRefCatGen2
is not None and astromRefCatGen2 != self.connections.astromRefCat:
318 f
"Gen2 ({astromRefCatGen2}) and Gen3 ({self.connections.astromRefCat}) astrometry reference "
319 f
"catalogs are different. These options must be kept in sync until Gen2 is retired."
321 photoRefCatGen2 = getattr(self.
photoRefObjLoaderphotoRefObjLoader,
"ref_dataset_name",
None)
322 if photoRefCatGen2
is not None and photoRefCatGen2 != self.connections.photoRefCat:
324 f
"Gen2 ({photoRefCatGen2}) and Gen3 ({self.connections.photoRefCat}) photometry reference "
325 f
"catalogs are different. These options must be kept in sync until Gen2 is retired."
337 r"""!Calibrate an exposure: measure sources and perform astrometric and
338 photometric calibration
340 @anchor CalibrateTask_
342 @section pipe_tasks_calibrate_Contents Contents
344 - @ref pipe_tasks_calibrate_Purpose
345 - @ref pipe_tasks_calibrate_Initialize
346 - @ref pipe_tasks_calibrate_IO
347 - @ref pipe_tasks_calibrate_Config
348 - @ref pipe_tasks_calibrate_Metadata
349 - @ref pipe_tasks_calibrate_Debug
352 @section pipe_tasks_calibrate_Purpose Description
354 Given an exposure with a good PSF model and aperture correction map
355 (e.g. as provided by @ref CharacterizeImageTask), perform the following
357 - Run detection and measurement
358 - Run astrometry subtask to fit an improved WCS
359 - Run photoCal subtask to fit the exposure's photometric zero-point
361 @section pipe_tasks_calibrate_Initialize Task initialisation
363 @copydoc \_\_init\_\_
365 @section pipe_tasks_calibrate_IO Invoking the Task
367 If you want this task to unpersist inputs or persist outputs, then call
368 the `runDataRef` method (a wrapper around the `run` method).
370 If you already have the inputs unpersisted and do not want to persist the
371 output then it is more direct to call the `run` method:
373 @section pipe_tasks_calibrate_Config Configuration parameters
375 See @ref CalibrateConfig
377 @section pipe_tasks_calibrate_Metadata Quantities set in exposure Metadata
381 <dt>MAGZERO_RMS <dd>MAGZERO's RMS == sigma reported by photoCal task
382 <dt>MAGZERO_NOBJ <dd>Number of stars used == ngood reported by photoCal
384 <dt>COLORTERM1 <dd>?? (always 0.0)
385 <dt>COLORTERM2 <dd>?? (always 0.0)
386 <dt>COLORTERM3 <dd>?? (always 0.0)
389 @section pipe_tasks_calibrate_Debug Debug variables
391 The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink
392 interface supports a flag
393 `--debug` to import `debug.py` from your `$PYTHONPATH`; see @ref baseDebug
394 for more about `debug.py`.
396 CalibrateTask has a debug dictionary containing one key:
399 <dd>frame (an int; <= 0 to not display) in which to display the exposure,
400 sources and matches. See @ref lsst.meas.astrom.displayAstrometry for
401 the meaning of the various symbols.
404 For example, put something like:
408 di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would
409 # call us recursively
410 if name == "lsst.pipe.tasks.calibrate":
417 lsstDebug.Info = DebugInfo
419 into your `debug.py` file and run `calibrateTask.py` with the `--debug`
422 Some subtasks may have their own debug variables; see individual Task
429 ConfigClass = CalibrateConfig
430 _DefaultName =
"calibrate"
431 RunnerClass = pipeBase.ButlerInitializedTaskRunner
433 def __init__(self, butler=None, astromRefObjLoader=None,
434 photoRefObjLoader=None, icSourceSchema=None,
435 initInputs=None, **kwargs):
436 """!Construct a CalibrateTask
438 @param[in] butler The butler is passed to the refObjLoader constructor
439 in case it is needed. Ignored if the refObjLoader argument
440 provides a loader directly.
441 @param[in] astromRefObjLoader An instance of LoadReferenceObjectsTasks
442 that supplies an external reference catalog for astrometric
443 calibration. May be None if the desired loader can be constructed
444 from the butler argument or all steps requiring a reference catalog
446 @param[in] photoRefObjLoader An instance of LoadReferenceObjectsTasks
447 that supplies an external reference catalog for photometric
448 calibration. May be None if the desired loader can be constructed
449 from the butler argument or all steps requiring a reference catalog
451 @param[in] icSourceSchema schema for icSource catalog, or None.
452 Schema values specified in config.icSourceFieldsToCopy will be
453 taken from this schema. If set to None, no values will be
454 propagated from the icSourceCatalog
455 @param[in,out] kwargs other keyword arguments for
456 lsst.pipe.base.CmdLineTask
460 if icSourceSchema
is None and butler
is not None:
462 icSourceSchema = butler.get(
"icSrc_schema", immediate=
True).schema
464 if icSourceSchema
is None and butler
is None and initInputs
is not None:
465 icSourceSchema = initInputs[
'icSourceSchema'].schema
467 if icSourceSchema
is not None:
470 minimumSchema = afwTable.SourceTable.makeMinimalSchema()
471 self.
schemaMapperschemaMapper.addMinimalSchema(minimumSchema,
False)
480 "Source was detected as an icSource"))
481 missingFieldNames = []
482 for fieldName
in self.config.icSourceFieldsToCopy:
484 schemaItem = icSourceSchema.find(fieldName)
486 missingFieldNames.append(fieldName)
489 self.
schemaMapperschemaMapper.addMapping(schemaItem.getKey())
491 if missingFieldNames:
492 raise RuntimeError(
"isSourceCat is missing fields {} "
493 "specified in icSourceFieldsToCopy"
494 .
format(missingFieldNames))
501 self.
schemaschema = afwTable.SourceTable.makeMinimalSchema()
502 self.makeSubtask(
'detection', schema=self.
schemaschema)
509 if self.config.doInsertFakes:
510 self.makeSubtask(
"insertFakes")
512 if self.config.doDeblend:
513 self.makeSubtask(
"deblend", schema=self.
schemaschema)
514 if self.config.doSkySources:
515 self.makeSubtask(
"skySources")
516 self.
skySourceKeyskySourceKey = self.
schemaschema.addField(
"sky_source", type=
"Flag", doc=
"Sky objects.")
517 self.makeSubtask(
'measurement', schema=self.
schemaschema,
519 self.makeSubtask(
"setPrimaryFlags", schema=self.
schemaschema, isSingleFrame=
True)
520 if self.config.doApCorr:
521 self.makeSubtask(
'applyApCorr', schema=self.
schemaschema)
522 self.makeSubtask(
'catalogCalculation', schema=self.
schemaschema)
524 if self.config.doAstrometry:
525 if astromRefObjLoader
is None and butler
is not None:
526 self.makeSubtask(
'astromRefObjLoader', butler=butler)
527 astromRefObjLoader = self.astromRefObjLoader
528 self.makeSubtask(
"astrometry", refObjLoader=astromRefObjLoader,
530 if self.config.doPhotoCal:
531 if photoRefObjLoader
is None and butler
is not None:
532 self.makeSubtask(
'photoRefObjLoader', butler=butler)
533 photoRefObjLoader = self.photoRefObjLoader
534 self.makeSubtask(
"photoCal", refObjLoader=photoRefObjLoader,
536 if self.config.doComputeSummaryStats:
537 self.makeSubtask(
'computeSummaryStats')
539 if initInputs
is not None and (astromRefObjLoader
is not None or photoRefObjLoader
is not None):
540 raise RuntimeError(
"PipelineTask form of this task should not be initialized with "
541 "reference object loaders.")
546 self.
schemaschema.checkUnits(parse_strict=self.config.checkUnitsParseStrict)
553 def runDataRef(self, dataRef, exposure=None, background=None, icSourceCat=None,
555 """!Calibrate an exposure, optionally unpersisting inputs and
558 This is a wrapper around the `run` method that unpersists inputs
559 (if `doUnpersist` true) and persists outputs (if `config.doWrite` true)
561 @param[in] dataRef butler data reference corresponding to a science
563 @param[in,out] exposure characterized exposure (an
564 lsst.afw.image.ExposureF or similar), or None to unpersist existing
565 icExp and icBackground. See `run` method for details of what is
567 @param[in,out] background initial model of background already
568 subtracted from exposure (an lsst.afw.math.BackgroundList). May be
569 None if no background has been subtracted, though that is unusual
570 for calibration. A refined background model is output. Ignored if
572 @param[in] icSourceCat catalog from which to copy the fields specified
573 by icSourceKeys, or None;
574 @param[in] doUnpersist unpersist data:
575 - if True, exposure, background and icSourceCat are read from
576 dataRef and those three arguments must all be None;
577 - if False the exposure must be provided; background and
578 icSourceCat are optional. True is intended for running as a
579 command-line task, False for running as a subtask
580 @return same data as the calibrate method
582 self.log.
info(
"Processing %s", dataRef.dataId)
585 if any(item
is not None for item
in (exposure, background,
587 raise RuntimeError(
"doUnpersist true; exposure, background "
588 "and icSourceCat must all be None")
589 exposure = dataRef.get(
"icExp", immediate=
True)
590 background = dataRef.get(
"icExpBackground", immediate=
True)
591 icSourceCat = dataRef.get(
"icSrc", immediate=
True)
592 elif exposure
is None:
593 raise RuntimeError(
"doUnpersist false; exposure must be provided")
595 exposureIdInfo = dataRef.get(
"expIdInfo")
597 calRes = self.
runrun(
599 exposureIdInfo=exposureIdInfo,
600 background=background,
601 icSourceCat=icSourceCat,
604 if self.config.doWrite:
607 exposure=calRes.exposure,
608 background=calRes.background,
609 sourceCat=calRes.sourceCat,
610 astromMatches=calRes.astromMatches,
611 matchMeta=calRes.matchMeta,
617 inputs = butlerQC.get(inputRefs)
618 inputs[
'exposureIdInfo'] = ExposureIdInfo.fromDataId(butlerQC.quantum.dataId,
"visit_detector")
620 if self.config.doAstrometry:
622 for ref
in inputRefs.astromRefCat],
623 refCats=inputs.pop(
'astromRefCat'),
624 config=self.config.astromRefObjLoader, log=self.log)
625 self.astrometry.setRefObjLoader(refObjLoader)
627 if self.config.doPhotoCal:
629 for ref
in inputRefs.photoRefCat],
630 refCats=inputs.pop(
'photoRefCat'),
631 config=self.config.photoRefObjLoader,
633 self.photoCal.match.setRefObjLoader(photoRefObjLoader)
635 outputs = self.
runrun(**inputs)
637 if self.config.doWriteMatches
and self.config.doAstrometry:
639 normalizedMatches.table.setMetadata(outputs.matchMeta)
640 if self.config.doWriteMatchesDenormalized:
642 outputs.matchesDenormalized = denormMatches
643 outputs.matches = normalizedMatches
644 butlerQC.put(outputs, outputRefs)
647 def run(self, exposure, exposureIdInfo=None, background=None,
649 """!Calibrate an exposure (science image or coadd)
651 @param[in,out] exposure exposure to calibrate (an
652 lsst.afw.image.ExposureF or similar);
657 - MaskedImage has background subtracted
659 - PhotoCalib is replaced
660 @param[in] exposureIdInfo ID info for exposure (an
661 lsst.obs.base.ExposureIdInfo) If not provided, returned
662 SourceCatalog IDs will not be globally unique.
663 @param[in,out] background background model already subtracted from
664 exposure (an lsst.afw.math.BackgroundList). May be None if no
665 background has been subtracted, though that is unusual for
666 calibration. A refined background model is output.
667 @param[in] icSourceCat A SourceCatalog from CharacterizeImageTask
668 from which we can copy some fields.
670 @return pipe_base Struct containing these fields:
671 - exposure calibrate science exposure with refined WCS and PhotoCalib
672 - background model of background subtracted from exposure (an
673 lsst.afw.math.BackgroundList)
674 - sourceCat catalog of measured sources
675 - astromMatches list of source/refObj matches from the astrometry
679 if exposureIdInfo
is None:
680 exposureIdInfo = ExposureIdInfo()
682 if background
is None:
684 sourceIdFactory = exposureIdInfo.makeSourceIdFactory()
685 table = SourceTable.make(self.
schemaschema, sourceIdFactory)
688 detRes = self.detection.
run(table=table, exposure=exposure,
690 sourceCat = detRes.sources
691 if detRes.fpSets.background:
692 for bg
in detRes.fpSets.background:
693 background.append(bg)
694 if self.config.doSkySources:
695 skySourceFootprints = self.skySources.
run(mask=exposure.mask, seed=exposureIdInfo.expId)
696 if skySourceFootprints:
697 for foot
in skySourceFootprints:
698 s = sourceCat.addNew()
701 if self.config.doDeblend:
702 self.deblend.
run(exposure=exposure, sources=sourceCat)
703 self.measurement.
run(
706 exposureId=exposureIdInfo.expId
708 if self.config.doApCorr:
709 self.applyApCorr.
run(
711 apCorrMap=exposure.getInfo().getApCorrMap()
713 self.catalogCalculation.
run(sourceCat)
715 self.setPrimaryFlags.
run(sourceCat)
717 if icSourceCat
is not None and \
718 len(self.config.icSourceFieldsToCopy) > 0:
726 if not sourceCat.isContiguous():
727 sourceCat = sourceCat.copy(deep=
True)
733 if self.config.doAstrometry:
735 astromRes = self.astrometry.
run(
739 astromMatches = astromRes.matches
740 matchMeta = astromRes.matchMeta
741 except Exception
as e:
742 if self.config.requireAstrometry:
744 self.log.
warning(
"Unable to perform astrometric calibration "
745 "(%s): attempting to proceed", e)
748 if self.config.doPhotoCal:
750 photoRes = self.photoCal.
run(exposure, sourceCat=sourceCat, expId=exposureIdInfo.expId)
751 exposure.setPhotoCalib(photoRes.photoCalib)
753 self.log.
info(
"Photometric zero-point: %f",
754 photoRes.photoCalib.instFluxToMagnitude(1.0))
755 self.
setMetadatasetMetadata(exposure=exposure, photoRes=photoRes)
756 except Exception
as e:
757 if self.config.requirePhotoCal:
759 self.log.
warning(
"Unable to perform photometric calibration "
760 "(%s): attempting to proceed", e)
761 self.
setMetadatasetMetadata(exposure=exposure, photoRes=
None)
763 if self.config.doInsertFakes:
764 self.insertFakes.
run(exposure, background=background)
766 table = SourceTable.make(self.
schemaschema, sourceIdFactory)
769 detRes = self.detection.
run(table=table, exposure=exposure,
771 sourceCat = detRes.sources
772 if detRes.fpSets.background:
773 for bg
in detRes.fpSets.background:
774 background.append(bg)
775 if self.config.doDeblend:
776 self.deblend.
run(exposure=exposure, sources=sourceCat)
777 self.measurement.
run(
780 exposureId=exposureIdInfo.expId
782 if self.config.doApCorr:
783 self.applyApCorr.
run(
785 apCorrMap=exposure.getInfo().getApCorrMap()
787 self.catalogCalculation.
run(sourceCat)
789 if icSourceCat
is not None and len(self.config.icSourceFieldsToCopy) > 0:
793 if self.config.doComputeSummaryStats:
794 summary = self.computeSummaryStats.
run(exposure=exposure,
796 background=background)
797 exposure.getInfo().setSummaryStats(summary)
804 matches=astromMatches,
809 return pipeBase.Struct(
811 background=background,
813 astromMatches=astromMatches,
817 outputExposure=exposure,
819 outputBackground=background,
823 astromMatches, matchMeta):
824 """Write output data to the output repository
826 @param[in] dataRef butler data reference corresponding to a science
828 @param[in] exposure exposure to write
829 @param[in] background background model for exposure
830 @param[in] sourceCat catalog of measured sources
831 @param[in] astromMatches list of source/refObj matches from the
834 dataRef.put(sourceCat,
"src")
835 if self.config.doWriteMatches
and astromMatches
is not None:
837 normalizedMatches.table.setMetadata(matchMeta)
838 dataRef.put(normalizedMatches,
"srcMatch")
839 if self.config.doWriteMatchesDenormalized:
841 dataRef.put(denormMatches,
"srcMatchFull")
842 if self.config.doWriteExposure:
843 dataRef.put(exposure,
"calexp")
844 dataRef.put(background,
"calexpBackground")
847 """Return a dict of empty catalogs for each catalog dataset produced
852 return {
"src": sourceCat}
855 """!Set task and exposure metadata
857 Logs a warning and continues if needed data is missing.
859 @param[in,out] exposure exposure whose metadata is to be set
860 @param[in] photoRes results of running photoCal; if None then it was
866 metadata = exposure.getMetadata()
870 exposureTime = exposure.getInfo().getVisitInfo().getExposureTime()
871 magZero = photoRes.zp - 2.5*math.log10(exposureTime)
873 self.log.
warning(
"Could not set normalized MAGZERO in header: no "
878 metadata.set(
'MAGZERO', magZero)
879 metadata.set(
'MAGZERO_RMS', photoRes.sigma)
880 metadata.set(
'MAGZERO_NOBJ', photoRes.ngood)
881 metadata.set(
'COLORTERM1', 0.0)
882 metadata.set(
'COLORTERM2', 0.0)
883 metadata.set(
'COLORTERM3', 0.0)
884 except Exception
as e:
885 self.log.
warning(
"Could not set exposure metadata: %s", e)
888 """!Match sources in icSourceCat and sourceCat and copy the specified fields
890 @param[in] icSourceCat catalog from which to copy fields
891 @param[in,out] sourceCat catalog to which to copy fields
893 The fields copied are those specified by `config.icSourceFieldsToCopy`
894 that actually exist in the schema. This was set up by the constructor
895 using self.schemaMapper.
898 raise RuntimeError(
"To copy icSource fields you must specify "
899 "icSourceSchema nd icSourceKeys when "
900 "constructing this task")
901 if icSourceCat
is None or sourceCat
is None:
902 raise RuntimeError(
"icSourceCat and sourceCat must both be "
904 if len(self.config.icSourceFieldsToCopy) == 0:
905 self.log.
warning(
"copyIcSourceFields doing nothing because "
906 "icSourceFieldsToCopy is empty")
910 mc.findOnlyClosest =
False
912 self.config.matchRadiusPix, mc)
913 if self.config.doDeblend:
914 deblendKey = sourceCat.schema[
"deblend_nChild"].asKey()
916 matches = [m
for m
in matches
if m[1].get(deblendKey) == 0]
923 for m0, m1, d
in matches:
925 match = bestMatches.get(id0)
926 if match
is None or d <= match[2]:
927 bestMatches[id0] = (m0, m1, d)
928 matches =
list(bestMatches.values())
933 numMatches = len(matches)
934 numUniqueSources = len(
set(m[1].getId()
for m
in matches))
935 if numUniqueSources != numMatches:
936 self.log.
warning(
"%d icSourceCat sources matched only %d sourceCat "
937 "sources", numMatches, numUniqueSources)
939 self.log.
info(
"Copying flags from icSourceCat to sourceCat for "
940 "%d sources", numMatches)
944 for icSrc, src, d
in matches:
950 icSrcFootprint = icSrc.getFootprint()
952 icSrc.setFootprint(src.getFootprint())
955 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.