lsst.meas.algorithms  16.0-12-g67c1616e+2
CoaddBoundedField.cc
Go to the documentation of this file.
1 // -*- LSST-C++ -*-
2 /*
3  * LSST Data Management System
4  * Copyright 2008-2014, 2010 LSST Corporation.
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 <http://www.lsstcorp.org/LegalNotices/>.
22  */
23 
25 #include "lsst/geom/Box.h"
31 
32 namespace lsst {
33 namespace meas {
34 namespace algorithms {
35 namespace {
36 
37 /*
38  * Compare two pointers of the same type
39  *
40  * If both pointers are set then return *a == *b
41  * else return a == b
42  */
43 template <typename T>
44 bool ptrEquals(T a, T b) {
45  if (a == b) {
46  // test this first for efficiency
47  return true;
48  } else if (a && b) {
49  // both pointers are set, so it is safe to check value equality
50  return *a == *b;
51  }
52  return false;
53 }
54 
55 } // namespace
56 
58  return ptrEquals(field, rhs.field) && ptrEquals(wcs, rhs.wcs) &&
59  ptrEquals(validPolygon, rhs.validPolygon) && (weight == rhs.weight);
60 }
61 
63  ElementVector const& elements)
64  : afw::math::BoundedField(bbox),
65  _throwOnMissing(true),
66  _default(0.0), // unused
67  _coaddWcs(coaddWcs),
68  _elements(elements) {}
69 
71  ElementVector const& elements, double default_)
72  : afw::math::BoundedField(bbox),
73  _throwOnMissing(false),
74  _default(default_),
75  _coaddWcs(coaddWcs),
76  _elements(elements) {}
77 
78 double CoaddBoundedField::evaluate(geom::Point2D const& position) const {
79  auto coord = _coaddWcs->pixelToSky(position);
80  double sum = 0.0;
81  double wSum = 0.0;
82  for (ElementVector::const_iterator i = _elements.begin(); i != _elements.end(); ++i) {
83  geom::Point2D transformedPosition = i->wcs->skyToPixel(coord);
84  bool inValidArea = i->validPolygon ? i->validPolygon->contains(transformedPosition) : true;
85  if (geom::Box2D(i->field->getBBox()).contains(transformedPosition) && inValidArea) {
86  sum += i->weight * i->field->evaluate(transformedPosition);
87  wSum += i->weight;
88  }
89  }
90  if (wSum == 0.0) {
91  if (_throwOnMissing) {
93  (boost::format("No constituent fields to evaluate at point %f, %f") %
94  position.getX() % position.getY())
95  .str());
96  } else {
97  return _default;
98  }
99  }
100  return sum / wSum;
101 }
102 
103 // ---------- Persistence -----------------------------------------------------------------------------------
104 
105 // For persistence of CoaddBoundedField, we have two catalogs: the first has just one record, and contains
106 // the archive ID of the coadd WCS and the parameters that control missing data. The other catalog
107 // has one record for each element, with fields corresponding to the data members of the Element struct.
108 
109 namespace {
110 
111 // Singleton class that manages the first persistence catalog's schema and keys
112 class CoaddBoundedFieldPersistenceKeys1 {
113 public:
114  afw::table::Schema schema;
115  afw::table::PointKey<int> bboxMin;
116  afw::table::PointKey<int> bboxMax;
117  afw::table::Key<int> coaddWcs;
118  afw::table::Key<afw::table::Flag> throwOnMissing;
119  afw::table::Key<double> default_;
120 
121  static CoaddBoundedFieldPersistenceKeys1 const& get() {
122  static CoaddBoundedFieldPersistenceKeys1 const instance;
123  return instance;
124  }
125 
126  // No copying
127  CoaddBoundedFieldPersistenceKeys1(const CoaddBoundedFieldPersistenceKeys1&) = delete;
128  CoaddBoundedFieldPersistenceKeys1& operator=(const CoaddBoundedFieldPersistenceKeys1&) = delete;
129 
130  // No moving
131  CoaddBoundedFieldPersistenceKeys1(CoaddBoundedFieldPersistenceKeys1&&) = delete;
132  CoaddBoundedFieldPersistenceKeys1& operator=(CoaddBoundedFieldPersistenceKeys1&&) = delete;
133 
134 private:
135  CoaddBoundedFieldPersistenceKeys1()
136  : schema(),
138  "lower-left corner of bounding box", "pixel")),
140  "upper-right corner of bounding box", "pixel")),
141  coaddWcs(schema.addField<int>("coaddWcs", "archive ID of the coadd's WCS")),
142  throwOnMissing(schema.addField<afw::table::Flag>(
143  "throwOnMissing", "whether to throw an exception on missing data")),
144  default_(schema.addField<double>("default",
145  "default value to use when throwOnMissing is False")) {
146  schema.getCitizen().markPersistent();
147  }
148 };
149 
150 // Singleton class that manages the second persistence catalog's schema and keys
151 class CoaddBoundedFieldPersistenceKeys2 {
152 public:
153  afw::table::Schema schema;
154  afw::table::Key<int> field;
155  afw::table::Key<int> wcs;
156  afw::table::Key<int> validPolygon;
157  afw::table::Key<double> weight;
158 
159  static CoaddBoundedFieldPersistenceKeys2 const& get() {
160  static CoaddBoundedFieldPersistenceKeys2 const instance;
161  return instance;
162  }
163 
164  // No copying
165  CoaddBoundedFieldPersistenceKeys2(const CoaddBoundedFieldPersistenceKeys2&) = delete;
166  CoaddBoundedFieldPersistenceKeys2& operator=(const CoaddBoundedFieldPersistenceKeys2&) = delete;
167 
168  // No moving
169  CoaddBoundedFieldPersistenceKeys2(CoaddBoundedFieldPersistenceKeys2&&) = delete;
170  CoaddBoundedFieldPersistenceKeys2& operator=(CoaddBoundedFieldPersistenceKeys2&&) = delete;
171 
172 private:
173  CoaddBoundedFieldPersistenceKeys2()
174  : schema(),
175  field(schema.addField<int>("field", "archive ID of the BoundedField to be coadded")),
176  wcs(schema.addField<int>("wcs", "archive ID of the Wcs associated with this element")),
177  validPolygon(schema.addField<int>("validPolygon",
178  "archive ID of the Polygon associated with this element")),
179  weight(schema.addField<double>("weight", "weight value for this element")) {
180  schema.getCitizen().markPersistent();
181  }
182 };
183 
184 } // namespace
185 
187 public:
189  read(InputArchive const& archive, CatalogVector const& catalogs) const {
190  CoaddBoundedFieldPersistenceKeys1 const& keys1 = CoaddBoundedFieldPersistenceKeys1::get();
191  CoaddBoundedFieldPersistenceKeys2 const& keys2 = CoaddBoundedFieldPersistenceKeys2::get();
192  LSST_ARCHIVE_ASSERT(catalogs.size() == 2u);
193  LSST_ARCHIVE_ASSERT(catalogs.front().getSchema() == keys1.schema);
194  LSST_ARCHIVE_ASSERT(catalogs.back().getSchema() == keys2.schema);
195  afw::table::BaseRecord const& record1 = catalogs.front().front();
196  ElementVector elements;
197  elements.reserve(catalogs.back().size());
198  for (afw::table::BaseCatalog::const_iterator i = catalogs.back().begin(); i != catalogs.back().end();
199  ++i) {
200  elements.push_back(Element(archive.get<afw::math::BoundedField>(i->get(keys2.field)),
201  archive.get<afw::geom::SkyWcs>(i->get(keys2.wcs)),
202  archive.get<afw::geom::polygon::Polygon>(i->get(keys2.validPolygon)),
203  i->get(keys2.weight)));
204  }
205  return std::make_shared<CoaddBoundedField>(
206  geom::Box2I(record1.get(keys1.bboxMin), record1.get(keys1.bboxMax)),
207  archive.get<afw::geom::SkyWcs>(record1.get(keys1.coaddWcs)), elements,
208  record1.get(keys1.default_));
209  }
210 
211  Factory(std::string const& name) : afw::table::io::PersistableFactory(name) {}
212 };
213 
214 namespace {
215 
216 std::string getCoaddBoundedFieldPersistenceName() { return "CoaddBoundedField"; }
217 
218 CoaddBoundedField::Factory registration(getCoaddBoundedFieldPersistenceName());
219 
220 } // namespace
221 
222 std::string CoaddBoundedField::getPersistenceName() const { return getCoaddBoundedFieldPersistenceName(); }
223 
224 std::string CoaddBoundedField::getPythonModule() const { return "lsst.meas.algorithms"; }
225 
227  CoaddBoundedFieldPersistenceKeys1 const& keys1 = CoaddBoundedFieldPersistenceKeys1::get();
228  CoaddBoundedFieldPersistenceKeys2 const& keys2 = CoaddBoundedFieldPersistenceKeys2::get();
229  afw::table::BaseCatalog cat1 = handle.makeCatalog(keys1.schema);
230  PTR(afw::table::BaseRecord) record1 = cat1.addNew();
231  record1->set(keys1.bboxMin, getBBox().getMin());
232  record1->set(keys1.bboxMax, getBBox().getMax());
233  record1->set(keys1.coaddWcs, handle.put(_coaddWcs));
234  record1->set(keys1.default_, _default);
235  handle.saveCatalog(cat1);
236  afw::table::BaseCatalog cat2 = handle.makeCatalog(keys2.schema);
237  for (ElementVector::const_iterator i = _elements.begin(); i != _elements.end(); ++i) {
238  PTR(afw::table::BaseRecord) record2 = cat2.addNew();
239  record2->set(keys2.field, handle.put(i->field));
240  record2->set(keys2.wcs, handle.put(i->wcs));
241  record2->set(keys2.validPolygon, handle.put(i->validPolygon));
242  record2->set(keys2.weight, i->weight);
243  }
244  handle.saveCatalog(cat2);
245 }
246 
248  throw LSST_EXCEPT(pex::exceptions::NotFoundError, "Scaling of CoaddBoundedField is not implemented");
249 }
250 
252  auto rhsCasted = dynamic_cast<CoaddBoundedField const*>(&rhs);
253  if (!rhsCasted) return false;
254 
255  return (getBBox() == rhsCasted->getBBox()) && (_default == rhsCasted->_default) &&
256  ptrEquals(_coaddWcs, rhsCasted->_coaddWcs) && (_elements == rhsCasted->_elements);
257 }
258 
259 } // namespace algorithms
260 } // namespace meas
261 } // namespace lsst
virtual std::string getPersistenceName() const
Struct used to hold one Exposure&#39;s data in a CoaddBoundedField.
virtual std::string getPythonModule() const
boost::shared_ptr< afw::geom::SkyWcs const > wcs
geom::Box2D bbox
#define LSST_ARCHIVE_ASSERT(EXPR)
afw::table::Key< int > wcs
static PointKey addFields(Schema &schema, std::string const &name, std::string const &doc, std::string const &unit)
afw::table::PointKey< int > bboxMax
afw::table::Key< int > validPolygon
#define PTR(...)
T end(T... args)
afw::table::PointKey< int > bboxMin
afw::table::Key< double > default_
virtual void write(OutputArchiveHandle &handle) const
STL class.
bool operator==(CoaddBoundedFieldElement const &rhs) const
Elements are equal if all their components are equal.
BoundedField & operator=(BoundedField const &)=delete
T push_back(T... args)
BoundedField(BoundedField const &)=default
afw::table::Key< afw::table::Flag > throwOnMissing
afw::table::Key< int > field
virtual bool operator==(BoundedField const &rhs) const
BoundedFields (of the same sublcass) are equal if their bounding boxes and parameters are equal...
afw::table::Schema schema
lsst::geom::Box2I getBBox() const
afw::table::Key< int > coaddWcs
virtual double evaluate(geom::Point2D const &position) const
CatalogIterator< typename Internal::const_iterator > const_iterator
#define LSST_EXCEPT(type,...)
T begin(T... args)
virtual boost::shared_ptr< afw::math::BoundedField > operator*(double const scale) const
io::OutputArchiveHandle OutputArchiveHandle
afw::table::Key< double > b
afw::table::Key< double > weight
CoaddBoundedField(geom::Box2I const &bbox, boost::shared_ptr< afw::geom::SkyWcs const > coaddWcs, ElementVector const &elements)
boost::shared_ptr< afw::math::BoundedField > field
T reserve(T... args)
std::shared_ptr< BaseRecord > addNew()
boost::shared_ptr< afw::geom::polygon::Polygon const > validPolygon