LSSTApplications  11.0-13-gbb96280,12.1.rc1,12.1.rc1+1,12.1.rc1+2,12.1.rc1+5,12.1.rc1+8,12.1.rc1-1-g06d7636+1,12.1.rc1-1-g253890b+5,12.1.rc1-1-g3d31b68+7,12.1.rc1-1-g3db6b75+1,12.1.rc1-1-g5c1385a+3,12.1.rc1-1-g83b2247,12.1.rc1-1-g90cb4cf+6,12.1.rc1-1-g91da24b+3,12.1.rc1-2-g3521f8a,12.1.rc1-2-g39433dd+4,12.1.rc1-2-g486411b+2,12.1.rc1-2-g4c2be76,12.1.rc1-2-gc9c0491,12.1.rc1-2-gda2cd4f+6,12.1.rc1-3-g3391c73+2,12.1.rc1-3-g8c1bd6c+1,12.1.rc1-3-gcf4b6cb+2,12.1.rc1-4-g057223e+1,12.1.rc1-4-g19ed13b+2,12.1.rc1-4-g30492a7
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 __all__ = ["LoadIndexedReferenceObjectsConfig", "LoadIndexedReferenceObjectsTask"]
32 
33 
34 class LoadIndexedReferenceObjectsConfig(LoadReferenceObjectsConfig):
35  ingest_config_name = pexConfig.Field(
36  dtype=str,
37  default='IngestIndexedReferenceTask_config',
38  doc='Name of the config dataset used to ingest the reference'
39  )
40 
41 
42 class LoadIndexedReferenceObjectsTask(LoadReferenceObjectsTask):
43  ConfigClass = LoadIndexedReferenceObjectsConfig
44  _DefaultName = 'LoadIndexedReferenceObjectsTask'
45 
46  def __init__(self, butler, ingest_factory=IngestIndexedReferenceTask, *args, **kwargs):
47  LoadReferenceObjectsTask.__init__(self, *args, **kwargs)
48  ingest_config = butler.get(self.config.ingest_config_name, immediate=True)
49  ingester = ingest_factory(butler=butler, config=ingest_config)
50  self.indexer = ingester.indexer
51  self.make_data_id = ingester.make_data_id
52  self.ref_dataset_name = ingester.config.ref_dataset_name
53  self.butler = butler
54 
55  @pipeBase.timeMethod
56  def loadSkyCircle(self, ctrCoord, radius, filterName=None):
57  """!Load reference objects that overlap a circular sky region
58 
59  @param[in] ctrCoord center of search region (an lsst.afw.geom.Coord)
60  @param[in] radius radius of search region (an lsst.afw.geom.Angle)
61  @param[in] filterName name of filter, or None for the default filter;
62  used for flux values in case we have flux limits (which are not yet implemented)
63 
64  @return an lsst.pipe.base.Struct containing:
65  - refCat a catalog of reference objects with the
66  \link meas_algorithms_loadReferenceObjects_Schema standard schema \endlink
67  as documented in LoadReferenceObjects, including photometric, resolved and variable;
68  hasCentroid is False for all objects.
69  - fluxField = name of flux field for specified filterName. None if refCat is None.
70  """
71  id_list, boundary_mask = self.indexer.get_pixel_ids(ctrCoord, radius)
72  shards = self.get_shards(id_list)
73  refCat = self.butler.get(self.ref_dataset_name, dataId=self.make_data_id('master_schema'),
74  immediate=True)
75  self._addFluxAliases(refCat.schema)
76  fluxField = getRefFluxField(schema=refCat.schema, filterName=filterName)
77  for shard, is_on_boundary in zip(shards, boundary_mask):
78  if shard is None:
79  continue
80  if is_on_boundary:
81  refCat.extend(self._trim_to_circle(shard, ctrCoord, radius))
82  else:
83  refCat.extend(shard)
84 
85  # make sure catalog is contiguous
86  if not refCat.isContiguous():
87  refCat = refCat.copy()
88 
89  # add and initialize centroid and hasCentroid fields (these are added
90  # after loading to avoid wasting space in the saved catalogs)
91  # the new fields are automatically initialized to (nan, nan) and False
92  # so no need to set them explicitly
93  mapper = afwTable.SchemaMapper(refCat.schema, True)
94  mapper.addMinimalSchema(refCat.schema, True)
95  mapper.editOutputSchema().addField("centroid_x", type=float)
96  mapper.editOutputSchema().addField("centroid_y", type=float)
97  mapper.editOutputSchema().addField("hasCentroid", type="Flag")
98  expandedCat = afwTable.SimpleCatalog(mapper.getOutputSchema())
99  expandedCat.extend(refCat, mapper=mapper)
100  del refCat # avoid accidentally returning the unexpanded reference catalog
101 
102  # return reference catalog
103  return pipeBase.Struct(
104  refCat=expandedCat,
105  fluxField=fluxField,
106  )
107 
108  def get_shards(self, id_list):
109  """!Get all shards that touch a circular aperture
110 
111  @param[in] id_list A list of integer pixel ids
112  @param[out] a list of SourceCatalogs for each pixel, None if not data exists
113  """
114  shards = []
115  for pixel_id in id_list:
116  if self.butler.datasetExists(self.ref_dataset_name, dataId=self.make_data_id(pixel_id)):
117  shards.append(self.butler.get(self.ref_dataset_name,
118  dataId=self.make_data_id(pixel_id), immediate=True))
119  return shards
120 
121  def _trim_to_circle(self, catalog_shard, ctrCoord, radius):
122  """!Trim a catalog to a circular aperture.
123 
124  @param[in] catalog_shard SourceCatalog to be trimmed
125  @param[in] ctrCoord afw.Coord to compare each record to
126  @param[in] radius afwGeom.Angle indicating maximume separation
127  @param[out] a SourceCatalog constructed from records that fall in the circular aperture
128  """
129  temp_cat = type(catalog_shard)(catalog_shard.schema)
130  for record in catalog_shard:
131  if record.getCoord().angularSeparation(ctrCoord) < radius:
132  temp_cat.append(record)
133  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.
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.