LSSTApplications  21.0.0+75b29a8a7f,21.0.0+e70536a077,21.0.0-1-ga51b5d4+62c747d40b,21.0.0-11-ga6ea59e8e+47cba9fc36,21.0.0-2-g103fe59+914993bf7c,21.0.0-2-g1367e85+e2614ded12,21.0.0-2-g45278ab+e70536a077,21.0.0-2-g4bc9b9f+7b2b5f8678,21.0.0-2-g5242d73+e2614ded12,21.0.0-2-g54e2caa+6403186824,21.0.0-2-g7f82c8f+3ac4acbffc,21.0.0-2-g8dde007+04a6aea1af,21.0.0-2-g8f08a60+9402881886,21.0.0-2-ga326454+3ac4acbffc,21.0.0-2-ga63a54e+81dd751046,21.0.0-2-gc738bc1+5f65c6e7a9,21.0.0-2-gde069b7+26c92b3210,21.0.0-2-gecfae73+0993ddc9bd,21.0.0-2-gfc62afb+e2614ded12,21.0.0-21-gba890a8+5a4f502a26,21.0.0-23-g9966ff26+03098d1af8,21.0.0-3-g357aad2+8ad216c477,21.0.0-3-g4be5c26+e2614ded12,21.0.0-3-g6d51c4a+4d2fe0280d,21.0.0-3-g7d9da8d+75b29a8a7f,21.0.0-3-gaa929c8+522e0f12c2,21.0.0-3-ge02ed75+4d2fe0280d,21.0.0-4-g3300ddd+e70536a077,21.0.0-4-gc004bbf+eac6615e82,21.0.0-4-gccdca77+f94adcd104,21.0.0-4-gd1c1571+18b81799f9,21.0.0-5-g7b47fff+4d2fe0280d,21.0.0-5-gb155db7+d2632f662b,21.0.0-5-gdf36809+637e4641ee,21.0.0-6-g722ad07+28c848f42a,21.0.0-7-g959bb79+522e0f12c2,21.0.0-7-gfd72ab2+cf01990774,21.0.0-9-g87fb7b8d+e2ab11cdd6,w.2021.04
LSSTDataManagementBasePackage
CoaddTransmissionCurve.cc
Go to the documentation of this file.
1 /*
2  * LSST Data Management System
3  * Copyright 2018 LSST/AURA.
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 <http://www.lsstcorp.org/LegalNotices/>.
21  */
22 
24 #include "lsst/geom/Box.h"
25 #include "lsst/afw/geom/SkyWcs.h"
30 
31 namespace lsst {
32 namespace meas {
33 namespace algorithms {
34 
35 namespace {
36 
37 struct CoaddInputData {
42  double weight;
43 };
44 
45 class CoaddTransmissionCurve : public afw::image::TransmissionCurve {
46 public:
48  afw::table::ExposureCatalog const& inputSensors)
49  : _coaddWcs(coaddWcs),
50  _wavelengthBounds(std::numeric_limits<double>::infinity(), // min = +inf, max = -inf *for now*
52  _throughputAtBounds(0.0, 0.0) {
53  _inputs.reserve(inputSensors.size());
54  afw::table::Key<double> weightKey = inputSensors.getSchema()["weight"];
55  double weightSum = 0.0;
56  for (auto const& record : inputSensors) {
57  double const weight = record.get(weightKey);
58  weightSum += weight;
59  auto transmission = record.getTransmissionCurve();
60  if (transmission == nullptr) {
61  throw LSST_EXCEPT(
62  pex::exceptions::InvalidParameterError,
63  (boost::format("No TransmissionCurve for input with ID %d") % record.getId()).str());
64  }
65  if (record.getWcs() == nullptr) {
66  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
67  (boost::format("No Wcs for input with ID %d") % record.getId()).str());
68  }
69  // Set wavelength bounds from the overall minimum and maximum wavelengths from all inputs.
70  auto const inputWavelengthBounds = transmission->getWavelengthBounds();
71  _wavelengthBounds.first = std::min(_wavelengthBounds.first, inputWavelengthBounds.first);
72  _wavelengthBounds.second = std::max(_wavelengthBounds.second, inputWavelengthBounds.second);
73  // Set throughput at and outside bounds from weighted average of throughput at and outside bounds.
74  auto const inputThroughputAtBounds = transmission->getThroughputAtBounds();
75  _throughputAtBounds.first += inputThroughputAtBounds.first * weight;
76  _throughputAtBounds.second += inputThroughputAtBounds.second * weight;
77  // Add an element to the vector with all the stuff we need to store for each epoch.
78  CoaddInputData input = {transmission, record.getWcs(), record.getValidPolygon(),
79  geom::Box2D(record.getBBox()), weight};
80  _inputs.push_back(std::move(input));
81  }
82  _throughputAtBounds.first /= weightSum;
83  _throughputAtBounds.second /= weightSum;
84  }
85 
86  // Private constructor used only for persistence
87  CoaddTransmissionCurve(std::shared_ptr<afw::geom::SkyWcs> coaddWcs,
88  std::pair<double, double> wavelengthBounds,
89  std::pair<double, double> throughputAtBounds, std::vector<CoaddInputData> inputs)
90  : _coaddWcs(std::move(coaddWcs)),
91  _wavelengthBounds(std::move(wavelengthBounds)),
92  _throughputAtBounds(std::move(throughputAtBounds)),
93  _inputs(std::move(inputs)) {}
94 
95  // All TransmissionCurves are immutable and noncopyable.
96  CoaddTransmissionCurve(CoaddTransmissionCurve const&) = delete;
97  CoaddTransmissionCurve(CoaddTransmissionCurve&&) = delete;
98  CoaddTransmissionCurve& operator=(CoaddTransmissionCurve const&) = delete;
99  CoaddTransmissionCurve& operator=(CoaddTransmissionCurve&&) = delete;
100 
101  std::pair<double, double> getWavelengthBounds() const override { return _wavelengthBounds; }
102 
103  std::pair<double, double> getThroughputAtBounds() const override { return _throughputAtBounds; }
104 
105  void sampleAt(geom::Point2D const& position, ndarray::Array<double const, 1, 1> const& wavelengths,
106  ndarray::Array<double, 1, 1> const& out) const override {
107  auto const coord = _coaddWcs->pixelToSky(position);
108  ndarray::Array<double, 1, 1> tmp = ndarray::allocate(out.getShape());
109  tmp.deep() = 0.0;
110  out.deep() = 0.0;
111  double weightSum = 0.0;
112  for (auto const& input : _inputs) {
113  geom::Point2D const inputPosition = input.sensorWcs->skyToPixel(coord);
114  if (!input.bbox.contains(inputPosition)) {
115  continue;
116  }
117  if (input.validPolygon && !input.validPolygon->contains(inputPosition)) {
118  continue;
119  }
120  // note that `tmp` is an output argument here
121  input.transmission->sampleAt(inputPosition, wavelengths, tmp);
122  tmp.deep() *= input.weight;
123  out.deep() += tmp;
124  weightSum += input.weight;
125  }
126  if (weightSum == 0.0) {
127  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
128  (boost::format("No input TransmissionCurves at point (%s, %s)") %
129  position.getX() % position.getY())
130  .str());
131  }
132  out.deep() /= weightSum;
133  }
134 
135  bool isPersistable() const noexcept override {
136  for (auto const& input : _inputs) {
137  if (!input.transmission->isPersistable()) {
138  return false;
139  }
140  }
141  return true;
142  }
143 
144 private:
145  std::string getPersistenceName() const override { return "CoaddTransmissionCurve"; }
146 
147  std::string getPythonModule() const override { return "lsst.meas.algorithms"; }
148 
149  struct PersistenceHelper;
150 
151  class Factory;
152 
153  void write(OutputArchiveHandle& handle) const override;
154 
155  static Factory registration;
156 
158  std::pair<double, double> _wavelengthBounds;
159  std::pair<double, double> _throughputAtBounds;
161 };
162 
163 struct CoaddTransmissionCurve::PersistenceHelper {
164  afw::table::Schema mainSchema;
165  afw::table::Key<int> coaddWcs;
166  afw::table::Key<double> wavelengthMin;
167  afw::table::Key<double> wavelengthMax;
168  afw::table::Key<double> throughputAtMin;
169  afw::table::Key<double> throughputAtMax;
170  afw::table::Schema inputDataSchema;
171  afw::table::Key<int> transmission;
172  afw::table::Key<int> sensorWcs;
173  afw::table::Key<int> validPolygon;
175  afw::table::Key<double> weight;
176 
177  static PersistenceHelper const& get() {
178  static PersistenceHelper const instance;
179  return instance;
180  }
181 
182 private:
183  PersistenceHelper()
184  : mainSchema(),
185  coaddWcs(mainSchema.addField<int>("coaddWcs", "archive ID for the coadd's WCS")),
186  wavelengthMin(mainSchema.addField<double>("wavelengthMin", "getWavelengthBounds().min")),
187  wavelengthMax(mainSchema.addField<double>("wavelengthMax", "getWavelengthBounds().max")),
188  throughputAtMin(mainSchema.addField<double>("throughputAtMin", "throughputAtBounds().first")),
189  throughputAtMax(mainSchema.addField<double>("throughputAtMax", "throughputAtBounds().second")),
190  inputDataSchema(),
191  transmission(inputDataSchema.addField<int>("transmission",
192  "archive ID for this sensor's TransmissionCurve")),
193  sensorWcs(inputDataSchema.addField<int>("sensorWcs", "archive ID for this sensor's WCS")),
194  validPolygon(inputDataSchema.addField<int>("validPolygon",
195  "archive ID for this sensor's ValidPolygon")),
196  bbox(afw::table::Box2DKey::addFields(inputDataSchema, "bbox", "bounding box of the sensor",
197  "pixel")),
198  weight(inputDataSchema.addField<double>("weight",
199  "relative weight for this sensor in the average")) {}
200 };
201 
202 void CoaddTransmissionCurve::write(OutputArchiveHandle& handle) const {
203  auto const& keys = PersistenceHelper::get();
204  auto mainCat = handle.makeCatalog(keys.mainSchema);
205  auto mainRecord = mainCat.addNew();
206  mainRecord->set(keys.coaddWcs, handle.put(_coaddWcs));
207  mainRecord->set(keys.wavelengthMin, _wavelengthBounds.first);
208  mainRecord->set(keys.wavelengthMax, _wavelengthBounds.second);
209  mainRecord->set(keys.throughputAtMin, _throughputAtBounds.first);
210  mainRecord->set(keys.throughputAtMax, _throughputAtBounds.second);
211  handle.saveCatalog(mainCat);
212  auto inputDataCat = handle.makeCatalog(keys.inputDataSchema);
213  for (auto const& input : _inputs) {
214  auto inputDataRecord = inputDataCat.addNew();
215  inputDataRecord->set(keys.transmission, handle.put(input.transmission));
216  inputDataRecord->set(keys.sensorWcs, handle.put(input.sensorWcs));
217  inputDataRecord->set(keys.validPolygon, handle.put(input.validPolygon));
218  inputDataRecord->set(keys.bbox, input.bbox);
219  inputDataRecord->set(keys.weight, input.weight);
220  }
221  handle.saveCatalog(inputDataCat);
222 }
223 
224 class CoaddTransmissionCurve::Factory : public afw::table::io::PersistableFactory {
225 public:
226  std::shared_ptr<afw::table::io::Persistable> read(InputArchive const& archive,
227  CatalogVector const& catalogs) const override {
228  auto const& keys = PersistenceHelper::get();
229  LSST_ARCHIVE_ASSERT(catalogs.size() == 2u);
230  LSST_ARCHIVE_ASSERT(catalogs.front().getSchema() == keys.mainSchema);
231  LSST_ARCHIVE_ASSERT(catalogs.back().getSchema() == keys.inputDataSchema);
232  auto const& mainRecord = catalogs.front().front();
234  inputs.reserve(catalogs.back().size());
235  for (auto const& inputDataRecord : catalogs.back()) {
236  CoaddInputData input = {
237  archive.get<afw::image::TransmissionCurve>(inputDataRecord.get(keys.transmission)),
238  archive.get<afw::geom::SkyWcs>(inputDataRecord.get(keys.sensorWcs)),
239  archive.get<afw::geom::polygon::Polygon>(inputDataRecord.get(keys.validPolygon)),
240  inputDataRecord.get(keys.bbox), inputDataRecord.get(keys.weight)};
241  inputs.push_back(std::move(input));
242  }
243  return std::make_shared<CoaddTransmissionCurve>(
244  archive.get<afw::geom::SkyWcs>(mainRecord.get(keys.coaddWcs)),
245  std::make_pair(mainRecord.get(keys.wavelengthMin), mainRecord.get(keys.wavelengthMax)),
246  std::make_pair(mainRecord.get(keys.throughputAtMin), mainRecord.get(keys.throughputAtMax)),
247  std::move(inputs));
248  }
249 
250  Factory(std::string const& name) : afw::table::io::PersistableFactory(name) {}
251 };
252 
253 CoaddTransmissionCurve::Factory CoaddTransmissionCurve::registration("CoaddTransmissionCurve");
254 
255 } // namespace
256 
259  return std::make_shared<CoaddTransmissionCurve>(coaddWcs, inputSensors);
260 }
261 
262 } // namespace algorithms
263 } // namespace meas
264 } // namespace lsst
validPolygon
std::shared_ptr< afw::geom::polygon::Polygon const > validPolygon
Definition: CoaddTransmissionCurve.cc:40
std::string
STL class.
std::shared_ptr
STL class.
weight
double weight
Definition: CoaddTransmissionCurve.cc:42
throughputAtMin
afw::table::Key< double > throughputAtMin
Definition: CoaddTransmissionCurve.cc:168
std::move
T move(T... args)
std::pair< double, double >
std::vector::reserve
T reserve(T... args)
std::vector
STL class.
lsst::afw::table::ExposureCatalogT
Custom catalog class for ExposureRecord/Table.
Definition: Exposure.h:311
lsst::afw
Definition: imageAlgorithm.dox:1
astshim.keyMap.keyMapContinued.keys
def keys(self)
Definition: keyMapContinued.py:6
SkyWcs.h
CatalogVector.h
lsst.pex.config.history.format
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:174
lsst::afw::geom.transform.transformContinued.name
string name
Definition: transformContinued.py:32
sensorWcs
std::shared_ptr< afw::geom::SkyWcs const > sensorWcs
Definition: CoaddTransmissionCurve.cc:39
mainSchema
afw::table::Schema mainSchema
Definition: CoaddTransmissionCurve.cc:164
std::vector::push_back
T push_back(T... args)
lsst.pipe.tasks.mergeDetections.write
def write(self, patchRef, catalog)
Write the output.
Definition: mergeDetections.py:389
LSST_ARCHIVE_ASSERT
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
Definition: Persistable.h:48
lsst::afw::table::Box2DKey
BoxKey< lsst::geom::Box2D > Box2DKey
Definition: aggregates.h:202
lsst::meas::algorithms::makeCoaddTransmissionCurve
std::shared_ptr< afw::image::TransmissionCurve const > makeCoaddTransmissionCurve(std::shared_ptr< afw::geom::SkyWcs const > coaddWcs, afw::table::ExposureCatalog const &inputSensors)
Create a TransmissionCurve that represents the effective throughput on a coadd.
Definition: CoaddTransmissionCurve.cc:257
CoaddTransmissionCurve.h
lsst
A base class for image defects.
Definition: imageAlgorithm.dox:1
wavelengthMax
afw::table::Key< double > wavelengthMax
Definition: CoaddTransmissionCurve.cc:167
LSST_EXCEPT
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
std::min
T min(T... args)
Polygon.h
lsst::afw::image.slicing.Factory
Factory
Definition: slicing.py:252
std
STL namespace.
lsst::geom::Point< double, 2 >
InputArchive.h
coaddWcs
afw::table::Key< int > coaddWcs
Definition: CoaddTransmissionCurve.cc:165
bbox
geom::Box2D bbox
Definition: CoaddTransmissionCurve.cc:41
std::make_pair
T make_pair(T... args)
inputDataSchema
afw::table::Schema inputDataSchema
Definition: CoaddTransmissionCurve.cc:170
lsst::afw::table::ExposureCatalog
ExposureCatalogT< ExposureRecord > ExposureCatalog
Definition: Exposure.h:489
std::max
T max(T... args)
lsst::geom::Box2D
A floating-point coordinate rectangle geometry.
Definition: Box.h:413
wavelengthMin
afw::table::Key< double > wavelengthMin
Definition: CoaddTransmissionCurve.cc:166
std::numeric_limits
Box.h
OutputArchive.h
transmission
std::shared_ptr< afw::image::TransmissionCurve const > transmission
Definition: CoaddTransmissionCurve.cc:38
throughputAtMax
afw::table::Key< double > throughputAtMax
Definition: CoaddTransmissionCurve.cc:169