LSSTApplications  11.0-13-gbb96280,12.1+18,12.1+7,12.1-1-g14f38d3+72,12.1-1-g16c0db7+5,12.1-1-g5961e7a+84,12.1-1-ge22e12b+23,12.1-11-g06625e2+4,12.1-11-g0d7f63b+4,12.1-19-gd507bfc,12.1-2-g7dda0ab+38,12.1-2-gc0bc6ab+81,12.1-21-g6ffe579+2,12.1-21-gbdb6c2a+4,12.1-24-g941c398+5,12.1-3-g57f6835+7,12.1-3-gf0736f3,12.1-37-g3ddd237,12.1-4-gf46015e+5,12.1-5-g06c326c+20,12.1-5-g648ee80+3,12.1-5-gc2189d7+4,12.1-6-ga608fc0+1,12.1-7-g3349e2a+5,12.1-7-gfd75620+9,12.1-9-g577b946+5,12.1-9-gc4df26a+10
LSSTDataManagementBasePackage
loadIndexedReferenceObjects.py
Go to the documentation of this file.
1 from __future__ import absolute_import, division, print_function
2 from builtins import zip
3 #
4 # LSST Data Management System
5 #
6 # Copyright 2008-2016 AURA/LSST.
7 #
8 # This product includes software developed by the
9 # LSST Project (http://www.lsst.org/).
10 #
11 # This program is free software: you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation, either version 3 of the License, or
14 # (at your option) any later version.
15 #
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
20 #
21 # You should have received a copy of the LSST License Statement and
22 # the GNU General Public License along with this program. If not,
23 # see <https://www.lsstcorp.org/LegalNotices/>.
24 #
25 
26 from lsst.meas.algorithms import getRefFluxField, LoadReferenceObjectsTask, LoadReferenceObjectsConfig
27 from .ingestIndexReferenceTask import IngestIndexedReferenceTask
28 import lsst.afw.table as afwTable
29 import lsst.pex.config as pexConfig
30 import lsst.pipe.base as pipeBase
31 from .indexerRegistry import IndexerRegistry
32 __all__ = ["LoadIndexedReferenceObjectsConfig", "LoadIndexedReferenceObjectsTask"]
33 
34 
35 class LoadIndexedReferenceObjectsConfig(LoadReferenceObjectsConfig):
36  ref_dataset_name = pexConfig.Field(
37  dtype=str,
38  default='cal_ref_cat',
39  doc='Name of the ingested reference dataset'
40  )
41 
42 
43 class LoadIndexedReferenceObjectsTask(LoadReferenceObjectsTask):
44  ConfigClass = LoadIndexedReferenceObjectsConfig
45  _DefaultName = 'LoadIndexedReferenceObjectsTask'
46 
47  def __init__(self, butler, *args, **kwargs):
48  LoadReferenceObjectsTask.__init__(self, *args, **kwargs)
49  dataset_config = butler.get("ref_cat_config", name=self.config.ref_dataset_name, immediate=True)
50  self.indexer = IndexerRegistry[dataset_config.indexer.name](dataset_config.indexer.active)
51  # This needs to come from the loader config, not the dataset_config since directory aliases can
52  # change the path where the shards are found.
53  self.ref_dataset_name = self.config.ref_dataset_name
54  self.butler = butler
55 
56  @pipeBase.timeMethod
57  def loadSkyCircle(self, ctrCoord, radius, filterName=None):
58  """!Load reference objects that overlap a circular sky region
59 
60  @param[in] ctrCoord center of search region (an lsst.afw.geom.Coord)
61  @param[in] radius radius of search region (an lsst.afw.geom.Angle)
62  @param[in] filterName name of filter, or None for the default filter;
63  used for flux values in case we have flux limits (which are not yet implemented)
64 
65  @return an lsst.pipe.base.Struct containing:
66  - refCat a catalog of reference objects with the
67  \link meas_algorithms_loadReferenceObjects_Schema standard schema \endlink
68  as documented in LoadReferenceObjects, including photometric, resolved and variable;
69  hasCentroid is False for all objects.
70  - fluxField = name of flux field for specified filterName. None if refCat is None.
71  """
72  id_list, boundary_mask = self.indexer.get_pixel_ids(ctrCoord, radius)
73  shards = self.get_shards(id_list)
74  refCat = self.butler.get('ref_cat', dataId=self.indexer.make_data_id('master_schema', self.ref_dataset_name),
75  immediate=True)
76  self._addFluxAliases(refCat.schema)
77  fluxField = getRefFluxField(schema=refCat.schema, filterName=filterName)
78  for shard, is_on_boundary in zip(shards, boundary_mask):
79  if shard is None:
80  continue
81  if is_on_boundary:
82  refCat.extend(self._trim_to_circle(shard, ctrCoord, radius))
83  else:
84  refCat.extend(shard)
85 
86  # make sure catalog is contiguous
87  if not refCat.isContiguous():
88  refCat = refCat.copy()
89 
90  # add and initialize centroid and hasCentroid fields (these are added
91  # after loading to avoid wasting space in the saved catalogs)
92  # the new fields are automatically initialized to (nan, nan) and False
93  # so no need to set them explicitly
94  mapper = afwTable.SchemaMapper(refCat.schema, True)
95  mapper.addMinimalSchema(refCat.schema, True)
96  mapper.editOutputSchema().addField("centroid_x", type=float)
97  mapper.editOutputSchema().addField("centroid_y", type=float)
98  mapper.editOutputSchema().addField("hasCentroid", type="Flag")
99  expandedCat = afwTable.SimpleCatalog(mapper.getOutputSchema())
100  expandedCat.extend(refCat, mapper=mapper)
101  del refCat # avoid accidentally returning the unexpanded reference catalog
102 
103  # return reference catalog
104  return pipeBase.Struct(
105  refCat=expandedCat,
106  fluxField=fluxField,
107  )
108 
109  def get_shards(self, id_list):
110  """!Get all shards that touch a circular aperture
111 
112  @param[in] id_list A list of integer pixel ids
113  @param[out] a list of SourceCatalogs for each pixel, None if not data exists
114  """
115  shards = []
116  for pixel_id in id_list:
117  if self.butler.datasetExists('ref_cat', dataId=self.indexer.make_data_id(pixel_id, self.ref_dataset_name)):
118  shards.append(self.butler.get('ref_cat',
119  dataId=self.indexer.make_data_id(pixel_id, self.ref_dataset_name), immediate=True))
120  return shards
121 
122  def _trim_to_circle(self, catalog_shard, ctrCoord, radius):
123  """!Trim a catalog to a circular aperture.
124 
125  @param[in] catalog_shard SourceCatalog to be trimmed
126  @param[in] ctrCoord afw.Coord to compare each record to
127  @param[in] radius afwGeom.Angle indicating maximume separation
128  @param[out] a SourceCatalog constructed from records that fall in the circular aperture
129  """
130  temp_cat = type(catalog_shard)(catalog_shard.schema)
131  for record in catalog_shard:
132  if record.getCoord().angularSeparation(ctrCoord) < radius:
133  temp_cat.append(record)
134  return temp_cat
A mapping between the keys of two Schemas, used to copy data between them.
Definition: SchemaMapper.h:19
def loadSkyCircle
Load reference objects that overlap a circular sky region.
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations...
Custom catalog class for record/table subclasses that are guaranteed to have an ID, and should generally be sorted by that ID.
Definition: fwd.h:55
def getRefFluxField
Get name of flux field in schema.