34 #include "boost/format.hpp"
35 #include "boost/algorithm/string/trim.hpp"
46 namespace lsst {
namespace afw {
namespace image {
50 Calib::Calib() : _midTime(), _exptime(0.0), _fluxMag0(0.0), _fluxMag0Sigma(0.0) {}
62 _midTime(), _exptime(0.0), _fluxMag0(0.0), _fluxMag0Sigma(0.0)
65 throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
66 "You must provide at least one input Calib");
69 double const fluxMag00 = calibs[0]->_fluxMag0;
70 double const fluxMag0Sigma0 = calibs[0]->_fluxMag0Sigma;
72 double midTimeSum = 0.0;
73 for (std::vector<
CONST_PTR(
Calib)>::const_iterator ptr = calibs.begin(); ptr != calibs.end(); ++ptr) {
74 Calib const& calib = **ptr;
76 if (::fabs(fluxMag00 - calib.
_fluxMag0) > std::numeric_limits<double>::epsilon() ||
77 ::fabs(fluxMag0Sigma0 - calib.
_fluxMag0Sigma) > std::numeric_limits<double>::epsilon()) {
78 throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
79 (
boost::format(
"You may only combine calibs with the same fluxMag0: "
80 "%g +- %g v %g +- %g")
82 % calibs[0]->getFluxMag0().first % calibs[0]->getFluxMag0().second
86 double const exptime = calib.
_exptime;
102 double exptime = 0.0;
105 std::string key =
"TIME-MID";
106 if (metadata->
exists(key)) {
112 if (metadata->
exists(key)) {
115 }
catch (lsst::pex::exceptions::TypeError & err) {
116 std::string exptimeStr = metadata->
getAsString(key);
117 exptime = std::stod(exptimeStr);
122 if (metadata->
exists(key)) {
126 if (metadata->
exists(key)) {
170 std::string key =
"TIME-MID";
171 if (metadata->
exists(key)) {
177 if (metadata->
exists(key)) {
183 if (metadata->
exists(key)) {
189 if (metadata->
exists(key)) {
237 std::shared_ptr<const lsst::afw::cameraGeom::Detector>,
286 inline void checkNegativeFlux0(
double fluxMag0) {
288 throw LSST_EXCEPT(lsst::pex::exceptions::DomainError,
289 (
boost::format(
"Flux of 0-mag object must be >= 0: saw %g") % fluxMag0).str());
292 inline bool isNegativeFlux(
double flux,
bool doThrow)
296 throw LSST_EXCEPT(lsst::pex::exceptions::DomainError,
303 inline double convertToFlux(
double fluxMag0,
double mag) {
304 return fluxMag0 * ::pow(10.0, -0.4 * mag);
306 inline double convertToFluxErr(
double fluxMag0InvSNR,
double flux,
double magErr) {
310 double a = fluxMag0InvSNR;
311 double b = 0.4 *
std::log(10.0) * magErr;
312 if (std::abs(a) < std::abs(b)) {
315 return flux * std::abs(a) * std::sqrt(1 + std::pow(b / a, 2));
317 inline double convertToMag(
double fluxMag0,
double flux) {
318 return -2.5*::log10(flux/fluxMag0);
320 inline void convertToMagWithErr(
double *mag,
double *magErr,
double fluxMag0,
double fluxMag0InvSNR,
321 double flux,
double fluxErr)
324 double const ratErr = ::sqrt((::pow(fluxErr, 2) + ::pow(flux*fluxMag0InvSNR, 2))/::pow(fluxMag0, 2));
326 *mag = -2.5*::log10(rat);
327 *magErr = 2.5/
::log(10.0)*ratErr/rat;
340 ndarray::Array<double,1>
Calib::getFlux(ndarray::Array<double const,1>
const & mag)
const {
342 ndarray::Array<double,1> flux = ndarray::allocate(mag.size());
343 ndarray::Array<double const,1>::Iterator inIter = mag.begin();
344 ndarray::Array<double,1>::Iterator outIter = flux.begin();
345 for (; inIter != mag.end(); ++inIter, ++outIter) {
346 *outIter = convertToFlux(
_fluxMag0, *inIter);
358 double const magSigma
362 double const flux = convertToFlux(
_fluxMag0, mag);
364 return std::make_pair(flux, fluxErr);
368 ndarray::Array<double const,1>
const & mag,
369 ndarray::Array<double const,1>
const & magErr
372 if (mag.size() != magErr.size()) {
373 throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
374 (
boost::format(
"Size of mag (%d) and magErr (%d) don't match") %
375 mag.size() % magErr.size()).str());
378 ndarray::Array<double,1> flux = ndarray::allocate(mag.size());
379 ndarray::Array<double,1> fluxErr = ndarray::allocate(mag.size());
380 ndarray::Array<double const,1>::Iterator magIter = mag.begin();
381 ndarray::Array<double const,1>::Iterator magErrIter = magErr.begin();
382 ndarray::Array<double,1>::Iterator fluxIter = flux.begin();
383 ndarray::Array<double,1>::Iterator fluxErrIter = fluxErr.begin();
386 for (; magIter != mag.end(); ++magIter, ++magErrIter, ++fluxIter, ++fluxErrIter) {
387 *fluxIter = convertToFlux(
_fluxMag0, *magIter);
388 *fluxErrIter = convertToFluxErr(fluxMag0InvSNR, *fluxIter, *magErrIter);
391 return std::make_pair(flux, fluxErr);
402 return std::numeric_limits<double>::quiet_NaN();
416 double const NaN = std::numeric_limits<double>::quiet_NaN();
417 return std::make_pair(NaN, NaN);
422 return std::make_pair(mag, magErr);
427 ndarray::Array<double,1> mag = ndarray::allocate(flux.size());
428 ndarray::Array<double const,1>::Iterator fluxIter = flux.begin();
429 ndarray::Array<double,1>::Iterator magIter = mag.begin();
431 for (; fluxIter != flux.end(); ++fluxIter, ++magIter) {
432 if (isNegativeFlux(*fluxIter,
false)) {
434 *magIter = std::numeric_limits<double>::quiet_NaN();
437 *magIter = convertToMag(
_fluxMag0, *fluxIter);
440 throw LSST_EXCEPT(lsst::pex::exceptions::DomainError,
441 (
boost::format(
"Flux must be >= 0: %d non-positive seen") % nonPositive).str());
447 ndarray::Array<double const,1>
const & flux,
448 ndarray::Array<double const,1>
const & fluxErr
451 if (flux.size() != fluxErr.size()) {
452 throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
453 (
boost::format(
"Size of flux (%d) and fluxErr (%d) don't match") %
454 flux.size() % fluxErr.size()).str());
457 ndarray::Array<double,1> mag = ndarray::allocate(flux.size());
458 ndarray::Array<double,1> magErr = ndarray::allocate(flux.size());
459 ndarray::Array<double const,1>::Iterator fluxIter = flux.begin();
460 ndarray::Array<double const,1>::Iterator fluxErrIter = fluxErr.begin();
461 ndarray::Array<double,1>::Iterator magIter = mag.begin();
462 ndarray::Array<double,1>::Iterator magErrIter = magErr.begin();
465 for (; fluxIter != flux.end(); ++fluxIter, ++fluxErrIter, ++magIter, ++magErrIter) {
466 if (isNegativeFlux(*fluxIter,
false)) {
468 double const NaN = std::numeric_limits<double>::quiet_NaN();
474 convertToMagWithErr(&f, &df,
_fluxMag0, fluxMag0InvSNR, *fluxIter, *fluxErrIter);
479 throw LSST_EXCEPT(lsst::pex::exceptions::DomainError,
480 (
boost::format(
"Flux must be >= 0: %d non-positive seen") % nonPositive).str());
482 return std::make_pair(mag, magErr);
495 static CalibSchema
const &
get() {
496 static CalibSchema instance;
501 CalibSchema (
const CalibSchema&) =
delete;
502 CalibSchema& operator=(
const CalibSchema&) =
delete;
505 CalibSchema (CalibSchema&&) =
delete;
506 CalibSchema& operator=(CalibSchema&&) =
delete;
512 "midtime",
"middle of the time of the exposure relative to Unix epoch",
"ns"
514 expTime(
schema.addField<double>(
"exptime",
"exposure time",
"s")),
515 fluxMag0(
schema.addField<double>(
"fluxmag0",
"flux of a zero-magnitude object",
"count")),
516 fluxMag0Sigma(
schema.addField<double>(
"fluxmag0.err",
"1-sigma error on fluxmag0",
"count"))
518 schema.getCitizen().markPersistent();
522 class CalibFactory :
public table::io::PersistableFactory {
525 virtual PTR(table::io::Persistable)
526 read(InputArchive const & archive, CatalogVector const & catalogs)
const {
527 CalibSchema
const & keys = CalibSchema::get();
531 table::BaseRecord
const & record = catalogs.front().front();
532 PTR(Calib) result(new Calib());
533 result->setMidTime(daf::base::DateTime(static_cast<
long long>(record.get(keys.
midTime))));
534 result->setExptime(record.get(keys.
expTime));
535 result->setFluxMag0(record.get(keys.fluxMag0), record.get(keys.
fluxMag0Sigma));
539 explicit CalibFactory(std::
string const &
name) : table::io::PersistableFactory(
name) {}
543 std::string getCalibPersistenceName() {
return "Calib"; }
545 CalibFactory registration(getCalibPersistenceName());
552 CalibSchema
const & keys = CalibSchema::get();
555 record->set(keys.midTime,
getMidTime().nsecs());
558 record->set(keys.fluxMag0, fluxMag0.first);
559 record->set(keys.fluxMag0Sigma, fluxMag0.second);
Class for handling dates/times, including MJD, UTC, and TAI.
table::Key< std::string > name
table::Key< double > fluxMag0Sigma
An object passed to Persistable::write to allow it to persist itself.
virtual void remove(std::string const &name)
A custom container class for records, based on std::vector.
afw::table::Schema schema
double get(DateSystem system=MJD, Timescale scale=TAI) const
void swap(Mask< PixelT > &a, Mask< PixelT > &b)
table::Key< double > expTime
void operator*=(double const scale)
table::Key< table::Array< Kernel::Pixel > > image
bool operator==(Calib const &rhs) const
table::Key< std::int64_t > midTime
void setExptime(double exptime)
virtual std::string getPersistenceName() const
Return the unique name used to persist this object and look up its factory.
static void setThrowOnNegativeFlux(bool raiseException)
double getExptime() const
std::pair< double, double > getFluxMag0() const
static bool _throwOnNegativeFlux
int stripCalibKeywords(boost::shared_ptr< lsst::daf::base::PropertySet > metadata)
BaseCatalog makeCatalog(Schema const &schema)
Return a new, empty catalog with the given schema.
#define LSST_EXCEPT(type,...)
double getFlux(double const mag) const
Base class for all records.
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
double getAsDouble(std::string const &name) const
Class for storing generic metadata.
virtual void write(OutputArchiveHandle &handle) const
Write the object to one or more catalogs.
boost::shared_ptr< RecordT > addNew()
Create a new record, add it to the end of the catalog, and return a pointer to it.
std::string getAsString(std::string const &name) const
void setFluxMag0(double fluxMag0, double fluxMag0Sigma=0.0)
afw::table::Key< double > b
static bool getThrowOnNegativeFlux()
table::Key< double > fluxMag0
Interface for PropertySet class.
void saveCatalog(BaseCatalog const &catalog)
Save a catalog in the archive.
Include files required for standard LSST Exception handling.
lsst::daf::base::DateTime getMidTime() const
bool exists(std::string const &name) const
lsst::daf::base::DateTime _midTime
double getMagnitude(double const flux) const
void setMidTime(lsst::daf::base::DateTime const &midTime)