37struct CoaddInputData {
45class CoaddTransmissionCurve :
public afw::image::TransmissionCurve {
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);
62 pex::exceptions::InvalidParameterError,
63 (boost::format(
"No TransmissionCurve for input with ID %d") % record.getId()).str());
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());
70 auto const inputWavelengthBounds =
transmission->getWavelengthBounds();
71 _wavelengthBounds.first =
std::min(_wavelengthBounds.first, inputWavelengthBounds.first);
72 _wavelengthBounds.second =
std::max(_wavelengthBounds.second, inputWavelengthBounds.second);
74 auto const inputThroughputAtBounds =
transmission->getThroughputAtBounds();
75 _throughputAtBounds.first += inputThroughputAtBounds.first *
weight;
76 _throughputAtBounds.second += inputThroughputAtBounds.second *
weight;
78 CoaddInputData input = {
transmission, record.getWcs(), record.getValidPolygon(),
82 _throughputAtBounds.first /= weightSum;
83 _throughputAtBounds.second /= weightSum;
91 _wavelengthBounds(
std::
move(wavelengthBounds)),
92 _throughputAtBounds(
std::
move(throughputAtBounds)),
96 CoaddTransmissionCurve(CoaddTransmissionCurve
const&) =
delete;
97 CoaddTransmissionCurve(CoaddTransmissionCurve&&) =
delete;
98 CoaddTransmissionCurve& operator=(CoaddTransmissionCurve
const&) =
delete;
99 CoaddTransmissionCurve& operator=(CoaddTransmissionCurve&&) =
delete;
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());
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)) {
117 if (input.validPolygon && !input.validPolygon->contains(inputPosition)) {
121 input.transmission->sampleAt(inputPosition, wavelengths, tmp);
122 tmp.deep() *= input.weight;
124 weightSum += input.weight;
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())
132 out.deep() /= weightSum;
135 bool isPersistable() const noexcept
override {
136 for (
auto const& input : _inputs) {
137 if (!input.transmission->isPersistable()) {
145 std::string getPersistenceName()
const override {
return "CoaddTransmissionCurve"; }
147 std::string getPythonModule()
const override {
return "lsst.meas.algorithms"; }
149 struct PersistenceHelper;
153 void write(OutputArchiveHandle& handle)
const override;
163struct CoaddTransmissionCurve::PersistenceHelper {
175 afw::table::Key<double>
weight;
177 static PersistenceHelper
const& get() {
178 static PersistenceHelper
const instance;
192 "archive ID for this sensor's TransmissionCurve")),
195 "archive ID for this sensor's ValidPolygon")),
199 "relative weight for this sensor in the average")) {}
202void 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);
221 handle.saveCatalog(inputDataCat);
224class CoaddTransmissionCurve::Factory :
public afw::table::io::PersistableFactory {
227 CatalogVector
const& catalogs)
const override {
228 auto const&
keys = PersistenceHelper::get();
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)};
243 return std::make_shared<CoaddTransmissionCurve>(
244 archive.get<afw::geom::SkyWcs>(mainRecord.get(
keys.coaddWcs)),
253CoaddTransmissionCurve::Factory CoaddTransmissionCurve::registration(
"CoaddTransmissionCurve");
259 return std::make_shared<CoaddTransmissionCurve>(
coaddWcs, inputSensors);
table::Key< std::string > name
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
table::Key< double > throughputAtMax
table::Key< double > throughputAtMin
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
Custom catalog class for ExposureRecord/Table.
A floating-point coordinate rectangle geometry.
BoxKey< lsst::geom::Box2D > Box2DKey
ExposureCatalogT< ExposureRecord > ExposureCatalog
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.
afw::table::Key< double > weight
afw::table::Key< int > coaddWcs
std::shared_ptr< afw::geom::SkyWcs const > sensorWcs
std::shared_ptr< afw::image::TransmissionCurve const > transmission
afw::table::Key< double > wavelengthMin
afw::table::Key< double > wavelengthMax
afw::table::Schema inputDataSchema
afw::table::Schema mainSchema
std::shared_ptr< table::io::Persistable > read(table::io::InputArchive const &archive, table::io::CatalogVector const &catalogs) const override