34 #include "boost/algorithm/string/trim.hpp"
35 #include "boost/regex.hpp"
48 using boost::algorithm::trim_copy;
50 using lsst::pex::exceptions::InvalidParameterError;
51 using lsst::pex::exceptions::RuntimeError;
65 namespace lsst {
namespace ap {
namespace match {
72 if (metadata->exists(
"FILTER")) {
73 _filter =
Filter(trim_copy(metadata->getAsString(
"FILTER")),
false);
76 _extent.setX(metadata->getAsInt(
"NAXIS1"));
77 _extent.setY(metadata->getAsInt(
"NAXIS2"));
78 if (metadata->exists(
"LTV1")) {
79 _xy0.setX(-metadata->getAsInt(
"LTV1"));
81 if (metadata->exists(
"LTV2")) {
82 _xy0.setY(-metadata->getAsInt(
"LTV2"));
85 if (metadata->exists(
"TIME-MID")) {
86 DateTime mid(metadata->getAsString(
"TIME-MID"));
87 _epoch = mid.get(DateTime::MJD, DateTime::TAI);
89 if (metadata->exists(
"EXPTIME")) {
90 _expTime = metadata->getAsDouble(
"EXPTIME");
93 if (metadata->exists(
"FLUXMAG0")) {
94 if (metadata->exists(
"FLUXMAG0ERR")) {
98 "negative magnitude zero point error");
103 _fluxMag0 = metadata->getAsDouble(
"FLUXMAG0");
106 "magnitude zero point is negative or zero");
132 std::string
const &idKey
136 _id(metadata->getAsInt64(idKey)),
137 _epoch(std::numeric_limits<double>::quiet_NaN()),
138 _expTime(std::numeric_limits<double>::quiet_NaN()),
139 _fluxMag0(std::numeric_limits<double>::quiet_NaN()),
140 _fluxMag0Sigma(std::numeric_limits<double>::quiet_NaN()),
145 _canCalibrateFlux(false),
158 _epoch(std::numeric_limits<double>::quiet_NaN()),
159 _expTime(std::numeric_limits<double>::quiet_NaN()),
160 _fluxMag0(std::numeric_limits<double>::quiet_NaN()),
161 _fluxMag0Sigma(std::numeric_limits<double>::quiet_NaN()),
166 _canCalibrateFlux(false),
175 if (fluxScale <= 0.0) {
177 "scaling factor is <= 0");
180 throw LSST_EXCEPT(RuntimeError,
"Cannot calibrate "
181 "flux without fluxMag0");
191 if (fluxScale <= 0.0) {
193 "scaling factor is <= 0");
195 if (fluxSigma <= 0.0) {
196 throw LSST_EXCEPT(InvalidParameterError,
"flux error is <= 0");
199 throw LSST_EXCEPT(RuntimeError,
"Cannot calibrate "
200 "flux without fluxMag0");
205 double f2 = flux*flux;
206 double fVar = fluxSigma*fluxSigma;
207 double var = (fVar*f02 + f0Var*f2)/(f02*f02);
208 return std::make_pair(fluxScale*flux/_fluxMag0, fluxScale*fluxScale*var);
228 return _wcs->pixelToSky(x, y)->toIcrs().getVector().asEigen();
240 throw LSST_EXCEPT(InvalidParameterError,
"Cannot insert a "
241 "null ExposureInfo into an ExposureInfoMap");
243 int64_t
id = info->getId();
245 throw LSST_EXCEPT(InvalidParameterError,
"ExposureInfoMap "
246 "already contains an exposure with the "
249 _map.insert(std::pair<int64_t, ExposureInfo::Ptr>(
id, info));
257 return _map.erase(
id) != 0u;
264 int const DOUBLE_T = 1;
265 int const STRING_T = 2;
267 std::tr1::unordered_map<std::string, int>
const & fitsKeyMap() {
268 static char const *
const I_KEYS[] = {
271 "A_ORDER",
"B_ORDER",
272 "AP_ORDER",
"BP_ORDER"
274 static char const *
const D_KEYS[] = {
275 "EQUINOX",
"EXPTIME",
276 "FLUXMAG0",
"FLUXMAG0ERR",
280 "CD1_1",
"CD1_2",
"CD2_1",
"CD2_2",
281 "PC1_1",
"PC1_2",
"PC2_1",
"PC2_2"
283 static char const *
const S_KEYS[] = {
284 "RADESYS",
"TIME-MID",
"FILTER",
288 static std::tr1::unordered_map<std::string, int> map;
289 if (map.size() == 0) {
291 for (
size_t i = 0; i <
sizeof(I_KEYS)/
sizeof(
char const *); ++i) {
292 map.insert(std::make_pair(std::string(I_KEYS[i]), INT_T));
294 for (
size_t i = 0; i <
sizeof(D_KEYS)/
sizeof(
char const *); ++i) {
295 map.insert(std::make_pair(std::string(D_KEYS[i]), DOUBLE_T));
297 for (
size_t i = 0; i <
sizeof(S_KEYS)/
sizeof(
char const *); ++i) {
298 map.insert(std::make_pair(std::string(S_KEYS[i]), STRING_T));
308 std::vector<ExposureInfo::Ptr> & exposures,
309 std::string
const & csvFile,
311 std::string
const & idColumn
313 typedef std::tr1::unordered_map<std::string, int> FkMap;
314 typedef FkMap::const_iterator FkIter;
316 static boost::regex
const sipRegex(
"^[AB]P?_[0-9]+_[0-9]+$");
318 Log log(Log::getDefaultLog(),
"lsst.ap.match");
319 log.
log(Log::INFO,
"Reading exposure metadata from " + csvFile);
321 FkMap
const & fkMap = fitsKeyMap();
323 CsvReader reader(csvFile, control,
true);
324 int const idCol = reader.
getIndexOf(idColumn);
325 int const keyCol = reader.
getIndexOf(
"metadataKey");
326 int const intCol = reader.
getIndexOf(
"intValue");
327 int const doubleCol = reader.
getIndexOf(
"doubleValue");
328 int const stringCol = reader.
getIndexOf(
"stringValue");
330 throw LSST_EXCEPT(RuntimeError,
"Exposure metadata table "
331 "has no column named " + idColumn);
334 throw LSST_EXCEPT(RuntimeError,
"Exposure metadata table "
335 "has no column named metadataKey");
338 throw LSST_EXCEPT(RuntimeError,
"Exposure metadata table "
339 "has no column named intValue");
341 if (doubleCol == -1) {
342 throw LSST_EXCEPT(RuntimeError,
"Exposure metadata table "
343 "has no column named doubleValue");
345 if (stringCol == -1) {
346 throw LSST_EXCEPT(RuntimeError,
"Exposure metadata table "
347 "has no column named stringValue");
350 int64_t lastId = reader.
get<int64_t>(idCol) - 1;
352 int64_t
id = reader.
get<int64_t>(idCol);
361 std::string
const key = reader.
get(keyCol);
362 FkIter
k = fkMap.find(key);
363 if (k != fkMap.end()) {
364 if (k->second == INT_T) {
365 ps->set(key, reader.
get<
int>(intCol));
366 }
else if (k->second == DOUBLE_T) {
367 ps->set(key, reader.
get<
double>(doubleCol));
369 ps->set(key, reader.
get(stringCol));
371 }
else if (boost::regex_search(key.begin(), key.end(), sipRegex)) {
373 ps->set(key, reader.
get<
double>(doubleCol));
virtual double getMaxCoord1() const
ExposureInfo(lsst::daf::base::PropertySet::Ptr props, std::string const &idKey=DEF_ID_KEY)
static std::string const DEF_ID_KEY
lsst::afw::geom::Angle const angularSeparation(Eigen::Vector3d const &v1, Eigen::Vector3d const &v2)
Class for handling dates/times, including MJD, UTC, and TAI.
lsst::afw::geom::Angle _radius
lsst::afw::image::Wcs::Ptr _wcs
Parameters that define a Character-Separated-Value dialect.
lsst::afw::geom::Angle getLongitude() const
The main access method for the longitudinal coordinate.
boost::shared_ptr< PropertySet > Ptr
lsst::afw::coord::IcrsCoord const cartesianToIcrs(Eigen::Vector3d const &v)
virtual double getMinCoord0() const
lsst::afw::image::Filter _filter
void log(int importance, const std::string &message, const lsst::daf::base::PropertySet &properties)
lsst::afw::geom::Point2I _xy0
void insert(ExposureInfo::Ptr info)
boost::shared_ptr< ExposureInfo > Ptr
a place to record messages and descriptions of the state of processing.
table::Key< table::Array< Kernel::Pixel > > image
definition of the DualLog class
bool contains(int64_t id) const
lsst::daf::base::PropertySet PropertySet
std::string const get(int i) const
Wcs::Ptr makeWcs(boost::shared_ptr< lsst::daf::base::PropertySet > const &fitsMetadata, bool stripMetadata=false)
Class that bundles together the WCS, extents, time, and calibration information from an image (typica...
Include files required for standard LSST Exception handling.
lsst::afw::geom::Angle _alpha
double maxAlpha(double const theta, double const centerDec)
void readExposureInfos(std::vector< ExposureInfo::Ptr > &exposures, std::string const &csvFile, CsvControl const &control, std::string const &idColumn)
virtual double getMaxCoord0() const
Holds an integer identifier for an LSST filter.
lsst::afw::coord::IcrsCoord _center
Interface for DateTime class.
#define LSST_EXCEPT(type,...)
Spatial utility functions.
lsst::afw::geom::Extent2I _extent
double calibrateFlux(double flux, double fluxScale) const
virtual double getMinCoord1() const
lsst::afw::geom::Angle getLatitude() const
The main access method for the latitudinal coordinate.
Eigen::Vector3d const _pixToSky(double x, double y) const
const double PixelZeroPos
FITS uses 1.0, SDSS uses 0.5, LSST uses 0.0 (http://dev.lsstcorp.org/trac/wiki/BottomLeftPixelProposa...
int getIndexOf(std::string const &name) const
bool canCalibrateFlux() const
Is there enough information to calibrate fluxes?
void _init(lsst::daf::base::PropertySet::Ptr props)
Angle const maxAlpha(Angle radius, Angle centerPhi)
Class encapsulating an identifier for an LSST filter.