36import lsst.pipe.base.connectionTypes
as cT
39from lsst.skymap
import BaseSkyMap
41from .forcedMeasurement
import ForcedMeasurementTask
42from .applyApCorr
import ApplyApCorrTask
43from .catalogCalculation
import CatalogCalculationTask
44from ._id_generator
import DetectorVisitIdGeneratorConfig
46__all__ = (
"ForcedPhotCcdConfig",
"ForcedPhotCcdTask",
47 "ForcedPhotCcdFromDataFrameTask",
"ForcedPhotCcdFromDataFrameConfig")
51 dimensions=(
"instrument",
"visit",
"detector",
"skymap",
"tract"),
52 defaultTemplates={
"inputCoaddName":
"deep",
53 "inputName":
"calexp",
54 "skyWcsName":
"gbdesAstrometricFit",
55 "photoCalibName":
"fgcm"}):
56 inputSchema = cT.InitInput(
57 doc=
"Schema for the input measurement catalogs.",
58 name=
"{inputCoaddName}Coadd_ref_schema",
59 storageClass=
"SourceCatalog",
61 outputSchema = cT.InitOutput(
62 doc=
"Schema for the output forced measurement catalogs.",
63 name=
"forced_src_schema",
64 storageClass=
"SourceCatalog",
67 doc=
"Input exposure to perform photometry on.",
69 storageClass=
"ExposureF",
70 dimensions=[
"instrument",
"visit",
"detector"],
73 doc=
"Catalog of shapes and positions at which to force photometry.",
74 name=
"{inputCoaddName}Coadd_ref",
75 storageClass=
"SourceCatalog",
76 dimensions=[
"skymap",
"tract",
"patch"],
81 doc=
"SkyMap dataset that defines the coordinate system of the reference catalog.",
82 name=BaseSkyMap.SKYMAP_DATASET_TYPE_NAME,
83 storageClass=
"SkyMap",
84 dimensions=[
"skymap"],
87 doc=
"Input Sky Correction to be subtracted from the calexp if doApplySkyCorr=True",
89 storageClass=
"Background",
90 dimensions=(
"instrument",
"visit",
"detector"),
92 externalSkyWcsTractCatalog = cT.Input(
93 doc=(
"Per-tract, per-visit wcs calibrations. These catalogs use the detector "
94 "id for the catalog id, sorted on id for fast lookup."),
95 name=
"{skyWcsName}SkyWcsCatalog",
96 storageClass=
"ExposureCatalog",
97 dimensions=[
"instrument",
"visit",
"tract"],
99 externalSkyWcsGlobalCatalog = cT.Input(
100 doc=(
"Per-visit wcs calibrations computed globally (with no tract information). "
101 "These catalogs use the detector id for the catalog id, sorted on id for "
103 name=
"finalVisitSummary",
104 storageClass=
"ExposureCatalog",
105 dimensions=[
"instrument",
"visit"],
107 externalPhotoCalibTractCatalog = cT.Input(
108 doc=(
"Per-tract, per-visit photometric calibrations. These catalogs use the "
109 "detector id for the catalog id, sorted on id for fast lookup."),
110 name=
"{photoCalibName}PhotoCalibCatalog",
111 storageClass=
"ExposureCatalog",
112 dimensions=[
"instrument",
"visit",
"tract"],
114 externalPhotoCalibGlobalCatalog = cT.Input(
115 doc=(
"Per-visit photometric calibrations computed globally (with no tract "
116 "information). These catalogs use the detector id for the catalog id, "
117 "sorted on id for fast lookup."),
118 name=
"finalVisitSummary",
119 storageClass=
"ExposureCatalog",
120 dimensions=[
"instrument",
"visit"],
122 finalizedPsfApCorrCatalog = cT.Input(
123 doc=(
"Per-visit finalized psf models and aperture correction maps. "
124 "These catalogs use the detector id for the catalog id, "
125 "sorted on id for fast lookup."),
126 name=
"finalized_psf_ap_corr_catalog",
127 storageClass=
"ExposureCatalog",
128 dimensions=[
"instrument",
"visit"],
131 doc=
"Output forced photometry catalog.",
133 storageClass=
"SourceCatalog",
134 dimensions=[
"instrument",
"visit",
"detector",
"skymap",
"tract"],
137 def __init__(self, *, config=None):
138 super().__init__(config=config)
139 if not config.doApplySkyCorr:
140 self.inputs.remove(
"skyCorr")
141 if config.doApplyExternalSkyWcs:
142 if config.useGlobalExternalSkyWcs:
143 self.inputs.remove(
"externalSkyWcsTractCatalog")
145 self.inputs.remove(
"externalSkyWcsGlobalCatalog")
147 self.inputs.remove(
"externalSkyWcsTractCatalog")
148 self.inputs.remove(
"externalSkyWcsGlobalCatalog")
149 if config.doApplyExternalPhotoCalib:
150 if config.useGlobalExternalPhotoCalib:
151 self.inputs.remove(
"externalPhotoCalibTractCatalog")
153 self.inputs.remove(
"externalPhotoCalibGlobalCatalog")
155 self.inputs.remove(
"externalPhotoCalibTractCatalog")
156 self.inputs.remove(
"externalPhotoCalibGlobalCatalog")
157 if not config.doApplyFinalizedPsf:
158 self.inputs.remove(
"finalizedPsfApCorrCatalog")
161class ForcedPhotCcdConfig(pipeBase.PipelineTaskConfig,
162 pipelineConnections=ForcedPhotCcdConnections):
163 """Config class for forced measurement driver task."""
164 measurement = lsst.pex.config.ConfigurableField(
165 target=ForcedMeasurementTask,
166 doc=
"subtask to do forced measurement"
168 coaddName = lsst.pex.config.Field(
169 doc=
"coadd name: typically one of deep or goodSeeing",
173 doApCorr = lsst.pex.config.Field(
176 doc=
"Run subtask to apply aperture corrections"
178 applyApCorr = lsst.pex.config.ConfigurableField(
179 target=ApplyApCorrTask,
180 doc=
"Subtask to apply aperture corrections"
182 catalogCalculation = lsst.pex.config.ConfigurableField(
183 target=CatalogCalculationTask,
184 doc=
"Subtask to run catalogCalculation plugins on catalog"
186 doApplyUberCal = lsst.pex.config.Field(
188 doc=
"Apply meas_mosaic ubercal results to input calexps?",
190 deprecated=
"Deprecated by DM-23352; use doApplyExternalPhotoCalib and doApplyExternalSkyWcs instead",
192 doApplyExternalPhotoCalib = lsst.pex.config.Field(
195 doc=(
"Whether to apply external photometric calibration via an "
196 "`lsst.afw.image.PhotoCalib` object."),
198 useGlobalExternalPhotoCalib = lsst.pex.config.Field(
201 doc=(
"When using doApplyExternalPhotoCalib, use 'global' calibrations "
202 "that are not run per-tract. When False, use per-tract photometric "
203 "calibration files.")
205 doApplyExternalSkyWcs = lsst.pex.config.Field(
208 doc=(
"Whether to apply external astrometric calibration via an "
209 "`lsst.afw.geom.SkyWcs` object."),
211 useGlobalExternalSkyWcs = lsst.pex.config.Field(
214 doc=(
"When using doApplyExternalSkyWcs, use 'global' calibrations "
215 "that are not run per-tract. When False, use per-tract wcs "
218 doApplyFinalizedPsf = lsst.pex.config.Field(
221 doc=
"Whether to apply finalized psf models and aperture correction map.",
223 doApplySkyCorr = lsst.pex.config.Field(
226 doc=
"Apply sky correction?",
228 includePhotoCalibVar = lsst.pex.config.Field(
231 doc=
"Add photometric calibration variance to warp variance plane?",
233 footprintSource = lsst.pex.config.ChoiceField(
235 doc=
"Where to obtain footprints to install in the measurement catalog, prior to measurement.",
237 "transformed":
"Transform footprints from the reference catalog (downgrades HeavyFootprints).",
238 "psf": (
"Use the scaled shape of the PSF at the position of each source (does not generate "
239 "HeavyFootprints)."),
242 default=
"transformed",
244 psfFootprintScaling = lsst.pex.config.Field(
246 doc=
"Scaling factor to apply to the PSF shape when footprintSource='psf' (ignored otherwise).",
249 idGenerator = DetectorVisitIdGeneratorConfig.make_field()
251 def setDefaults(self):
253 super().setDefaults()
256 self.measurement.doReplaceWithNoise =
False
259 self.measurement.plugins.names = [
"base_PixelFlags",
260 "base_TransformedCentroid",
262 "base_LocalBackground",
263 "base_LocalPhotoCalib",
266 self.measurement.slots.shape =
None
269 self.catalogCalculation.plugins.names = []
273 """A pipeline task for performing forced measurement on CCD images.
278 The schema of the reference catalog, passed to the constructor of the
279 references subtask. Optional, but must be specified if ``initInputs``
280 is not;
if both are specified, ``initInputs`` takes precedence.
282 Dictionary that can contain a key ``inputSchema`` containing the
283 schema. If present will override the value of ``refSchema``.
285 Keyword arguments are passed to the supertask constructor.
288 ConfigClass = ForcedPhotCcdConfig
289 _DefaultName = "forcedPhotCcd"
292 def __init__(self, refSchema=None, initInputs=None, **kwargs):
293 super().__init__(**kwargs)
295 if initInputs
is not None:
296 refSchema = initInputs[
'inputSchema'].schema
298 if refSchema
is None:
299 raise ValueError(
"No reference schema provided.")
301 self.makeSubtask(
"measurement", refSchema=refSchema)
305 if self.config.doApCorr:
306 self.makeSubtask(
"applyApCorr", schema=self.measurement.schema)
307 self.makeSubtask(
'catalogCalculation', schema=self.measurement.schema)
310 def runQuantum(self, butlerQC, inputRefs, outputRefs):
311 inputs = butlerQC.get(inputRefs)
313 tract = butlerQC.quantum.dataId[
'tract']
314 skyMap = inputs.pop(
'skyMap')
315 inputs[
'refWcs'] = skyMap[tract].getWcs()
318 skyCorr = inputs.pop(
'skyCorr',
None)
319 if self.config.useGlobalExternalSkyWcs:
320 externalSkyWcsCatalog = inputs.pop(
'externalSkyWcsGlobalCatalog',
None)
322 externalSkyWcsCatalog = inputs.pop(
'externalSkyWcsTractCatalog',
None)
323 if self.config.useGlobalExternalPhotoCalib:
324 externalPhotoCalibCatalog = inputs.pop(
'externalPhotoCalibGlobalCatalog',
None)
326 externalPhotoCalibCatalog = inputs.pop(
'externalPhotoCalibTractCatalog',
None)
327 finalizedPsfApCorrCatalog = inputs.pop(
'finalizedPsfApCorrCatalog',
None)
329 inputs[
'exposure'] = self.prepareCalibratedExposure(
332 externalSkyWcsCatalog=externalSkyWcsCatalog,
333 externalPhotoCalibCatalog=externalPhotoCalibCatalog,
334 finalizedPsfApCorrCatalog=finalizedPsfApCorrCatalog
337 inputs[
'refCat'] = self.mergeAndFilterReferences(inputs[
'exposure'], inputs[
'refCat'],
340 if inputs[
'refCat']
is None:
341 self.log.info(
"No WCS for exposure %s. No %s catalog will be written.",
342 butlerQC.quantum.dataId, outputRefs.measCat.datasetType.name)
344 inputs[
'measCat'], inputs[
'exposureId'] = self.generateMeasCat(inputRefs.exposure.dataId,
346 inputs[
'refCat'], inputs[
'refWcs'])
347 self.attachFootprints(inputs[
'measCat'], inputs[
'refCat'], inputs[
'exposure'], inputs[
'refWcs'])
348 outputs = self.run(**inputs)
349 butlerQC.put(outputs, outputRefs)
351 def prepareCalibratedExposure(self, exposure, skyCorr=None, externalSkyWcsCatalog=None,
352 externalPhotoCalibCatalog=None, finalizedPsfApCorrCatalog=None):
353 """Prepare a calibrated exposure and apply external calibrations
354 and sky corrections
if so configured.
358 exposure : `lsst.afw.image.exposure.Exposure`
359 Input exposure to adjust calibrations.
360 skyCorr : `lsst.afw.math.backgroundList`, optional
361 Sky correction frame to apply
if doApplySkyCorr=
True.
363 Exposure catalog
with external skyWcs to be applied
364 if config.doApplyExternalSkyWcs=
True. Catalog uses the detector id
365 for the catalog id, sorted on id
for fast lookup.
367 Exposure catalog
with external photoCalib to be applied
368 if config.doApplyExternalPhotoCalib=
True. Catalog uses the detector
369 id
for the catalog id, sorted on id
for fast lookup.
371 Exposure catalog
with finalized psf models
and aperture correction
372 maps to be applied
if config.doApplyFinalizedPsf=
True. Catalog uses
373 the detector id
for the catalog id, sorted on id
for fast lookup.
377 exposure : `lsst.afw.image.exposure.Exposure`
378 Exposure
with adjusted calibrations.
380 detectorId = exposure.getInfo().getDetector().getId()
382 if externalPhotoCalibCatalog
is not None:
383 row = externalPhotoCalibCatalog.find(detectorId)
385 self.log.warning(
"Detector id %s not found in externalPhotoCalibCatalog; "
386 "Using original photoCalib.", detectorId)
388 photoCalib = row.getPhotoCalib()
389 if photoCalib
is None:
390 self.log.warning(
"Detector id %s has None for photoCalib in externalPhotoCalibCatalog; "
391 "Using original photoCalib.", detectorId)
393 exposure.setPhotoCalib(photoCalib)
395 if externalSkyWcsCatalog
is not None:
396 row = externalSkyWcsCatalog.find(detectorId)
398 self.log.warning(
"Detector id %s not found in externalSkyWcsCatalog; "
399 "Using original skyWcs.", detectorId)
401 skyWcs = row.getWcs()
403 self.log.warning(
"Detector id %s has None for skyWcs in externalSkyWcsCatalog; "
404 "Using original skyWcs.", detectorId)
406 exposure.setWcs(skyWcs)
408 if finalizedPsfApCorrCatalog
is not None:
409 row = finalizedPsfApCorrCatalog.find(detectorId)
411 self.log.warning(
"Detector id %s not found in finalizedPsfApCorrCatalog; "
412 "Using original psf.", detectorId)
415 apCorrMap = row.getApCorrMap()
416 if psf
is None or apCorrMap
is None:
417 self.log.warning(
"Detector id %s has None for psf/apCorrMap in "
418 "finalizedPsfApCorrCatalog; Using original psf.", detectorId)
421 exposure.setApCorrMap(apCorrMap)
423 if skyCorr
is not None:
424 exposure.maskedImage -= skyCorr.getImage()
428 def mergeAndFilterReferences(self, exposure, refCats, refWcs):
429 """Filter reference catalog so that all sources are within the
430 boundaries of the exposure.
434 exposure : `lsst.afw.image.exposure.Exposure`
435 Exposure to generate the catalog for.
436 refCats : sequence of `lsst.daf.butler.DeferredDatasetHandle`
437 Handles
for catalogs of shapes
and positions at which to force
439 refWcs : `lsst.afw.image.SkyWcs`
440 Reference world coordinate system.
445 Filtered catalog of forced sources to measure.
449 The majority of this code
is based on the methods of
450 lsst.meas.algorithms.loadReferenceObjects.ReferenceObjectLoader
457 expWcs = exposure.getWcs()
459 self.log.info(
"Exposure has no WCS. Returning None for mergedRefCat.")
461 expRegion = exposure.getBBox(lsst.afw.image.PARENT)
463 expBoxCorners = expBBox.getCorners()
464 expSkyCorners = [expWcs.pixelToSky(corner).getVector()
for
465 corner
in expBoxCorners]
473 for refCat
in refCats:
474 refCat = refCat.get()
475 if mergedRefCat
is None:
478 for record
in refCat:
479 if (expPolygon.contains(record.getCoord().getVector())
and record.getParent()
481 record.setFootprint(record.getFootprint())
482 mergedRefCat.append(record)
483 containedIds.add(record.getId())
484 if mergedRefCat
is None:
485 raise RuntimeError(
"No reference objects for forced photometry.")
489 def generateMeasCat(self, dataId, exposure, refCat, refWcs):
490 """Generate a measurement catalog.
494 dataId : `lsst.daf.butler.DataCoordinate`
495 Butler data ID for this image,
with ``{visit, detector}`` keys.
496 exposure : `lsst.afw.image.exposure.Exposure`
497 Exposure to generate the catalog
for.
499 Catalog of shapes
and positions at which to force photometry.
500 refWcs : `lsst.afw.image.SkyWcs`
501 Reference world coordinate system.
502 This parameter
is not currently used.
507 Catalog of forced sources to measure.
509 Unique binary id associated
with the input exposure
511 id_generator = self.config.idGenerator.apply(dataId)
512 measCat = self.measurement.generateMeasCat(exposure, refCat, refWcs,
513 idFactory=id_generator.make_table_id_factory())
514 return measCat, id_generator.catalog_id
516 def run(self, measCat, exposure, refCat, refWcs, exposureId=None):
517 """Perform forced measurement on a single exposure.
522 The measurement catalog, based on the sources listed in the
525 The measurement image upon which to perform forced detection.
527 The reference catalog of sources to measure.
528 refWcs : `lsst.afw.image.SkyWcs`
529 The WCS
for the references.
531 Optional unique exposureId used
for random seed
in measurement
536 result : `lsst.pipe.base.Struct`
537 Structure
with fields:
540 Catalog of forced measurement results
543 self.measurement.run(measCat, exposure, refCat, refWcs, exposureId=exposureId)
544 if self.config.doApCorr:
545 self.applyApCorr.run(
547 apCorrMap=exposure.getInfo().getApCorrMap()
549 self.catalogCalculation.run(measCat)
551 return pipeBase.Struct(measCat=measCat)
553 def attachFootprints(self, sources, refCat, exposure, refWcs):
554 """Attach footprints to blank sources prior to measurements.
559 be
in the pixel coordinate system of the image being measured,
while
560 the actual detections may start out
in a different coordinate system.
562 Subclasses of this
class may implement this method to define how
565 This default implementation transforms depends on the
566 ``footprintSource`` configuration parameter.
568 if self.
config.footprintSource ==
"transformed":
569 return self.measurement.attachTransformedFootprints(sources, refCat, exposure, refWcs)
570 elif self.
config.footprintSource ==
"psf":
571 return self.measurement.attachPsfShapeFootprints(sources, exposure,
572 scaling=self.
config.psfFootprintScaling)
575class ForcedPhotCcdFromDataFrameConnections(PipelineTaskConnections,
576 dimensions=(
"instrument",
"visit",
"detector",
"skymap",
"tract"),
577 defaultTemplates={
"inputCoaddName":
"goodSeeing",
578 "inputName":
"calexp",
579 "skyWcsName":
"gbdesAstrometricFit",
580 "photoCalibName":
"fgcm"}):
582 doc=
"Catalog of positions at which to force photometry.",
583 name=
"{inputCoaddName}Diff_fullDiaObjTable",
584 storageClass=
"DataFrame",
585 dimensions=[
"skymap",
"tract",
"patch"],
590 doc=
"Input exposure to perform photometry on.",
592 storageClass=
"ExposureF",
593 dimensions=[
"instrument",
"visit",
"detector"],
596 doc=
"Input Sky Correction to be subtracted from the calexp if doApplySkyCorr=True",
598 storageClass=
"Background",
599 dimensions=(
"instrument",
"visit",
"detector"),
601 externalSkyWcsTractCatalog = cT.Input(
602 doc=(
"Per-tract, per-visit wcs calibrations. These catalogs use the detector "
603 "id for the catalog id, sorted on id for fast lookup."),
604 name=
"{skyWcsName}SkyWcsCatalog",
605 storageClass=
"ExposureCatalog",
606 dimensions=[
"instrument",
"visit",
"tract"],
608 externalSkyWcsGlobalCatalog = cT.Input(
609 doc=(
"Per-visit wcs calibrations computed globally (with no tract information). "
610 "These catalogs use the detector id for the catalog id, sorted on id for "
612 name=
"{skyWcsName}SkyWcsCatalog",
613 storageClass=
"ExposureCatalog",
614 dimensions=[
"instrument",
"visit"],
616 externalPhotoCalibTractCatalog = cT.Input(
617 doc=(
"Per-tract, per-visit photometric calibrations. These catalogs use the "
618 "detector id for the catalog id, sorted on id for fast lookup."),
619 name=
"{photoCalibName}PhotoCalibCatalog",
620 storageClass=
"ExposureCatalog",
621 dimensions=[
"instrument",
"visit",
"tract"],
623 externalPhotoCalibGlobalCatalog = cT.Input(
624 doc=(
"Per-visit photometric calibrations computed globally (with no tract "
625 "information). These catalogs use the detector id for the catalog id, "
626 "sorted on id for fast lookup."),
627 name=
"{photoCalibName}PhotoCalibCatalog",
628 storageClass=
"ExposureCatalog",
629 dimensions=[
"instrument",
"visit"],
631 finalizedPsfApCorrCatalog = cT.Input(
632 doc=(
"Per-visit finalized psf models and aperture correction maps. "
633 "These catalogs use the detector id for the catalog id, "
634 "sorted on id for fast lookup."),
635 name=
"finalized_psf_ap_corr_catalog",
636 storageClass=
"ExposureCatalog",
637 dimensions=[
"instrument",
"visit"],
640 doc=
"Output forced photometry catalog.",
641 name=
"forced_src_diaObject",
642 storageClass=
"SourceCatalog",
643 dimensions=[
"instrument",
"visit",
"detector",
"skymap",
"tract"],
645 outputSchema = cT.InitOutput(
646 doc=
"Schema for the output forced measurement catalogs.",
647 name=
"forced_src_diaObject_schema",
648 storageClass=
"SourceCatalog",
651 def __init__(self, *, config=None):
652 super().__init__(config=config)
653 if not config.doApplySkyCorr:
654 self.inputs.remove(
"skyCorr")
655 if config.doApplyExternalSkyWcs:
656 if config.useGlobalExternalSkyWcs:
657 self.inputs.remove(
"externalSkyWcsTractCatalog")
659 self.inputs.remove(
"externalSkyWcsGlobalCatalog")
661 self.inputs.remove(
"externalSkyWcsTractCatalog")
662 self.inputs.remove(
"externalSkyWcsGlobalCatalog")
663 if config.doApplyExternalPhotoCalib:
664 if config.useGlobalExternalPhotoCalib:
665 self.inputs.remove(
"externalPhotoCalibTractCatalog")
667 self.inputs.remove(
"externalPhotoCalibGlobalCatalog")
669 self.inputs.remove(
"externalPhotoCalibTractCatalog")
670 self.inputs.remove(
"externalPhotoCalibGlobalCatalog")
671 if not config.doApplyFinalizedPsf:
672 self.inputs.remove(
"finalizedPsfApCorrCatalog")
675class ForcedPhotCcdFromDataFrameConfig(ForcedPhotCcdConfig,
676 pipelineConnections=ForcedPhotCcdFromDataFrameConnections):
677 def setDefaults(self):
678 super().setDefaults()
679 self.footprintSource =
"psf"
680 self.measurement.doReplaceWithNoise =
False
683 self.measurement.plugins.names = [
"base_PixelFlags",
684 "base_TransformedCentroidFromCoord",
686 "base_LocalBackground",
687 "base_LocalPhotoCalib",
690 self.measurement.slots.shape =
None
693 self.catalogCalculation.plugins.names = []
695 self.measurement.copyColumns = {
'id':
'diaObjectId',
'coord_ra':
'coord_ra',
'coord_dec':
'coord_dec'}
696 self.measurement.slots.centroid =
"base_TransformedCentroidFromCoord"
697 self.measurement.slots.psfFlux =
"base_PsfFlux"
701 if self.footprintSource ==
"transformed":
702 raise ValueError(
"Cannot transform footprints from reference catalog, "
703 "because DataFrames can't hold footprints.")
706class ForcedPhotCcdFromDataFrameTask(ForcedPhotCcdTask):
707 """Force Photometry on a per-detector exposure with coords from a DataFrame
709 Uses input from a DataFrame instead of SourceCatalog
710 like the base
class ForcedPhotCcd does.
711 Writes out a SourceCatalog so that the downstream
712 WriteForcedSourceTableTask can be reused
with output
from this Task.
714 _DefaultName = "forcedPhotCcdFromDataFrame"
715 ConfigClass = ForcedPhotCcdFromDataFrameConfig
717 def __init__(self, refSchema=None, initInputs=None, **kwargs):
719 pipeBase.PipelineTask.__init__(self, **kwargs)
725 self.
makeSubtask(
'catalogCalculation', schema=self.measurement.schema)
729 inputs = butlerQC.get(inputRefs)
732 inputs[
'refWcs'] =
None
735 skyCorr = inputs.pop(
'skyCorr',
None)
736 if self.
config.useGlobalExternalSkyWcs:
737 externalSkyWcsCatalog = inputs.pop(
'externalSkyWcsGlobalCatalog',
None)
739 externalSkyWcsCatalog = inputs.pop(
'externalSkyWcsTractCatalog',
None)
740 if self.
config.useGlobalExternalPhotoCalib:
741 externalPhotoCalibCatalog = inputs.pop(
'externalPhotoCalibGlobalCatalog',
None)
743 externalPhotoCalibCatalog = inputs.pop(
'externalPhotoCalibTractCatalog',
None)
744 finalizedPsfApCorrCatalog = inputs.pop(
'finalizedPsfApCorrCatalog',
None)
746 inputs[
'exposure'] = self.prepareCalibratedExposure(
749 externalSkyWcsCatalog=externalSkyWcsCatalog,
750 externalPhotoCalibCatalog=externalPhotoCalibCatalog,
751 finalizedPsfApCorrCatalog=finalizedPsfApCorrCatalog
754 self.log.info(
"Filtering ref cats: %s",
','.
join([
str(i.dataId)
for i
in inputs[
'refCat']]))
755 if inputs[
"exposure"].getWcs()
is not None:
756 refCat = self.
df2RefCat([i.get(parameters={
"columns": [
'diaObjectId',
'ra',
'dec']})
757 for i
in inputs[
'refCat']],
758 inputs[
'exposure'].
getBBox(), inputs[
'exposure'].getWcs())
759 inputs[
'refCat'] = refCat
761 inputs[
'measCat'], inputs[
'exposureId'] = self.generateMeasCat(
762 inputRefs.exposure.dataId, inputs[
'exposure'], inputs[
'refCat'], inputs[
'refWcs']
766 self.attachFootprints(inputs[
"measCat"], inputs[
"refCat"], inputs[
"exposure"], inputs[
"refWcs"])
767 outputs = self.run(**inputs)
769 butlerQC.put(outputs, outputRefs)
771 self.log.info(
"No WCS for %s. Skipping and no %s catalog will be written.",
772 butlerQC.quantum.dataId, outputRefs.measCat.datasetType.name)
775 """Convert list of DataFrames to reference catalog
777 Concatenate list of DataFrames presumably from multiple patches
and
778 downselect rows that overlap the exposureBBox using the exposureWcs.
782 dfList : `list` of `pandas.DataFrame`
783 Each element containst diaObjects
with ra/dec position
in degrees
784 Columns
'diaObjectId',
'ra',
'dec' are expected
786 Bounding box on which to select rows that overlap
788 World coordinate system to convert sky coords
in ref cat to
789 pixel coords
with which to compare
with exposureBBox
794 Source Catalog
with minimal schema that overlaps exposureBBox
796 df = pd.concat(dfList)
799 mapping = exposureWcs.getTransform().getMapping()
800 x, y = mapping.applyInverse(np.array(df[[
'ra',
'dec']].values*2*np.pi/360).T)
806 """Create minimal schema SourceCatalog from a pandas DataFrame.
808 The forced measurement subtask expects this as input.
812 df : `pandas.DataFrame`
813 DiaObjects
with locations
and ids.
818 Output catalog
with minimal schema.
822 outputCatalog.reserve(len(df))
824 for diaObjectId, ra, dec
in df[[
'ra',
'dec']].itertuples():
825 outputRecord = outputCatalog.addNew()
826 outputRecord.setId(diaObjectId)
std::string join(std::string const &a, std::string const &b) const
static Schema makeMinimalSchema()
static Key< RecordId > getParentKey()
def df2RefCat(self, dfList, exposureBBox, exposureWcs)
def runQuantum(self, butlerQC, inputRefs, outputRefs)
def df2SourceCat(self, df)