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" 35 struct insertionOrderTag{};
36 typedef boost::multi_index_container<
38 boost::multi_index::indexed_by<
39 boost::multi_index::sequenced<
40 boost::multi_index::tag<insertionOrderTag>
42 boost::multi_index::ordered_unique<
43 boost::multi_index::tag<refIdTag>,
44 boost::multi_index::global_fun<
48 > MultiIndexedProxyPairList;
59 inline double absDeltaAngle(
double ang1,
double ang2) {
63 bool cmpPair(ProxyPair
const &a, ProxyPair
const &b) {
72 struct CompareProxyFlux {
75 double aFlux = a.
record->get(key);
76 double bFlux = b.
record->get(key);
105 if (startInd >= a.
size()) {
108 CompareProxyFlux cmp = {key};
112 return ProxyVector(b.begin() + startInd, b.begin() + endInd);
123 for (
size_t i = 0; i < a.
size(); i++) {
125 double dpa = absDeltaAngle(a[i].pa, p.
pa);
126 if (dd < e && dpa < e_dpa) {
143 double dd_min = 1.E+10;
146 for (
auto i = a.
begin(); i != a.
end(); ++i) {
150 absDeltaAngle(p.
pa, i->pa - dpa) < e_dpa &&
152 (i->first == q.
first)) {
158 absDeltaAngle(p.
pa, i->pa - dpa) < dpa_min) {
170 boost::shared_array<double>
const & coeff,
176 int ncoeff = (order + 1) * (order + 2) / 2;
180 for (
int i = 0; i <= order; i++) {
181 for (
int k = 0; k <= i; k++) {
183 *xn += coeff[n] *
pow(x, j) *
pow(y, k);
184 *yn += coeff[n+ncoeff] *
pow(x, j) *
pow(y, k);
190 boost::shared_array<double> polyfit(
195 int ncoeff = (order + 1) * (order + 2) / 2;
200 for (
int i = 0; i <= order; i++) {
201 for (
int k = 0; k <= i; k++) {
210 for (
size_t k = 0; k < img.
size(); k++) {
218 boost::shared_array<double> coeff(
new double[ncoeff*2]);
220 for (
int loop = 0; loop < 1; loop++) {
221 for (
int i = 0; i < ncoeff; i++) {
222 for (
int j = 0; j < ncoeff; j++) {
223 a_data[i*ncoeff+j] = 0.0;
224 for (
size_t k = 0; k < img.
size(); k++) {
226 a_data[i*ncoeff+j] +=
pow(img[k].getX(), xorder[i]) *
227 pow(img[k].getY(), yorder[i]) *
228 pow(img[k].getX(), xorder[j]) *
229 pow(img[k].getY(), yorder[j]);
233 b_data[i] = c_data[i] = 0.0;
234 for (
unsigned int k = 0; k < img.
size(); k++) {
236 b_data[i] +=
pow(img[k].getX(), xorder[i]) *
237 pow(img[k].getY(), yorder[i]) *
239 c_data[i] +=
pow(img[k].getX(), xorder[i]) *
240 pow(img[k].getY(), yorder[i]) *
246 gsl_matrix_view a = gsl_matrix_view_array(a_data.get(), ncoeff, ncoeff);
247 gsl_vector_view b = gsl_vector_view_array(b_data.get(), ncoeff);
248 gsl_vector_view c = gsl_vector_view_array(c_data.get(), ncoeff);
257 gsl_linalg_LU_decomp(&a.matrix, p.get(), &s);
258 gsl_linalg_LU_solve(&a.matrix, p.get(), &b.vector, x.get());
259 gsl_linalg_LU_solve(&a.matrix, p.get(), &c.vector, y.get());
261 for (
int i = 0; i < ncoeff; i++) {
262 coeff[i] = x->data[i];
263 coeff[i+ncoeff] = y->data[i];
266 double S, Sx, Sy, Sxx, Syy;
267 S = Sx = Sy = Sxx = Syy = 0.0;
268 for (
size_t k = 0; k < img.
size(); k++) {
270 double x0 = img[k].getX();
271 double y0 = img[k].getY();
273 transform(order, coeff, x0, y0, &x1, &y1);
275 Sx += (x1 - posRefCat[k].getX());
276 Sxx += (x1 - posRefCat[k].getX()) * (x1 - posRefCat[k].getX());
277 Sy += (y1 - posRefCat[k].getY());
278 Syy += (y1 - posRefCat[k].getY()) * (y1 - posRefCat[k].getY());
281 double x_sig =
std::sqrt((Sxx - Sx * Sx / S) / S);
282 double y_sig =
std::sqrt((Syy - Sy * Sy / S) / S);
285 for (
size_t k = 0; k < img.
size(); k++) {
286 double x0 = img[k].getX();
287 double y0 = img[k].getY();
289 transform(order, coeff, x0, y0, &x1, &y1);
290 if (
std::fabs(x1-posRefCat[k].getX()) > 2. * x_sig ||
291 std::fabs(y1-posRefCat[k].getY()) > 2. * y_sig) {
317 double matchingAllowancePix
319 auto minDistSq = matchingAllowancePix*matchingAllowancePix;
320 auto foundPtr = posRefCat.
end();
321 for (
auto posRefPtr = posRefCat.
begin(); posRefPtr != posRefCat.
end(); ++posRefPtr) {
322 auto const dx = posRefPtr->getX() - x;
323 auto const dy = posRefPtr->getY() - y;
324 auto const distSq = dx*dx + dy*dy;
325 if (distSq < minDistSq) {
326 foundPtr = posRefPtr;
351 void addNearestMatch(
352 MultiIndexedProxyPairList &proxyPairList,
353 boost::shared_array<double> coeff,
356 double matchingAllowancePix
359 auto x0 = source.
getX();
360 auto y0 = source.
getY();
362 auto refObjDist = searchNearestPoint(posRefCat, x1, y1, matchingAllowancePix);
363 if (refObjDist.first == posRefCat.
end()) {
367 auto existingMatch = proxyPairList.get<refIdTag>().
find(refObjDist.first->record->getId());
368 if (existingMatch == proxyPairList.get<refIdTag>().end()) {
370 auto proxyPair = ProxyPair(*refObjDist.first, source);
371 proxyPairList.get<refIdTag>().insert(proxyPair);
379 if (existingMatch->distance <= refObjDist.second) {
384 proxyPairList.get<refIdTag>().
erase(existingMatch);
385 auto proxyPair = ProxyPair(*refObjDist.first, source);
386 proxyPairList.get<refIdTag>().insert(proxyPair);
402 boost::shared_array<double> coeff,
405 double matchingAllowancePix,
408 MultiIndexedProxyPairList proxyPairList;
410 for (
auto sourcePtr = sourceCat.
begin(); sourcePtr != sourceCat.
end(); ++sourcePtr) {
411 addNearestMatch(proxyPairList, coeff, posRefCat, *sourcePtr, matchingAllowancePix);
414 if (proxyPairList.size() > 5) {
415 for (
auto j = 0; j < 100; j++) {
416 auto prevNumMatches = proxyPairList.size();
419 srcMat.reserve(proxyPairList.size());
420 catMat.reserve(proxyPairList.size());
421 for (
auto matchPtr = proxyPairList.get<refIdTag>().begin();
422 matchPtr != proxyPairList.get<refIdTag>().
end(); ++matchPtr) {
423 catMat.push_back(matchPtr->first);
424 srcMat.push_back(matchPtr->second);
426 coeff = polyfit(order, srcMat, catMat);
427 proxyPairList.clear();
429 for (ProxyVector::const_iterator sourcePtr = sourceCat.
begin();
430 sourcePtr != sourceCat.
end(); ++sourcePtr) {
431 addNearestMatch(proxyPairList, coeff, posRefCat, *sourcePtr, matchingAllowancePix);
433 if (proxyPairList.size() == prevNumMatches) {
439 matPair.reserve(proxyPairList.size());
440 for (
auto proxyPairIter = proxyPairList.get<insertionOrderTag>().begin();
441 proxyPairIter != proxyPairList.get<insertionOrderTag>().
end(); ++proxyPairIter) {
443 proxyPairIter->first.record,
444 std::static_pointer_cast<afwTable::SourceRecord>(proxyPairIter->second.record),
445 proxyPairIter->distance
458 void MatchOptimisticBControl::validate()
const {
459 if (refFluxField.empty()) {
462 if (sourceFluxField.empty()) {
465 if (numBrightStars <= 0) {
468 if (minMatchedPairs < 0) {
471 if (matchingAllowancePix <= 0) {
474 if (maxOffsetPix <= 0) {
477 if (maxRotationDeg <= 0) {
480 if (allowedNonperpDeg <= 0) {
483 if (numPointsForShape <= 0) {
486 if (maxDeterminant <= 0) {
499 sourcePtr != sourceCat.
end(); ++sourcePtr) {
514 posRefPtr != posRefCat.
end(); ++posRefPtr) {
529 if (posRefCat.
empty()) {
532 if (sourceCat.
empty()) {
535 if (posRefBegInd < 0) {
538 if (static_cast<size_t>(posRefBegInd) >= posRefCat.
size()) {
546 for (
auto iter = sourceCat.
begin(); iter != sourceCat.
end(); ++iter) {
549 srcCenter /= sourceCat.
size();
552 for (
auto iter = posRefCat.
begin(); iter != posRefCat.
end(); ++iter) {
553 refCenter += iter->getCoord().getVector();
555 refCenter /= posRefCat.
size();
557 auto tanWcs = afw::geom::makeSkyWcs(
577 sourceSubCat.
size()+25,
585 size_t const posRefCatSubSize = posRefSubCat.
size();
586 for (
size_t i = 0; i < posRefCatSubSize-1; i++) {
587 for (
size_t j = i+1; j < posRefCatSubSize; j++) {
588 posRefPairList.
push_back(ProxyPair(posRefSubCat[i], posRefSubCat[j]));
595 size_t const sourceSubCatSize = sourceSubCat.
size();
596 for (
size_t i = 0; i < sourceSubCatSize-1; i++) {
597 for (
size_t j = i+1; j < sourceSubCatSize; j++) {
598 sourcePairList.push_back(ProxyPair(sourceSubCat[i], sourceSubCat[j]));
601 std::sort(sourcePairList.begin(), sourcePairList.end(), cmpPair);
608 for (
size_t ii = 0; ii < sourcePairList.size(); ii++) {
609 ProxyPair p = sourcePairList[ii];
621 for (
size_t l = 0; l < q.
size(); l++) {
624 double dpa = p.
pa - q[l].pa;
637 for (
size_t k = 0; k < sourceSubCat.
size(); k++) {
638 if (p.
first == sourceSubCat[k] || p.
second == sourceSubCat[k])
continue;
640 ProxyPair pp(p.
first, sourceSubCat[k]);
644 if (r != posRefPairList.
end()) {
651 if (srcMatPair.
size() == fullShapeSize) {
657 bool goodMatch =
false;
658 if (srcMatPair.
size() == fullShapeSize) {
660 for (
size_t k = 1; k < catMatPair.
size(); k++) {
661 if (catMatPair[0].
first != catMatPair[k].
first) {
668 if (goodMatch && srcMatPair.
size() == fullShapeSize) {
675 for (
size_t k = 0; k < srcMatPair.
size(); k++) {
680 boost::shared_array<double> coeff = polyfit(1, srcMat, catMat);
683 for (
size_t k = 0; k < srcMat.
size(); k++) {
684 std::cout <<
"circle(" << srcMat[k].getX() <<
"," 685 << srcMat[k].getY() <<
",10) # color=green" <<
std::endl;
686 std::cout <<
"circle(" << catMat[k].getX() <<
"," 687 << catMat[k].getY() <<
",10) # color=red" <<
std::endl;
688 std::cout <<
"line(" << srcMat[0].getX() <<
"," << srcMat[0].getY() <<
"," 689 << srcMat[k].getX() <<
"," << srcMat[k].getY()
690 <<
") # line=0 0 color=green" <<
std::endl;
691 std::cout <<
"line(" << catMat[0].getX() <<
"," << catMat[0].getY() <<
"," 692 << catMat[k].getX() <<
"," << catMat[k].getY()
693 <<
") # line=0 0 color=red" <<
std::endl;
710 std::cout <<
"Angle between axes (deg; allowed 90 +/- ";
714 if (
std::fabs(coeff[1] * coeff[5] - coeff[2] * coeff[4] - 1.)
724 double x0, y0, x1, y1;
728 for (
size_t i = 0; i < sourceSubCat.
size(); i++) {
729 x0 = sourceSubCat[i].getX();
730 y0 = sourceSubCat[i].getY();
732 auto refObjDist = searchNearestPoint(posRefSubCat, x1, y1,
734 if (refObjDist.first != posRefSubCat.
end()) {
739 std::cout <<
"Match: " << x0 <<
"," << y0 <<
" --> " 740 << x1 <<
"," << y1 <<
" <==> " 741 << refObjDist.first->getX() <<
"," << refObjDist.first->getY()
753 coeff = polyfit(1, srcMat, catMat);
756 for (
size_t i = 0; i < 6; ++i) {
762 matPair = FinalVerify(coeff, posRefProxyCat, sourceProxyCat,
765 std::cout <<
"Number of matches: " << matPair.size() <<
" vs " <<
772 if (matPair.size() > matPairSave.
size()) {
773 matPairSave = matPair;
781 if (matPairCand.
size() == 3) {
792 if (matPairCand.
size() == 0) {
795 size_t nmatch = matPairCand[0].
size();
797 for (
size_t i = 1; i < matPairCand.
size(); i++) {
798 if (matPairCand[i].size() > nmatch) {
799 nmatch = matPairCand[i].
size();
800 matPairRet = matPairCand[i];
Eigen::Matrix2d getCdMatrix(Point2D const &pixel) const
int numPointsForShape
"number of points in a matching shape" ;
double matchingAllowancePix
"maximum allowed distance between reference objects and sources (pixels)" ;
ProxyVector makeProxies(lsst::afw::table::SourceCatalog const &sourceCat, afw::geom::SkyWcs const &distortedWcs, afw::geom::SkyWcs const &tanWcs)
std::vector< RecordProxy > ProxyVector
SchemaItem< T > find(std::string const &name) const
double maxDeterminant
"?" ;
double maxOffsetPix
"maximum allowed frame translation (pixels)" ;
double degToRad(long double angleInDegrees)
#define LSST_EXCEPT(type,...)
int numBrightStars
"maximum number of bright reference stars to use" ;
std::string refFluxField
"name of flux field in reference catalog" ;
Base::const_iterator const_iterator
SpherePoint pixelToSky(Point2D const &pixel) const
A wrapper around a SimpleRecord or SourceRecord that allows us to record a pixel position in a way th...
Point2D skyToPixel(SpherePoint const &sky) const
lsst::afw::table::ReferenceMatchVector matchOptimisticB(lsst::afw::table::SimpleCatalog const &posRefCat, lsst::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...
double maxRotationDeg
"maximum allowed frame rotation (deg)" ;
std::string sourceFluxField
"name of flux field in source catalog" ;
constexpr double asDegrees() const noexcept
table::Key< int > transform
double allowedNonperpDeg
"allowed non-perpendicularity of x and y axes (deg)" ;
int minMatchedPairs
"minimum number of matches" ;
boost::shared_ptr< lsst::afw::table::SimpleRecord > record