LSST Applications g070148d5b3+33e5256705,g0d53e28543+25c8b88941,g0da5cf3356+2dd1178308,g1081da9e2a+62d12e78cb,g17e5ecfddb+7e422d6136,g1c76d35bf8+ede3a706f7,g295839609d+225697d880,g2e2c1a68ba+cc1f6f037e,g2ffcdf413f+853cd4dcde,g38293774b4+62d12e78cb,g3b44f30a73+d953f1ac34,g48ccf36440+885b902d19,g4b2f1765b6+7dedbde6d2,g5320a0a9f6+0c5d6105b6,g56b687f8c9+ede3a706f7,g5c4744a4d9+ef6ac23297,g5ffd174ac0+0c5d6105b6,g6075d09f38+66af417445,g667d525e37+2ced63db88,g670421136f+2ced63db88,g71f27ac40c+2ced63db88,g774830318a+463cbe8d1f,g7876bc68e5+1d137996f1,g7985c39107+62d12e78cb,g7fdac2220c+0fd8241c05,g96f01af41f+368e6903a7,g9ca82378b8+2ced63db88,g9d27549199+ef6ac23297,gabe93b2c52+e3573e3735,gb065e2a02a+3dfbe639da,gbc3249ced9+0c5d6105b6,gbec6a3398f+0c5d6105b6,gc9534b9d65+35b9f25267,gd01420fc67+0c5d6105b6,geee7ff78d7+a14128c129,gf63283c776+ede3a706f7,gfed783d017+0c5d6105b6,w.2022.47
LSST Data Management Base Package
Loading...
Searching...
No Matches
loadReferenceObjects.py
Go to the documentation of this file.
2# LSST Data Management System
3#
4# Copyright 2008-2017 AURA/LSST.
5#
6# This product includes software developed by the
7# LSST Project (http://www.lsst.org/).
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the LSST License Statement and
20# the GNU General Public License along with this program. If not,
21# see <https://www.lsstcorp.org/LegalNotices/>.
22#
23
24__all__ = ["getRefFluxField", "getRefFluxKeys", "LoadReferenceObjectsTask", "LoadReferenceObjectsConfig",
25 "ReferenceObjectLoader", "ReferenceObjectLoaderBase"]
26
27import abc
28import logging
29import warnings
30from deprecated.sphinx import deprecated
31
32import astropy.time
33import astropy.units
34import numpy
35
36import lsst.geom as geom
37import lsst.afw.table as afwTable
38import lsst.pex.config as pexConfig
39import lsst.pipe.base as pipeBase
40from lsst import sphgeom
41from lsst.daf.base import PropertyList
42
43
44# TODO DM-34793: remove this function
45def isOldFluxField(name, units):
46 """Return True if this name/units combination corresponds to an
47 "old-style" reference catalog flux field.
48 """
49 unitsCheck = units != 'nJy' # (units == 'Jy' or units == '' or units == '?')
50 isFlux = name.endswith('_flux')
51 isFluxSigma = name.endswith('_fluxSigma')
52 isFluxErr = name.endswith('_fluxErr')
53 return (isFlux or isFluxSigma or isFluxErr) and unitsCheck
54
55
56# TODO DM-34793: remove this function
58 """Return True if the units of all flux and fluxErr are correct (nJy).
59 """
60 for field in schema:
61 if isOldFluxField(field.field.getName(), field.field.getUnits()):
62 return False
63 return True
64
65
67 """"Return the format version stored in a reference catalog header.
68
69 Parameters
70 ----------
72 Reference catalog to inspect.
73
74 Returns
75 -------
76 version : `int`
77 Format verison integer. Returns `0` if the catalog has no metadata
78 or the metadata does not include a "REFCAT_FORMAT_VERSION" key.
79 """
80 # TODO DM-34793: change to "Version 0 refcats are no longer supported: refcat fluxes must have nJy units."
81 # TODO DM-34793: and raise an exception instead of returning 0.
82 deprecation_msg = "Support for version 0 refcats (pre-nJy fluxes) will be removed after v25."
83 md = refCat.getMetadata()
84 if md is None:
85 warnings.warn(deprecation_msg)
86 return 0
87 try:
88 return md.getScalar("REFCAT_FORMAT_VERSION")
89 except KeyError:
90 warnings.warn(deprecation_msg)
91 return 0
92
93
94# TODO DM-34793: remove this function
95@deprecated(reason="Support for version 0 refcats (pre-nJy fluxes) will be removed after v25.",
96 version="v24.0", category=FutureWarning)
97def convertToNanojansky(catalog, log, doConvert=True):
98 """Convert fluxes in a catalog from jansky to nanojansky.
99
100 Parameters
101 ----------
103 The catalog to convert.
104 log : `lsst.log.Log` or `logging.Logger`
105 Log to send messages to.
106 doConvert : `bool`, optional
107 Return a converted catalog, or just identify the fields that need to be converted?
108 This supports the "write=False" mode of `bin/convert_to_nJy.py`.
109
110 Returns
111 -------
112 catalog : `lsst.afw.table.SimpleCatalog` or None
113 The converted catalog, or None if ``doConvert`` is False.
114
115 Notes
116 -----
117 Support for old units in reference catalogs will be removed after the
118 release of late calendar year 2019.
119 Use `meas_algorithms/bin/convert_to_nJy.py` to update your reference catalog.
120 """
121 # Do not share the AliasMap: for refcats, that gets created when the
122 # catalog is read from disk and should not be propagated.
123 mapper = afwTable.SchemaMapper(catalog.schema, shareAliasMap=False)
124 mapper.addMinimalSchema(afwTable.SimpleTable.makeMinimalSchema())
125 input_fields = []
126 output_fields = []
127 for field in catalog.schema:
128 oldName = field.field.getName()
129 oldUnits = field.field.getUnits()
130 if isOldFluxField(oldName, oldUnits):
131 units = 'nJy'
132 # remap Sigma flux fields to Err, so we can drop the alias
133 if oldName.endswith('_fluxSigma'):
134 name = oldName.replace('_fluxSigma', '_fluxErr')
135 else:
136 name = oldName
137 newField = afwTable.Field[field.dtype](name, field.field.getDoc(), units)
138 mapper.addMapping(field.getKey(), newField)
139 input_fields.append(field.field)
140 output_fields.append(newField)
141 else:
142 mapper.addMapping(field.getKey())
143
144 fluxFieldsStr = '; '.join("(%s, '%s')" % (field.getName(), field.getUnits()) for field in input_fields)
145
146 if doConvert:
147 newSchema = mapper.getOutputSchema()
148 output = afwTable.SimpleCatalog(newSchema)
149 output.reserve(len(catalog))
150 output.extend(catalog, mapper=mapper)
151 for field in output_fields:
152 output[field.getName()] *= 1e9
153 log.info("Converted refcat flux fields to nJy (name, units): %s", fluxFieldsStr)
154 return output
155 else:
156 log.info("Found old-style refcat flux fields (name, units): %s", fluxFieldsStr)
157 return None
158
159
161 """This is a private helper class which filters catalogs by
162 row based on the row being inside the region used to initialize
163 the class.
164
165 Parameters
166 ----------
167 region : `lsst.sphgeom.Region`
168 The spatial region which all objects should lie within
169 """
170 def __init__(self, region):
171 self.region = region
172
173 def __call__(self, refCat, catRegion):
174 """This call method on an instance of this class takes in a reference
175 catalog, and the region from which the catalog was generated.
176
177 If the catalog region is entirely contained within the region used to
178 initialize this class, then all the entries in the catalog must be
179 within the region and so the whole catalog is returned.
180
181 If the catalog region is not entirely contained, then the location for
182 each record is tested against the region used to initialize the class.
183 Records which fall inside this region are added to a new catalog, and
184 this catalog is then returned.
185
186 Parameters
187 ---------
189 SourceCatalog to be filtered.
190 catRegion : `lsst.sphgeom.Region`
191 Region in which the catalog was created
192 """
193 if catRegion.isWithin(self.region):
194 # no filtering needed, region completely contains refcat
195 return refCat
196
197 filteredRefCat = type(refCat)(refCat.table)
198 for record in refCat:
199 if self.region.contains(record.getCoord().getVector()):
200 filteredRefCat.append(record)
201 return filteredRefCat
202
203
204class LoadReferenceObjectsConfig(pexConfig.Config):
205 pixelMargin = pexConfig.RangeField(
206 doc="Padding to add to 4 all edges of the bounding box (pixels)",
207 dtype=int,
208 default=250,
209 min=0,
210 )
211 anyFilterMapsToThis = pexConfig.Field(
212 doc=("Always use this reference catalog filter, no matter whether or what filter name is "
213 "supplied to the loader. Effectively a trivial filterMap: map all filter names to this filter."
214 " This can be set for purely-astrometric catalogs (e.g. Gaia DR2) where there is only one "
215 "reasonable choice for every camera filter->refcat mapping, but not for refcats used for "
216 "photometry, which need a filterMap and/or colorterms/transmission corrections."),
217 dtype=str,
218 default=None,
219 optional=True
220 )
221 filterMap = pexConfig.DictField(
222 doc=("Mapping of camera filter name: reference catalog filter name; "
223 "each reference filter must exist in the refcat."
224 " Note that this does not perform any bandpass corrections: it is just a lookup."),
225 keytype=str,
226 itemtype=str,
227 default={},
228 )
229 requireProperMotion = pexConfig.Field(
230 doc="Require that the fields needed to correct proper motion "
231 "(epoch, pm_ra and pm_dec) are present?",
232 dtype=bool,
233 default=False,
234 )
235 ref_dataset_name = pexConfig.Field(
236 doc="Deprecated; do not use. Added for easier transition from LoadIndexedReferenceObjectsConfig to "
237 "LoadReferenceObjectsConfig",
238 dtype=str,
239 default='',
240 deprecated='This field is not used. It will be removed after v25.',
241 )
242
243 def validate(self):
244 super().validate()
245 if self.filterMap != {} and self.anyFilterMapsToThis is not None:
246 msg = "`filterMap` and `anyFilterMapsToThis` are mutually exclusive"
247 raise pexConfig.FieldValidationError(LoadReferenceObjectsConfig.anyFilterMapsToThis,
248 self, msg)
249
250
252 """This class facilitates loading reference catalogs.
253
254 The QuantumGraph generation will create a list of datasets that may
255 possibly overlap a given region. These datasets are then used to construct
256 an instance of this class. The class instance should then be passed into
257 a task which needs reference catalogs. These tasks should then determine
258 the exact region of the sky reference catalogs will be loaded for, and
259 call a corresponding method to load the reference objects.
260
261 Parameters
262 ----------
263 dataIds : iterable of `lsst.daf.butler.DataCoordinate`
264 An iterable object of data IDs that point to reference catalogs.
265 refCats : iterable of `lsst.daf.butler.DeferredDatasetHandle`
266 Handles to load refCats on demand.
267 name : `str`, optional
268 The name of the refcat that this object will load. This name is used
269 for applying colorterms, for example.
270 config : `LoadReferenceObjectsConfig`
271 Configuration of this reference loader.
272 log : `lsst.log.Log`, `logging.Logger` or `None`, optional
273 Logger object used to write out messages. If `None` a default
274 logger will be used.
275 """
276 ConfigClass = LoadReferenceObjectsConfig
277
278 def __init__(self, dataIds, refCats, name=None, log=None, config=None, **kwargs):
279 if kwargs:
280 warnings.warn("Instantiating ReferenceObjectLoader with additional kwargs is deprecated "
281 "and will be removed after v25.0", FutureWarning, stacklevel=2)
282
283 if config is None:
284 config = self.ConfigClass()
285 self.config = config
286 self.dataIds = dataIds
287 self.refCats = refCats
288 self.name = name
289 self.log = log or logging.getLogger(__name__).getChild("ReferenceObjectLoader")
290
291 def applyProperMotions(self, catalog, epoch):
292 """Apply proper motion correction to a reference catalog.
293
294 Adjust position and position error in the ``catalog``
295 for proper motion to the specified ``epoch``,
296 modifying the catalog in place.
297
298 Parameters
299 ----------
301 Catalog of positions, containing at least these fields:
302
303 - Coordinates, retrieved by the table's coordinate key.
304 - ``coord_raErr`` : Error in Right Ascension (rad).
305 - ``coord_decErr`` : Error in Declination (rad).
306 - ``pm_ra`` : Proper motion in Right Ascension (rad/yr,
307 East positive)
308 - ``pm_raErr`` : Error in ``pm_ra`` (rad/yr), optional.
309 - ``pm_dec`` : Proper motion in Declination (rad/yr,
310 North positive)
311 - ``pm_decErr`` : Error in ``pm_dec`` (rad/yr), optional.
312 - ``epoch`` : Mean epoch of object (an astropy.time.Time)
313 epoch : `astropy.time.Time`
314 Epoch to which to correct proper motion.
315 If None, do not apply PM corrections or raise if
316 ``config.requireProperMotion`` is True.
317
318 Raises
319 ------
320 RuntimeError
321 Raised if ``config.requireProperMotion`` is set but we cannot
322 apply the proper motion correction for some reason.
323 """
324 if epoch is None:
325 if self.config.requireProperMotion:
326 raise RuntimeError("requireProperMotion=True but epoch not provided to loader.")
327 else:
328 self.log.debug("No epoch provided: not applying proper motion corrections to refcat.")
329 return
330
331 # Warn/raise for a catalog in an incorrect format, if epoch was specified.
332 if ("pm_ra" in catalog.schema
333 and not isinstance(catalog.schema["pm_ra"].asKey(), afwTable.KeyAngle)):
334 if self.config.requireProperMotion:
335 raise RuntimeError("requireProperMotion=True but refcat pm_ra field is not an Angle.")
336 else:
337 self.log.warning("Reference catalog pm_ra field is not an Angle; cannot apply proper motion.")
338 return
339
340 if ("epoch" not in catalog.schema or "pm_ra" not in catalog.schema):
341 if self.config.requireProperMotion:
342 raise RuntimeError("requireProperMotion=True but PM data not available from catalog.")
343 else:
344 self.log.warning("Proper motion correction not available for this reference catalog.")
345 return
346
347 applyProperMotionsImpl(self.log, catalog, epoch)
348
349 @staticmethod
350 def makeMinimalSchema(filterNameList, *, addCentroid=False,
351 addIsPhotometric=False, addIsResolved=False,
352 addIsVariable=False, coordErrDim=2,
353 addProperMotion=False, properMotionErrDim=2,
354 addParallax=False):
355 """Make a standard schema for reference object catalogs.
356
357 Parameters
358 ----------
359 filterNameList : `list` of `str`
360 List of filter names. Used to create <filterName>_flux fields.
361 addIsPhotometric : `bool`
362 If True then add field "photometric".
363 addIsResolved : `bool`
364 If True then add field "resolved".
365 addIsVariable : `bool`
366 If True then add field "variable".
367 coordErrDim : `int`
368 Number of coord error fields; must be one of 0, 2, 3:
369
370 - If 2 or 3: add fields "coord_raErr" and "coord_decErr".
371 - If 3: also add field "coord_radecErr".
372 addProperMotion : `bool`
373 If True add fields "epoch", "pm_ra", "pm_dec" and "pm_flag".
374 properMotionErrDim : `int`
375 Number of proper motion error fields; must be one of 0, 2, 3;
376 ignored if addProperMotion false:
377 - If 2 or 3: add fields "pm_raErr" and "pm_decErr".
378 - If 3: also add field "pm_radecErr".
379 addParallax : `bool`
380 If True add fields "epoch", "parallax", "parallaxErr"
381 and "parallax_flag".
382
383 Returns
384 -------
385 schema : `lsst.afw.table.Schema`
386 Schema for reference catalog, an
388
389 Notes
390 -----
391 Reference catalogs support additional covariances, such as
392 covariance between RA and proper motion in declination,
393 that are not supported by this method, but can be added after
394 calling this method.
395 """
396 schema = afwTable.SimpleTable.makeMinimalSchema()
397 if addCentroid:
398 afwTable.Point2DKey.addFields(
399 schema,
400 "centroid",
401 "centroid on an exposure, if relevant",
402 "pixel",
403 )
404 schema.addField(
405 field="hasCentroid",
406 type="Flag",
407 doc="is position known?",
408 )
409 for filterName in filterNameList:
410 schema.addField(
411 field="%s_flux" % (filterName,),
412 type=numpy.float64,
413 doc="flux in filter %s" % (filterName,),
414 units="nJy",
415 )
416 for filterName in filterNameList:
417 schema.addField(
418 field="%s_fluxErr" % (filterName,),
419 type=numpy.float64,
420 doc="flux uncertainty in filter %s" % (filterName,),
421 units="nJy",
422 )
423 if addIsPhotometric:
424 schema.addField(
425 field="photometric",
426 type="Flag",
427 doc="set if the object can be used for photometric calibration",
428 )
429 if addIsResolved:
430 schema.addField(
431 field="resolved",
432 type="Flag",
433 doc="set if the object is spatially resolved",
434 )
435 if addIsVariable:
436 schema.addField(
437 field="variable",
438 type="Flag",
439 doc="set if the object has variable brightness",
440 )
441 if coordErrDim not in (0, 2, 3):
442 raise ValueError("coordErrDim={}; must be (0, 2, 3)".format(coordErrDim))
443 if coordErrDim > 0:
444 afwTable.CovarianceMatrix2fKey.addFields(
445 schema=schema,
446 prefix="coord",
447 names=["ra", "dec"],
448 units=["rad", "rad"],
449 diagonalOnly=(coordErrDim == 2),
450 )
451
452 if addProperMotion or addParallax:
453 schema.addField(
454 field="epoch",
455 type=numpy.float64,
456 doc="date of observation (TAI, MJD)",
457 units="day",
458 )
459
460 if addProperMotion:
461 schema.addField(
462 field="pm_ra",
463 type="Angle",
464 doc="proper motion in the right ascension direction = dra/dt * cos(dec)",
465 units="rad/year",
466 )
467 schema.addField(
468 field="pm_dec",
469 type="Angle",
470 doc="proper motion in the declination direction",
471 units="rad/year",
472 )
473 if properMotionErrDim not in (0, 2, 3):
474 raise ValueError("properMotionErrDim={}; must be (0, 2, 3)".format(properMotionErrDim))
475 if properMotionErrDim > 0:
476 afwTable.CovarianceMatrix2fKey.addFields(
477 schema=schema,
478 prefix="pm",
479 names=["ra", "dec"],
480 units=["rad/year", "rad/year"],
481 diagonalOnly=(properMotionErrDim == 2),
482 )
483 schema.addField(
484 field="pm_flag",
485 type="Flag",
486 doc="Set if proper motion or proper motion error is bad",
487 )
488
489 if addParallax:
490 schema.addField(
491 field="parallax",
492 type="Angle",
493 doc="parallax",
494 units="rad",
495 )
496 schema.addField(
497 field="parallaxErr",
498 type="Angle",
499 doc="uncertainty in parallax",
500 units="rad",
501 )
502 schema.addField(
503 field="parallax_flag",
504 type="Flag",
505 doc="Set if parallax or parallax error is bad",
506 )
507 return schema
508
509 @staticmethod
510 def _remapReferenceCatalogSchema(refCat, *, anyFilterMapsToThis=None,
511 filterMap=None, centroids=False):
512 """This function takes in a reference catalog and returns a new catalog
513 with additional columns defined from the remaining function arguments.
514
515 Parameters
516 ----------
518 Reference catalog to map to new catalog
519 anyFilterMapsToThis : `str`, optional
520 Always use this reference catalog filter.
521 Mutually exclusive with `filterMap`
522 filterMap : `dict` [`str`,`str`], optional
523 Mapping of camera filter name: reference catalog filter name.
524 centroids : `bool`, optional
525 Add centroid fields to the loaded Schema. ``loadPixelBox`` expects
526 these fields to exist.
527
528 Returns
529 -------
530 expandedCat : `lsst.afw.table.SimpleCatalog`
531 Deep copy of input reference catalog with additional columns added
532 """
533 if anyFilterMapsToThis or filterMap:
534 ReferenceObjectLoader._addFluxAliases(refCat.schema, anyFilterMapsToThis, filterMap)
535
536 mapper = afwTable.SchemaMapper(refCat.schema, True)
537 mapper.addMinimalSchema(refCat.schema, True)
538 mapper.editOutputSchema().disconnectAliases()
539
540 if centroids:
541 # Add and initialize centroid and hasCentroid fields (these are
542 # added after loading to avoid wasting space in the saved catalogs).
543 # The new fields are automatically initialized to (nan, nan) and
544 # False so no need to set them explicitly.
545 mapper.editOutputSchema().addField("centroid_x", type=float, doReplace=True)
546 mapper.editOutputSchema().addField("centroid_y", type=float, doReplace=True)
547 mapper.editOutputSchema().addField("hasCentroid", type="Flag", doReplace=True)
548 mapper.editOutputSchema().getAliasMap().set("slot_Centroid", "centroid")
549
550 expandedCat = afwTable.SimpleCatalog(mapper.getOutputSchema())
551 expandedCat.setMetadata(refCat.getMetadata())
552 expandedCat.extend(refCat, mapper=mapper)
553
554 return expandedCat
555
556 @staticmethod
557 def _addFluxAliases(schema, anyFilterMapsToThis=None, filterMap=None):
558 """Add aliases for camera filter fluxes to the schema.
559
560 For each camFilter: refFilter in filterMap, adds these aliases:
561 <camFilter>_camFlux: <refFilter>_flux
562 <camFilter>_camFluxErr: <refFilter>_fluxErr, if the latter exists
563 or sets `anyFilterMapsToThis` in the schema.
564
565 Parameters
566 ----------
567 schema : `lsst.afw.table.Schema`
568 Schema for reference catalog.
569 anyFilterMapsToThis : `str`, optional
570 Always use this reference catalog filter.
571 Mutually exclusive with `filterMap`.
572 filterMap : `dict` [`str`,`str`], optional
573 Mapping of camera filter name: reference catalog filter name.
574 Mutually exclusive with `anyFilterMapsToThis`.
575
576 Raises
577 ------
578 RuntimeError
579 Raised if any required reference flux field is missing from the
580 schema.
581 """
582 # Fail on any truthy value for either of these.
583 if anyFilterMapsToThis and filterMap:
584 raise ValueError("anyFilterMapsToThis and filterMap are mutually exclusive!")
585
586 aliasMap = schema.getAliasMap()
587
588 if anyFilterMapsToThis is not None:
589 refFluxName = anyFilterMapsToThis + "_flux"
590 if refFluxName not in schema:
591 msg = f"Unknown reference filter for anyFilterMapsToThis='{refFluxName}'"
592 raise RuntimeError(msg)
593 aliasMap.set("anyFilterMapsToThis", refFluxName)
594 return # this is mutually exclusive with filterMap
595
596 def addAliasesForOneFilter(filterName, refFilterName):
597 """Add aliases for a single filter
598
599 Parameters
600 ----------
601 filterName : `str` (optional)
602 Camera filter name. The resulting alias name is
603 <filterName>_camFlux
604 refFilterName : `str`
605 Reference catalog filter name; the field
606 <refFilterName>_flux must exist.
607 """
608 camFluxName = filterName + "_camFlux"
609 refFluxName = refFilterName + "_flux"
610 if refFluxName not in schema:
611 raise RuntimeError("Unknown reference filter %s" % (refFluxName,))
612 aliasMap.set(camFluxName, refFluxName)
613 refFluxErrName = refFluxName + "Err"
614 if refFluxErrName in schema:
615 camFluxErrName = camFluxName + "Err"
616 aliasMap.set(camFluxErrName, refFluxErrName)
617
618 if filterMap is not None:
619 for filterName, refFilterName in filterMap.items():
620 addAliasesForOneFilter(filterName, refFilterName)
621
622 @staticmethod
623 def _makeBoxRegion(BBox, wcs, BBoxPadding):
624 outerLocalBBox = geom.Box2D(BBox)
625 innerLocalBBox = geom.Box2D(BBox)
626
627 # Grow the bounding box to allow for effects not fully captured by the
628 # wcs provided (which represents the current best-guess wcs solution
629 # associated with the dataset for which the calibration is to be
630 # computed using the loaded and trimmed reference catalog being defined
631 # here). These effects could include pointing errors and/or an
632 # insufficient optical distorition model for the instrument. The idea
633 # is to ensure the spherical geometric region created contains the
634 # entire region covered by the bbox.
635 # Also create an inner region that is sure to be inside the bbox.
636 outerLocalBBox.grow(BBoxPadding)
637 innerLocalBBox.grow(-1*BBoxPadding)
638
639 # Handle the case where the inner bounding box shrank to a zero sized
640 # region (which will be the case if the shrunken size of either
641 # dimension is less than or equal to zero). In this case, the inner
642 # bounding box is set to the original input bounding box. This is
643 # probably not the best way to handle an empty inner bounding box, but
644 # it is what the calling code currently expects.
645 if innerLocalBBox.getDimensions() == geom.Extent2D(0, 0):
646 innerLocalBBox = geom.Box2D(BBox)
647
648 # Convert the corners of the bounding boxes to sky coordinates.
649 innerBoxCorners = innerLocalBBox.getCorners()
650 innerSphCorners = [wcs.pixelToSky(corner).getVector() for corner in innerBoxCorners]
651 innerSkyRegion = sphgeom.ConvexPolygon(innerSphCorners)
652
653 outerBoxCorners = outerLocalBBox.getCorners()
654 outerSphCorners = [wcs.pixelToSky(corner).getVector() for corner in outerBoxCorners]
655 outerSkyRegion = sphgeom.ConvexPolygon(outerSphCorners)
656
657 return innerSkyRegion, outerSkyRegion, innerSphCorners, outerSphCorners
658
659 @staticmethod
660 def _calculateCircle(bbox, wcs, pixelMargin):
661 """Compute on-sky center and radius of search region.
662
663 Parameters
664 ----------
665 bbox : `lsst.geom.Box2I` or `lsst.geom.Box2D`
666 Pixel bounding box.
668 WCS; used to convert pixel positions to sky coordinates.
669 pixelMargin : `int`
670 Padding to add to 4 all edges of the bounding box (pixels).
671
672 Returns
673 -------
674 results : `lsst.pipe.base.Struct`
675 A Struct containing:
676
677 - coord : `lsst.geom.SpherePoint`
678 ICRS center of the search region.
679 - radius : `lsst.geom.Angle`
680 Radius of the search region.
681 - bbox : `lsst.geom.Box2D`
682 Bounding box used to compute the circle.
683 """
684 bbox = geom.Box2D(bbox) # we modify the box, so use a copy
685 bbox.grow(pixelMargin)
686 coord = wcs.pixelToSky(bbox.getCenter())
687 radius = max(coord.separation(wcs.pixelToSky(pp)) for pp in bbox.getCorners())
688 return pipeBase.Struct(coord=coord, radius=radius, bbox=bbox)
689
690 @staticmethod
691 def getMetadataCircle(coord, radius, filterName, epoch=None):
692 """Return metadata about the loaded reference catalog, in an on-sky
693 circle.
694
695 This metadata is used for reloading the catalog (e.g. for
696 reconstituting a normalized match list).
697
698 Parameters
699 ----------
700 coord : `lsst.geom.SpherePoint`
701 ICRS center of the search region.
702 radius : `lsst.geom.Angle`
703 Radius of the search region.
704 filterName : `str`
705 Name of the camera filter.
706 epoch : `astropy.time.Time` or `None`, optional
707 Epoch that proper motion and parallax were corrected to, or `None`
708 if no such corrections were applied.
709
710 Returns
711 -------
713 Metadata about the catalog.
714 """
715 md = PropertyList()
716 md.add('RA', coord.getRa().asDegrees(), 'field center in degrees')
717 md.add('DEC', coord.getDec().asDegrees(), 'field center in degrees')
718 md.add('RADIUS', radius.asDegrees(), 'field radius in degrees, minimum')
719 # Version 1: Initial version
720 # Version 2: JEPOCH for TAI Julian Epoch year of PM/parallax correction
721 md.add('SMATCHV', 2, 'SourceMatchVector version number')
722 md.add('FILTER', filterName, 'camera filter name for photometric data')
723 md.add('TIMESYS', "TAI", "time scale of time keywords")
724 md.add('JEPOCH', None if epoch is None else epoch.tai.jyear,
725 'Julian epoch (TAI Julian Epoch year) for catalog')
726 return md
727
728 def getMetadataBox(self, bbox, wcs, filterName, epoch=None,
729 bboxToSpherePadding=100):
730 """Return metadata about the loaded reference catalog, in an
731 on-detector box.
732
733 This metadata is used for reloading the catalog (e.g., for
734 reconstituting a normalised match list).
735
736 Parameters
737 ----------
738 bbox : `lsst.geom.Box2I` or `lsst.geom.Box2D`
739 Bounding box for the pixels.
741 The WCS object associated with ``bbox``.
742 filterName : `str`
743 Name of the camera filter.
744 epoch : `astropy.time.Time` or `None`, optional
745 Epoch that proper motion and parallax were corrected to, or `None`
746 if no such corrections were applied.
747 bboxToSpherePadding : `int`, optional
748 Padding in pixels to account for translating a set of corners into
749 a spherical (convex) boundary that is certain to encompass the
750 enitre area covered by the box.
751
752 Returns
753 -------
755 The metadata detailing the search parameters used for this
756 dataset.
757 """
758 circle = self._calculateCircle(bbox, wcs, self.config.pixelMargin)
759 md = self.getMetadataCircle(circle.coord, circle.radius, filterName, epoch=epoch)
760
761 paddedBbox = circle.bbox
762 _, _, innerCorners, outerCorners = self._makeBoxRegion(paddedBbox, wcs, bboxToSpherePadding)
763 for box, corners in zip(("INNER", "OUTER"), (innerCorners, outerCorners)):
764 for (name, corner) in zip(("UPPER_LEFT", "UPPER_RIGHT", "LOWER_LEFT", "LOWER_RIGHT"),
765 corners):
766 md.add(f"{box}_{name}_RA", geom.SpherePoint(corner).getRa().asDegrees(), f"{box}_corner")
767 md.add(f"{box}_{name}_DEC", geom.SpherePoint(corner).getDec().asDegrees(), f"{box}_corner")
768 return md
769
770 def loadPixelBox(self, bbox, wcs, filterName, epoch=None,
771 bboxToSpherePadding=100):
772 """Load reference objects that are within a pixel-based rectangular
773 region.
774
775 This algorithm works by creating a spherical box whose corners
776 correspond to the WCS converted corners of the input bounding box
777 (possibly padded). It then defines a filtering function which looks at
778 the pixel position of the reference objects and accepts only those that
779 lie within the specified bounding box.
780
781 The spherical box region and filtering function are passed to the
782 generic loadRegion method which loads and filters the reference objects
783 from the datastore and returns a single catalog containing the filtered
784 set of reference objects.
785
786 Parameters
787 ----------
788 bbox : `lsst.geom.Box2I` or `lsst.geom.Box2D`
789 Box which bounds a region in pixel space.
791 Wcs object defining the pixel to sky (and inverse) transform for
792 the supplied ``bbox``.
793 filterName : `str`
794 Name of camera filter.
795 epoch : `astropy.time.Time` or `None`, optional
796 Epoch to which to correct proper motion and parallax, or `None`
797 to not apply such corrections.
798 bboxToSpherePadding : `int`, optional
799 Padding to account for translating a set of corners into a
800 spherical (convex) boundary that is certain to encompase the
801 enitre area covered by the box.
802
803 Returns
804 -------
805 output : `lsst.pipe.base.Struct`
806 Results struct with attributes:
807
808 ``refCat``
809 Catalog containing reference objects inside the specified
810 bounding box (padded by self.config.pixelMargin).
811 ``fluxField``
812 Name of the field containing the flux associated with
813 ``filterName``.
814
815 Raises
816 ------
817 RuntimeError
818 Raised if no reference catalogs could be found for the specified
819 region.
820 TypeError
821 Raised if the loaded reference catalogs do not have matching
822 schemas.
823 """
824 paddedBbox = geom.Box2D(bbox)
825 paddedBbox.grow(self.config.pixelMargin)
826 innerSkyRegion, outerSkyRegion, _, _ = self._makeBoxRegion(paddedBbox, wcs, bboxToSpherePadding)
827
828 def _filterFunction(refCat, region):
829 # Perform an initial "pre filter" step based on the refCat coords
830 # and the outerSkyRegion created from the self.config.pixelMargin-
831 # paddedBbox plus an "extra" padding of bboxToSpherePadding and the
832 # raw wcs. This should ensure a large enough projected area on the
833 # sky that accounts for any projection/distortion issues, but small
834 # enough to filter out loaded reference objects that lie well
835 # beyond the projected detector of interest. This step is required
836 # due to the very local nature of the wcs available for the
837 # sky <--> pixel conversions.
838 preFiltFunc = _FilterCatalog(outerSkyRegion)
839 refCat = preFiltFunc(refCat, region)
840
841 # Add columns to the pre-filtered reference catalog relating their
842 # coordinates to equivalent pixel positions for the wcs provided
843 # and use to populate those columns.
844 refCat = self._remapReferenceCatalogSchema(refCat, centroids=True)
845 afwTable.updateRefCentroids(wcs, refCat)
846 # No need to filter the catalog if it is entirely contained in the
847 # region defined by the inner sky region.
848 if innerSkyRegion.contains(region):
849 return refCat
850 # Create a new reference catalog, and populate it only with records
851 # that fall inside the padded bbox.
852 filteredRefCat = type(refCat)(refCat.table)
853 centroidKey = afwTable.Point2DKey(refCat.schema['centroid'])
854 for record in refCat:
855 pixCoords = record[centroidKey]
856 if paddedBbox.contains(geom.Point2D(pixCoords)):
857 filteredRefCat.append(record)
858 return filteredRefCat
859 return self.loadRegion(outerSkyRegion, filterName, filtFunc=_filterFunction, epoch=epoch)
860
861 def loadRegion(self, region, filterName, filtFunc=None, epoch=None):
862 """Load reference objects within a specified region.
863
864 This function loads the DataIds used to construct an instance of this
865 class which intersect or are contained within the specified region. The
866 reference catalogs which intersect but are not fully contained within
867 the input region are further filtered by the specified filter function.
868 This function returns a single source catalog containing all reference
869 objects inside the specified region.
870
871 Parameters
872 ----------
873 region : `lsst.sphgeom.Region`
874 This can be any type that is derived from `lsst.sphgeom.Region` and
875 should define the spatial region for which reference objects are to
876 be loaded.
877 filtFunc : callable or `None`, optional
878 This optional parameter should be a callable object that takes a
879 reference catalog and its corresponding region as parameters,
880 filters the catalog by some criteria and returns the filtered
881 reference catalog. If `None`, an internal filter function is used
882 which filters according to if a reference object falls within the
883 input region.
884 filterName : `str`
885 Name of camera filter.
886 epoch : `astropy.time.Time` or `None`, optional
887 Epoch to which to correct proper motion and parallax, or `None` to
888 not apply such corrections.
889
890 Returns
891 -------
892 output : `lsst.pipe.base.Struct`
893 Results struct with attributes:
894
895 ``refCat``
896 Catalog containing reference objects which intersect the
897 input region, filtered by the specified filter function.
898 ``fluxField``
899 Name of the field containing the flux associated with
900 ``filterName``.
901
902 Raises
903 ------
904 RuntimeError
905 Raised if no reference catalogs could be found for the specified
906 region.
907 TypeError
908 Raised if the loaded reference catalogs do not have matching
909 schemas.
910 """
911 regionLat = region.getBoundingBox().getLat()
912 regionLon = region.getBoundingBox().getLon()
913 self.log.info("Loading reference objects from %s in region bounded by "
914 "[%.8f, %.8f], [%.8f, %.8f] RA Dec",
915 self.name,
916 regionLon.getA().asDegrees(), regionLon.getB().asDegrees(),
917 regionLat.getA().asDegrees(), regionLat.getB().asDegrees())
918 if filtFunc is None:
919 filtFunc = _FilterCatalog(region)
920 # filter out all the regions supplied by the constructor that do not overlap
921 overlapList = []
922 for dataId, refCat in zip(self.dataIds, self.refCats):
923 # SphGeom supports some objects intersecting others, but is not symmetric,
924 # try the intersect operation in both directions
925 try:
926 intersects = dataId.region.intersects(region)
927 except TypeError:
928 intersects = region.intersects(dataId.region)
929
930 if intersects:
931 overlapList.append((dataId, refCat))
932
933 if len(overlapList) == 0:
934 raise RuntimeError("No reference tables could be found for input region")
935
936 firstCat = overlapList[0][1].get()
937 refCat = filtFunc(firstCat, overlapList[0][0].region)
938 trimmedAmount = len(firstCat) - len(refCat)
939
940 # Load in the remaining catalogs
941 for dataId, inputRefCat in overlapList[1:]:
942 tmpCat = inputRefCat.get()
943
944 if tmpCat.schema != firstCat.schema:
945 raise TypeError("Reference catalogs have mismatching schemas")
946
947 filteredCat = filtFunc(tmpCat, dataId.region)
948 refCat.extend(filteredCat)
949 trimmedAmount += len(tmpCat) - len(filteredCat)
950
951 self.log.debug("Trimmed %d refCat objects lying outside padded region, leaving %d",
952 trimmedAmount, len(refCat))
953 self.log.info("Loaded %d reference objects", len(refCat))
954
955 # Ensure that the loaded reference catalog is continuous in memory
956 if not refCat.isContiguous():
957 refCat = refCat.copy(deep=True)
958
959 self.applyProperMotions(refCat, epoch)
960
961 # TODO DM-34793: remove this entire if block.
962 # Verify the schema is in the correct units and has the correct version; automatically convert
963 # it with a warning if this is not the case.
964 if not hasNanojanskyFluxUnits(refCat.schema) or not getFormatVersionFromRefCat(refCat) >= 1:
965 self.log.warning("Found version 0 reference catalog with old style units in schema.")
966 self.log.warning("run `meas_algorithms/bin/convert_refcat_to_nJy.py` to convert fluxes to nJy.")
967 self.log.warning("See RFC-575 for more details.")
968 refCat = convertToNanojansky(refCat, self.log)
969
970 expandedCat = self._remapReferenceCatalogSchema(refCat,
971 anyFilterMapsToThis=self.config.anyFilterMapsToThis,
972 filterMap=self.config.filterMap)
973
974 # Ensure that the returned reference catalog is continuous in memory
975 if not expandedCat.isContiguous():
976 expandedCat = expandedCat.copy(deep=True)
977
978 fluxField = getRefFluxField(expandedCat.schema, filterName)
979 return pipeBase.Struct(refCat=expandedCat, fluxField=fluxField)
980
981 def loadSkyCircle(self, ctrCoord, radius, filterName, epoch=None):
982 """Load reference objects that lie within a circular region on the sky.
983
984 This method constructs a circular region from an input center and
985 angular radius, loads reference catalogs which are contained in or
986 intersect the circle, and filters reference catalogs which intersect
987 down to objects which lie within the defined circle.
988
989 Parameters
990 ----------
991 ctrCoord : `lsst.geom.SpherePoint`
992 Point defining the center of the circular region.
993 radius : `lsst.geom.Angle`
994 Defines the angular radius of the circular region.
995 filterName : `str`
996 Name of camera filter.
997 epoch : `astropy.time.Time` or `None`, optional
998 Epoch to which to correct proper motion and parallax, or `None` to
999 not apply such corrections.
1000
1001 Returns
1002 -------
1003 output : `lsst.pipe.base.Struct`
1004 Results struct with attributes:
1005
1006 ``refCat``
1007 Catalog containing reference objects inside the specified
1008 search circle.
1009 ``fluxField``
1010 Name of the field containing the flux associated with
1011 ``filterName``.
1012 """
1013 centerVector = ctrCoord.getVector()
1014 sphRadius = sphgeom.Angle(radius.asRadians())
1015 circularRegion = sphgeom.Circle(centerVector, sphRadius)
1016 return self.loadRegion(circularRegion, filterName, epoch=epoch)
1017
1018
1019def getRefFluxField(schema, filterName):
1020 """Get the name of a flux field from a schema.
1021
1022 Parameters
1023 ----------
1024 schema : `lsst.afw.table.Schema`
1025 Reference catalog schema.
1026 filterName : `str`
1027 Name of camera filter.
1028
1029 Returns
1030 -------
1031 fluxFieldName : `str`
1032 Name of flux field.
1033
1034 Notes
1035 -----
1036 Return the alias of ``anyFilterMapsToThis``, if present
1037 else, return ``*filterName*_camFlux`` if present,
1038 else, return ``*filterName*_flux`` if present (camera filter name
1039 matches reference filter name), else raise an exception.
1040
1041 Raises
1042 ------
1043 RuntimeError
1044 Raised if an appropriate field is not found.
1045 """
1046 if not isinstance(schema, afwTable.Schema):
1047 raise RuntimeError("schema=%s is not a schema" % (schema,))
1048 try:
1049 return schema.getAliasMap().get("anyFilterMapsToThis")
1050 except LookupError:
1051 pass # try the filterMap next
1052
1053 fluxFieldList = [filterName + "_camFlux", filterName + "_flux"]
1054 for fluxField in fluxFieldList:
1055 if fluxField in schema:
1056 return fluxField
1057
1058 raise RuntimeError("Could not find flux field(s) %s" % (", ".join(fluxFieldList)))
1059
1060
1061def getRefFluxKeys(schema, filterName):
1062 """Return keys for flux and flux error.
1063
1064 Parameters
1065 ----------
1066 schema : `lsst.afw.table.Schema`
1067 Reference catalog schema.
1068 filterName : `str`
1069 Name of camera filter.
1070
1071 Returns
1072 -------
1073 keys : `tuple` of (`lsst.afw.table.Key`, `lsst.afw.table.Key`)
1074 Two keys:
1075
1076 - flux key
1077 - flux error key, if present, else None
1078
1079 Raises
1080 ------
1081 RuntimeError
1082 If flux field not found.
1083 """
1084 fluxField = getRefFluxField(schema, filterName)
1085 fluxErrField = fluxField + "Err"
1086 fluxKey = schema[fluxField].asKey()
1087 try:
1088 fluxErrKey = schema[fluxErrField].asKey()
1089 except Exception:
1090 fluxErrKey = None
1091 return (fluxKey, fluxErrKey)
1092
1093
1094@deprecated(reason=("This task is used in gen2 only; it will be removed after v25. "
1095 "See DM-35671 for details on updating code to avoid this warning."),
1096 version="v25.0", category=FutureWarning)
1097class LoadReferenceObjectsTask(pipeBase.Task, ReferenceObjectLoader, metaclass=abc.ABCMeta):
1098 """Abstract gen2 base class to load objects from reference catalogs.
1099 """
1100 _DefaultName = "LoadReferenceObjects"
1101
1102 @abc.abstractmethod
1103 def loadSkyCircle(self, ctrCoord, radius, filterName, epoch=None, centroids=False):
1104 """Load reference objects that overlap a circular sky region.
1105
1106 Parameters
1107 ----------
1108 ctrCoord : `lsst.geom.SpherePoint`
1109 ICRS center of search region.
1110 radius : `lsst.geom.Angle`
1111 Radius of search region.
1112 filterName : `str`
1113 Name of filter. This can be used for flux limit comparisons.
1114 epoch : `astropy.time.Time` or `None`, optional
1115 Epoch to which to correct proper motion and parallax, or `None` to
1116 not apply such corrections.
1117 centroids : `bool`, optional
1118 Add centroid fields to the loaded Schema. ``loadPixelBox`` expects
1119 these fields to exist.
1120
1121 Returns
1122 -------
1123 results : `lsst.pipe.base.Struct`
1124 A `~lsst.pipe.base.Struct` containing the following fields:
1125
1126 ``refCat``
1127 A catalog of reference objects with the standard
1128 schema, as documented in the main doc string for
1129 `LoadReferenceObjects`.
1130 The catalog is guaranteed to be contiguous.
1131 (`lsst.afw.catalog.SimpleCatalog`)
1132 ``fluxField``
1133 Name of flux field for specified `filterName`. (`str`)
1134
1135 Notes
1136 -----
1137 Note that subclasses are responsible for performing the proper motion
1138 correction, since this is the lowest-level interface for retrieving
1139 the catalog.
1140 """
1141 return
1142
1143
1144@deprecated(reason="Base class only used for gen2 interface, and will be removed after v25.0. "
1145 "Please use ReferenceObjectLoader directly.",
1146 version="v25.0", category=FutureWarning)
1148 """Stub of a deprecated class.
1149
1150 Parameters
1151 ----------
1152 config : `lsst.pex.config.Config`
1153 Configuration for the loader.
1154 """
1155 def __init__(self, config=None, *args, **kwargs):
1156 pass
1157
1158
1159def applyProperMotionsImpl(log, catalog, epoch):
1160 """Apply proper motion correction to a reference catalog.
1161
1162 Adjust position and position error in the ``catalog``
1163 for proper motion to the specified ``epoch``,
1164 modifying the catalog in place.
1165
1166 Parameters
1167 ----------
1168 log : `lsst.log.Log` or `logging.getLogger`
1169 Log object to write to.
1171 Catalog of positions, containing:
1172
1173 - Coordinates, retrieved by the table's coordinate key.
1174 - ``coord_raErr`` : Error in Right Ascension (rad).
1175 - ``coord_decErr`` : Error in Declination (rad).
1176 - ``pm_ra`` : Proper motion in Right Ascension (rad/yr,
1177 East positive)
1178 - ``pm_raErr`` : Error in ``pm_ra`` (rad/yr), optional.
1179 - ``pm_dec`` : Proper motion in Declination (rad/yr,
1180 North positive)
1181 - ``pm_decErr`` : Error in ``pm_dec`` (rad/yr), optional.
1182 - ``epoch`` : Mean epoch of object (an astropy.time.Time)
1183 epoch : `astropy.time.Time`
1184 Epoch to which to correct proper motion.
1185 """
1186 if "epoch" not in catalog.schema or "pm_ra" not in catalog.schema or "pm_dec" not in catalog.schema:
1187 log.warning("Proper motion correction not available from catalog")
1188 return
1189 if not catalog.isContiguous():
1190 raise RuntimeError("Catalog must be contiguous")
1191 catEpoch = astropy.time.Time(catalog["epoch"], scale="tai", format="mjd")
1192 log.info("Correcting reference catalog for proper motion to %r", epoch)
1193 # Use `epoch.tai` to make sure the time difference is in TAI
1194 timeDiffsYears = (epoch.tai - catEpoch).to(astropy.units.yr).value
1195 coordKey = catalog.table.getCoordKey()
1196 # Compute the offset of each object due to proper motion
1197 # as components of the arc of a great circle along RA and Dec
1198 pmRaRad = catalog["pm_ra"]
1199 pmDecRad = catalog["pm_dec"]
1200 offsetsRaRad = pmRaRad*timeDiffsYears
1201 offsetsDecRad = pmDecRad*timeDiffsYears
1202 # Compute the corresponding bearing and arc length of each offset
1203 # due to proper motion, and apply the offset
1204 # The factor of 1e6 for computing bearing is intended as
1205 # a reasonable scale for typical values of proper motion
1206 # in order to avoid large errors for small values of proper motion;
1207 # using the offsets is another option, but it can give
1208 # needlessly large errors for short duration
1209 offsetBearingsRad = numpy.arctan2(pmDecRad*1e6, pmRaRad*1e6)
1210 offsetAmountsRad = numpy.hypot(offsetsRaRad, offsetsDecRad)
1211 for record, bearingRad, amountRad in zip(catalog, offsetBearingsRad, offsetAmountsRad):
1212 record.set(coordKey,
1213 record.get(coordKey).offset(bearing=bearingRad*geom.radians,
1214 amount=amountRad*geom.radians))
1215 # Increase error in RA and Dec based on error in proper motion
1216 if "coord_raErr" in catalog.schema:
1217 catalog["coord_raErr"] = numpy.hypot(catalog["coord_raErr"],
1218 catalog["pm_raErr"]*timeDiffsYears)
1219 if "coord_decErr" in catalog.schema:
1220 catalog["coord_decErr"] = numpy.hypot(catalog["coord_decErr"],
1221 catalog["pm_decErr"]*timeDiffsYears)
int max
table::Key< int > type
Definition: Detector.cc:163
table::Key< int > to
A 2-dimensional celestial WCS that transform pixels to ICRS RA/Dec, using the LSST standard for pixel...
Definition: SkyWcs.h:117
A class used as a handle to a particular field in a table.
Definition: Key.h:53
Defines the fields and offsets for a table.
Definition: Schema.h:51
A mapping between the keys of two Schemas, used to copy data between them.
Definition: SchemaMapper.h:21
Custom catalog class for record/table subclasses that are guaranteed to have an ID,...
Definition: SortedCatalog.h:42
Class for storing ordered metadata with comments.
Definition: PropertyList.h:68
A class representing an angle.
Definition: Angle.h:128
A floating-point coordinate rectangle geometry.
Definition: Box.h:413
An integer coordinate rectangle.
Definition: Box.h:55
Point in an unspecified spherical coordinate system.
Definition: SpherePoint.h:57
This static class includes a variety of methods for interacting with the the logging module.
Definition: Log.h:724
def loadSkyCircle(self, ctrCoord, radius, filterName, epoch=None, centroids=False)
def __init__(self, dataIds, refCats, name=None, log=None, config=None, **kwargs)
def loadSkyCircle(self, ctrCoord, radius, filterName, epoch=None)
def _remapReferenceCatalogSchema(refCat, *anyFilterMapsToThis=None, filterMap=None, centroids=False)
def loadRegion(self, region, filterName, filtFunc=None, epoch=None)
def getMetadataBox(self, bbox, wcs, filterName, epoch=None, bboxToSpherePadding=100)
def loadPixelBox(self, bbox, wcs, filterName, epoch=None, bboxToSpherePadding=100)
def makeMinimalSchema(filterNameList, *addCentroid=False, addIsPhotometric=False, addIsResolved=False, addIsVariable=False, coordErrDim=2, addProperMotion=False, properMotionErrDim=2, addParallax=False)
Angle represents an angle in radians.
Definition: Angle.h:43
Circle is a circular region on the unit sphere that contains its boundary.
Definition: Circle.h:46
ConvexPolygon is a closed convex polygon on the unit sphere.
Definition: ConvexPolygon.h:57
Region is a minimal interface for 2-dimensional regions on the unit sphere.
Definition: Region.h:79
daf::base::PropertySet * set
Definition: fits.cc:927
void updateRefCentroids(geom::SkyWcs const &wcs, ReferenceCollection &refList)
Update centroids in a collection of reference objects.
Definition: wcsUtils.cc:72
def convertToNanojansky(catalog, log, doConvert=True)
A description of a field in a table.
Definition: Field.h:24