9 #include "boost/shared_array.hpp"
10 #include "boost/multi_index_container.hpp"
11 #include "boost/multi_index/sequenced_index.hpp"
12 #include "boost/multi_index/ordered_index.hpp"
13 #include "boost/multi_index/global_fun.hpp"
15 #include "gsl/gsl_linalg.h"
36 struct insertionOrderTag {};
37 typedef boost::multi_index_container<
39 boost::multi_index::indexed_by<
40 boost::multi_index::sequenced<boost::multi_index::tag<insertionOrderTag> >,
41 boost::multi_index::ordered_unique<
42 boost::multi_index::tag<refIdTag>,
43 boost::multi_index::global_fun<ProxyPair const &, afwTable::RecordId, &getRefId> > > >
44 MultiIndexedProxyPairList;
55 inline double absDeltaAngle(
double ang1,
double ang2) {
return std::fmod(
std::fabs(ang1 - ang2),
M_PI * 2); }
64 struct CompareProxyFlux {
66 double aFlux =
a.record->get(key);
67 double bFlux =
b.record->get(key);
92 if (startInd >=
a.size()) {
95 CompareProxyFlux cmp = {key};
106 for (
size_t i = 0; i <
a.size(); i++) {
108 double dpa = absDeltaAngle(
a[i].pa, p.
pa);
109 if (dd < e && dpa < e_dpa) {
118 ProxyPair const &q,
double e,
double dpa,
double e_dpa = 0.02) {
120 double dd_min = 1.E+10;
123 for (
auto i =
a.begin(); i !=
a.end(); ++i) {
126 if (dd < e && absDeltaAngle(p.
pa, i->pa - dpa) < e_dpa && dd < dd_min && (i->first == q.
first)) {
131 if (dd < e && absDeltaAngle(p.
pa, i->pa - dpa) < dpa_min) {
147 for (
int i = 0; i <=
order; i++) {
148 for (
int k = 0; k <= i; k++) {
163 for (
int i = 0; i <=
order; i++) {
164 for (
int k = 0; k <= i; k++) {
173 for (
size_t k = 0; k < img.
size(); k++) {
181 boost::shared_array<double>
coeff(
new double[
ncoeff * 2]);
183 for (
int loop = 0; loop < 1; loop++) {
184 for (
int i = 0; i <
ncoeff; i++) {
185 for (
int j = 0; j <
ncoeff; j++) {
186 a_data[i *
ncoeff + j] = 0.0;
187 for (
size_t k = 0; k < img.
size(); k++) {
190 pow(img[k].getX(), xorder[i]) *
pow(img[k].getY(), yorder[i]) *
191 pow(img[k].getX(), xorder[j]) *
pow(img[k].getY(), yorder[j]);
195 b_data[i] = c_data[i] = 0.0;
196 for (
unsigned int k = 0; k < img.
size(); k++) {
198 b_data[i] +=
pow(img[k].getX(), xorder[i]) *
pow(img[k].getY(), yorder[i]) *
200 c_data[i] +=
pow(img[k].getX(), xorder[i]) *
pow(img[k].getY(), yorder[i]) *
206 gsl_matrix_view
a = gsl_matrix_view_array(a_data.get(),
ncoeff,
ncoeff);
207 gsl_vector_view
b = gsl_vector_view_array(b_data.get(),
ncoeff);
208 gsl_vector_view c = gsl_vector_view_array(c_data.get(),
ncoeff);
217 gsl_linalg_LU_decomp(&
a.matrix, p.get(), &s);
218 gsl_linalg_LU_solve(&
a.matrix, p.get(), &
b.vector,
x.get());
219 gsl_linalg_LU_solve(&
a.matrix, p.get(), &c.vector,
y.get());
221 for (
int i = 0; i <
ncoeff; i++) {
226 double S, Sx, Sy, Sxx, Syy;
227 S = Sx = Sy = Sxx = Syy = 0.0;
228 for (
size_t k = 0; k < img.
size(); k++) {
230 double x0 = img[k].getX();
231 double y0 = img[k].getY();
235 Sx += (x1 - posRefCat[k].getX());
236 Sxx += (x1 - posRefCat[k].getX()) * (x1 - posRefCat[k].getX());
237 Sy += (y1 - posRefCat[k].getY());
238 Syy += (y1 - posRefCat[k].getY()) * (y1 - posRefCat[k].getY());
241 double x_sig =
std::sqrt((Sxx - Sx * Sx / S) / S);
242 double y_sig =
std::sqrt((Syy - Sy * Sy / S) / S);
245 for (
size_t k = 0; k < img.
size(); k++) {
246 double x0 = img[k].getX();
247 double y0 = img[k].getY();
250 if (
std::fabs(x1 - posRefCat[k].getX()) > 2. * x_sig ||
251 std::fabs(y1 - posRefCat[k].getY()) > 2. * y_sig) {
273 double y,
double matchingAllowancePix) {
274 auto minDistSq = matchingAllowancePix * matchingAllowancePix;
275 auto foundPtr = posRefCat.
end();
276 for (
auto posRefPtr = posRefCat.
begin(); posRefPtr != posRefCat.
end(); ++posRefPtr) {
277 auto const dx = posRefPtr->getX() -
x;
278 auto const dy = posRefPtr->getY() -
y;
279 auto const distSq = dx * dx + dy * dy;
280 if (distSq < minDistSq) {
281 foundPtr = posRefPtr;
306 void addNearestMatch(MultiIndexedProxyPairList &proxyPairList, boost::shared_array<double>
coeff,
312 auto refObjDist = searchNearestPoint(posRefCat, x1, y1, matchingAllowancePix);
313 if (refObjDist.first == posRefCat.
end()) {
317 auto existingMatch = proxyPairList.get<refIdTag>().
find(refObjDist.first->record->getId());
318 if (existingMatch == proxyPairList.get<refIdTag>().end()) {
321 proxyPairList.get<refIdTag>().insert(proxyPair);
329 if (existingMatch->distance <= refObjDist.second) {
334 proxyPairList.get<refIdTag>().
erase(existingMatch);
336 proxyPairList.get<refIdTag>().insert(proxyPair);
352 ProxyVector const &sourceCat,
double matchingAllowancePix,
354 MultiIndexedProxyPairList proxyPairList;
356 for (
auto sourcePtr = sourceCat.
begin(); sourcePtr != sourceCat.
end(); ++sourcePtr) {
357 addNearestMatch(proxyPairList,
coeff, posRefCat, *sourcePtr, matchingAllowancePix);
360 if (proxyPairList.size() > 5) {
361 for (
auto j = 0; j < 100; j++) {
362 auto prevNumMatches = proxyPairList.size();
365 srcMat.reserve(proxyPairList.size());
366 catMat.reserve(proxyPairList.size());
367 for (
auto matchPtr = proxyPairList.get<refIdTag>().begin();
368 matchPtr != proxyPairList.get<refIdTag>().end(); ++matchPtr) {
369 catMat.push_back(matchPtr->first);
370 srcMat.push_back(matchPtr->second);
373 proxyPairList.clear();
375 for (ProxyVector::const_iterator sourcePtr = sourceCat.
begin(); sourcePtr != sourceCat.
end();
377 addNearestMatch(proxyPairList,
coeff, posRefCat, *sourcePtr, matchingAllowancePix);
379 if (proxyPairList.size() == prevNumMatches) {
385 matPair.reserve(proxyPairList.size());
386 for (
auto proxyPairIter = proxyPairList.get<insertionOrderTag>().begin();
387 proxyPairIter != proxyPairList.get<insertionOrderTag>().end(); ++proxyPairIter) {
389 proxyPairIter->first.record,
390 std::static_pointer_cast<afwTable::SourceRecord>(proxyPairIter->second.record),
391 proxyPairIter->distance));
404 if (refFluxField.empty()) {
407 if (sourceFluxField.empty()) {
410 if (numBrightStars <= 0) {
413 if (minMatchedPairs < 0) {
416 if (matchingAllowancePix <= 0) {
419 if (maxOffsetPix <= 0) {
422 if (maxRotationDeg <= 0) {
425 if (allowedNonperpDeg <= 0) {
428 if (numPointsForShape <= 0) {
431 if (maxDeterminant <= 0) {
440 for (afwTable::SourceCatalog::const_iterator sourcePtr = sourceCat.begin(); sourcePtr != sourceCat.end();
465 if (posRefCat.
empty()) {
468 if (sourceCat.empty()) {
471 if (posRefBegInd < 0) {
474 if (
static_cast<size_t>(posRefBegInd) >= posRefCat.
size()) {
482 for (
auto iter = sourceCat.begin();
iter != sourceCat.end(); ++
iter) {
485 srcCenter /= sourceCat.size();
489 refCenter +=
iter->getCoord().getVector();
491 refCenter /= posRefCat.
size();
501 selectPoint(sourceProxyCat, sourceCat.getSchema().find<
double>(control.
sourceFluxField).key,
508 sourceSubCat.
size() + 25, posRefBegInd);
515 size_t const posRefCatSubSize = posRefSubCat.
size();
516 for (
size_t i = 0; i < posRefCatSubSize - 1; i++) {
517 for (
size_t j = i + 1; j < posRefCatSubSize; j++) {
525 size_t const sourceSubCatSize = sourceSubCat.
size();
526 for (
size_t i = 0; i < sourceSubCatSize - 1; i++) {
527 for (
size_t j = i + 1; j < sourceSubCatSize; j++) {
538 for (
size_t ii = 0; ii < sourcePairList.
size(); ii++) {
550 for (
size_t l = 0; l < q.
size(); l++) {
553 double dpa = p.
pa - q[l].pa;
566 for (
size_t k = 0; k < sourceSubCat.
size(); k++) {
567 if (p.
first == sourceSubCat[k] || p.
second == sourceSubCat[k])
continue;
573 if (r != posRefPairList.
end()) {
580 if (srcMatPair.
size() == fullShapeSize) {
586 bool goodMatch =
false;
587 if (srcMatPair.
size() == fullShapeSize) {
589 for (
size_t k = 1; k < catMatPair.
size(); k++) {
590 if (catMatPair[0].
first != catMatPair[k].
first) {
597 if (goodMatch && srcMatPair.
size() == fullShapeSize) {
603 for (
size_t k = 0; k < srcMatPair.
size(); k++) {
608 boost::shared_array<double>
coeff = polyfit(1, srcMat, catMat);
611 for (
size_t k = 0; k < srcMat.
size(); k++) {
612 std::cout <<
"circle(" << srcMat[k].getX() <<
"," << srcMat[k].getY()
614 std::cout <<
"circle(" << catMat[k].getX() <<
"," << catMat[k].getY()
616 std::cout <<
"line(" << srcMat[0].getX() <<
"," << srcMat[0].getY() <<
","
617 << srcMat[k].getX() <<
"," << srcMat[k].getY()
618 <<
") # line=0 0 color=green" <<
std::endl;
619 std::cout <<
"line(" << catMat[0].getX() <<
"," << catMat[0].getY() <<
","
620 << catMat[k].getX() <<
"," << catMat[k].getY()
621 <<
") # line=0 0 color=red" <<
std::endl;
638 std::cout <<
"Angle between axes (deg; allowed 90 +/- ";
651 double x0, y0, x1, y1;
655 for (
size_t i = 0; i < sourceSubCat.
size(); i++) {
656 x0 = sourceSubCat[i].getX();
657 y0 = sourceSubCat[i].getY();
661 if (refObjDist.first != posRefSubCat.
end()) {
666 std::cout <<
"Match: " << x0 <<
"," << y0 <<
" --> " << x1 <<
"," << y1
667 <<
" <==> " << refObjDist.first->getX() <<
","
668 << refObjDist.first->getY() <<
std::endl;
679 coeff = polyfit(1, srcMat, catMat);
682 for (
size_t i = 0; i < 6; ++i) {
688 matPair = FinalVerify(
coeff, posRefProxyCat, sourceProxyCat,
691 std::cout <<
"Number of matches: " << matPair.
size() <<
" vs "
698 if (matPair.
size() > matPairSave.
size()) {
699 matPairSave = matPair;
707 if (matPairCand.
size() == 3) {
718 if (matPairCand.
size() == 0) {
721 size_t nmatch = matPairCand[0].
size();
723 for (
size_t i = 1; i < matPairCand.
size(); i++) {
724 if (matPairCand[i].size() > nmatch) {
725 nmatch = matPairCand[i].
size();
726 matPairRet = matPairCand[i];
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
table::Key< table::Array< std::uint8_t > > wcs
This file declares a class for representing vectors in ℝ³.
A 2-dimensional celestial WCS that transform pixels to ICRS RA/Dec, using the LSST standard for pixel...
lsst::geom::SpherePoint pixelToSky(lsst::geom::Point2D const &pixel) const
Compute sky position(s) from pixel position(s)
lsst::geom::Point2D skyToPixel(lsst::geom::SpherePoint const &sky) const
Compute pixel position(s) from sky position(s)
size_type size() const
Return the number of elements in the catalog.
bool empty() const
Return true if the catalog has no records.
iterator begin()
Iterator access.
Schema getSchema() const
Return the schema associated with the catalog's table.
A FunctorKey used to get or set celestial coordinates from a pair of lsst::geom::Angle keys.
SchemaItem< T > find(std::string const &name) const
Find a SchemaItem in the Schema by name.
Custom catalog class for record/table subclasses that are guaranteed to have an ID,...
typename Base::const_iterator const_iterator
A class representing an angle.
constexpr double asDegrees() const noexcept
Return an Angle's value in degrees.
Point in an unspecified spherical coordinate system.
Reports invalid arguments.
Vector3d is a vector in ℝ³ with components stored in double precision.
const char * source()
Source function that allows astChannel to source from a Stream.
std::shared_ptr< SkyWcs > makeSkyWcs(daf::base::PropertySet &metadata, bool strip=false)
Construct a SkyWcs from FITS keywords.
std::vector< ReferenceMatch > ReferenceMatchVector
Extent< double, 2 > Extent2D
constexpr double degToRad(double x) noexcept
constexpr AngleUnit radians
constant with units of radians
std::vector< RecordProxy > ProxyVector
afw::table::ReferenceMatchVector matchOptimisticB(afw::table::SimpleCatalog const &posRefCat, afw::table::SourceCatalog const &sourceCat, MatchOptimisticBControl const &control, afw::geom::SkyWcs const &wcs, int posRefBegInd=0, bool verbose=false)
Match sources to stars in a position reference catalog using optimistic pattern matching B.
ProxyVector makeProxies(afw::table::SourceCatalog const &sourceCat, afw::geom::SkyWcs const &distortedWcs, afw::geom::SkyWcs const &tanWcs)
A base class for image defects.
table::Key< table::Array< double > > coeff
Lightweight representation of a geometric match between two records.
std::string refFluxField
"name of flux field in reference catalog" ;
double maxRotationDeg
"maximum allowed frame rotation (deg)" ;
double matchingAllowancePix
"maximum allowed distance between reference objects and sources (pixels)" ;
int numPointsForShape
"number of points in a matching shape" ;
double maxDeterminant
"?" ;
int minMatchedPairs
"minimum number of matches" ;
int numBrightStars
"maximum number of bright reference stars to use" ;
std::string sourceFluxField
"name of flux field in source catalog" ;
double maxOffsetPix
"maximum allowed frame translation (pixels)" ;
double allowedNonperpDeg
"allowed non-perpendicularity of x and y axes (deg)" ;
A wrapper around a SimpleRecord or SourceRecord that allows us to record a pixel position in a way th...
std::shared_ptr< afw::table::SimpleRecord > record