32 namespace algorithms {
36 struct CoaddInputData {
44 class CoaddTransmissionCurve :
public afw::image::TransmissionCurve {
47 CoaddTransmissionCurve(
50 ) : _coaddWcs(coaddWcs),
53 _throughputAtBounds(0.0, 0.0)
55 _inputs.reserve(inputSensors.size());
56 afw::table::Key<double> weightKey = inputSensors.getSchema()[
"weight"];
57 double weightSum = 0.0;
58 for (
auto const & record : inputSensors) {
59 double const weight = record.get(weightKey);
64 pex::exceptions::InvalidParameterError,
65 (boost::format(
"No TransmissionCurve for input with ID %d") % record.getId()).str()
68 if (record.getWcs() ==
nullptr) {
70 pex::exceptions::InvalidParameterError,
71 (boost::format(
"No Wcs for input with ID %d") % record.getId()).str()
75 auto const inputWavelengthBounds =
transmission->getWavelengthBounds();
76 _wavelengthBounds.first =
std::min(_wavelengthBounds.first, inputWavelengthBounds.first);
77 _wavelengthBounds.second =
std::max(_wavelengthBounds.second, inputWavelengthBounds.second);
79 auto const inputThroughputAtBounds =
transmission->getThroughputAtBounds();
80 _throughputAtBounds.first += inputThroughputAtBounds.first*
weight;
81 _throughputAtBounds.second += inputThroughputAtBounds.second*
weight;
83 CoaddInputData input = {
86 record.getValidPolygon(),
87 afw::geom::Box2D(record.getBBox()),
92 _throughputAtBounds.first /= weightSum;
93 _throughputAtBounds.second /= weightSum;
97 CoaddTransmissionCurve(
104 _wavelengthBounds(
std::move(wavelengthBounds)),
105 _throughputAtBounds(
std::move(throughputAtBounds)),
110 CoaddTransmissionCurve(CoaddTransmissionCurve
const &) =
delete;
111 CoaddTransmissionCurve(CoaddTransmissionCurve &&) =
delete;
112 CoaddTransmissionCurve & operator=(CoaddTransmissionCurve
const &) =
delete;
113 CoaddTransmissionCurve & operator=(CoaddTransmissionCurve &&) =
delete;
116 return _wavelengthBounds;
120 return _throughputAtBounds;
125 ndarray::Array<double const,1,1>
const & wavelengths,
126 ndarray::Array<double,1,1>
const & out
128 auto const coord = _coaddWcs->pixelToSky(position);
129 ndarray::Array<double,1,1> tmp = ndarray::allocate(out.getShape());
132 double weightSum = 0.0;
133 for (
auto const & input : _inputs) {
135 if (!input.bbox.contains(inputPosition)) {
138 if (input.validPolygon && !input.validPolygon->contains(inputPosition)) {
142 input.transmission->sampleAt(inputPosition, wavelengths, tmp);
143 tmp.deep() *= input.weight;
145 weightSum += input.weight;
147 if (weightSum == 0.0) {
149 pex::exceptions::InvalidParameterError,
150 (boost::format(
"No input TransmissionCurves at point (%s, %s)")
151 % position.getX() % position.getY()).str()
154 out.deep() /= weightSum;
157 bool isPersistable()
const override {
158 for (
auto const & input : _inputs) {
159 if (!input.transmission->isPersistable()) {
168 std::string getPersistenceName()
const override {
return "CoaddTransmissionCurve"; }
170 std::string getPythonModule()
const override {
return "lsst.meas.algorithms"; }
172 struct PersistenceHelper;
176 void write(OutputArchiveHandle& handle)
const override;
186 struct CoaddTransmissionCurve::PersistenceHelper {
198 afw::table::Key<double>
weight;
200 static PersistenceHelper
const &
get() {
201 static PersistenceHelper
const instance;
207 PersistenceHelper() :
209 coaddWcs(mainSchema.addField<
int>(
"coaddWcs",
"archive ID for the coadd's WCS")),
210 wavelengthMin(mainSchema.addField<
double>(
"wavelengthMin",
"getWavelengthBounds().min")),
211 wavelengthMax(mainSchema.addField<
double>(
"wavelengthMax",
"getWavelengthBounds().max")),
212 throughputAtMin(mainSchema.addField<
double>(
"throughputAtMin",
"throughputAtBounds().first")),
213 throughputAtMax(mainSchema.addField<
double>(
"throughputAtMax",
"throughputAtBounds().second")),
215 transmission(inputDataSchema.addField<
int>(
"transmission",
"archive ID for this sensor's TransmissionCurve")),
216 sensorWcs(inputDataSchema.addField<
int>(
"sensorWcs",
"archive ID for this sensor's WCS")),
217 validPolygon(inputDataSchema.addField<
int>(
"validPolygon",
"archive ID for this sensor's ValidPolygon")),
219 weight(inputDataSchema.addField<
double>(
"weight",
"relative weight for this sensor in the average"))
221 mainSchema.getCitizen().markPersistent();
222 inputDataSchema.getCitizen().markPersistent();
227 void CoaddTransmissionCurve::write(OutputArchiveHandle & handle)
const {
228 auto const &
keys = PersistenceHelper::get();
229 auto mainCat = handle.makeCatalog(
keys.mainSchema);
230 auto mainRecord = mainCat.addNew();
231 mainRecord->set(
keys.coaddWcs, handle.put(_coaddWcs));
232 mainRecord->set(
keys.wavelengthMin, _wavelengthBounds.first);
233 mainRecord->set(
keys.wavelengthMax, _wavelengthBounds.second);
234 mainRecord->set(
keys.throughputAtMin, _throughputAtBounds.first);
235 mainRecord->set(
keys.throughputAtMax, _throughputAtBounds.second);
236 handle.saveCatalog(mainCat);
237 auto inputDataCat = handle.makeCatalog(
keys.inputDataSchema);
238 for (
auto const & input : _inputs) {
239 auto inputDataRecord = inputDataCat.addNew();
240 inputDataRecord->set(
keys.transmission, handle.put(input.transmission));
241 inputDataRecord->set(
keys.sensorWcs, handle.put(input.sensorWcs));
242 inputDataRecord->set(
keys.validPolygon, handle.put(input.validPolygon));
243 inputDataRecord->set(
keys.bbox, input.bbox);
244 inputDataRecord->set(
keys.weight, input.weight);
246 handle.saveCatalog(inputDataCat);
249 class CoaddTransmissionCurve::Factory :
public afw::table::io::PersistableFactory {
253 InputArchive
const& archive,
254 CatalogVector
const& catalogs
256 auto const&
keys = PersistenceHelper::get();
260 auto const & mainRecord = catalogs.front().front();
262 inputs.
reserve(catalogs.back().size());
263 for (
auto const & inputDataRecord : catalogs.back()) {
264 CoaddInputData input = {
265 archive.get<afw::image::TransmissionCurve>(inputDataRecord.get(
keys.transmission)),
266 archive.get<afw::geom::SkyWcs>(inputDataRecord.get(
keys.sensorWcs)),
267 archive.get<afw::geom::polygon::Polygon>(inputDataRecord.get(
keys.validPolygon)),
268 inputDataRecord.get(
keys.bbox),
269 inputDataRecord.get(
keys.weight)
273 return std::make_shared<CoaddTransmissionCurve>(
274 archive.get<afw::geom::SkyWcs>(mainRecord.get(
keys.coaddWcs)),
284 CoaddTransmissionCurve::Factory CoaddTransmissionCurve::registration(
"CoaddTransmissionCurve");
294 return std::make_shared<CoaddTransmissionCurve>(
coaddWcs, inputSensors);
afw::table::Schema mainSchema
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.
#define LSST_ARCHIVE_ASSERT(EXPR)
BoxKey< geom::Box2D > Box2DKey
afw::table::Key< double > throughputAtMax
afw::table::Key< double > wavelengthMax
std::shared_ptr< afw::geom::polygon::Polygon const > validPolygon
afw::table::Schema inputDataSchema
Point< double, 2 > Point2D
afw::table::Key< double > throughputAtMin
std::shared_ptr< afw::image::TransmissionCurve const > transmission
afw::table::Key< int > coaddWcs
afw::table::Key< double > wavelengthMin
#define LSST_EXCEPT(type,...)
std::shared_ptr< afw::geom::SkyWcs const > sensorWcs
ExposureCatalogT< ExposureRecord > ExposureCatalog
static BoxKey addFields(Schema &schema, std::string const &name, std::string const &doc, std::string const &unit)