24 from lsstDebug
import getDebugFrame
25 import lsst.pex.config
as pexConfig
29 from lsst.meas.astrom import AstrometryTask, displayAstrometry, denormalizeMatches
38 CatalogCalculationTask)
40 from .fakes
import BaseFakeSourcesTask
41 from .photoCal
import PhotoCalTask
43 __all__ = [
"CalibrateConfig",
"CalibrateTask"]
46 class CalibrateConnections(pipeBase.PipelineTaskConnections, dimensions=(
"instrument",
"visit",
"detector"),
49 icSourceSchema = cT.InitInput(
50 doc=
"Schema produced by characterize image task, used to initialize this task",
52 storageClass=
"SourceCatalog",
55 outputSchema = cT.InitOutput(
56 doc=
"Schema after CalibrateTask has been initialized",
58 storageClass=
"SourceCatalog",
62 doc=
"Input image to calibrate",
64 storageClass=
"ExposureF",
65 dimensions=(
"instrument",
"visit",
"detector"),
68 background = cT.Input(
69 doc=
"Backgrounds determined by characterize task",
70 name=
"icExpBackground",
71 storageClass=
"Background",
72 dimensions=(
"instrument",
"visit",
"detector"),
75 icSourceCat = cT.Input(
76 doc=
"Source catalog created by characterize task",
78 storageClass=
"SourceCatalog",
79 dimensions=(
"instrument",
"visit",
"detector"),
82 astromRefCat = cT.PrerequisiteInput(
83 doc=
"Reference catalog to use for astrometry",
85 storageClass=
"SimpleCatalog",
86 dimensions=(
"skypix",),
91 photoRefCat = cT.PrerequisiteInput(
92 doc=
"Reference catalog to use for photometric calibration",
94 storageClass=
"SimpleCatalog",
95 dimensions=(
"skypix",),
100 outputExposure = cT.Output(
101 doc=
"Exposure after running calibration task",
103 storageClass=
"ExposureF",
104 dimensions=(
"instrument",
"visit",
"detector"),
107 outputCat = cT.Output(
108 doc=
"Source catalog produced in calibrate task",
110 storageClass=
"SourceCatalog",
111 dimensions=(
"instrument",
"visit",
"detector"),
114 outputBackground = cT.Output(
115 doc=
"Background models estimated in calibration task",
116 name=
"calexpBackground",
117 storageClass=
"Background",
118 dimensions=(
"instrument",
"visit",
"detector"),
122 doc=
"Source/refObj matches from the astrometry solver",
124 storageClass=
"Catalog",
125 dimensions=(
"instrument",
"visit",
"detector"),
128 matchesDenormalized = cT.Output(
129 doc=
"Denormalized matches from astrometry solver",
131 storageClass=
"Catalog",
132 dimensions=(
"instrument",
"visit",
"detector"),
138 if config.doAstrometry
is False:
139 self.prerequisiteInputs.remove(
"astromRefCat")
140 if config.doPhotoCal
is False:
141 self.prerequisiteInputs.remove(
"photoRefCat")
143 if config.doWriteMatches
is False or config.doAstrometry
is False:
144 self.outputs.remove(
"matches")
145 if config.doWriteMatchesDenormalized
is False or config.doAstrometry
is False:
146 self.outputs.remove(
"matchesDenormalized")
149 class CalibrateConfig(pipeBase.PipelineTaskConfig, pipelineConnections=CalibrateConnections):
150 """Config for CalibrateTask""" 151 doWrite = pexConfig.Field(
154 doc=
"Save calibration results?",
156 doWriteHeavyFootprintsInSources = pexConfig.Field(
159 doc=
"Include HeavyFootprint data in source table? If false then heavy " 160 "footprints are saved as normal footprints, which saves some space" 162 doWriteMatches = pexConfig.Field(
165 doc=
"Write reference matches (ignored if doWrite or doAstrometry false)?",
167 doWriteMatchesDenormalized = pexConfig.Field(
170 doc=(
"Write reference matches in denormalized format? " 171 "This format uses more disk space, but is more convenient to " 172 "read. Ignored if doWriteMatches=False or doWrite=False."),
174 doAstrometry = pexConfig.Field(
177 doc=
"Perform astrometric calibration?",
179 astromRefObjLoader = pexConfig.ConfigurableField(
180 target=LoadIndexedReferenceObjectsTask,
181 doc=
"reference object loader for astrometric calibration",
183 photoRefObjLoader = pexConfig.ConfigurableField(
184 target=LoadIndexedReferenceObjectsTask,
185 doc=
"reference object loader for photometric calibration",
187 astrometry = pexConfig.ConfigurableField(
188 target=AstrometryTask,
189 doc=
"Perform astrometric calibration to refine the WCS",
191 requireAstrometry = pexConfig.Field(
194 doc=(
"Raise an exception if astrometry fails? Ignored if doAstrometry " 197 doPhotoCal = pexConfig.Field(
200 doc=
"Perform phometric calibration?",
202 requirePhotoCal = pexConfig.Field(
205 doc=(
"Raise an exception if photoCal fails? Ignored if doPhotoCal " 208 photoCal = pexConfig.ConfigurableField(
210 doc=
"Perform photometric calibration",
212 icSourceFieldsToCopy = pexConfig.ListField(
214 default=(
"calib_psf_candidate",
"calib_psf_used",
"calib_psf_reserved"),
215 doc=(
"Fields to copy from the icSource catalog to the output catalog " 216 "for matching sources Any missing fields will trigger a " 217 "RuntimeError exception. Ignored if icSourceCat is not provided.")
219 matchRadiusPix = pexConfig.Field(
222 doc=(
"Match radius for matching icSourceCat objects to sourceCat " 225 checkUnitsParseStrict = pexConfig.Field(
226 doc=(
"Strictness of Astropy unit compatibility check, can be 'raise', " 227 "'warn' or 'silent'"),
231 detection = pexConfig.ConfigurableField(
232 target=SourceDetectionTask,
235 doDeblend = pexConfig.Field(
238 doc=
"Run deblender input exposure" 240 deblend = pexConfig.ConfigurableField(
241 target=SourceDeblendTask,
242 doc=
"Split blended sources into their components" 244 measurement = pexConfig.ConfigurableField(
245 target=SingleFrameMeasurementTask,
246 doc=
"Measure sources" 248 doApCorr = pexConfig.Field(
251 doc=
"Run subtask to apply aperture correction" 253 applyApCorr = pexConfig.ConfigurableField(
254 target=ApplyApCorrTask,
255 doc=
"Subtask to apply aperture corrections" 260 catalogCalculation = pexConfig.ConfigurableField(
261 target=CatalogCalculationTask,
262 doc=
"Subtask to run catalogCalculation plugins on catalog" 264 doInsertFakes = pexConfig.Field(
267 doc=
"Run fake sources injection task" 269 insertFakes = pexConfig.ConfigurableField(
270 target=BaseFakeSourcesTask,
271 doc=
"Injection of fake sources for testing purposes (must be " 274 doWriteExposure = pexConfig.Field(
277 doc=
"Write the calexp? If fakes have been added then we do not want to write out the calexp as a " 278 "normal calexp but as a fakes_calexp." 283 self.
detection.doTempLocalBackground =
False 284 self.
deblend.maxFootprintSize = 2000
289 if astromRefCatGen2
is not None and astromRefCatGen2 != self.connections.astromRefCat:
291 f
"Gen2 ({astromRefCatGen2}) and Gen3 ({self.connections.astromRefCat}) astrometry reference " 292 f
"catalogs are different. These options must be kept in sync until Gen2 is retired." 295 if photoRefCatGen2
is not None and photoRefCatGen2 != self.connections.photoRefCat:
297 f
"Gen2 ({photoRefCatGen2}) and Gen3 ({self.connections.photoRefCat}) photometry reference " 298 f
"catalogs are different. These options must be kept in sync until Gen2 is retired." 310 r"""!Calibrate an exposure: measure sources and perform astrometric and 311 photometric calibration 313 @anchor CalibrateTask_ 315 @section pipe_tasks_calibrate_Contents Contents 317 - @ref pipe_tasks_calibrate_Purpose 318 - @ref pipe_tasks_calibrate_Initialize 319 - @ref pipe_tasks_calibrate_IO 320 - @ref pipe_tasks_calibrate_Config 321 - @ref pipe_tasks_calibrate_Metadata 322 - @ref pipe_tasks_calibrate_Debug 325 @section pipe_tasks_calibrate_Purpose Description 327 Given an exposure with a good PSF model and aperture correction map 328 (e.g. as provided by @ref CharacterizeImageTask), perform the following 330 - Run detection and measurement 331 - Run astrometry subtask to fit an improved WCS 332 - Run photoCal subtask to fit the exposure's photometric zero-point 334 @section pipe_tasks_calibrate_Initialize Task initialisation 336 @copydoc \_\_init\_\_ 338 @section pipe_tasks_calibrate_IO Invoking the Task 340 If you want this task to unpersist inputs or persist outputs, then call 341 the `runDataRef` method (a wrapper around the `run` method). 343 If you already have the inputs unpersisted and do not want to persist the 344 output then it is more direct to call the `run` method: 346 @section pipe_tasks_calibrate_Config Configuration parameters 348 See @ref CalibrateConfig 350 @section pipe_tasks_calibrate_Metadata Quantities set in exposure Metadata 354 <dt>MAGZERO_RMS <dd>MAGZERO's RMS == sigma reported by photoCal task 355 <dt>MAGZERO_NOBJ <dd>Number of stars used == ngood reported by photoCal 357 <dt>COLORTERM1 <dd>?? (always 0.0) 358 <dt>COLORTERM2 <dd>?? (always 0.0) 359 <dt>COLORTERM3 <dd>?? (always 0.0) 362 @section pipe_tasks_calibrate_Debug Debug variables 364 The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink 365 interface supports a flag 366 `--debug` to import `debug.py` from your `$PYTHONPATH`; see @ref baseDebug 367 for more about `debug.py`. 369 CalibrateTask has a debug dictionary containing one key: 372 <dd>frame (an int; <= 0 to not display) in which to display the exposure, 373 sources and matches. See @ref lsst.meas.astrom.displayAstrometry for 374 the meaning of the various symbols. 377 For example, put something like: 381 di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would 382 # call us recursively 383 if name == "lsst.pipe.tasks.calibrate": 390 lsstDebug.Info = DebugInfo 392 into your `debug.py` file and run `calibrateTask.py` with the `--debug` 395 Some subtasks may have their own debug variables; see individual Task 402 ConfigClass = CalibrateConfig
403 _DefaultName =
"calibrate" 404 RunnerClass = pipeBase.ButlerInitializedTaskRunner
406 def __init__(self, butler=None, astromRefObjLoader=None,
407 photoRefObjLoader=None, icSourceSchema=None,
408 initInputs=None, **kwargs):
409 """!Construct a CalibrateTask 411 @param[in] butler The butler is passed to the refObjLoader constructor 412 in case it is needed. Ignored if the refObjLoader argument 413 provides a loader directly. 414 @param[in] astromRefObjLoader An instance of LoadReferenceObjectsTasks 415 that supplies an external reference catalog for astrometric 416 calibration. May be None if the desired loader can be constructed 417 from the butler argument or all steps requiring a reference catalog 419 @param[in] photoRefObjLoader An instance of LoadReferenceObjectsTasks 420 that supplies an external reference catalog for photometric 421 calibration. May be None if the desired loader can be constructed 422 from the butler argument or all steps requiring a reference catalog 424 @param[in] icSourceSchema schema for icSource catalog, or None. 425 Schema values specified in config.icSourceFieldsToCopy will be 426 taken from this schema. If set to None, no values will be 427 propagated from the icSourceCatalog 428 @param[in,out] kwargs other keyword arguments for 429 lsst.pipe.base.CmdLineTask 433 if icSourceSchema
is None and butler
is not None:
435 icSourceSchema = butler.get(
"icSrc_schema", immediate=
True).schema
437 if icSourceSchema
is None and butler
is None and initInputs
is not None:
438 icSourceSchema = initInputs[
'icSourceSchema'].schema
440 if icSourceSchema
is not None:
443 minimumSchema = afwTable.SourceTable.makeMinimalSchema()
444 self.
schemaMapper.addMinimalSchema(minimumSchema,
False)
452 afwTable.Field[
"Flag"](
"calib_detected",
453 "Source was detected as an icSource"))
454 missingFieldNames = []
455 for fieldName
in self.config.icSourceFieldsToCopy:
457 schemaItem = icSourceSchema.find(fieldName)
459 missingFieldNames.append(fieldName)
464 if missingFieldNames:
465 raise RuntimeError(
"isSourceCat is missing fields {} " 466 "specified in icSourceFieldsToCopy" 467 .format(missingFieldNames))
474 self.
schema = afwTable.SourceTable.makeMinimalSchema()
475 self.makeSubtask(
'detection', schema=self.
schema)
482 if self.config.doInsertFakes:
483 self.makeSubtask(
"insertFakes")
485 if self.config.doDeblend:
486 self.makeSubtask(
"deblend", schema=self.
schema)
487 self.makeSubtask(
'measurement', schema=self.
schema,
489 if self.config.doApCorr:
490 self.makeSubtask(
'applyApCorr', schema=self.
schema)
491 self.makeSubtask(
'catalogCalculation', schema=self.
schema)
493 if self.config.doAstrometry:
494 if astromRefObjLoader
is None and butler
is not None:
495 self.makeSubtask(
'astromRefObjLoader', butler=butler)
496 astromRefObjLoader = self.astromRefObjLoader
498 self.makeSubtask(
"astrometry", refObjLoader=astromRefObjLoader,
500 if self.config.doPhotoCal:
501 if photoRefObjLoader
is None and butler
is not None:
502 self.makeSubtask(
'photoRefObjLoader', butler=butler)
503 photoRefObjLoader = self.photoRefObjLoader
504 self.
pixelMargin = photoRefObjLoader.config.pixelMargin
505 self.makeSubtask(
"photoCal", refObjLoader=photoRefObjLoader,
508 if initInputs
is not None and (astromRefObjLoader
is not None or photoRefObjLoader
is not None):
509 raise RuntimeError(
"PipelineTask form of this task should not be initialized with " 510 "reference object loaders.")
515 self.
schema.checkUnits(parse_strict=self.config.checkUnitsParseStrict)
517 sourceCatSchema = afwTable.SourceCatalog(self.
schema)
522 def runDataRef(self, dataRef, exposure=None, background=None, icSourceCat=None,
524 """!Calibrate an exposure, optionally unpersisting inputs and 527 This is a wrapper around the `run` method that unpersists inputs 528 (if `doUnpersist` true) and persists outputs (if `config.doWrite` true) 530 @param[in] dataRef butler data reference corresponding to a science 532 @param[in,out] exposure characterized exposure (an 533 lsst.afw.image.ExposureF or similar), or None to unpersist existing 534 icExp and icBackground. See `run` method for details of what is 536 @param[in,out] background initial model of background already 537 subtracted from exposure (an lsst.afw.math.BackgroundList). May be 538 None if no background has been subtracted, though that is unusual 539 for calibration. A refined background model is output. Ignored if 541 @param[in] icSourceCat catalog from which to copy the fields specified 542 by icSourceKeys, or None; 543 @param[in] doUnpersist unpersist data: 544 - if True, exposure, background and icSourceCat are read from 545 dataRef and those three arguments must all be None; 546 - if False the exposure must be provided; background and 547 icSourceCat are optional. True is intended for running as a 548 command-line task, False for running as a subtask 549 @return same data as the calibrate method 551 self.log.info(
"Processing %s" % (dataRef.dataId))
554 if any(item
is not None for item
in (exposure, background,
556 raise RuntimeError(
"doUnpersist true; exposure, background " 557 "and icSourceCat must all be None")
558 exposure = dataRef.get(
"icExp", immediate=
True)
559 background = dataRef.get(
"icExpBackground", immediate=
True)
560 icSourceCat = dataRef.get(
"icSrc", immediate=
True)
561 elif exposure
is None:
562 raise RuntimeError(
"doUnpersist false; exposure must be provided")
564 exposureIdInfo = dataRef.get(
"expIdInfo")
568 exposureIdInfo=exposureIdInfo,
569 background=background,
570 icSourceCat=icSourceCat,
573 if self.config.doWrite:
576 exposure=calRes.exposure,
577 background=calRes.background,
578 sourceCat=calRes.sourceCat,
579 astromMatches=calRes.astromMatches,
580 matchMeta=calRes.matchMeta,
586 inputs = butlerQC.get(inputRefs)
587 expId, expBits = butlerQC.quantum.dataId.pack(
"visit_detector",
589 inputs[
'exposureIdInfo'] = ExposureIdInfo(expId, expBits)
591 if self.config.doAstrometry:
592 refObjLoader = ReferenceObjectLoader(dataIds=[ref.datasetRef.dataId
593 for ref
in inputRefs.astromRefCat],
594 refCats=inputs.pop(
'astromRefCat'),
595 config=self.config.astromRefObjLoader, log=self.log)
597 self.astrometry.setRefObjLoader(refObjLoader)
599 if self.config.doPhotoCal:
600 photoRefObjLoader = ReferenceObjectLoader(dataIds=[ref.datasetRef.dataId
601 for ref
in inputRefs.photoRefCat],
602 refCats=inputs.pop(
'photoRefCat'),
603 config=self.config.photoRefObjLoader,
605 self.
pixelMargin = photoRefObjLoader.config.pixelMargin
606 self.photoCal.match.setRefObjLoader(photoRefObjLoader)
608 outputs = self.
run(**inputs)
610 if self.config.doWriteMatches
and self.config.doAstrometry:
611 normalizedMatches = afwTable.packMatches(outputs.astromMatches)
612 normalizedMatches.table.setMetadata(outputs.matchMeta)
613 if self.config.doWriteMatchesDenormalized:
614 denormMatches = denormalizeMatches(outputs.astromMatches, outputs.matchMeta)
615 outputs.matchesDenormalized = denormMatches
616 outputs.matches = normalizedMatches
617 butlerQC.put(outputs, outputRefs)
619 def run(self, exposure, exposureIdInfo=None, background=None,
621 """!Calibrate an exposure (science image or coadd) 623 @param[in,out] exposure exposure to calibrate (an 624 lsst.afw.image.ExposureF or similar); 629 - MaskedImage has background subtracted 631 - PhotoCalib is replaced 632 @param[in] exposureIdInfo ID info for exposure (an 633 lsst.obs.base.ExposureIdInfo) If not provided, returned 634 SourceCatalog IDs will not be globally unique. 635 @param[in,out] background background model already subtracted from 636 exposure (an lsst.afw.math.BackgroundList). May be None if no 637 background has been subtracted, though that is unusual for 638 calibration. A refined background model is output. 639 @param[in] icSourceCat A SourceCatalog from CharacterizeImageTask 640 from which we can copy some fields. 642 @return pipe_base Struct containing these fields: 643 - exposure calibrate science exposure with refined WCS and PhotoCalib 644 - background model of background subtracted from exposure (an 645 lsst.afw.math.BackgroundList) 646 - sourceCat catalog of measured sources 647 - astromMatches list of source/refObj matches from the astrometry 651 if exposureIdInfo
is None:
652 exposureIdInfo = ExposureIdInfo()
654 if background
is None:
655 background = BackgroundList()
656 sourceIdFactory = IdFactory.makeSource(exposureIdInfo.expId,
657 exposureIdInfo.unusedBits)
658 table = SourceTable.make(self.
schema, sourceIdFactory)
661 detRes = self.detection.
run(table=table, exposure=exposure,
663 sourceCat = detRes.sources
664 if detRes.fpSets.background:
665 for bg
in detRes.fpSets.background:
666 background.append(bg)
667 if self.config.doDeblend:
668 self.deblend.
run(exposure=exposure, sources=sourceCat)
669 self.measurement.
run(
672 exposureId=exposureIdInfo.expId
674 if self.config.doApCorr:
675 self.applyApCorr.
run(
677 apCorrMap=exposure.getInfo().getApCorrMap()
679 self.catalogCalculation.
run(sourceCat)
681 if icSourceCat
is not None and \
682 len(self.config.icSourceFieldsToCopy) > 0:
690 if not sourceCat.isContiguous():
691 sourceCat = sourceCat.copy(deep=
True)
697 if self.config.doAstrometry:
699 astromRes = self.astrometry.
run(
703 astromMatches = astromRes.matches
704 matchMeta = astromRes.matchMeta
705 except Exception
as e:
706 if self.config.requireAstrometry:
708 self.log.warn(
"Unable to perform astrometric calibration " 709 "(%s): attempting to proceed" % e)
712 if self.config.doPhotoCal:
714 photoRes = self.photoCal.
run(exposure, sourceCat=sourceCat, expId=exposureIdInfo.expId)
715 exposure.setPhotoCalib(photoRes.photoCalib)
717 self.log.info(
"Photometric zero-point: %f" %
718 photoRes.photoCalib.instFluxToMagnitude(1.0))
719 self.
setMetadata(exposure=exposure, photoRes=photoRes)
720 except Exception
as e:
721 if self.config.requirePhotoCal:
723 self.log.warn(
"Unable to perform photometric calibration " 724 "(%s): attempting to proceed" % e)
727 if self.config.doInsertFakes:
728 self.insertFakes.
run(exposure, background=background)
730 table = SourceTable.make(self.
schema, sourceIdFactory)
733 detRes = self.detection.
run(table=table, exposure=exposure,
735 sourceCat = detRes.sources
736 if detRes.fpSets.background:
737 for bg
in detRes.fpSets.background:
738 background.append(bg)
739 if self.config.doDeblend:
740 self.deblend.
run(exposure=exposure, sources=sourceCat)
741 self.measurement.
run(
744 exposureId=exposureIdInfo.expId
746 if self.config.doApCorr:
747 self.applyApCorr.
run(
749 apCorrMap=exposure.getInfo().getApCorrMap()
751 self.catalogCalculation.
run(sourceCat)
753 if icSourceCat
is not None and len(self.config.icSourceFieldsToCopy) > 0:
757 frame = getDebugFrame(self._display,
"calibrate")
762 matches=astromMatches,
767 return pipeBase.Struct(
769 background=background,
771 astromMatches=astromMatches,
775 outputExposure=exposure,
777 outputBackground=background,
780 def writeOutputs(self, dataRef, exposure, background, sourceCat,
781 astromMatches, matchMeta):
782 """Write output data to the output repository 784 @param[in] dataRef butler data reference corresponding to a science 786 @param[in] exposure exposure to write 787 @param[in] background background model for exposure 788 @param[in] sourceCat catalog of measured sources 789 @param[in] astromMatches list of source/refObj matches from the 792 dataRef.put(sourceCat,
"src")
793 if self.config.doWriteMatches
and astromMatches
is not None:
794 normalizedMatches = afwTable.packMatches(astromMatches)
795 normalizedMatches.table.setMetadata(matchMeta)
796 dataRef.put(normalizedMatches,
"srcMatch")
797 if self.config.doWriteMatchesDenormalized:
798 denormMatches = denormalizeMatches(astromMatches, matchMeta)
799 dataRef.put(denormMatches,
"srcMatchFull")
800 if self.config.doWriteExposure:
801 dataRef.put(exposure,
"calexp")
802 dataRef.put(background,
"calexpBackground")
805 """Return a dict of empty catalogs for each catalog dataset produced 808 sourceCat = afwTable.SourceCatalog(self.
schema)
810 return {
"src": sourceCat}
813 """!Set task and exposure metadata 815 Logs a warning and continues if needed data is missing. 817 @param[in,out] exposure exposure whose metadata is to be set 818 @param[in] photoRes results of running photoCal; if None then it was 824 metadata = exposure.getMetadata()
828 exposureTime = exposure.getInfo().getVisitInfo().getExposureTime()
829 magZero = photoRes.zp - 2.5*math.log10(exposureTime)
831 self.log.warn(
"Could not set normalized MAGZERO in header: no " 836 metadata.set(
'MAGZERO', magZero)
837 metadata.set(
'MAGZERO_RMS', photoRes.sigma)
838 metadata.set(
'MAGZERO_NOBJ', photoRes.ngood)
839 metadata.set(
'COLORTERM1', 0.0)
840 metadata.set(
'COLORTERM2', 0.0)
841 metadata.set(
'COLORTERM3', 0.0)
842 except Exception
as e:
843 self.log.warn(
"Could not set exposure metadata: %s" % (e,))
846 """!Match sources in icSourceCat and sourceCat and copy the specified fields 848 @param[in] icSourceCat catalog from which to copy fields 849 @param[in,out] sourceCat catalog to which to copy fields 851 The fields copied are those specified by `config.icSourceFieldsToCopy` 852 that actually exist in the schema. This was set up by the constructor 853 using self.schemaMapper. 856 raise RuntimeError(
"To copy icSource fields you must specify " 857 "icSourceSchema nd icSourceKeys when " 858 "constructing this task")
859 if icSourceCat
is None or sourceCat
is None:
860 raise RuntimeError(
"icSourceCat and sourceCat must both be " 862 if len(self.config.icSourceFieldsToCopy) == 0:
863 self.log.warn(
"copyIcSourceFields doing nothing because " 864 "icSourceFieldsToCopy is empty")
867 mc = afwTable.MatchControl()
868 mc.findOnlyClosest =
False 869 matches = afwTable.matchXy(icSourceCat, sourceCat,
870 self.config.matchRadiusPix, mc)
871 if self.config.doDeblend:
872 deblendKey = sourceCat.schema[
"deblend_nChild"].asKey()
874 matches = [m
for m
in matches
if m[1].get(deblendKey) == 0]
881 for m0, m1, d
in matches:
883 match = bestMatches.get(id0)
884 if match
is None or d <= match[2]:
885 bestMatches[id0] = (m0, m1, d)
886 matches = list(bestMatches.values())
891 numMatches = len(matches)
892 numUniqueSources = len(set(m[1].getId()
for m
in matches))
893 if numUniqueSources != numMatches:
894 self.log.warn(
"{} icSourceCat sources matched only {} sourceCat " 895 "sources".format(numMatches, numUniqueSources))
897 self.log.info(
"Copying flags from icSourceCat to sourceCat for " 898 "%s sources" % (numMatches,))
902 for icSrc, src, d
in matches:
908 icSrcFootprint = icSrc.getFootprint()
910 icSrc.setFootprint(src.getFootprint())
913 icSrc.setFootprint(icSrcFootprint)
def copyIcSourceFields(self, icSourceCat, sourceCat)
Match sources in icSourceCat and sourceCat and copy the specified fields.
def __init__(self, butler=None, astromRefObjLoader=None, photoRefObjLoader=None, icSourceSchema=None, initInputs=None, kwargs)
Construct a CalibrateTask.
def run(self, exposure, exposureIdInfo=None, background=None, icSourceCat=None)
Calibrate an exposure (science image or coadd)
def writeOutputs(self, dataRef, exposure, background, sourceCat, astromMatches, matchMeta)
def __init__(self, config=None)
def setMetadata(self, exposure, photoRes=None)
Set task and exposure metadata.
def getSchemaCatalogs(self)
def runDataRef(self, dataRef, exposure=None, background=None, icSourceCat=None, doUnpersist=True)
Calibrate an exposure, optionally unpersisting inputs and persisting outputs.
Calibrate an exposure: measure sources and perform astrometric and photometric calibration.
def runQuantum(self, butlerQC, inputRefs, outputRefs)