From 59eea10a51bff6ac487ab7dd3342a2ac41b57a6c Mon Sep 17 00:00:00 2001 From: Clare Saunders Date: Sat, 24 Jun 2023 17:51:49 -0700 Subject: [PATCH] Propagate coordinate covariance in catalogs --- python/lsst/pipe/tasks/calibrate.py | 1 + python/lsst/pipe/tasks/calibrateImage.py | 1 + python/lsst/pipe/tasks/functors.py | 34 ++++++++++++++++++++++++ python/lsst/pipe/tasks/multiBand.py | 1 + schemas/Object.yaml | 26 ++++++++++++++++-- schemas/Source.yaml | 11 +++++--- tests/test_calibrateImage.py | 6 ++--- 7 files changed, 70 insertions(+), 10 deletions(-) diff --git a/python/lsst/pipe/tasks/calibrate.py b/python/lsst/pipe/tasks/calibrate.py index f9c4365f6d..28066aef53 100644 --- a/python/lsst/pipe/tasks/calibrate.py +++ b/python/lsst/pipe/tasks/calibrate.py @@ -417,6 +417,7 @@ def __init__(self, astromRefObjLoader=None, else: self.schemaMapper = None self.schema = afwTable.SourceTable.makeMinimalSchema() + afwTable.CoordKey.addErrorFields(self.schema) self.makeSubtask('detection', schema=self.schema) self.algMetadata = dafBase.PropertyList() diff --git a/python/lsst/pipe/tasks/calibrateImage.py b/python/lsst/pipe/tasks/calibrateImage.py index 882108491e..2effba94d5 100644 --- a/python/lsst/pipe/tasks/calibrateImage.py +++ b/python/lsst/pipe/tasks/calibrateImage.py @@ -352,6 +352,7 @@ def __init__(self, initial_stars_schema=None, **kwargs): # star measurement subtasks if initial_stars_schema is None: initial_stars_schema = afwTable.SourceTable.makeMinimalSchema() + afwTable.CoordKey.addErrorFields(initial_stars_schema) self.makeSubtask("star_detection", schema=initial_stars_schema) self.makeSubtask("star_deblend", schema=initial_stars_schema) self.makeSubtask("star_measurement", schema=initial_stars_schema) diff --git a/python/lsst/pipe/tasks/functors.py b/python/lsst/pipe/tasks/functors.py index 75629c6a44..ac6149a843 100644 --- a/python/lsst/pipe/tasks/functors.py +++ b/python/lsst/pipe/tasks/functors.py @@ -708,6 +708,40 @@ def __call__(self, catalog, **kwargs): return super().__call__(catalog, **kwargs) +class RAErrColumn(CoordColumn): + """Uncertainty in Right Ascension, in degrees.""" + name = 'RAErr' + _defaultNoDup = True + + def __init__(self, **kwargs): + super().__init__('coord_raErr', **kwargs) + + +class DecErrColumn(CoordColumn): + """Uncertainty in declination, in degrees.""" + name = 'DecErr' + _defaultNoDup = True + + def __init__(self, **kwargs): + super().__init__('coord_decErr', **kwargs) + + +class RADecCovColumn(Column): + """Coordinate covariance column, in degrees.""" + _radians = True + name = 'RADecCov' + _defaultNoDup = True + + def __init__(self, **kwargs): + super().__init__('coord_ra_dec_Cov', **kwargs) + + def _func(self, df): + # Must not modify original column in case that column is used by + # another functor. + output = df[self.col]*(180/np.pi)**2 if self._radians else df[self.col] + return output + + class HtmIndex20(Functor): """Compute the level 20 HtmIndex for the catalog. diff --git a/python/lsst/pipe/tasks/multiBand.py b/python/lsst/pipe/tasks/multiBand.py index 8ce64fa2ac..892170c56c 100644 --- a/python/lsst/pipe/tasks/multiBand.py +++ b/python/lsst/pipe/tasks/multiBand.py @@ -508,6 +508,7 @@ def __init__(self, schema=None, peakSchema=None, refObjLoader=None, initInputs=N self.schemaMapper = afwTable.SchemaMapper(schema) self.schemaMapper.addMinimalSchema(schema) self.schema = self.schemaMapper.getOutputSchema() + afwTable.CoordKey.addErrorFields(self.schema) self.algMetadata = PropertyList() self.makeSubtask("measurement", schema=self.schema, algMetadata=self.algMetadata) self.makeSubtask("setPrimaryFlags", schema=self.schema) diff --git a/schemas/Object.yaml b/schemas/Object.yaml index 7e7ee6c29a..b7f4f4d20d 100644 --- a/schemas/Object.yaml +++ b/schemas/Object.yaml @@ -18,6 +18,18 @@ funcs: # coord_dec because "dec" is reserved in most SQL DBs functor: DecColumn dataset: ref + coord_raErr: + # error in reference position for merged "ref" cat. + functor: RAErrColumn + dataset: ref + coord_decErr: + # error in reference position for merged "ref" cat. + functor: DecErrColumn + dataset: ref + coord_ra_dec_Cov: + # covariance in reference position for merged "ref" cat. + functor: RADecCovColumn + dataset: ref ra: functor: CoordColumn args: coord_ra @@ -34,8 +46,18 @@ funcs: args: coord_dec dataset: meas - # raErr: not available yet DM-15180 - # decErr: not available yet DM-15180 + raErr: + functor: RAErrColumn + dataset: meas + noDup: False + decErr: + functor: DecErrColumn + dataset: meas + noDup: False + ra_dec_Cov: + functor: RADecCovColumn + dataset: meas + noDup: False # Reference band is same for all measurements refBand: functor: ReferenceBand diff --git a/schemas/Source.yaml b/schemas/Source.yaml index fc37e8dee4..fb50da57ed 100644 --- a/schemas/Source.yaml +++ b/schemas/Source.yaml @@ -37,7 +37,6 @@ funcs: # x_y_Cov: not available ra: functor: RAColumn - # raErr: not available yet DM-15180 dec: functor: DecColumn @@ -45,9 +44,13 @@ funcs: # compatibility. To be removed after September 2023. decl: functor: DecColumn - - # decErr: not available yet DM-15180 - # ra_dec_Cov: not available yet + + raErr: + functor: RAErrColumn + decErr: + functor: DecErrColumn + ra_dec_Cov: + functor: RADecCovColumn # One calibrated Calib flux is important: calibFlux: functor: LocalNanojansky diff --git a/tests/test_calibrateImage.py b/tests/test_calibrateImage.py index 6b314d80fb..bea38a3e41 100644 --- a/tests/test_calibrateImage.py +++ b/tests/test_calibrateImage.py @@ -75,10 +75,8 @@ def setUp(self): dataset.addSource(instFlux=500*noise*psf_scale, centroid=center, shape=shape) schema = dataset.makeMinimalSchema() - schema.addField("truth_flux", type=np.float64, doc="true flux", units="nJy") - schema.addField("truth_fluxErr", type=np.float64, doc="true fluxErr", units="nJy") - - self.truth_exposure, self.truth_cat = dataset.realize(noise=noise, schema=dataset.makeMinimalSchema()) + afwTable.CoordKey.addErrorFields(schema) + self.truth_exposure, self.truth_cat = dataset.realize(noise=noise, schema=schema) lsst.afw.table.updateSourceCoords(self.truth_exposure.wcs, self.truth_cat) # To make it look like a version=1 (nJy fluxes) refcat self.truth_cat = self.truth_exposure.photoCalib.calibrateCatalog(self.truth_cat)