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
catalogMatches.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 # Copyright 2008-2016 AURA/LSST.
4 #
5 # This product includes software developed by the
6 # LSST Project (http://www.lsst.org/).
7 #
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the LSST License Statement and
19 # the GNU General Public License along with this program. If not,
20 # see <https://www.lsstcorp.org/LegalNotices/>.
21 #
22 from __future__ import absolute_import
23 from builtins import zip
24 from builtins import range
25 
26 import os.path
27 
28 from .tableLib import (BaseCatalog, SimpleCatalog, SourceCatalog, SimpleTable, SourceTable,
29  Schema, SchemaMapper, ReferenceMatch)
30 from lsst.utils import getPackageDir
31 
32 __all__ = ["makeMergedSchema", "copyIntoCatalog", "matchesToCatalog", "matchesFromCatalog"]
33 
34 def makeMapper(sourceSchema, targetSchema, sourcePrefix=None, targetPrefix=None):
35  """Create a SchemaMapper between the input source and target schemas
36 
37  \param[in] sourceSchema input source schema that fields will be mapped from
38  \param[in] targetSchema target schema that fields will be mapped to
39  \param[in] sourcePrefix if set, only those keys with that prefix will be mapped
40  \param[in] targetPrefix if set, prepend it to the mapped (target) key name
41 
42  \return SchemaMapper between source and target schemas
43  """
44  m = SchemaMapper(sourceSchema, targetSchema)
45  for key, field in sourceSchema:
46  keyName = field.getName()
47  if sourcePrefix is not None:
48  if not keyName.startswith(sourcePrefix):
49  continue
50  else:
51  keyName = field.getName().replace(sourcePrefix, "", 1)
52  m.addMapping(key, (targetPrefix or "") + keyName)
53  return m
54 
55 def makeMergedSchema(sourceSchema, targetSchema, sourcePrefix=None, targetPrefix=None):
56  """Return a schema that is a deep copy of a mapping between source and target schemas
57  \param[in] sourceSchema input source schema that fields will be mapped from
58  \param[in] targetSchema target schema that fields will be mapped to
59  \param[in] sourcePrefix if set, only those keys with that prefix will be mapped
60  \param[in] targetPrefix if set, prepend it to the mapped (target) key name
61 
62  \return schema schema that is the result of the mapping between source and target schemas
63  """
64  return makeMapper(sourceSchema, targetSchema, sourcePrefix, targetPrefix).getOutputSchema()
65 
66 def copyIntoCatalog(catalog, target, sourceSchema=None, sourcePrefix=None, targetPrefix=None):
67  """Copy entries from one Catalog into another
68 
69  \param[in] catalog source catalog to be copied from
70  \param[in/out] target target catalog to be copied to (edited in place)
71  \param[in] souceSchema schema of source catalog (optional)
72  \param[in] sourcePrefix if set, only those keys with that prefix will be copied
73  \param[in] targetPrefix if set, prepend it to the copied (target) key name
74  """
75  if sourceSchema is None:
76  sourceSchema = catalog.schema
77 
78  targetSchema = target.schema
79  target.reserve(len(catalog))
80  for i in range(len(target), len(catalog)):
81  target.addNew()
82 
83  if len(catalog) != len(target):
84  raise RuntimeError("Length mismatch: %d vs %d" % (len(catalog), len(target)))
85 
86  m = makeMapper(sourceSchema, targetSchema, sourcePrefix, targetPrefix)
87  for rFrom, rTo in zip(catalog, target):
88  rTo.assign(rFrom, m)
89 
90 def matchesToCatalog(matches, matchMeta):
91  """Denormalise matches into a Catalog of "unpacked matches"
92 
93  \param[in] matches unpacked matches, i.e. a std::vector of Match objects whose schema
94  has "first" and "second" attributes which, resepectively, contain the
95  reference and source catalog entries, and a "distance" field (the
96  measured distance between the reference and source objects)
97  \param[in] matchMeta metadata for matches (must have .add attribute)
98 
99  \return lsst.afw.table.BaseCatalog of matches (with ref_ and src_ prefix identifiers
100  for referece and source entries, respectively)
101  """
102  if len(matches) == 0:
103  raise RuntimeError("No matches provided.")
104 
105  refSchema = matches[0].first.getSchema()
106  srcSchema = matches[0].second.getSchema()
107 
108  mergedSchema = makeMergedSchema(refSchema, Schema(), targetPrefix="ref_")
109  mergedSchema = makeMergedSchema(srcSchema, mergedSchema, targetPrefix="src_")
110  distKey = mergedSchema.addField("distance", type=float, doc="Distance between ref and src")
111 
112  mergedCatalog = BaseCatalog(mergedSchema)
113  copyIntoCatalog([m.first for m in matches], mergedCatalog, sourceSchema=refSchema, targetPrefix="ref_")
114  copyIntoCatalog([m.second for m in matches], mergedCatalog, sourceSchema=srcSchema, targetPrefix="src_")
115  for m, r in zip(matches, mergedCatalog):
116  r.set(distKey, m.distance)
117 
118  # obtain reference catalog name if one is setup
119  try:
120  catalogName = os.path.basename(getPackageDir("astrometry_net_data"))
121  except:
122  catalogName = "NOT_SET"
123  matchMeta.add("REFCAT", catalogName)
124  mergedCatalog.getTable().setMetadata(matchMeta)
125 
126  return mergedCatalog
127 
128 def matchesFromCatalog(catalog, sourceSlotConfig=None):
129  """Generate a list of ReferenceMatches from a Catalog of "unpacked matches"
130 
131  \param[in] catalog catalog of matches. Must have schema where reference entries are
132  prefixed with "ref_" and source entries are prefixed with "src_"
133  \param[in] sourceSlotConfig an lsst.meas.base.baseMeasurement.SourceSlotConfig configuration
134  for source slots (optional)
135 
136  \returns lsst.afw.table.ReferenceMatch of matches
137  """
138  refSchema = makeMergedSchema(catalog.schema, SimpleTable.makeMinimalSchema(), sourcePrefix="ref_")
139  refCatalog = SimpleCatalog(refSchema)
140  copyIntoCatalog(catalog, refCatalog, sourcePrefix="ref_")
141 
142  srcSchema = makeMergedSchema(catalog.schema, SourceTable.makeMinimalSchema(), sourcePrefix="src_")
143  srcCatalog = SourceCatalog(srcSchema)
144  copyIntoCatalog(catalog, srcCatalog, sourcePrefix="src_")
145 
146  if sourceSlotConfig is not None:
147  sourceSlotConfig.setupSchema(srcCatalog.schema)
148 
149  matches = []
150  distKey = catalog.schema.find("distance").key
151  for ref, src, cat in zip(refCatalog, srcCatalog, catalog):
152  matches.append(ReferenceMatch(ref, src, cat[distKey]))
153 
154  return matches
Defines the fields and offsets for a table.
Definition: Schema.h:44
A custom container class for records, based on std::vector.
Definition: Catalog.h:95
A mapping between the keys of two Schemas, used to copy data between them.
Definition: SchemaMapper.h:19
std::string getPackageDir(std::string const &packageName)
return the root directory of a setup package
Definition: Utils.cc:34
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
Lightweight representation of a geometric match between two records.
Definition: fwd.h:90