24from lsstDebug
import getDebugFrame
27import lsst.pipe.base.connectionTypes
as cT
29from lsst.meas.astrom import AstrometryTask, displayAstrometry, denormalizeMatches
38 CatalogCalculationTask)
40from lsst.utils.timer
import timeMethod
42from .fakes
import BaseFakeSourcesTask
43from .photoCal
import PhotoCalTask
44from .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",
88 name=
"gaia_dr2_20200414",
89 storageClass=
"SimpleCatalog",
90 dimensions=(
"skypix",),
95 photoRefCat = cT.PrerequisiteInput(
96 doc=
"Reference catalog to use for photometric calibration",
97 name=
"ps1_pv3_3pi_20170110",
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
326 self.
photoCalphotoCal.photoCatName = self.connections.photoRefCat
330 self.
photoRefObjLoaderphotoRefObjLoader.ref_dataset_name =
"ps1_pv3_3pi_20170110"
334 astromRefCatGen2 = getattr(self.
astromRefObjLoaderastromRefObjLoader,
"ref_dataset_name",
None)
335 if astromRefCatGen2
is not None and astromRefCatGen2 != self.connections.astromRefCat:
337 f
"Gen2 ({astromRefCatGen2}) and Gen3 ({self.connections.astromRefCat}) astrometry reference "
338 f
"catalogs are different. These options must be kept in sync until Gen2 is retired."
340 photoRefCatGen2 = getattr(self.
photoRefObjLoaderphotoRefObjLoader,
"ref_dataset_name",
None)
341 if photoRefCatGen2
is not None and photoRefCatGen2 != self.connections.photoRefCat:
343 f
"Gen2 ({photoRefCatGen2}) and Gen3 ({self.connections.photoRefCat}) photometry reference "
344 f
"catalogs are different. These options must be kept in sync until Gen2 is retired."
356 r"""!Calibrate an exposure: measure sources and perform astrometric and
357 photometric calibration
359 @anchor CalibrateTask_
361 @section pipe_tasks_calibrate_Contents Contents
363 -
@ref pipe_tasks_calibrate_Purpose
364 -
@ref pipe_tasks_calibrate_Initialize
365 -
@ref pipe_tasks_calibrate_IO
366 -
@ref pipe_tasks_calibrate_Config
367 -
@ref pipe_tasks_calibrate_Metadata
368 -
@ref pipe_tasks_calibrate_Debug
370 @section pipe_tasks_calibrate_Purpose Description
372 Given an exposure
with a good PSF model
and aperture correction map
373 (e.g.
as provided by
@ref characterizeImage::CharacterizeImageTask
"CharacterizeImageTask"),
374 perform the following operations:
375 - Run detection
and measurement
376 - Run astrometry subtask to fit an improved WCS
377 - Run photoCal subtask to fit the exposure
's photometric zero-point
379 @section pipe_tasks_calibrate_Initialize Task initialisation
381 @copydoc \_\_init\_\_
383 @section pipe_tasks_calibrate_IO Invoking the Task
385 If you want this task to unpersist inputs
or persist outputs, then call
386 the `runDataRef` method (a wrapper around the `run` method).
388 If you already have the inputs unpersisted
and do
not want to persist the
389 output then it
is more direct to call the `run` method:
391 @section pipe_tasks_calibrate_Config Configuration parameters
393 See
@ref CalibrateConfig
395 @section pipe_tasks_calibrate_Metadata Quantities set
in exposure Metadata
399 <dt>MAGZERO_RMS <dd>MAGZERO
's RMS == sigma reported by photoCal task
400 <dt>MAGZERO_NOBJ <dd>Number of stars used == ngood reported by photoCal
402 <dt>COLORTERM1 <dd>?? (always 0.0)
403 <dt>COLORTERM2 <dd>?? (always 0.0)
404 <dt>COLORTERM3 <dd>?? (always 0.0)
407 @section pipe_tasks_calibrate_Debug Debug variables
409 The command line task
410 interface supports a flag
411 `--debug` to
import `debug.py`
from your `$PYTHONPATH`; see
412 <a href=
"https://pipelines.lsst.io/modules/lsstDebug/">the lsstDebug documentation</a>
413 for more about `debug.py`.
415 CalibrateTask has a debug dictionary containing one key:
418 <dd>frame (an int; <= 0 to
not display)
in which to display the exposure,
419 sources
and matches. See
@ref lsst.meas.astrom.displayAstrometry
for
420 the meaning of the various symbols.
423 For example, put something like:
429 if name ==
"lsst.pipe.tasks.calibrate":
438 into your `debug.py` file
and run `calibrateTask.py`
with the `--debug`
441 Some subtasks may have their own debug variables; see individual Task
448 ConfigClass = CalibrateConfig
449 _DefaultName =
"calibrate"
450 RunnerClass = pipeBase.ButlerInitializedTaskRunner
452 def __init__(self, butler=None, astromRefObjLoader=None,
453 photoRefObjLoader=None, icSourceSchema=None,
454 initInputs=None, **kwargs):
455 """!Construct a CalibrateTask
457 @param[
in] butler The butler
is passed to the refObjLoader constructor
458 in case it
is needed. Ignored
if the refObjLoader argument
459 provides a loader directly.
460 @param[
in] astromRefObjLoader An instance of LoadReferenceObjectsTasks
461 that supplies an external reference catalog
for astrometric
462 calibration. May be
None if the desired loader can be constructed
463 from the butler argument
or all steps requiring a reference catalog
465 @param[
in] photoRefObjLoader An instance of LoadReferenceObjectsTasks
466 that supplies an external reference catalog
for photometric
467 calibration. May be
None if the desired loader can be constructed
468 from the butler argument
or all steps requiring a reference catalog
470 @param[
in] icSourceSchema schema
for icSource catalog,
or None.
471 Schema values specified
in config.icSourceFieldsToCopy will be
472 taken
from this schema. If set to
None, no values will be
473 propagated
from the icSourceCatalog
474 @param[
in,out] kwargs other keyword arguments
for
475 lsst.pipe.base.CmdLineTask
479 if icSourceSchema
is None and butler
is not None:
481 icSourceSchema = butler.get(
"icSrc_schema", immediate=
True).schema
483 if icSourceSchema
is None and butler
is None and initInputs
is not None:
484 icSourceSchema = initInputs[
'icSourceSchema'].schema
486 if icSourceSchema
is not None:
489 minimumSchema = afwTable.SourceTable.makeMinimalSchema()
490 self.
schemaMapperschemaMapper.addMinimalSchema(minimumSchema,
False)
499 "Source was detected as an icSource"))
500 missingFieldNames = []
501 for fieldName
in self.config.icSourceFieldsToCopy:
503 schemaItem = icSourceSchema.find(fieldName)
505 missingFieldNames.append(fieldName)
508 self.
schemaMapperschemaMapper.addMapping(schemaItem.getKey())
510 if missingFieldNames:
511 raise RuntimeError(
"isSourceCat is missing fields {} "
512 "specified in icSourceFieldsToCopy"
513 .
format(missingFieldNames))
520 self.
schemaschema = afwTable.SourceTable.makeMinimalSchema()
521 self.makeSubtask(
'detection', schema=self.
schemaschema)
525 if self.config.doDeblend:
526 self.makeSubtask(
"deblend", schema=self.
schemaschema)
527 if self.config.doSkySources:
528 self.makeSubtask(
"skySources")
529 self.
skySourceKeyskySourceKey = self.
schemaschema.addField(
"sky_source", type=
"Flag", doc=
"Sky objects.")
530 self.makeSubtask(
'measurement', schema=self.
schemaschema,
532 self.makeSubtask(
'postCalibrationMeasurement', schema=self.
schemaschema,
534 self.makeSubtask(
"setPrimaryFlags", schema=self.
schemaschema, isSingleFrame=
True)
535 if self.config.doApCorr:
536 self.makeSubtask(
'applyApCorr', schema=self.
schemaschema)
537 self.makeSubtask(
'catalogCalculation', schema=self.
schemaschema)
539 if self.config.doAstrometry:
540 if astromRefObjLoader
is None and butler
is not None:
541 self.makeSubtask(
'astromRefObjLoader', butler=butler)
542 astromRefObjLoader = self.astromRefObjLoader
543 self.makeSubtask(
"astrometry", refObjLoader=astromRefObjLoader,
545 if self.config.doPhotoCal:
546 if photoRefObjLoader
is None and butler
is not None:
547 self.makeSubtask(
'photoRefObjLoader', butler=butler)
548 photoRefObjLoader = self.photoRefObjLoader
549 self.makeSubtask(
"photoCal", refObjLoader=photoRefObjLoader,
551 if self.config.doComputeSummaryStats:
552 self.makeSubtask(
'computeSummaryStats')
554 if initInputs
is not None and (astromRefObjLoader
is not None or photoRefObjLoader
is not None):
555 raise RuntimeError(
"PipelineTask form of this task should not be initialized with "
556 "reference object loaders.")
561 self.
schemaschema.checkUnits(parse_strict=self.config.checkUnitsParseStrict)
568 def runDataRef(self, dataRef, exposure=None, background=None, icSourceCat=None,
570 """!Calibrate an exposure, optionally unpersisting inputs and
573 This is a wrapper around the `run` method that unpersists inputs
574 (
if `doUnpersist` true)
and persists outputs (
if `config.doWrite` true)
576 @param[
in] dataRef butler data reference corresponding to a science
578 @param[
in,out] exposure characterized exposure (an
579 lsst.afw.image.ExposureF
or similar),
or None to unpersist existing
580 icExp
and icBackground. See `run` method
for details of what
is
582 @param[
in,out] background initial model of background already
584 None if no background has been subtracted, though that
is unusual
585 for calibration. A refined background model
is output. Ignored
if
587 @param[
in] icSourceCat catalog
from which to copy the fields specified
588 by icSourceKeys,
or None;
589 @param[
in] doUnpersist unpersist data:
590 -
if True, exposure, background
and icSourceCat are read
from
591 dataRef
and those three arguments must all be
None;
592 -
if False the exposure must be provided; background
and
593 icSourceCat are optional.
True is intended
for running
as a
594 command-line task,
False for running
as a subtask
595 @return same data
as the calibrate method
597 self.log.info("Processing %s", dataRef.dataId)
600 if any(item
is not None for item
in (exposure, background,
602 raise RuntimeError(
"doUnpersist true; exposure, background "
603 "and icSourceCat must all be None")
604 exposure = dataRef.get(
"icExp", immediate=
True)
605 background = dataRef.get(
"icExpBackground", immediate=
True)
606 icSourceCat = dataRef.get(
"icSrc", immediate=
True)
607 elif exposure
is None:
608 raise RuntimeError(
"doUnpersist false; exposure must be provided")
610 exposureIdInfo = dataRef.get(
"expIdInfo")
612 calRes = self.
runrun(
614 exposureIdInfo=exposureIdInfo,
615 background=background,
616 icSourceCat=icSourceCat,
619 if self.config.doWrite:
622 exposure=calRes.exposure,
623 background=calRes.background,
624 sourceCat=calRes.sourceCat,
625 astromMatches=calRes.astromMatches,
626 matchMeta=calRes.matchMeta,
632 inputs = butlerQC.get(inputRefs)
633 inputs[
'exposureIdInfo'] = ExposureIdInfo.fromDataId(butlerQC.quantum.dataId,
"visit_detector")
635 if self.config.doAstrometry:
637 for ref
in inputRefs.astromRefCat],
638 refCats=inputs.pop(
'astromRefCat'),
639 config=self.config.astromRefObjLoader, log=self.log)
640 self.astrometry.setRefObjLoader(refObjLoader)
642 if self.config.doPhotoCal:
644 for ref
in inputRefs.photoRefCat],
645 refCats=inputs.pop(
'photoRefCat'),
646 config=self.config.photoRefObjLoader,
648 self.photoCal.match.setRefObjLoader(photoRefObjLoader)
650 outputs = self.
runrun(**inputs)
652 if self.config.doWriteMatches
and self.config.doAstrometry:
654 normalizedMatches.table.setMetadata(outputs.matchMeta)
655 if self.config.doWriteMatchesDenormalized:
657 outputs.matchesDenormalized = denormMatches
658 outputs.matches = normalizedMatches
659 butlerQC.put(outputs, outputRefs)
662 def run(self, exposure, exposureIdInfo=None, background=None,
664 """!Calibrate an exposure (science image or coadd)
666 @param[
in,out] exposure exposure to calibrate (an
667 lsst.afw.image.ExposureF
or similar);
672 - MaskedImage has background subtracted
674 - PhotoCalib
is replaced
675 @param[
in] exposureIdInfo ID info
for exposure (an
676 lsst.obs.base.ExposureIdInfo) If
not provided, returned
677 SourceCatalog IDs will
not be globally unique.
678 @param[
in,out] background background model already subtracted
from
680 background has been subtracted, though that
is unusual
for
681 calibration. A refined background model
is output.
682 @param[
in] icSourceCat A SourceCatalog
from CharacterizeImageTask
683 from which we can copy some fields.
685 @return pipe_base Struct containing these fields:
686 - exposure calibrate science exposure
with refined WCS
and PhotoCalib
687 - background model of background subtracted
from exposure (an
689 - sourceCat catalog of measured sources
690 - astromMatches list of source/refObj matches
from the astrometry
694 if exposureIdInfo
is None:
695 exposureIdInfo = ExposureIdInfo()
697 if background
is None:
699 sourceIdFactory = exposureIdInfo.makeSourceIdFactory()
700 table = SourceTable.make(self.
schemaschema, sourceIdFactory)
703 detRes = self.detection.
run(table=table, exposure=exposure,
705 sourceCat = detRes.sources
706 if detRes.fpSets.background:
707 for bg
in detRes.fpSets.background:
708 background.append(bg)
709 if self.config.doSkySources:
710 skySourceFootprints = self.skySources.
run(mask=exposure.mask, seed=exposureIdInfo.expId)
711 if skySourceFootprints:
712 for foot
in skySourceFootprints:
713 s = sourceCat.addNew()
716 if self.config.doDeblend:
717 self.deblend.
run(exposure=exposure, sources=sourceCat)
718 self.measurement.
run(
721 exposureId=exposureIdInfo.expId
723 if self.config.doApCorr:
724 self.applyApCorr.
run(
726 apCorrMap=exposure.getInfo().getApCorrMap()
728 self.catalogCalculation.
run(sourceCat)
730 self.setPrimaryFlags.
run(sourceCat)
732 if icSourceCat
is not None and \
733 len(self.config.icSourceFieldsToCopy) > 0:
741 if not sourceCat.isContiguous():
742 sourceCat = sourceCat.copy(deep=
True)
748 if self.config.doAstrometry:
750 astromRes = self.astrometry.
run(
754 astromMatches = astromRes.matches
755 matchMeta = astromRes.matchMeta
756 except Exception
as e:
757 if self.config.requireAstrometry:
759 self.log.
warning(
"Unable to perform astrometric calibration "
760 "(%s): attempting to proceed", e)
763 if self.config.doPhotoCal:
765 photoRes = self.photoCal.
run(exposure, sourceCat=sourceCat, expId=exposureIdInfo.expId)
766 exposure.setPhotoCalib(photoRes.photoCalib)
768 self.log.
info(
"Photometric zero-point: %f",
769 photoRes.photoCalib.instFluxToMagnitude(1.0))
770 self.
setMetadatasetMetadata(exposure=exposure, photoRes=photoRes)
771 except Exception
as e:
772 if self.config.requirePhotoCal:
774 self.log.
warning(
"Unable to perform photometric calibration "
775 "(%s): attempting to proceed", e)
776 self.
setMetadatasetMetadata(exposure=exposure, photoRes=
None)
778 self.postCalibrationMeasurement.
run(
781 exposureId=exposureIdInfo.expId
784 if self.config.doComputeSummaryStats:
785 summary = self.computeSummaryStats.
run(exposure=exposure,
787 background=background)
788 exposure.getInfo().setSummaryStats(summary)
795 matches=astromMatches,
800 return pipeBase.Struct(
802 background=background,
804 astromMatches=astromMatches,
808 outputExposure=exposure,
810 outputBackground=background,
814 astromMatches, matchMeta):
815 """Write output data to the output repository
817 @param[
in] dataRef butler data reference corresponding to a science
819 @param[
in] exposure exposure to write
820 @param[
in] background background model
for exposure
821 @param[
in] sourceCat catalog of measured sources
822 @param[
in] astromMatches list of source/refObj matches
from the
825 dataRef.put(sourceCat, "src")
826 if self.config.doWriteMatches
and astromMatches
is not None:
828 normalizedMatches.table.setMetadata(matchMeta)
829 dataRef.put(normalizedMatches,
"srcMatch")
830 if self.config.doWriteMatchesDenormalized:
832 dataRef.put(denormMatches,
"srcMatchFull")
833 if self.config.doWriteExposure:
834 dataRef.put(exposure,
"calexp")
835 dataRef.put(background,
"calexpBackground")
838 """Return a dict of empty catalogs for each catalog dataset produced
843 return {
"src": sourceCat}
846 """!Set task and exposure metadata
848 Logs a warning and continues
if needed data
is missing.
850 @param[
in,out] exposure exposure whose metadata
is to be set
851 @param[
in] photoRes results of running photoCal;
if None then it was
857 metadata = exposure.getMetadata()
861 exposureTime = exposure.getInfo().getVisitInfo().getExposureTime()
862 magZero = photoRes.zp - 2.5*math.log10(exposureTime)
864 self.log.
warning(
"Could not set normalized MAGZERO in header: no "
869 metadata.set(
'MAGZERO', magZero)
870 metadata.set(
'MAGZERO_RMS', photoRes.sigma)
871 metadata.set(
'MAGZERO_NOBJ', photoRes.ngood)
872 metadata.set(
'COLORTERM1', 0.0)
873 metadata.set(
'COLORTERM2', 0.0)
874 metadata.set(
'COLORTERM3', 0.0)
875 except Exception
as e:
876 self.log.
warning(
"Could not set exposure metadata: %s", e)
879 """!Match sources in icSourceCat and sourceCat and copy the specified fields
881 @param[
in] icSourceCat catalog
from which to copy fields
882 @param[
in,out] sourceCat catalog to which to copy fields
884 The fields copied are those specified by `config.icSourceFieldsToCopy`
885 that actually exist
in the schema. This was set up by the constructor
889 raise RuntimeError(
"To copy icSource fields you must specify "
890 "icSourceSchema nd icSourceKeys when "
891 "constructing this task")
892 if icSourceCat
is None or sourceCat
is None:
893 raise RuntimeError(
"icSourceCat and sourceCat must both be "
895 if len(self.config.icSourceFieldsToCopy) == 0:
896 self.log.
warning(
"copyIcSourceFields doing nothing because "
897 "icSourceFieldsToCopy is empty")
901 mc.findOnlyClosest =
False
903 self.config.matchRadiusPix, mc)
904 if self.config.doDeblend:
905 deblendKey = sourceCat.schema[
"deblend_nChild"].asKey()
907 matches = [m
for m
in matches
if m[1].get(deblendKey) == 0]
914 for m0, m1, d
in matches:
916 match = bestMatches.get(id0)
917 if match
is None or d <= match[2]:
918 bestMatches[id0] = (m0, m1, d)
919 matches =
list(bestMatches.values())
924 numMatches = len(matches)
925 numUniqueSources = len(
set(m[1].getId()
for m
in matches))
926 if numUniqueSources != numMatches:
927 self.log.
warning(
"%d icSourceCat sources matched only %d sourceCat "
928 "sources", numMatches, numUniqueSources)
930 self.log.
info(
"Copying flags from icSourceCat to sourceCat for "
931 "%d sources", numMatches)
935 for icSrc, src, d
in matches:
941 icSrcFootprint = icSrc.getFootprint()
943 icSrc.setFootprint(src.getFootprint())
946 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.
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)
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.