31#define M_PI 3.14159265358979323846
44LOG_LOGGER _log =
LOG_GET(
"lsst.jointcal.ListMatch");
94static bool DecreasingLength(
const Segment &first,
const Segment &second) {
return (first.r > second.r); }
110 sort(DecreasingLength);
147 int idiff = first->size() - second->size();
151 return (first->getDist2() < second->getDist2());
184 if (
seg1->r == 0)
continue;
229 if (
seg1->r == 0)
continue;
259 LOGLS_DEBUG(_log,
"Best solution " <<
best->computeResidual() <<
" npairs " <<
best->size());
276 const AstrometryTransform &transform,
277 const MatchConditions &conditions) {
278 if (list1.size() <= 4 || list2.size() <= 4) {
279 LOGL_FATAL(_log,
"ListMatchupRotShift_New : (at least) one of the lists is too short.");
283 SegmentList sList1(list1, conditions.nStarsList1, transform);
284 SegmentList sList2(list2, conditions.nStarsList2, AstrometryTransformIdentity());
292 int nBinsAngle = 180;
293 double angleOffset =
M_PI / nBinsAngle;
294 double minRatio = conditions.minSizeRatio();
295 double maxRatio = conditions.maxSizeRatio();
296 SparseHisto4d histo(nBinsR, minRatio, maxRatio, nBinsAngle, -
M_PI - angleOffset,
M_PI - angleOffset,
297 conditions.nStarsList1, 0., conditions.nStarsList1, conditions.nStarsList2, 0.,
298 conditions.nStarsList2, sList1.size() * sList2.size());
301 Segment *seg1, *seg2;
304 for (segi1 = sList1.begin(); segi1 != sList1.end(); ++segi1) {
306 if (seg1->r == 0)
continue;
307 for (segi2 = sList2.begin(); segi2 != sList2.end(); ++segi2) {
314 ratio = seg2->r / seg1->r;
315 if (ratio > maxRatio)
continue;
316 if (ratio < minRatio)
break;
317 angle = seg1->relativeAngle(seg2);
319 histo.fill(ratio, angle, seg1->s1rank + 0.5, seg2->s1rank + 0.5);
330 int oldMaxContent = 0;
332 for (
int i = 0; i < 4 * conditions.maxTrialCount;
336 int maxContent = histo.maxBin(pars);
337 if (maxContent == 0)
break;
338 if (conditions.printLevel >= 1) {
339 LOGLS_DEBUG(_log,
"ValMax " << maxContent <<
" ratio " << pars[0] <<
" angle " << pars[1]);
346 if (maxContent < oldMaxContent && i >= conditions.maxTrialCount)
break;
348 oldMaxContent = maxContent;
350 int rank1L1 = int(pars[2]);
351 int rank1L2 = int(pars[3]);
352 double minAngle, maxAngle;
353 histo.binLimits(pars, 0, minRatio, maxRatio);
354 histo.binLimits(pars, 1, minAngle, maxAngle);
358 for (segi1 = sList1.begin(); segi1 != sList1.end(); ++segi1) {
360 if (seg1->s1rank != rank1L1)
continue;
361 if (seg1->r == 0)
continue;
362 for (segi2 = sList2.begin(); segi2 != sList2.end(); ++segi2) {
364 if (seg2->s1rank != rank1L2)
continue;
367 a_list->push_back(StarMatch(*(seg1->s1), *(seg2->s1), seg1->s1, seg2->s1));
368 ratio = seg2->r / seg1->r;
369 if (ratio > maxRatio)
continue;
370 if (ratio < minRatio)
372 angle = seg1->relativeAngle(seg2);
374 if (angle < minAngle || angle > maxAngle)
continue;
380 a_list->push_back(StarMatch(*(seg1->s2), *(seg2->s2), seg1->s2, seg2->s2));
386 if (
int(a_list->size()) != maxContent + 1) {
387 LOGLS_ERROR(_log,
"There is an internal inconsistency in ListMatchupRotShift.");
389 LOGLS_ERROR(_log,
"matches->size() = " << a_list->size());
391 a_list->refineTransform(conditions.nSigmas);
395 if (Solutions.empty()) {
396 LOGLS_ERROR(_log,
"Error In ListMatchup : not a single pair match.");
397 LOGLS_ERROR(_log,
"Probably, the relative scale of lists is not within bounds.");
398 LOGLS_ERROR(_log,
"min/max ratios: " << minRatio <<
' ' << maxRatio);
402 Solutions.sort(DecreasingQuality);
404 best.
swap(*Solutions.begin());
406 Solutions.pop_front();
407 if (conditions.printLevel >= 1) {
408 LOGLS_INFO(_log,
"Best solution " << best->computeResidual() <<
" npairs " << best->size());
410 LOGLS_INFO(_log,
"Chi2 " << best->getChi2() <<
", Number of solutions " << Solutions.size());
416 const AstrometryTransform &transform,
417 const MatchConditions &conditions) {
418 if (conditions.algorithm == 1)
419 return ListMatchupRotShift_Old(list1, list2, transform, conditions);
421 return ListMatchupRotShift_New(list1, list2, transform, conditions);
444 "unflipped Residual " <<
unflipped->computeResidual() <<
" nused " <<
unflipped->size());
463 const AstrometryTransform &transform,
465 int ncomb = list1.size() * list2.size();
466 if (!ncomb)
return nullptr;
471 nx = (int)
sqrt(ncomb);
473 Histo2d histo(nx, -maxShift, maxShift, nx, -maxShift, maxShift);
477 for (s1 = list1.begin(); s1 != list1.end(); ++s1) {
478 transform.apply((*s1)->x, (*s1)->y, x1, y1);
479 for (s2 = list2.begin(); s2 != list2.end(); ++s2) {
480 histo.fill((*s2)->x - x1, (*s2)->y - y1);
483 double dx = 0, dy = 0;
484 histo.maxBin(dx, dy);
493 double maxShift,
double binSize) {
503 nx =
int(2 * maxShift / binSize + 0.5);
505 Histo2d histo(nx, -maxShift, maxShift, nx, -maxShift, maxShift);
511 for (s1 =
list1.begin(); s1 !=
list1.end(); ++s1) {
516 histo.fill(s2->x - x1, s2->y -
y1);
521 for (
int i = 0;
i < 4; ++
i) {
522 double dx = 0, dy = 0;
547 const AstrometryTransform *guess,
const double maxDist) {
551 const Point *p1 = (*si);
552 const Point p2 = guess->apply(*p1);
553 const BaseStar *neighbour = list2.findClosest(p2);
554 if (!neighbour)
continue;
555 double distance = p2.Distance(*neighbour);
557 matches->push_back(StarMatch(*p1, *neighbour, *si, neighbour));
559 matches->back().distance =
distance;
573 for (
const auto &
si :
list1) {
594 const AstrometryTransform *guess,
const double maxDist) {
595 const AstrometryTransform *bestTransform = guess;
599 m->setTransform(bestTransform);
600 m->refineTransform(3.);
601 LOGLS_INFO(_log,
"Iterating: resid " <<
m->computeResidual() <<
" size " <<
m->size());
603 (prevMatch &&
m->computeResidual() < prevMatch->computeResidual() * 0.999 &&
m->Chi2() > 0)) {
605 bestTransform = prevMatch->Transform();
618 for (
const auto &
si :
list1) {
635static bool is_transform_ok(
const StarMatchList *match,
double pixSizeRatio2,
const size_t nmin) {
641 (match->size() > nmin))
644 match->printTransform();
649static double transform_diff(
const BaseStarList &List,
const AstrometryTransform *T1,
650 const AstrometryTransform *T2) {
655 for (
const auto & it : List) {
656 const BaseStar &s = *it;
657 T1->transformPosAndErrors(s, tf1);
659 double dx = tf1.x - tf2.x;
660 double dy = tf1.y - tf2.y;
661 diff2 += (tf1.vy * dx * dx + tf1.vx * dy * dy - 2 * tf1.vxy * dx * dy) /
662 (tf1.vx * tf1.vy - tf1.vxy * tf1.vxy);
669static double median_distance(
const StarMatchList *match,
const AstrometryTransform *transform) {
670 size_t nstars = match->size();
672 auto ir = resid.begin();
673 for (
auto it = match->begin(); it != match->end(); ++it, ++ir)
674 *ir =
sqrt(
transform->apply(it->point1).computeDist2(it->point2));
675 sort(resid.begin(), resid.end());
676 return (nstars & 1) ? resid[nstars / 2] : (resid[nstars / 2 - 1] + resid[nstars / 2]) * 0.5;
688 LOGLS_INFO(_log,
"listMatchCombinatorial: find match between " <<
list1.size() <<
" and " <<
list2.size()
699 LOGL_ERROR(_log,
"listMatchCombinatorial: direct transform failed, trying reverse");
711 LOGL_DEBUG(_log,
" listMatchCombinatorial: found the following transform.");
715 LOGL_ERROR(_log,
"listMatchCombinatorial: failed to find a transform");
729 const double nSigmas = 3.;
730 const size_t nStars = 500;
770 LOGLS_INFO(_log,
" listMatchRefine: order " <<
order <<
" was a better guess.");
#define LOGL_INFO(logger, message...)
#define LOGLS_INFO(logger, message)
#define LOGLS_ERROR(logger, message)
#define LOGL_ERROR(logger, message...)
#define LOGLS_DEBUG(logger, message)
#define LOGL_DEBUG(logger, message...)
#define LOGL_FATAL(logger, message...)
Fast locator in starlists.
table::Key< double > angle
Combinatorial searches for linear transformations to go from list1 to list2.
Iterator meant to traverse objects within some limiting distance.
This is an auxillary class for matching objects from starlists.
std::shared_ptr< const BaseStar > findClosest(const Point &where, double maxDist, bool(*SkipIt)(const BaseStar &)=nullptr) const
Find the closest with some rejection capability.
Iterator beginScan(const Point &where, double maxDist) const
SegmentList(const BaseStarList &list, int nStar, const AstrometryTransform &transform=AstrometryTransformIdentity())
A hanger for star associations.
std::list< std::unique_ptr< StarMatchList > > SolList
std::unique_ptr< AstrometryTransform > listMatchRefine(const BaseStarList &list1, const BaseStarList &list2, std::unique_ptr< AstrometryTransform > transform, int maxOrder=3)
std::unique_ptr< AstrometryTransform > listMatchCombinatorial(const BaseStarList &list1, const BaseStarList &list2, const MatchConditions &conditions=MatchConditions())
std::unique_ptr< AstrometryTransform > compose(AstrometryTransform const &left, AstrometryTransform const &right)
Returns a pointer to a composition of transforms, representing left(right()).
std::list< Segment >::const_iterator SegmentCIterator
std::list< Segment >::iterator SegmentIterator
SegmentPairList::const_iterator SegmentPairListCIterator
std::unique_ptr< StarMatchList > listMatchCollect(const BaseStarList &list1, const BaseStarList &list2, const AstrometryTransform *guess, double maxDist)
assembles star matches.
BaseStarList::const_iterator BaseStarCIterator
double computeChi2(const StarMatchList &L, const AstrometryTransform &transform)
the actual chi2
std::unique_ptr< StarMatchList > matchSearchRotShift(BaseStarList &list1, BaseStarList &list2, const MatchConditions &conditions)
searches a geometrical transformation that goes from list1 to list2.
StarList< BaseStar > BaseStarList
std::unique_ptr< StarMatchList > matchSearchRotShiftFlip(BaseStarList &list1, BaseStarList &list2, const MatchConditions &conditions)
same as above but searches also a flipped solution.
std::unique_ptr< AstrometryTransformLinear > listMatchupShift(const BaseStarList &list1, const BaseStarList &list2, const AstrometryTransform &transform, double maxShift, double binSize=0)
searches for a 2 dimensional shift using a very crude histogram method.
SegmentPairList::iterator SegmentPairListIterator
Segment push_back(Segment ... args)
Segment sort(Segment ... args)
Parameters to be provided to combinatorial searches.
std::shared_ptr< const BaseStar > s1
double relativeAngle(Segment *other) const
Segment(std::shared_ptr< const BaseStar > star1, std::shared_ptr< const BaseStar > star2, const int star1Rank, const AstrometryTransform &transform)
friend std::ostream & operator<<(std::ostream &stream, const Segment &segment)
std::shared_ptr< const BaseStar > s2
SegmentPair(Segment *f, Segment *s)