32 #include "boost/format.hpp"
33 #include "boost/lexical_cast.hpp"
34 #include "boost/algorithm/string/trim.hpp"
45 namespace lsst {
namespace afw {
namespace image {
49 Calib::Calib() : _midTime(), _exptime(0.0), _fluxMag0(0.0), _fluxMag0Sigma(0.0) {}
57 _midTime(), _exptime(0.0), _fluxMag0(0.0), _fluxMag0Sigma(0.0)
60 throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
61 "You must provide at least one input Calib");
64 double const fluxMag00 = calibs[0]->_fluxMag0;
65 double const fluxMag0Sigma0 = calibs[0]->_fluxMag0Sigma;
67 double midTimeSum = 0.0;
68 for (std::vector<
CONST_PTR(
Calib)>::const_iterator ptr = calibs.begin(); ptr != calibs.end(); ++ptr) {
69 Calib const& calib = **ptr;
71 if (::fabs(fluxMag00 - calib.
_fluxMag0) > std::numeric_limits<double>::epsilon() ||
72 ::fabs(fluxMag0Sigma0 - calib.
_fluxMag0Sigma) > std::numeric_limits<double>::epsilon()) {
73 throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
74 (
boost::format(
"You may only combine calibs with the same fluxMag0: "
75 "%g +- %g v %g +- %g")
77 % calibs[0]->getFluxMag0().first % calibs[0]->getFluxMag0().second
81 double const exptime = calib.
_exptime;
100 std::string key =
"TIME-MID";
101 if (metadata->
exists(key)) {
106 if (metadata->
exists(key)) {
109 }
catch (lsst::pex::exceptions::TypeError & err) {
110 std::string exptimeStr = metadata->
getAsString(key);
111 exptime = boost::lexical_cast<
double>(exptimeStr);
116 if (metadata->
exists(key)) {
120 if (metadata->
exists(key)) {
164 std::string key =
"TIME-MID";
165 if (metadata->
exists(key)) {
171 if (metadata->
exists(key)) {
177 if (metadata->
exists(key)) {
183 if (metadata->
exists(key)) {
231 boost::shared_ptr<const lsst::afw::cameraGeom::Detector>,
280 inline void checkNegativeFlux0(
double fluxMag0) {
282 throw LSST_EXCEPT(lsst::pex::exceptions::DomainError,
283 (
boost::format(
"Flux of 0-mag object must be >= 0: saw %g") % fluxMag0).str());
286 inline bool isNegativeFlux(
double flux,
bool doThrow)
290 throw LSST_EXCEPT(lsst::pex::exceptions::DomainError,
297 inline double convertToFlux(
double fluxMag0,
double mag) {
298 return fluxMag0 * ::pow(10.0, -0.4 * mag);
300 inline double convertToFluxErr(
double fluxMag0InvSNR,
double flux,
double magErr) {
304 double a = fluxMag0InvSNR;
305 double b = 0.4 *
std::log(10.0) * magErr;
306 if (std::abs(a) < std::abs(b)) {
309 return flux * std::abs(a) * std::sqrt(1 + std::pow(b / a, 2));
311 inline double convertToMag(
double fluxMag0,
double flux) {
312 return -2.5*::log10(flux/fluxMag0);
314 inline void convertToMagWithErr(
double *mag,
double *magErr,
double fluxMag0,
double fluxMag0InvSNR,
315 double flux,
double fluxErr)
318 double const ratErr = ::sqrt((::pow(fluxErr, 2) + ::pow(flux*fluxMag0InvSNR, 2))/::pow(fluxMag0, 2));
320 *mag = -2.5*::log10(rat);
321 *magErr = 2.5/
::log(10.0)*ratErr/rat;
339 for (; inIter != mag.
end(); ++inIter, ++outIter) {
340 *outIter = convertToFlux(
_fluxMag0, *inIter);
352 double const magSigma
356 double const flux = convertToFlux(
_fluxMag0, mag);
358 return std::make_pair(flux, fluxErr);
367 throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
368 (
boost::format(
"Size of mag (%d) and magErr (%d) don't match") %
380 for (; magIter != mag.
end(); ++magIter, ++magErrIter, ++fluxIter, ++fluxErrIter) {
381 *fluxIter = convertToFlux(
_fluxMag0, *magIter);
382 *fluxErrIter = convertToFluxErr(fluxMag0InvSNR, *fluxIter, *magErrIter);
385 return std::make_pair(flux, fluxErr);
396 return std::numeric_limits<double>::quiet_NaN();
410 double const NaN = std::numeric_limits<double>::quiet_NaN();
411 return std::make_pair(NaN, NaN);
416 return std::make_pair(mag, magErr);
425 for (; fluxIter != flux.
end(); ++fluxIter, ++magIter) {
426 if (isNegativeFlux(*fluxIter,
false)) {
428 *magIter = std::numeric_limits<double>::quiet_NaN();
431 *magIter = convertToMag(
_fluxMag0, *fluxIter);
434 throw LSST_EXCEPT(lsst::pex::exceptions::DomainError,
435 (
boost::format(
"Flux must be >= 0: %d non-positive seen") % nonPositive).str());
445 if (flux.
size() != fluxErr.
size()) {
446 throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
447 (
boost::format(
"Size of flux (%d) and fluxErr (%d) don't match") %
448 flux.
size() % fluxErr.
size()).str());
459 for (; fluxIter != flux.
end(); ++fluxIter, ++fluxErrIter, ++magIter, ++magErrIter) {
460 if (isNegativeFlux(*fluxIter,
false)) {
462 double const NaN = std::numeric_limits<double>::quiet_NaN();
468 convertToMagWithErr(&f, &df,
_fluxMag0, fluxMag0InvSNR, *fluxIter, *fluxErrIter);
473 throw LSST_EXCEPT(lsst::pex::exceptions::DomainError,
474 (
boost::format(
"Flux must be >= 0: %d non-positive seen") % nonPositive).str());
476 return std::make_pair(mag, magErr);
481 class CalibSchema :
private boost::noncopyable {
489 static CalibSchema
const &
get() {
490 static CalibSchema instance;
498 "midtime",
"middle of the time of the exposure relative to Unix epoch",
"nanoseconds"
500 expTime(
schema.addField<double>(
"exptime",
"exposure time",
"seconds")),
501 fluxMag0(
schema.addField<double>(
"fluxmag0",
"flux of a zero-magnitude object",
"dn")),
504 schema.getCitizen().markPersistent();
508 class CalibFactory :
public table::io::PersistableFactory {
511 virtual PTR(table::io::Persistable)
512 read(InputArchive const & archive, CatalogVector const & catalogs)
const {
513 CalibSchema
const & keys = CalibSchema::get();
517 table::BaseRecord
const & record = catalogs.front().front();
518 PTR(Calib) result(new Calib());
519 result->setMidTime(daf::base::DateTime(static_cast<
long long>(record.get(keys.
midTime))));
520 result->setExptime(record.get(keys.
expTime));
521 result->setFluxMag0(record.get(keys.fluxMag0), record.get(keys.
fluxMag0Sigma));
525 explicit CalibFactory(std::
string const &
name) : table::io::PersistableFactory(
name) {}
529 std::string getCalibPersistenceName() {
return "Calib"; }
531 CalibFactory registration(getCalibPersistenceName());
538 CalibSchema
const & keys = CalibSchema::get();
541 record->set(keys.midTime,
getMidTime().nsecs());
544 record->set(keys.fluxMag0, fluxMag0.first);
545 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
void swap(ImageBase< PixelT > &a, ImageBase< PixelT > &b)
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
Include files required for standard LSST Exception handling.
double get(DateSystem system=MJD, Timescale scale=TAI) const
table::Key< boost::int64_t > midTime
table::Key< double > expTime
table::Key< table::Array< Kernel::Pixel > > image
bool operator==(Calib const &rhs) const
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
size_type size() const
Return the size of the first dimension.
std::pair< double, double > getFluxMag0() const
static bool _throwOnNegativeFlux
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
int stripCalibKeywords(boost::shared_ptr< lsst::daf::base::PropertySet > metadata)
BaseCatalog makeCatalog(Schema const &schema)
Return a new, empty catalog with the given schema.
detail::SimpleInitializer< N > allocate(Vector< int, N > const &shape)
Create an expression that allocates uninitialized memory for an array.
#define LSST_EXCEPT(type,...)
double getFlux(double const mag) const
A multidimensional strided array.
Base class for all records.
Iterator end() const
Return an Iterator to one past the end of the array.
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.
ExpressionTraits< Derived >::Iterator Iterator
Nested expression or element iterator.
void saveCatalog(BaseCatalog const &catalog)
Save a catalog in the archive.
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)
Iterator begin() const
Return an Iterator to the beginning of the array.