39 #include "boost/scoped_ptr.hpp"
63 using std::numeric_limits;
93 namespace lsst {
namespace ap {
namespace match {
98 double const RADY_PER_MASD = 1.32734751843815467101961424328e-11;
110 RefPosMatch(MatchableRef *ref,
112 Eigen::Vector3d
const &v,
129 MatchableRef
const *getRef()
const {
132 MatchableRef *getRef() {
135 MatchablePos
const *getPos()
const {
138 MatchablePos *getPos() {
141 IcrsCoord const & getSphericalCoordinates()
const {
144 Angle getAngularSeparation()
const {
148 int getRefCount()
const {
151 int decrementRefCount() {
166 class Matchable :
public BBox {
170 Matchable(std::string
const &record) :
179 virtual ~Matchable() { }
181 int64_t getClosestId()
const {
184 int getNumMatches()
const {
187 std::string
const & getRecord()
const {
191 MatchVector & getMatches() {
194 MatchVector
const & getMatches()
const {
198 void appendMatch(int64_t
id, RefPosMatch *m) {
207 int decrementRefCount() {
210 int getRefCount()
const {
234 class MatchablePos :
public Matchable {
236 MatchablePos(int64_t
id,
241 std::string
const &record);
243 virtual ~MatchablePos() { }
245 int64_t getId()
const {
248 double getEpoch()
const {
251 IcrsCoord const & getSphericalCoordinates()
const {
254 Eigen::Vector3d
const & getPosition()
const {
257 Angle getRadius()
const {
262 virtual double getMinCoord0()
const {
265 virtual double getMaxCoord0()
const {
268 virtual double getMinCoord1()
const {
271 virtual double getMaxCoord1()
const {
284 MatchablePos::MatchablePos(
290 std::string
const &record
296 _p(
_sc.getVector().asEigen()),
304 class MatchableRef :
public Matchable {
306 MatchableRef(ReferencePosition
const &rp,
307 std::string
const &record,
310 virtual ~MatchableRef() { }
312 ReferencePosition & getReferencePosition() {
315 ReferencePosition
const & getReferencePosition()
const {
320 virtual double getMinCoord0()
const {
321 return _rp.getMinCoord0();
323 virtual double getMaxCoord0()
const {
324 return _rp.getMaxCoord0();
326 virtual double getMinCoord1()
const {
327 return _rp.getMinCoord1();
329 virtual double getMaxCoord1()
const {
330 return _rp.getMaxCoord1();
337 MatchableRef::MatchableRef(
338 ReferencePosition
const &rp,
339 std::string
const &record,
346 inline bool operator<(std::pair<Angle, MatchableRef *>
const &r1,
347 std::pair<Angle, MatchableRef *>
const &r2) {
348 return r1.first > r2.first;
354 class RefWithCov :
public BBox {
356 RefWithCov(ReferencePosition
const &rp,
357 std::string
const &record,
360 virtual ~RefWithCov() { }
362 ReferencePosition & getReferencePosition() {
365 ReferencePosition
const & getReferencePosition()
const {
369 std::string
const & getRecord()
const {
379 int isCovered()
const {
383 void appendMatch(ExposureInfo *e) {
389 virtual double getMinCoord0()
const {
390 return _rp.getMinCoord0();
392 virtual double getMaxCoord0()
const {
393 return _rp.getMaxCoord0();
395 virtual double getMinCoord1()
const {
396 return _rp.getMinCoord1();
398 virtual double getMaxCoord1()
const {
399 return _rp.getMaxCoord1();
403 ReferencePosition
_rp;
410 RefWithCov::RefWithCov(
411 ReferencePosition
const &rp,
412 std::string
const &record,
418 _numFilters(numFilters),
421 for (
int i = 0; i < numFilters; ++i) {
426 inline bool operator<(std::pair<Angle, RefWithCov *>
const &r1,
427 std::pair<Angle, RefWithCov *>
const &r2) {
428 return r1.first > r2.first;
439 class MatchablePosReader {
441 MatchablePosReader(std::string
const &path,
442 CatalogControl
const &control,
447 ~MatchablePosReader();
449 double getMinEpoch()
const {
return _minEpoch; }
450 double getMaxEpoch()
const {
return _maxEpoch; }
456 std::string
const & getNullRecord()
const {
462 bool haveOutputRecord()
const {
468 bool isDone()
const {
481 MatchablePos *
next() {
482 MatchablePos *p =
_next;
489 void destroy(MatchablePos *p) {
518 MatchablePosReader::MatchablePosReader(
519 std::string
const &path,
520 CatalogControl
const &control,
539 typedef std::vector<std::string>::const_iterator Iter;
541 Log log(Log::getDefaultLog(),
"lsst.ap.match");
546 if (!control.fieldNames.empty()) {
547 _reader->setFieldNames(control.fieldNames);
551 if (!control.epochColumn.empty()) {
562 "Position table does not contain unique id, "
563 "right ascension, or declination column(s)");
566 if (!control.outputFields.empty()) {
569 if (control.outputFields.size() == 1 &&
570 control.outputFields[0] ==
"*") {
571 int nFields =
static_cast<int>(
_reader->getFieldNames().size());
572 for (
int i = 0; i < nFields; ++i) {
577 for (Iter i = control.outputFields.begin(),
578 e = control.outputFields.end(); i != e; ++i) {
579 int idx =
_reader->getIndexOf(*i);
581 throw LSST_EXCEPT(pexExcept::InvalidParameterError,
582 "Position table has no column named " +
597 log.
log(
Log::INFO,
"Scanning position table to determine min/max "
598 "epoch of input positions");
599 CsvReader reader(path, dialect, control.fieldNames.empty());
602 static_cast<unsigned long long>(reader.getNumRecords()));
611 MatchablePosReader::~MatchablePosReader() { }
613 void MatchablePosReader::_read() {
614 typedef std::vector<int>::const_iterator Iter;
631 "NULL unique id found in position table");
637 "Position table contains NULL or NaN right "
638 "ascension, declination, or epoch");
640 if (decl < -HALFPI || decl >
HALFPI) {
642 "Invalid declination found in position table");
644 if (epoch < J2000_MJD - 200.0*DAYS_PER_JY ||
645 epoch > J2000_MJD + 200.0*DAYS_PER_JY) {
647 "Position table epoch is not within 200 years of "
648 "J2000. Check your units - MJD required.");
653 "Position table is not sorted by declination");
679 "Position table contains NULL or NaN epoch");
682 while (!reader.
isDone()) {
686 "Position table contains NULL or NaN epoch");
690 }
else if (epoch > _maxEpoch) {
705 class RefReaderBase {
707 RefReaderBase(std::string
const &path,
708 CatalogControl
const &control,
711 double minMatchEpoch,
712 double maxMatchEpoch,
713 Angle parallaxThresh);
715 virtual ~RefReaderBase();
717 double getMinEpoch()
const {
return _minEpoch; }
718 double getMaxEpoch()
const {
return _maxEpoch; }
729 std::string
const & getNullRecord()
const {
736 bool haveOutputRecord()
const {
741 ReferencePosition
const * _readReferencePosition();
743 std::string
const & getRecord()
const {
749 boost::scoped_ptr<CsvReader>
_reader;
755 bool needMotionStats);
757 ReferencePosition
_pos;
784 std::stringstream
_buf;
788 RefReaderBase::RefReaderBase(
789 std::string
const &path,
790 CatalogControl
const &control,
793 double minMatchEpoch,
794 double maxMatchEpoch,
800 _numFilters(static_cast<int>(
Filter::getNames().size())),
816 typedef std::vector<std::string>::const_iterator Iter;
818 Log log(Log::getDefaultLog(),
"lsst.ap.match");
819 log.
log(
Log::INFO,
"Opening reference catalog " + path);
823 if (!control.fieldNames.empty()) {
824 _reader->setFieldNames(control.fieldNames);
828 if (!control.epochColumn.empty()) {
848 "Reference catalog doesn't contain unique id, "
849 "right ascension, or declination column(s)");
852 if (!control.outputFields.empty()) {
855 if (control.outputFields.size() == 1 &&
856 control.outputFields[0] ==
"*") {
857 int nFields =
static_cast<int>(
_reader->getFieldNames().size());
858 for (
int i = 0; i < nFields; ++i) {
863 for (Iter i = control.outputFields.begin(),
864 e = control.outputFields.end(); i != e; ++i) {
865 int idx =
_reader->getIndexOf(*i);
867 throw LSST_EXCEPT(pexExcept::InvalidParameterError,
868 "Reference catalog has no column "
880 bool needEpochStats =
false;
881 bool needMotionStats =
false;
886 _maxEpoch = control.maxEpoch;
888 needEpochStats =
true;
897 needMotionStats =
true;
901 if (needEpochStats || needMotionStats) {
902 log.
log(
Log::INFO,
"Scanning reference catalog to determine "
903 "time-range and/or maximum velocity/parallax");
904 CsvReader reader(path, dialect, control.fieldNames.empty());
905 _scan(reader, needEpochStats, needMotionStats);
920 log.
format(
Log::INFO,
" - max angular velocity is %.3f milliarcsec/yr",
926 RefReaderBase::~RefReaderBase() { }
928 ReferencePosition
const * RefReaderBase::_readReferencePosition() {
929 typedef std::vector<int>::const_iterator Iter;
945 "NULL unique id found in reference catalog");
951 "Reference catalog record contains NULL/NaN right "
952 "ascension, declination, or epoch");
954 if (decl < -HALFPI || decl > HALFPI) {
956 "Invalid declination found in reference catalog");
958 if (epoch < J2000_MJD - 200.0*DAYS_PER_JY ||
959 epoch > J2000_MJD + 200.0*DAYS_PER_JY) {
961 "Reference catalog epoch is not within 200 years "
962 "of J2000. Check your units - MJD required.");
967 "Reference catalog is not sorted by declination");
979 _pos = ReferencePosition(
id, ra, decl, epoch);
988 if (parallax < 0.0) {
990 "Reference catalog contains negative parallax");
997 _pos.setMotion(muRa, muDecl, parallax, vRadial,
1008 bool needEpochStats,
1009 bool needMotionStats)
1014 if (needEpochStats) {
1018 while (!reader.
isDone()) {
1019 if (needEpochStats) {
1023 "Record contains NULL or NaN epoch");
1027 }
else if (epoch > _maxEpoch) {
1031 if (needMotionStats) {
1041 if (decl < -HALFPI || decl > HALFPI ||
1044 "Invalid declination found in "
1045 "reference catalog");
1047 muRa *= std::cos(decl.asRadians());
1052 double v = sqrt(muRa*muRa + muDecl*muDecl);
1066 template <
typename Ref>
1067 class RefReader :
public RefReaderBase {
1069 RefReader(std::string
const &path,
1070 CatalogControl
const &control,
1073 double minMatchEpoch,
1074 double maxMatchEpoch,
1075 Angle parallaxThresh);
1081 bool isDone()
const {
1082 return _heap.empty();
1088 Angle peek()
const {
1089 return _heap.front().first;
1099 Ref *r =
_heap.back().second;
1106 void destroy(Ref *r) {
1112 ReferencePosition
const *p = _readReferencePosition();
1115 _heap.push_back(std::pair<Angle, Ref *>(
Angle(r->getMinCoord1()), r));
1121 std::vector<std::pair<Angle, Ref *> >
_heap;
1124 template <
typename Ref>
1125 RefReader<Ref>::RefReader(
1126 std::string
const &path,
1127 CatalogControl
const &control,
1130 double minMatchEpoch,
1131 double maxMatchEpoch,
1132 Angle parallaxThresh
1145 template <
typename Ref>
1146 RefReader<Ref>::~RefReader() { }
1153 class RefPosMatcher {
1155 RefPosMatcher(
bool outputRefExtras);
1159 void operator()(MatchablePos *p) {
1162 void operator()(MatchableRef *r) {
1165 void operator()(MatchableRef *r, MatchablePos *p) {
1166 _candidateMatch(r, p);
1168 void operator()(MatchablePos *p, MatchableRef *r) {
1169 _candidateMatch(r, p);
1173 RefReader<MatchableRef> &refReader,
1174 MatchablePosReader &posReader);
1177 void _writeMatch(RefPosMatch
const *m);
1178 void _finish(MatchablePos *p);
1179 void _finish(MatchableRef *r);
1180 void _candidateMatch(MatchableRef *r, MatchablePos *p);
1197 RefPosMatcher::RefPosMatcher(
bool outputRefExtras) :
1207 RefPosMatcher::~RefPosMatcher() {
1215 void RefPosMatcher::match(
CsvWriter &writer,
1216 RefReader<MatchableRef> &refReader,
1217 MatchablePosReader &posReader)
1248 if (refDecl < posDecl) {
1267 void RefPosMatcher::_writeMatch(RefPosMatch
const *m) {
1268 MatchableRef
const *r = m->getRef();
1269 MatchablePos
const *p = m->getPos();
1274 m->getSphericalCoordinates().getLongitude().asDegrees());
1276 m->getSphericalCoordinates().getLatitude().asDegrees());
1300 void RefPosMatcher::_finish(MatchablePos *p) {
1301 typedef MatchablePos::MatchVector::iterator Iter;
1303 if (p->getNumMatches() == 0) {
1338 for (Iter i = p->getMatches().begin(), e = p->getMatches().end();
1340 RefPosMatch *m = *i;
1341 MatchableRef *r = m->getRef();
1342 if (m->decrementRefCount() == 0) {
1347 if (r->decrementRefCount() == 0) {
1351 p->decrementRefCount();
1354 if (p->getRefCount() == 0) {
1362 void RefPosMatcher::_finish(MatchableRef *r) {
1363 typedef MatchablePos::MatchVector::iterator Iter;
1365 if (r->getNumMatches() == 0) {
1400 for (Iter i = r->getMatches().begin(), e = r->getMatches().end();
1402 RefPosMatch *m = *i;
1403 MatchablePos *p = m->getPos();
1404 if (m->decrementRefCount() == 0) {
1409 if (p->decrementRefCount() == 0) {
1413 r->decrementRefCount();
1416 if (r->getRefCount() == 0) {
1423 void RefPosMatcher::_candidateMatch(MatchableRef *r, MatchablePos *p) {
1424 Eigen::Vector3d v = r->getReferencePosition().getPosition(p->getEpoch());
1426 if (sep <= p->getRadius()) {
1428 RefPosMatch *m =
new (
_arena) RefPosMatch(r, p, v, sep);
1429 r->appendMatch(p->getId(), m);
1430 p->appendMatch(r->getReferencePosition().getId(), m);
1437 class RefExpMatcher {
1443 void operator()(ExposureInfo *e) { }
1445 void operator()(RefWithCov *r) {
1448 void operator()(RefWithCov *r, ExposureInfo *e) {
1449 _candidateMatch(r, e);
1451 void operator()(ExposureInfo *e, RefWithCov *r) {
1452 _candidateMatch(r, e);
1456 RefReader<RefWithCov> &refReader,
1457 std::vector<ExposureInfo::Ptr> &exposures);
1460 struct ExposureInfoComparator {
1461 bool operator()(ExposureInfo::Ptr
const &e1,
1462 ExposureInfo::Ptr
const &e2)
const
1464 return e1->getMinCoord1() < e2->getMinCoord1();
1468 void _finish(RefWithCov *r);
1469 void _candidateMatch(RefWithCov *r, ExposureInfo *e);
1472 std::vector<std::pair<Angle, RefWithCov *> >
_heap;
1483 RefExpMatcher::RefExpMatcher() :
1491 RefExpMatcher::~RefExpMatcher() {
1498 void RefExpMatcher::match(
CsvWriter &writer,
1499 RefReader<RefWithCov> &refReader,
1500 std::vector<ExposureInfo::Ptr> &exposures)
1502 typedef std::vector<ExposureInfo::Ptr>::const_iterator Iter;
1508 std::sort(exposures.begin(), exposures.end(), ExposureInfoComparator());
1509 Iter i = exposures.begin();
1510 Iter
const end = exposures.end();
1525 for (; i != end; ++i) {
1527 _refSweep.advance(expDecl.asRadians(), *
this);
1528 ExposureInfo *
info = i->get();
1535 _refSweep.advance(expDecl.asRadians(), *
this);
1536 _expSweep.advance(refDecl.asRadians(), *
this);
1537 if (refDecl < expDecl) {
1542 ExposureInfo *info = i->get();
1550 while (!
_heap.empty()) {
1554 RefWithCov *r =
_heap.back().second;
1571 void RefExpMatcher::_finish(RefWithCov *r) {
1572 if (!r->isCovered()) {
1577 Angle decl = r->getReferencePosition().getSphericalCoords().getLatitude();
1581 _heap.push_back(std::pair<Angle, RefWithCov *>(decl, r));
1583 while (!
_heap.empty() &&
1586 r =
_heap.back().second;
1602 void RefExpMatcher::_candidateMatch(RefWithCov *r, ExposureInfo *e) {
1603 double epoch = e->getEpoch();
1604 Eigen::Vector3d v = r->getReferencePosition().getPosition(
1605 epoch, e->getEarthPosition());
1609 p.getX() <= e->getX0() + e->getWidth() +
PixelZeroPos - 0.5 &&
1611 p.getY() <= e->getY0() + e->getHeight() +
PixelZeroPos - 0.5) {
1619 void checkFilters() {
1620 typedef std::vector<std::string>::const_iterator Iter;
1622 std::vector<std::string>
const names = Filter::getNames();
1623 int n =
static_cast<int>(names.size());
1624 for (Iter i = names.begin(), e = names.end(); i != e; ++i) {
1628 "Filter IDs do not have contiguous IDs starting at 0");
1638 std::string
const &refFile,
1641 std::string
const &posFile,
1644 std::string
const &outFile,
1648 bool outputRefExtras,
1649 bool truncateOutFile
1651 Log log(Log::getDefaultLog(),
"lsst.ap.match");
1652 log.
log(
Log::INFO,
"Matching reference catalog to position table...");
1655 MatchablePosReader posReader(
1656 posFile, posControl, posDialect, outDialect, radius);
1657 RefReader<MatchableRef> refReader(
1658 refFile, refControl, refDialect, outDialect,
1659 posReader.getMinEpoch(), posReader.getMaxEpoch(), parallaxThresh);
1660 CsvWriter writer(outFile, outDialect, truncateOutFile);
1661 RefPosMatcher matcher(outputRefExtras);
1663 log.
log(
Log::INFO,
"Starting reference catalog to position table match");
1664 matcher.match(writer, refReader, posReader);
1666 static_cast<unsigned long long>(writer.getNumRecords()),
1672 std::vector<ExposureInfo::Ptr> &exposures,
1673 std::string
const &refFile,
1676 std::string
const &outFile,
1679 bool truncateOutFile
1681 typedef std::vector<ExposureInfo::Ptr>::const_iterator Iter;
1682 if (exposures.empty()) {
1683 throw LSST_EXCEPT(pexExcept::InvalidParameterError,
1684 "no input exposure information");
1688 Log log(Log::getDefaultLog(),
"lsst.ap.match");
1689 log.
log(
Log::INFO,
"Filtering out reference catalog entries not "
1690 "observable in any exposure...");
1693 Iter i = exposures.begin();
1694 double minEpoch = (*i)->getEpoch();
1695 double maxEpoch = minEpoch;
1697 for (Iter e = exposures.end(); i != e; ++i) {
1698 double epoch = (*i)->getEpoch();
1699 if (epoch < minEpoch) {
1701 }
else if (epoch > maxEpoch) {
1706 minEpoch, maxEpoch);
1709 RefReader<RefWithCov> refReader(
1710 refFile, refControl, refDialect, outDialect,
1711 minEpoch, maxEpoch, parallaxThresh);
1712 CsvWriter writer(outFile, outDialect, truncateOutFile);
1713 RefExpMatcher matcher;
1715 log.
log(
Log::INFO,
"Starting reference catalog to exposure match");
1716 matcher.match(writer, refReader, exposures);
An include file to include the public header files for lsst::afw::math.
Class for simulated reference catalog positions.
SphericalSweep< MatchableRef > _refSweep
void referenceMatch(std::string const &refFile, CatalogControl const &refControl, CsvControl const &refDialect, std::string const &posFile, CatalogControl const &posControl, CsvControl const &posDialect, std::string const &outFile, CsvControl const &outDialect, lsst::afw::geom::Angle const radius, lsst::afw::geom::Angle const parallaxThresh, bool outputRefExtras, bool truncateOutFile)
char getDelimiter() const
lsst::afw::geom::Angle const angularSeparation(Eigen::Vector3d const &v1, Eigen::Vector3d const &v2)
void appendField(std::string const &v)
Parameters that define a Character-Separated-Value dialect.
size_t getNumRecords() const
AngleUnit const radians
constant with units of radians
boost::scoped_array< int > _filterCov
lsst::afw::coord::IcrsCoord const cartesianToIcrs(Eigen::Vector3d const &v)
size_t getNumRecords() const
MatchablePosReader * _posReader
lsst::afw::coord::IcrsCoord IcrsCoord
a place to record messages and descriptions of the state of processing.
Class that bundles together the WCS, extents, time, and calibration information from an image (typica...
void referenceFilter(std::vector< ExposureInfo::Ptr > &exposures, std::string const &refFile, CatalogControl const &refControl, CsvControl const &refDialect, std::string const &outFile, CsvControl const &outDialect, lsst::afw::geom::Angle const parallaxThresh, bool truncateOutFile)
std::string const get(int i) const
Matching against simulated reference catalog positions.
RefReader< MatchableRef > * _refReader
Config parameters for catalogs involved in reference matching.
void log(int importance, const std::string &message, const lsst::daf::base::PropertySet &properties)
double maxAlpha(double const theta, double const centerDec)
double _maxAngularVelocity
SphericalSweep< ExposureInfo > _expSweep
void format(int importance, const char *fmt,...)
Holds an integer identifier for an LSST filter.
SphericalSweep< MatchablePos > _posSweep
#define LSST_EXCEPT(type,...)
Spatial utility functions.
std::vector< std::pair< Angle, Ref * > > _heap
lsst::afw::geom::Angle Angle
Arena< MatchablePos > _arena
const double PixelZeroPos
FITS uses 1.0, SDSS uses 0.5, LSST uses 0.0 (http://dev.lsstcorp.org/trac/wiki/BottomLeftPixelProposa...
lsst::afw::geom::Angle getLongitude() const
The main access method for the longitudinal coordinate.
Single threaded arena (pool) memory allocator.
2D bounding box interface.
double arcsecToRad(double x)
double radToMas(double x)
double masToRad(double x)
Pointer vector that avoids memory allocation for small vectors.
void write(std::string const &v)
lsst::afw::geom::Angle getLatitude() const
The main access method for the latitudinal coordinate.
std::vector< int > _columns
Angle const maxAlpha(Angle radius, Angle centerPhi)
boost::scoped_ptr< CsvReader > _reader
A class to handle Icrs coordinates (inherits from Coord)
void push_back(value_type v)
Sweep line data structures useful for region-region matching.
Useful astronomical constants.
CsvControl const & getControl() const
Functions to handle coordinates.
lsst::afw::geom::Angle const clampPhi(lsst::afw::geom::Angle const a)