32 #include "boost/format.hpp" 33 #include "boost/algorithm/string/trim.hpp" 44 #include "lsst/afw/table/io/Persistable.cc" 56 ndarray::Array<T, 1>
abMagFromFlux(ndarray::Array<T const, 1>
const& flux) {
57 ndarray::Array<T, 1> out = ndarray::allocate(flux.getShape());
58 for (
std::size_t ii = 0; ii < flux.getNumElements(); ++ii) {
67 ndarray::Array<T const, 1>
const& flux) {
68 if (flux.getNumElements() != fluxErr.getNumElements()) {
70 flux.getNumElements() % fluxErr.getNumElements())
73 ndarray::Array<T, 1> out = ndarray::allocate(flux.getShape());
74 for (
std::size_t ii = 0; ii < flux.getNumElements(); ++ii) {
82 ndarray::Array<T, 1>
fluxFromABMag(ndarray::Array<T const, 1>
const& mag) {
83 ndarray::Array<T, 1> out = ndarray::allocate(mag.getShape());
84 for (
std::size_t ii = 0; ii < mag.getNumElements(); ++ii) {
93 ndarray::Array<T const, 1>
const& mag) {
94 if (mag.getNumElements() != magErr.getNumElements()) {
96 mag.getNumElements() % magErr.getNumElements())
99 ndarray::Array<T, 1> out = ndarray::allocate(mag.getShape());
100 for (
std::size_t ii = 0; ii < mag.getNumElements(); ++ii) {
106 Calib::Calib() noexcept : _fluxMag0(0.0), _fluxMag0Err(0.0) {}
107 Calib::Calib(
double fluxMag0) : _fluxMag0(fluxMag0), _fluxMag0Err(0.0) {}
109 if (calibs.empty()) {
111 "You must provide at least one input Calib");
114 double const fluxMag00 = calibs[0]->_fluxMag0;
115 double const fluxMag0Err0 = calibs[0]->_fluxMag0Err;
124 (
boost::format(
"You may only combine calibs with the same fluxMag0: " 125 "%g +- %g v %g +- %g") %
127 calibs[0]->getFluxMag0().first % calibs[0]->getFluxMag0().second)
136 auto key =
"FLUXMAG0";
137 if (metadata->exists(
key)) {
138 fluxMag0 = metadata->getAsDouble(
key);
141 if (metadata->exists(
key)) {
149 bool Calib::_throwOnNegativeFlux =
true;
164 auto key =
"FLUXMAG0";
165 if (metadata->exists(
key)) {
166 metadata->remove(
key);
171 if (metadata->exists(
key)) {
172 metadata->remove(
key);
181 return _fluxMag0 == rhs._fluxMag0 && _fluxMag0Err == rhs._fluxMag0Err;
194 _fluxMag0 = fluxMag0AndErr.first;
195 _fluxMag0Err = fluxMag0AndErr.second;
202 inline void checkNegativeFlux0(
double fluxMag0) {
205 (
boost::format(
"Flux of 0-mag object must be >= 0: saw %g") % fluxMag0).
str());
208 inline bool isNegativeFlux(
double flux,
bool doThrow) {
218 inline double convertToFlux(
double fluxMag0,
double mag) {
return fluxMag0 * ::pow(10.0, -0.4 * mag); }
219 inline double convertToFluxErr(
double fluxMag0InvSNR,
double flux,
double magErr) {
223 double a = fluxMag0InvSNR;
224 double b = 0.4 *
std::log(10.0) * magErr;
230 inline double convertToMag(
double fluxMag0,
double flux) {
return -2.5 * ::log10(flux / fluxMag0); }
232 inline void convertToMagWithErr(
double* mag,
double* magErr,
double fluxMag0,
double fluxMag0Err,
double flux,
235 double const x = fluxErr / flux;
243 checkNegativeFlux0(_fluxMag0);
244 return convertToFlux(_fluxMag0, mag);
246 ndarray::Array<double, 1>
Calib::getFlux(ndarray::Array<double const, 1>
const& mag)
const {
247 checkNegativeFlux0(_fluxMag0);
248 ndarray::Array<double, 1> flux = ndarray::allocate(mag.size());
251 for (; inIter != mag.end(); ++inIter, ++outIter) {
252 *outIter = convertToFlux(_fluxMag0, *inIter);
258 checkNegativeFlux0(_fluxMag0);
259 double const flux = convertToFlux(_fluxMag0, mag);
260 double const fluxErr = convertToFluxErr(_fluxMag0Err / _fluxMag0, flux, magSigma);
265 ndarray::Array<double const, 1>
const& mag, ndarray::Array<double const, 1>
const& magErr)
const {
266 checkNegativeFlux0(_fluxMag0);
267 if (mag.size() != magErr.size()) {
270 (
boost::format(
"Size of mag (%d) and magErr (%d) don't match") % mag.size() % magErr.size())
274 ndarray::Array<double, 1> flux = ndarray::allocate(mag.size());
275 ndarray::Array<double, 1> fluxErr = ndarray::allocate(mag.size());
281 double fluxMag0InvSNR = _fluxMag0Err / _fluxMag0;
282 for (; magIter != mag.end(); ++magIter, ++magErrIter, ++fluxIter, ++fluxErrIter) {
283 *fluxIter = convertToFlux(_fluxMag0, *magIter);
284 *fluxErrIter = convertToFluxErr(fluxMag0InvSNR, *fluxIter, *magErrIter);
291 checkNegativeFlux0(_fluxMag0);
295 return convertToMag(_fluxMag0, flux);
299 checkNegativeFlux0(_fluxMag0);
306 convertToMagWithErr(&mag, &magErr, _fluxMag0, _fluxMag0Err, flux, fluxErr);
311 checkNegativeFlux0(_fluxMag0);
312 ndarray::Array<double, 1> mag = ndarray::allocate(flux.size());
316 for (; fluxIter != flux.end(); ++fluxIter, ++magIter) {
317 if (isNegativeFlux(*fluxIter,
false)) {
322 *magIter = convertToMag(_fluxMag0, *fluxIter);
326 (
boost::format(
"Flux must be >= 0: %d non-positive seen") % nonPositive).
str());
332 ndarray::Array<double const, 1>
const& flux, ndarray::Array<double const, 1>
const& fluxErr)
const {
333 checkNegativeFlux0(_fluxMag0);
334 if (flux.size() != fluxErr.size()) {
336 (
boost::format(
"Size of flux (%d) and fluxErr (%d) don't match") % flux.size() %
341 ndarray::Array<double, 1> mag = ndarray::allocate(flux.size());
342 ndarray::Array<double, 1> magErr = ndarray::allocate(flux.size());
348 for (; fluxIter != flux.end(); ++fluxIter, ++fluxErrIter, ++magIter, ++magErrIter) {
349 if (isNegativeFlux(*fluxIter,
false)) {
357 convertToMagWithErr(&f, &df, _fluxMag0, _fluxMag0Err, *fluxIter, *fluxErrIter);
363 (
boost::format(
"Flux must be >= 0: %d non-positive seen") % nonPositive).
str());
370 int const CALIB_TABLE_CURRENT_VERSION = 2;
382 CalibKeys(
const CalibKeys&) =
delete;
383 CalibKeys&
operator=(
const CalibKeys&) =
delete;
386 CalibKeys(CalibKeys&&) =
delete;
387 CalibKeys&
operator=(CalibKeys&&) =
delete;
389 CalibKeys(
int tableVersion = CALIB_TABLE_CURRENT_VERSION)
390 : schema(), midTime(), expTime(), fluxMag0(), fluxMag0Err() {
391 if (tableVersion == 1) {
394 "midtime",
"middle of the time of the exposure relative to Unix epoch",
"ns");
395 expTime = schema.addField<
double>(EXPTIME_FIELD_NAME,
"exposure time",
"s");
397 fluxMag0 = schema.addField<
double>(
"fluxmag0",
"flux of a zero-magnitude object",
"count");
398 fluxMag0Err = schema.addField<
double>(
"fluxmag0.err",
"1-sigma error on fluxmag0",
"count");
402 class CalibFactory :
public table::io::PersistableFactory {
405 CatalogVector
const& catalogs)
const override {
408 int tableVersion = 1;
410 catalogs.front().getSchema().find<
double>(EXPTIME_FIELD_NAME);
411 }
catch (pex::exceptions::NotFoundError) {
412 tableVersion = CALIB_TABLE_CURRENT_VERSION;
415 CalibKeys
const keys{tableVersion};
419 table::BaseRecord
const& record = catalogs.front().front();
421 result->setFluxMag0(record.get(
keys.fluxMag0), record.get(
keys.fluxMag0Err));
425 explicit CalibFactory(
std::string const&
name) : table::io::PersistableFactory(name) {}
428 std::string getCalibPersistenceName() {
return "Calib"; }
430 CalibFactory registration(getCalibPersistenceName());
437 CalibKeys
const keys{};
441 record->set(
keys.fluxMag0, fluxMag0.first);
442 record->set(
keys.fluxMag0Err, fluxMag0.second);
448 _fluxMag0Err *=
scale;
453 #define INSTANTIATE(TYPE) \ 454 template ndarray::Array<TYPE, 1> abMagFromFlux(ndarray::Array<TYPE const, 1> const& flux); \ 455 template ndarray::Array<TYPE, 1> abMagErrFromFluxErr(ndarray::Array<TYPE const, 1> const& fluxErr, \ 456 ndarray::Array<TYPE const, 1> const& flux); \ 457 template ndarray::Array<TYPE, 1> fluxFromABMag(ndarray::Array<TYPE const, 1> const& mag); \ 458 template ndarray::Array<TYPE, 1> fluxErrFromABMagErr(ndarray::Array<TYPE const, 1> const& magErr, \ 459 ndarray::Array<TYPE const, 1> const& mag);
Angle abs(Angle const &a)
static std::shared_ptr< T > dynamicCast(std::shared_ptr< Persistable > const &ptr)
Dynamically cast a shared_ptr.
std::size_t hash_value() const noexcept
Return a hash of this object.
template ndarray::Array< double, 1 > abMagErrFromFluxErr(ndarray::Array< double const, 1 > const &fluxErr, ndarray::Array< double const, 1 > const &flux)
An object passed to Persistable::write to allow it to persist itself.
static void setThrowOnNegativeFlux(bool raiseException) noexcept
Set whether Calib should throw an exception when asked to convert a flux to a magnitude.
Reports attempts to exceed implementation-defined length limits for some classes. ...
def scale(algorithm, min, max=None, frame=None)
double getFlux(double const mag) const
Return a flux (in ADUs) given a magnitude.
template ndarray::Array< double, 1 > fluxFromABMag(ndarray::Array< double const, 1 > const &mag)
Calib & operator=(Calib const &) noexcept
Reports arguments outside the domain of an operation.
static bool getThrowOnNegativeFlux() noexcept
Tell me whether Calib will throw an exception if asked to convert a flux to a magnitude.
Describe an exposure's calibration.
Calib & operator*=(double const scale)
template ndarray::Array< double, 1 > abMagFromFlux(ndarray::Array< double const, 1 > const &flux)
#define INSTANTIATE(TYPE)
FastFinder::Iterator Iterator
A base class for image defects.
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
std::string getPersistenceName() const override
Return the unique name used to persist this object and look up its factory.
void setFluxMag0(double fluxMag0, double fluxMag0Err=0.0)
Set the flux of a zero-magnitude object.
int stripCalibKeywords(std::shared_ptr< lsst::daf::base::PropertySet > metadata)
Remove Calib-related keywords from the metadata.
template ndarray::Array< double, 1 > fluxErrFromABMagErr(ndarray::Array< double const, 1 > const &magErr, ndarray::Array< double const, 1 > const &mag)
double getMagnitude(double const flux) const
Return a magnitude given a flux.
BaseCatalog makeCatalog(Schema const &schema)
Return a new, empty catalog with the given schema.
table::Key< double > expTime
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
~Calib() noexcept override
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
table::Key< std::int64_t > midTime
Reports invalid arguments.
table::Key< double > fluxMag0
std::pair< double, double > getFluxMag0() const
Return the flux, and error in flux, of a zero-magnitude object.
void saveCatalog(BaseCatalog const &catalog)
Save a catalog in the archive.
std::size_t hashCombine(std::size_t seed) noexcept
Combine hashes.
bool operator==(Calib const &rhs) const noexcept
Are two Calibs identical?
void write(OutputArchiveHandle &handle) const override
Write the object to one or more catalogs.
table::Key< double > fluxMag0Err
std::shared_ptr< RecordT > addNew()
Create a new record, add it to the end of the catalog, and return a pointer to it.