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;
243 for (
int iteration = 0; iteration <
conditions.maxTrialCount; iteration++) {
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.");
Fast locator in starlists.
table::Key< double > angle
Combinatorial searches for linear transformations to go from list1 to list2.
#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...)
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::unique_ptr< AstrometryTransform > listMatchRefine(const BaseStarList &list1, const BaseStarList &list2, std::unique_ptr< AstrometryTransform > transform, int maxOrder=3)
std::list< Segment >::const_iterator SegmentCIterator
BaseStarList::const_iterator BaseStarCIterator
std::list< std::unique_ptr< StarMatchList > > SolList
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::unique_ptr< StarMatchList > listMatchCollect(const BaseStarList &list1, const BaseStarList &list2, const AstrometryTransform *guess, double maxDist)
assembles star matches.
StarList< BaseStar > BaseStarList
double computeChi2(const StarMatchList &L, const AstrometryTransform &transform)
the actual chi2
SegmentPairList::const_iterator SegmentPairListCIterator
std::unique_ptr< StarMatchList > matchSearchRotShift(BaseStarList &list1, BaseStarList &list2, const MatchConditions &conditions)
searches a geometrical transformation that goes from list1 to list2.
std::unique_ptr< StarMatchList > matchSearchRotShiftFlip(BaseStarList &list1, BaseStarList &list2, const MatchConditions &conditions)
same as above but searches also a flipped solution.
std::list< Segment >::iterator SegmentIterator
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)