LSSTApplications  11.0-24-g0a022a1,14.0+77,15.0,15.0+1
LSSTDataManagementBasePackage
Gtransfo.cc
Go to the documentation of this file.
1 #include <iostream>
2 #include <iomanip>
3 #include <iterator> /* for ostream_iterator */
4 #include <math.h> // for sin and cos and may be others
5 #include <fstream>
6 #include "assert.h"
7 #include <sstream>
8 
9 #include "Eigen/Core"
10 
11 #include "lsst/log/Log.h"
12 #include "lsst/afw/geom/Point.h"
13 #include "lsst/jointcal/Gtransfo.h"
14 #include "lsst/jointcal/Frame.h"
16 #include "lsst/pex/exceptions.h"
17 #include "Eigen/Cholesky"
18 
20 
21 using namespace std;
22 
23 namespace {
24 LOG_LOGGER _log = LOG_GET("jointcal.Gtransfo");
25 }
26 
27 namespace lsst {
28 namespace jointcal {
29 
31  return (dynamic_cast<const GtransfoIdentity *>(gtransfo) != nullptr);
32 }
33 
35  const GtransfoPoly *shift = dynamic_cast<const GtransfoPoly *>(gtransfo);
36  if (shift == nullptr) return false;
37 
38  static const double eps = 1e-5;
39 
40  double dx = shift->coeff(0, 0, 0);
41  double dy = shift->coeff(0, 0, 1);
42 
43  static Point dumb(4000, 4000);
44  if (fabs(dx - int(floor(dx + 0.5))) < eps && fabs(dy - int(floor(dy + 0.5))) < eps &&
45  fabs(dumb.x + dx - shift->apply(dumb).x) < eps && fabs(dumb.y + dy - shift->apply(dumb).y) < eps)
46  return true;
47 
48  return false;
49 }
50 
51 /********* Gtransfo ***********************/
52 
53 std::unique_ptr<Gtransfo> Gtransfo::reduceCompo(const Gtransfo *) const { // by default no way to compose
54  return std::unique_ptr<Gtransfo>(nullptr);
55 }
56 
57 double Gtransfo::getJacobian(const double x, const double y) const {
58  double x2, y2;
59  double eps = x * 0.01;
60  if (eps == 0) eps = 0.01;
61  apply(x, y, x2, y2);
62  double dxdx, dydx;
63  apply(x + eps, y, dxdx, dydx);
64  dxdx -= x2;
65  dydx -= y2;
66  double dxdy, dydy;
67  apply(x, y + eps, dxdy, dydy);
68  dxdy -= x2;
69  dydy -= y2;
70  return ((dxdx * dydy - dxdy * dydx) / (eps * eps));
71 }
72 
76 void Gtransfo::computeDerivative(const Point &where, GtransfoLin &derivative, const double step) const {
77  double x = where.x;
78  double y = where.y;
79  double xp0, yp0;
80  apply(x, y, xp0, yp0);
81 
82  double xp, yp;
83  apply(x + step, y, xp, yp);
84  derivative.a11() = (xp - xp0) / step;
85  derivative.a21() = (yp - yp0) / step;
86  apply(x, y + step, xp, yp);
87  derivative.a12() = (xp - xp0) / step;
88  derivative.a22() = (yp - yp0) / step;
89  derivative.dx() = 0;
90  derivative.dy() = 0;
91 }
92 
93 GtransfoLin Gtransfo::linearApproximation(const Point &where, const double step) const {
94  Point outwhere = apply(where);
95  GtransfoLin der;
96  computeDerivative(where, der, step);
97  return GtransfoLinShift(outwhere.x, outwhere.y) * der * GtransfoLinShift(-where.x, -where.y);
98 }
99 
100 void Gtransfo::transformPosAndErrors(const FatPoint &in, FatPoint &out) const {
101  FatPoint res; // in case in and out are the same address...
102  res = apply(in);
103  GtransfoLin der;
104  // could save a call here, since Derivative needs the transform of where that we already have
105  // 0.01 may not be a very good idea in all cases. May be we should provide a way of altering that.
106  computeDerivative(in, der, 0.01);
107  double a11 = der.A11();
108  double a22 = der.A22();
109  double a21 = der.A21();
110  double a12 = der.A12();
111  res.vx = a11 * (a11 * in.vx + 2 * a12 * in.vxy) + a12 * a12 * in.vy;
112  res.vy = a21 * a21 * in.vx + a22 * a22 * in.vy + 2. * a21 * a22 * in.vxy;
113  res.vxy = a21 * a11 * in.vx + a22 * a12 * in.vy + (a21 * a12 + a11 * a22) * in.vxy;
114  out = res;
115 }
116 
117 void Gtransfo::transformErrors(const Point &where, const double *vIn, double *vOut) const {
118  GtransfoLin der;
119  computeDerivative(where, der, 0.01);
120  double a11 = der.A11();
121  double a22 = der.A22();
122  double a21 = der.A21();
123  double a12 = der.A12();
124 
125  /* (a11 a12) (vxx vxy)
126  M = ( ) and V = ( )
127  (a21 a22) (xvy vyy)
128 
129  Vxx = Vin[0], vyy = Vin[1], Vxy = Vin[2];
130  we want to compute M*V*tp(M)
131  A lin alg light package would be perfect...
132  */
133  int xx = 0;
134  int yy = 1;
135  int xy = 2;
136  // M*V :
137 
138  double b11 = a11 * vIn[xx] + a12 * vIn[xy];
139  double b22 = a21 * vIn[xy] + a22 * vIn[yy];
140  double b12 = a11 * vIn[xy] + a12 * vIn[yy];
141  double b21 = a21 * vIn[xx] + a22 * vIn[xy];
142 
143  // (M*V) * tp(M)
144 
145  vOut[xx] = b11 * a11 + b12 * a12;
146  vOut[xy] = b11 * a21 + b12 * a22;
147  vOut[yy] = b21 * a21 + b22 * a22;
148 }
149 
150 std::unique_ptr<Gtransfo> Gtransfo::roughInverse(const Frame &region) const {
151  // "in" and "out" refer to the inverse direction.
152  Point centerOut = region.getCenter();
153  Point centerIn = apply(centerOut);
154  GtransfoLin der;
155  computeDerivative(centerOut, der, sqrt(region.getArea()) / 5.);
156  der = der.invert();
157  der = GtransfoLinShift(centerOut.x, centerOut.y) * der * GtransfoLinShift(-centerIn.x, -centerIn.y);
158  return std::unique_ptr<Gtransfo>(new GtransfoLin(der));
159 }
160 
161 /* implement one in Gtransfo, so that all derived
162  classes do not need to provide one... */
163 
164 /* the routines that follow are used for ea generic parameter
165  transformation serialization, used e.g. for fits. Enables
166  to manipulate transformation parameters as vectors.
167 */
168 
169 // not dummy : what it does is virtual because paramRef is virtual.
170 void Gtransfo::getParams(double *params) const {
171  int npar = getNpar();
172  for (int i = 0; i < npar; ++i) params[i] = paramRef(i);
173 }
174 
175 void Gtransfo::offsetParams(Eigen::VectorXd const &delta) {
176  int npar = getNpar();
177  for (int i = 0; i < npar; ++i) paramRef(i) += delta[i];
178 }
179 
180 double Gtransfo::paramRef(const int) const {
182  std::string("Gtransfo::paramRef should never be called "));
183 }
184 
185 double &Gtransfo::paramRef(const int) {
186  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, "Gtransfo::paramRef should never be called ");
187 }
188 
189 void Gtransfo::paramDerivatives(const Point &, double *, double *) const {
191  "Gtransfo::paramDerivatives() should never be called ");
192 }
193 
195  gtransfo.dump(stream);
196  return stream;
197 }
198 
199 void Gtransfo::write(const std::string &fileName) const {
200  ofstream s(fileName.c_str());
201  write(s);
202  bool ok = !s.fail();
203  s.close();
204  if (!ok)
206  "Gtransfo::write, something went wrong for file " + fileName);
207 }
208 
209 void Gtransfo::write(ostream &stream) const {
211  "Gtransfo::write(ostream), should never be called. MEans that it is missing in some "
212  "derived class ");
213 }
214 
215 /******************* GTransfoInverse ****************/
216 /* inverse transformation, solved by iterations. Before using
217  it (probably via Gtransfo::inverseTransfo), consider
218  seriously StarMatchList::inverseTransfo */
219 class GtransfoInverse : public Gtransfo {
220 private:
223  double precision2;
224 
225 public:
226  GtransfoInverse(const Gtransfo *direct, const double precision, const Frame &region);
227 
230  void apply(const double xIn, const double yIn, double &xOut, double &yOut) const;
231 
232  void dump(ostream &stream) const;
233 
234  double fit(const StarMatchList &starMatchList);
235 
236  virtual std::unique_ptr<Gtransfo> clone() const;
237 
239 
241  std::unique_ptr<Gtransfo> roughInverse(const Frame &) const { return _direct->clone(); }
242 
244  std::unique_ptr<Gtransfo> inverseTransfo(double, const Frame &) const { return _direct->clone(); }
245 
246  ~GtransfoInverse();
247 
248 private:
249  void operator=(const GtransfoInverse &);
250 };
251 
252 std::unique_ptr<Gtransfo> Gtransfo::inverseTransfo(const double precision, const Frame &region) const {
253  return std::unique_ptr<Gtransfo>(new GtransfoInverse(this, precision, region));
254 }
255 
256 GtransfoInverse::GtransfoInverse(const Gtransfo *direct, const double precision, const Frame &region) {
257  _direct = direct->clone();
258  _roughInverse = _direct->roughInverse(region);
259  precision2 = precision * precision;
260 }
261 
262 GtransfoInverse::GtransfoInverse(const GtransfoInverse &model) : Gtransfo() {
263  _direct = model._direct->clone();
264  _roughInverse = model._roughInverse->clone();
265  precision2 = model.precision2;
266 }
267 
269 
271  _direct = model._direct->clone();
272  _roughInverse = model._roughInverse->clone();
273  precision2 = model.precision2;
274 }
275 
276 void GtransfoInverse::apply(const double xIn, const double yIn, double &xOut, double &yOut) const {
277  Point in(xIn, yIn);
278  Point outGuess = _roughInverse->apply(in);
279  GtransfoLin directDer, reverseDer;
280  int loop = 0;
281  int maxloop = 20;
282  double move2;
283  do {
284  loop++;
285  Point inGuess = _direct->apply(outGuess);
286  _direct->computeDerivative(outGuess, directDer);
287  reverseDer = directDer.invert();
288  double xShift, yShift;
289  reverseDer.apply(xIn - inGuess.x, yIn - inGuess.y, xShift, yShift);
290  outGuess.x += xShift;
291  outGuess.y += yShift;
292  move2 = xShift * xShift + yShift * yShift;
293  } while ((move2 > precision2) && (loop < maxloop));
294  if (loop == maxloop) LOGLS_WARN(_log, "Problems applying GtransfoInverse at " << in);
295  xOut = outGuess.x;
296  yOut = outGuess.y;
297 }
298 
300  stream << " GtransfoInverse of :" << endl << *_direct << endl;
301 }
302 
304  throw pexExcept::RuntimeError("Cannot fit a GtransfoInverse. Use StarMatchList::inverseTransfo instead.");
305 }
306 
308  return std::unique_ptr<Gtransfo>(new GtransfoInverse(*this));
309 }
310 
311 /************* GtransfoComposition **************/
312 
313 // This class was done to allow composition of Gtransfo's, without specifications of their types.
314 // does not need to be public. Invoked by gtransfoCompose(left,right)
315 
319 private:
321 
322 public:
325 
327  void apply(const double xIn, const double yIn, double &xOut, double &yOut) const;
328  void dump(ostream &stream = cout) const;
329 
331  double fit(const StarMatchList &starMatchList);
332 
335 };
336 
338  _first = first->clone();
339  _second = second->clone();
340 }
341 
342 void GtransfoComposition::apply(const double xIn, const double yIn, double &xOut, double &yOut) const {
343  double xout, yout;
344  _first->apply(xIn, yIn, xout, yout);
345  _second->apply(xout, yout, xOut, yOut);
346 }
347 
349  _first->dump(stream);
350  _second->dump(stream);
351 }
352 
353 double GtransfoComposition::fit(const StarMatchList &starMatchList) {
354  /* fits only one of them. could check that first can actually be fitted... */
355  return _first->fit(starMatchList);
356 }
357 
359  return std::unique_ptr<Gtransfo>(new GtransfoComposition(_second.get(), _first.get()));
360 }
361 
363 
369  /* is right Identity ? if left is Identity , GtransfoIdentity::reduceCompo does the right job */
370  if (isIdentity(right)) {
371  return left->clone();
372  }
373  /* Try to use the reduceCompo method from left. If absent,
374  Gtransfo::reduceCompo return NULL. reduceCompo is non trivial for
375  polynomials */
376  std::unique_ptr<Gtransfo> composition(left->reduceCompo(right));
377  /* composition == NULL means no reduction : just build a Composition
378  that pipelines "left" and "right" */
379  if (composition == nullptr)
380  return std::unique_ptr<Gtransfo>(new GtransfoComposition(left, right));
381  else
382  return composition;
383 }
384 
385 // just a speed up, to avoid useless numerical derivation.
386 void GtransfoIdentity::computeDerivative(const Point &, GtransfoLin &derivative, const double) const {
387  derivative = GtransfoLin();
388 }
389 
391  GtransfoLin result;
392  return result; // rely on default Gtransfolin constructor;
393 }
394 
395 void GtransfoIdentity::write(ostream &stream) const { stream << "GtransfoIdentity 1" << endl; }
396 
398  int format;
399  stream >> format;
400  if (format != 1)
402  " GtransfoIdentity::read : format is not 1 ");
403 }
404 
405 /*************** GtransfoPoly **************************************/
406 
408 
409 GtransfoPoly::GtransfoPoly(const unsigned degree) : _degree(degree) {
410  _nterms = (degree + 1) * (degree + 2) / 2;
411 
412  // allocate and fill coefficients
413  _coeffs.resize(2 * _nterms, 0.);
414  // the default is supposed to be the identity, (for degree>=1).
415  if (_degree >= 1) {
416  coeff(1, 0, 0) = 1;
417  coeff(0, 1, 1) = 1;
418  }
419 }
420 
421 //#ifdef TO_BE_FIXED
422 GtransfoPoly::GtransfoPoly(const Gtransfo *gtransfo, const Frame &frame, unsigned degree, unsigned nPoint) {
423  StarMatchList sm;
424 
425  double step = sqrt(fabs(frame.getArea()) / double(nPoint));
426  for (double x = frame.xMin + step / 2; x <= frame.xMax; x += step)
427  for (double y = frame.yMin + step / 2; y <= frame.yMax; y += step) {
428  auto pix = std::make_shared<BaseStar>(x, y, 0, 0);
429  double xtr, ytr;
430  gtransfo->apply(x, y, xtr, ytr);
431  auto tp = std::make_shared<BaseStar>(xtr, ytr, 0, 0);
432  /* These are fake stars so no need to transform fake errors.
433  all errors (and weights) will be equal : */
434  sm.push_back(StarMatch(*pix, *tp, pix, tp));
435  }
436  GtransfoPoly ret(degree);
437  ret.fit(sm);
438  *this = ret;
439 }
440 //#endif
441 
442 void GtransfoPoly::computeMonomials(double xIn, double yIn, double *monomial) const {
443  /* The ordering of monomials is implemented here.
444  You may not change it without updating the "mapping" routines
445  coeff(unsigned, unsigned, unsigned).
446  I (P.A.) did not find a clever way to loop over monomials.
447  Improvements welcome.
448  This routine is used also by the fit to fill monomials.
449  We could certainly be more elegant.
450  */
451 
452  double xx = 1;
453  for (unsigned ix = 0; ix <= _degree; ++ix) {
454  double yy = 1;
455  unsigned k = ix * (ix + 1) / 2;
456  for (unsigned iy = 0; iy <= _degree - ix; ++iy) {
457  monomial[k] = xx * yy;
458  yy *= yIn;
459  k += ix + iy + 2;
460  }
461  xx *= xIn;
462  }
463 }
464 
465 void GtransfoPoly::setDegree(const unsigned degree) {
466  _degree = degree;
467  unsigned old_nterms = _nterms;
468  _nterms = (_degree + 1) * (_degree + 2) / 2;
469 
470  // temporarily save coefficients
471  vector<double> old_coeffs = _coeffs;
472  // reallocate enough size
473  _coeffs.resize(2 * _nterms);
474  // reassign to zero (this is necessary because ycoeffs
475  // are after xcoeffs and so their meaning changes
476  for (unsigned k = 0; k < _nterms; ++k) _coeffs[k] = 0;
477  // put back what we had before
478  unsigned kmax = min(old_nterms, _nterms);
479  for (unsigned k = 0; k < kmax; ++k) {
480  _coeffs[k] = old_coeffs[k]; // x terms
481  _coeffs[k + _nterms] = old_coeffs[k + old_nterms]; // y terms
482  }
483 }
484 
485 /* this is reasonably fast, when optimized */
486 void GtransfoPoly::apply(const double xIn, const double yIn, double &xOut, double &yOut) const {
487  /*
488  This routine computes the monomials only once for both
489  polynomials. This is why GtransfoPoly does not use an auxilary
490  class (such as PolyXY) to handle each polynomial.
491 
492  The code works even if &xIn == &xOut (or &yIn == &yOut)
493  It uses Variable Length Allocation (VLA) rather than a vector<double>
494  because allocating the later costs about 50 ns. All VLA uses are tagged.
495  */
496  double monomials[_nterms]; // this is VLA, which is (perhaps) not casher C++
497  computeMonomials(xIn, yIn, monomials);
498 
499  xOut = 0;
500  yOut = 0;
501  const double *c = &_coeffs[0];
502  const double *pm = &monomials[0];
503  // the ordering of the coefficients and the monomials are identical.
504  for (int k = _nterms; k--;) xOut += (*(pm++)) * (*(c++));
505  pm = &monomials[0];
506  for (int k = _nterms; k--;) yOut += (*(pm++)) * (*(c++));
507 }
508 
509 void GtransfoPoly::computeDerivative(const Point &where, GtransfoLin &derivative, const double step)
510  const { /* routine checked against numerical derivatives from Gtransfo::Derivative */
511  if (_degree == 1) {
512  derivative = GtransfoLin(*this);
513  derivative.dx() = derivative.dy() = 0;
514  return;
515  }
516 
517  double dermx[2 * _nterms]; // VLA
518  double *dermy = dermx + _nterms;
519  double xin = where.x;
520  double yin = where.y;
521 
522  double xx = 1;
523  double xxm1 = 1; // xx^(ix-1)
524  for (unsigned ix = 0; ix <= _degree; ++ix) {
525  unsigned k = (ix) * (ix + 1) / 2;
526  // iy = 0
527  dermx[k] = ix * xxm1;
528  dermy[k] = 0;
529  k += ix + 2;
530  double yym1 = 1; // yy^(iy-1)
531  for (unsigned iy = 1; iy <= _degree - ix; ++iy) {
532  dermx[k] = ix * xxm1 * yym1 * yin;
533  dermy[k] = iy * xx * yym1;
534  yym1 *= yin;
535  k += ix + iy + 2;
536  }
537  xx *= xin;
538  if (ix >= 1) xxm1 *= xin;
539  }
540 
541  derivative.dx() = 0;
542  derivative.dy() = 0;
543 
544  const double *mx = &dermx[0];
545  const double *my = &dermy[0];
546  const double *c = &_coeffs[0];
547  // dx'
548  double a11 = 0, a12 = 0;
549  for (int k = _nterms; k--;) {
550  a11 += (*(mx++)) * (*c);
551  a12 += (*(my++)) * (*(c++));
552  }
553  derivative.a11() = a11;
554  derivative.a12() = a12;
555  // dy'
556  double a21 = 0, a22 = 0;
557  mx = &dermx[0];
558  my = &dermy[0];
559  for (int k = _nterms; k--;) {
560  a21 += (*(mx++)) * (*c);
561  a22 += (*(my++)) * (*(c++));
562  }
563  derivative.a21() = a21;
564  derivative.a22() = a22;
565 }
566 
568  /*
569  The results from this routine were compared to what comes out
570  from apply and transformErrors. The Derivative routine was
571  checked against numerical derivatives from
572  Gtransfo::Derivative. (P.A dec 2009).
573 
574  This routine could be made much simpler by calling apply and
575  Derivative (i.e. you just suppress it, and the fallback is the
576  generic version in Gtransfo). BTW, I checked that both routines
577  provide the same result. This version is however faster
578  (monomials get recycled).
579  */
580  double monomials[_nterms]; // VLA
581 
582  FatPoint res; // to store the result, because nothing forbids &in == &out.
583 
584  double dermx[2 * _nterms]; // monomials for derivative w.r.t. x (VLA)
585  double *dermy = dermx + _nterms; // same for y
586  double xin = in.x;
587  double yin = in.y;
588 
589  double xx = 1;
590  double xxm1 = 1; // xx^(ix-1)
591  for (unsigned ix = 0; ix <= _degree; ++ix) {
592  unsigned k = (ix) * (ix + 1) / 2;
593  // iy = 0
594  dermx[k] = ix * xxm1;
595  dermy[k] = 0;
596  monomials[k] = xx;
597  k += ix + 2;
598  double yy = yin;
599  double yym1 = 1; // yy^(iy-1)
600  for (unsigned iy = 1; iy <= _degree - ix; ++iy) {
601  monomials[k] = xx * yy;
602  dermx[k] = ix * xxm1 * yy;
603  dermy[k] = iy * xx * yym1;
604  yym1 *= yin;
605  yy *= yin;
606  k += ix + iy + 2;
607  }
608  xx *= xin;
609  if (ix >= 1) xxm1 *= xin;
610  }
611 
612  // output position
613  double xout = 0, yout = 0;
614  const double *c = &_coeffs[0];
615  const double *pm = &monomials[0];
616  for (int k = _nterms; k--;) xout += (*(pm++)) * (*(c++));
617  pm = &monomials[0];
618  for (int k = _nterms; k--;) yout += (*(pm++)) * (*(c++));
619  res.x = xout;
620  res.y = yout;
621 
622  // derivatives
623  c = &_coeffs[0];
624  const double *mx = &dermx[0];
625  const double *my = &dermy[0];
626  double a11 = 0, a12 = 0;
627  for (int k = _nterms; k--;) {
628  a11 += (*(mx++)) * (*c);
629  a12 += (*(my++)) * (*(c++));
630  }
631 
632  double a21 = 0, a22 = 0;
633  mx = &dermx[0];
634  my = &dermy[0];
635  for (int k = _nterms; k--;) {
636  a21 += (*(mx++)) * (*c);
637  a22 += (*(my++)) * (*(c++));
638  }
639 
640  // output co-variance
641  res.vx = a11 * (a11 * in.vx + 2 * a12 * in.vxy) + a12 * a12 * in.vy;
642  res.vy = a21 * a21 * in.vx + a22 * a22 * in.vy + 2. * a21 * a22 * in.vxy;
643  res.vxy = a21 * a11 * in.vx + a22 * a12 * in.vy + (a21 * a12 + a11 * a22) * in.vxy;
644  out = res;
645 }
646 
647 /* The coefficient ordering is defined both here *AND* in the
648  GtransfoPoly::apply, GtransfoPoly::Derivative, ... routines
649  Change all or none ! */
650 
651 double GtransfoPoly::coeff(const unsigned degX, const unsigned degY, const unsigned whichCoord) const {
652  assert((degX + degY <= _degree) && whichCoord < 2);
653  /* this assertion above is enough to ensure that the index used just
654  below is within bounds since the reserved length is
655  2*_nterms=(degree+1)*(degree+2) */
656  return _coeffs[(degX + degY) * (degX + degY + 1) / 2 + degY + whichCoord * _nterms];
657 }
658 
659 double &GtransfoPoly::coeff(const unsigned degX, const unsigned degY, const unsigned whichCoord) {
660  assert((degX + degY <= _degree) && whichCoord < 2);
661  return _coeffs[(degX + degY) * (degX + degY + 1) / 2 + degY + whichCoord * _nterms];
662 }
663 
664 double GtransfoPoly::coeffOrZero(const unsigned degX, const unsigned degY, const unsigned whichCoord) const {
665  // assert((degX+degY<=degree) && whichCoord<2);
666  assert(whichCoord < 2);
667  if (degX + degY <= _degree)
668  return _coeffs[(degX + degY) * (degX + degY + 1) / 2 + degY + whichCoord * _nterms];
669  return 0;
670 }
671 
672 /* parameter serialization for "virtual" fits */
673 double GtransfoPoly::paramRef(const int i) const {
674  assert(unsigned(i) < 2 * _nterms);
675  return _coeffs[i];
676 }
677 
678 double &GtransfoPoly::paramRef(const int i) {
679  assert(unsigned(i) < 2 * _nterms);
680  return _coeffs[i];
681 }
682 
683 void GtransfoPoly::paramDerivatives(const Point &where, double *dx, double *dy)
684  const { /* first half : dxout/dpar, second half : dyout/dpar */
685  computeMonomials(where.x, where.y, dx);
686  for (unsigned k = 0; k < _nterms; ++k) {
687  dy[_nterms + k] = dx[k];
688  dx[_nterms + k] = dy[k] = 0;
689  }
690 }
691 
692 /* utility for the dump(ostream&) routine */
693 static string monomialString(const unsigned powX, const unsigned powY) {
694  stringstream ss;
695  if (powX + powY) ss << "*";
696  if (powX > 0) ss << "x";
697  if (powX > 1) ss << "^" << powX;
698  if (powY > 0) ss << "y";
699  if (powY > 1) ss << "^" << powY;
700  return ss.str();
701 }
702 
704  for (unsigned ic = 0; ic < 2; ++ic) {
705  if (ic == 0)
706  stream << "newx = ";
707  else
708  stream << "newy = ";
709  for (unsigned p = 0; p <= _degree; ++p)
710  for (unsigned py = 0; py <= p; ++py) {
711  if (p + py != 0) stream << " + ";
712  stream << coeff(p - py, py, ic) << monomialString(p - py, py);
713  }
714  stream << endl;
715  }
716  if (_degree > 0) stream << " Linear determinant = " << determinant() << endl;
717 }
718 
720  if (_degree >= 1) return coeff(1, 0, 0) * coeff(0, 1, 1) - coeff(0, 1, 0) * coeff(1, 0, 1);
721  return 0;
722 }
723 
726  Point center = frame.getCenter();
727  return GtransfoLinScale(2. / frame.getWidth(), 2. / frame.getHeight()) *
728  GtransfoLinShift(-center.x, -center.y);
729 }
730 
731 /*utility for the GtransfoPoly::fit() routine */
732 static GtransfoLin shiftAndNormalize(const StarMatchList &starMatchList) {
733  double xav = 0;
734  double x2 = 0;
735  double yav = 0;
736  double y2 = 0;
737  double count = 0;
738  for (auto it = starMatchList.begin(); it != starMatchList.end(); ++it) {
739  const StarMatch &a_match = *it;
740  const Point &point1 = a_match.point1;
741  xav += point1.x;
742  yav += point1.y;
743  x2 += std::pow(point1.x, 2);
744  y2 += std::pow(point1.y, 2);
745  count++;
746  }
747  if (count == 0) return GtransfoLin();
748  xav /= count;
749  yav /= count;
750  // 3.5 stands for sqrt(12).
751  double xspan = 3.5 * sqrt(x2 / count - std::pow(xav, 2));
752  double yspan = 3.5 * sqrt(y2 / count - std::pow(yav, 2));
753  return GtransfoLinScale(2. / xspan, 2. / yspan) * GtransfoLinShift(-xav, -yav);
754 }
755 
756 static double sq(double x) { return x * x; }
757 
758 double GtransfoPoly::computeFit(const StarMatchList &starMatchList, const Gtransfo &shiftToCenter,
759  const bool useErrors) {
760  Eigen::MatrixXd A(2 * _nterms, 2 * _nterms);
761  A.setZero();
762  Eigen::VectorXd B(2 * _nterms);
763  B.setZero();
764  double sumr2 = 0;
765  double monomials[_nterms];
766  for (auto it = starMatchList.begin(); it != starMatchList.end(); ++it) {
767  const StarMatch &a_match = *it;
768  Point tmp = shiftToCenter.apply(a_match.point1);
769  FatPoint point1(tmp, a_match.point1.vx, a_match.point1.vy, a_match.point1.vxy);
770  const FatPoint &point2 = a_match.point2;
771  double wxx, wyy, wxy;
772  FatPoint tr1;
773  computeMonomials(point1.x, point1.y, monomials);
774  if (useErrors) {
775  transformPosAndErrors(point1, tr1); // we might consider recycling the monomials
776  double vxx = (tr1.vx + point2.vx);
777  double vyy = (tr1.vy + point2.vy);
778  double vxy = (tr1.vxy + point2.vxy);
779  double det = vxx * vyy - vxy * vxy;
780  wxx = vyy / det;
781  wyy = vxx / det;
782  wxy = -vxy / det;
783  } else {
784  wxx = wyy = 1;
785  wxy = 0;
786  apply(point1.x, point1.y, tr1.x, tr1.y);
787  }
788  double resx = point2.x - tr1.x;
789  double resy = point2.y - tr1.y;
790  sumr2 += wxx * sq(resx) + wyy * sq(resy) + 2 * wxy * resx * resy;
791 
792  double bxcoeff = wxx * resx + wxy * resy;
793  double bycoeff = wyy * resy + wxy * resx;
794  for (unsigned j = 0; j < _nterms; ++j) {
795  for (unsigned i = j; i < _nterms; ++i) {
796  A(i, j) += wxx * monomials[i] * monomials[j];
797  A(i + _nterms, j + _nterms) += wyy * monomials[i] * monomials[j];
798  A(j, i + _nterms) = A(i, j + _nterms) += wxy * monomials[i] * monomials[j];
799  }
800  B(j) += bxcoeff * monomials[j];
801  B(j + _nterms) += bycoeff * monomials[j];
802  }
803  } // end loop on points
804  Eigen::LDLT<Eigen::MatrixXd, Eigen::Lower> factor(A);
805  // should probably throw
806  if (factor.info() != Eigen::Success) {
807  LOGL_ERROR(_log, "GtransfoPoly::fit could not factorize");
808  return -1;
809  }
810 
811  Eigen::VectorXd sol = factor.solve(B);
812  for (unsigned k = 0; k < 2 * _nterms; ++k) _coeffs[k] += sol(k);
813  if (starMatchList.size() == _nterms) return 0;
814  return (sumr2 - B.dot(sol));
815 }
816 
817 double GtransfoPoly::fit(const StarMatchList &starMatchList) {
818  if (starMatchList.size() < _nterms) {
819  LOGLS_FATAL(_log, "GtransfoPoly::fit trying to fit a polynomial transfo of degree "
820  << _degree << " with only " << starMatchList.size() << " matches.");
821  return -1;
822  }
823 
824  GtransfoPoly conditionner = shiftAndNormalize(starMatchList);
825 
826  computeFit(starMatchList, conditionner, false); // get a rough solution
827  computeFit(starMatchList, conditionner, true); // weight with it
828  double chi2 = computeFit(starMatchList, conditionner, true); // once more
829 
830  (*this) = (*this) * conditionner;
831  if (starMatchList.size() == _nterms) return 0;
832  return chi2;
833 }
834 
836  const GtransfoPoly *p = dynamic_cast<const GtransfoPoly *>(right);
837  if (p) {
838  if (getDegree() == 1 && p->getDegree() == 1)
839  return std::unique_ptr<Gtransfo>(new GtransfoLin((*this) * (*p))); // does the composition
840  else
841  return std::unique_ptr<Gtransfo>(new GtransfoPoly((*this) * (*p))); // does the composition
842  } else
843  return std::unique_ptr<Gtransfo>(nullptr);
844 }
845 
846 /* PolyXY the class used to perform polynomial algebra (and in
847  particular composition) at the coefficient level. This class
848  handles a single polynomial, while a GtransfoPoly is a couple of
849  polynomials. This class does not have any routine to evaluate
850  polynomials. Efficiency is not a concern since these routines are
851  seldom used. There is no need to expose this tool class to
852  Gtransfo users.
853 */
854 
855 class PolyXY {
856  unsigned degree;
857  unsigned nterms;
859 
860 public:
861  PolyXY(const int degree) : degree(degree), nterms((degree + 1) * (degree + 2) / 2) {
862  coeffs.reserve(nterms);
863  coeffs.insert(coeffs.begin(), nterms, 0L); // fill & initialize to 0.
864  }
865 
866  unsigned getDegree() const { return degree; }
867 
868  PolyXY(const GtransfoPoly &gtransfoPoly, const unsigned whichCoord)
869  : degree(gtransfoPoly.getDegree()), nterms((degree + 1) * (degree + 2) / 2), coeffs(nterms, 0L) {
870  for (unsigned px = 0; px <= degree; ++px)
871  for (unsigned py = 0; py <= degree - px; ++py)
872  coeff(px, py) = gtransfoPoly.coeff(px, py, whichCoord);
873  }
874 
875  long double coeff(const unsigned powX, const unsigned powY) const {
876  assert(powX + powY <= degree);
877  return coeffs.at((powX + powY) * (powX + powY + 1) / 2 + powY);
878  }
879 
880  long double &coeff(const unsigned powX, const unsigned powY) {
881  assert(powX + powY <= degree);
882  return coeffs.at((powX + powY) * (powX + powY + 1) / 2 + powY);
883  }
884 };
885 
886 /* ===================== PolyXY Algebra routines ================== */
887 
888 static void operator+=(PolyXY &left, const PolyXY &right) {
889  unsigned rdeg = right.getDegree();
890  assert(left.getDegree() >= rdeg);
891  for (unsigned i = 0; i <= rdeg; ++i)
892  for (unsigned j = 0; j <= rdeg - i; ++j) left.coeff(i, j) += right.coeff(i, j);
893 }
894 
895 /* multiplication by a scalar */
896 static PolyXY operator*(const long double &a, const PolyXY &polyXY) {
897  PolyXY result(polyXY);
898  // no direct access to coefficients: do it the soft way
899  unsigned degree = polyXY.getDegree();
900  for (unsigned i = 0; i <= degree; ++i)
901  for (unsigned j = 0; j <= degree - i; ++j) result.coeff(i, j) *= a;
902  return result;
903 }
904 
906 static PolyXY product(const PolyXY &p1, const PolyXY &p2) {
907  unsigned deg1 = p1.getDegree();
908  unsigned deg2 = p2.getDegree();
909  PolyXY result(deg1 + deg2);
910  for (unsigned i1 = 0; i1 <= deg1; ++i1)
911  for (unsigned j1 = 0; j1 <= deg1 - i1; ++j1)
912  for (unsigned i2 = 0; i2 <= deg2; ++i2)
913  for (unsigned j2 = 0; j2 <= deg2 - i2; ++j2)
914  result.coeff(i1 + i2, j1 + j2) += p1.coeff(i1, j1) * p2.coeff(i2, j2);
915  return result;
916 }
917 
918 /* powers[k](x,y) = polyXY(x,y)**k, 0 <= k <= maxP */
919 static void computePowers(const PolyXY &polyXY, const unsigned maxP, vector<PolyXY> &powers) {
920  powers.reserve(maxP + 1);
921  powers.push_back(PolyXY(0));
922  powers[0].coeff(0, 0) = 1L;
923  for (unsigned k = 1; k <= maxP; ++k) powers.push_back(product(powers[k - 1], polyXY));
924 }
925 
927 static PolyXY composition(const PolyXY &polyXY, const PolyXY &polyX, const PolyXY &polyY) {
928  unsigned pdeg = polyXY.getDegree();
929  PolyXY result(pdeg * max(polyX.getDegree(), polyY.getDegree()));
930  vector<PolyXY> pXPowers;
931  vector<PolyXY> pYPowers;
932  computePowers(polyX, pdeg, pXPowers);
933  computePowers(polyY, pdeg, pYPowers);
934  for (unsigned px = 0; px <= pdeg; ++px)
935  for (unsigned py = 0; py <= pdeg - px; ++py)
936  result += polyXY.coeff(px, py) * product(pXPowers.at(px), pYPowers.at(py));
937  return result;
938 }
939 
940 /* ===================== end of PolyXY Algebra routines ============= */
941 
942 /* reducing polynomial composition is the reason for PolyXY stuff : */
943 
945  // split each transfo into 2d polynomials
946  PolyXY plx(*this, 0);
947  PolyXY ply(*this, 1);
948  PolyXY prx(right, 0);
949  PolyXY pry(right, 1);
950 
951  // compute the compositions
952  PolyXY rx(composition(plx, prx, pry));
953  PolyXY ry(composition(ply, prx, pry));
954 
955  // copy the results the hard way.
956  GtransfoPoly result(_degree * right._degree);
957  for (unsigned px = 0; px <= result._degree; ++px)
958  for (unsigned py = 0; py <= result._degree - px; ++py) {
959  result.coeff(px, py, 0) = rx.coeff(px, py);
960  result.coeff(px, py, 1) = ry.coeff(px, py);
961  }
962  return result;
963 }
964 
966  if (_degree >= right._degree) {
967  GtransfoPoly res(*this);
968  for (unsigned i = 0; i <= right._degree; ++i)
969  for (unsigned j = 0; j <= right._degree - i; ++j) {
970  res.coeff(i, j, 0) += right.coeff(i, j, 0);
971  res.coeff(i, j, 1) += right.coeff(i, j, 1);
972  }
973  return res;
974  } else
975  return (right + (*this));
976 }
977 
979  GtransfoPoly res(std::max(_degree, right._degree));
980  for (unsigned i = 0; i <= res._degree; ++i)
981  for (unsigned j = 0; j <= res._degree - i; ++j) {
982  res.coeff(i, j, 0) = coeffOrZero(i, j, 0) - right.coeffOrZero(i, j, 0);
983  res.coeff(i, j, 1) = coeffOrZero(i, j, 1) - right.coeffOrZero(i, j, 1);
984  }
985  return res;
986 }
987 
989  s << " GtransfoPoly 1" << endl;
990  s << "degree " << _degree << endl;
991  int oldprec = s.precision();
992  s << setprecision(12);
993  for (unsigned k = 0; k < 2 * _nterms; ++k) s << _coeffs[k] << ' ';
994  s << endl;
995  s << setprecision(oldprec);
996 }
997 
999  int format;
1000  s >> format;
1001  if (format != 1)
1002  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, " GtransfoPoly::read : format is not 1 ");
1003 
1004  string degree;
1005  s >> degree >> _degree;
1006  if (degree != "degree")
1008  " GtransfoPoly::read : expecting \"degree\" and found " + degree);
1009  setDegree(_degree);
1010  for (unsigned k = 0; k < 2 * _nterms; ++k) s >> _coeffs[k];
1011 }
1012 
1014  const double precision) {
1015  StarMatchList sm;
1016  unsigned nx = 50;
1017  double stepx = frame.getWidth() / (nx + 1);
1018  unsigned ny = 50;
1019  double stepy = frame.getHeight() / (ny + 1);
1020  for (unsigned i = 0; i < nx; ++i)
1021  for (unsigned j = 0; j < ny; ++j) {
1022  Point in((i + 0.5) * stepx, (j + 0.5) * stepy);
1023  Point out(direct.apply(in));
1024  sm.push_back(StarMatch(out, in, nullptr, nullptr));
1025  }
1026  unsigned npairs = sm.size();
1027  int maxdeg = 9;
1028  int degree;
1030  for (degree = 1; degree <= maxdeg; ++degree) {
1031  poly.reset(new GtransfoPoly(degree));
1032  poly->fit(sm);
1033  // compute the chi2 ignoring errors:
1034  double chi2 = 0;
1035  for (auto const &i : sm) chi2 += i.point2.computeDist2(poly->apply((i.point1)));
1036  if (chi2 / npairs < precision * precision) break;
1037  }
1038  if (degree > maxdeg)
1039  LOGLS_WARN(_log, "inversePolyTransfo: Reached max degree without reaching requested precision: "
1040  << precision);
1041  return poly;
1042 }
1043 
1044 /**************** GtransfoLin ***************************************/
1045 /* GtransfoLin is a specialized constructor of GtransfoPoly
1046  May be it could just disappear ??
1047 */
1048 
1049 GtransfoLin::GtransfoLin(const double Dx, const double Dy, const double A11, const double A12,
1050  const double A21, const double A22)
1051  : GtransfoPoly(1) {
1052  dx() = Dx;
1053  a11() = A11;
1054  a12() = A12;
1055  dy() = Dy;
1056  a21() = A21;
1057  a22() = A22;
1058 }
1059 
1061  if (gtransfoPoly.getDegree() != 1)
1063  "Trying to build a GtransfoLin from a higher order transfo. Aborting. ");
1064  (GtransfoPoly &)(*this) = gtransfoPoly;
1065 }
1066 
1068  // There is a general routine in GtransfoPoly that would do the job:
1069  // return GtransfoLin(GtransfoPoly::operator*(right));
1070  // however, we are using this composition of linear stuff heavily in
1071  // Gtransfo::linearApproximation, itself used in inverseTransfo::apply.
1072  // So, for sake of efficiency, and since it is easy, we take a shortcut:
1073  GtransfoLin result;
1074  apply(right.Dx(), right.Dy(), result.dx(), result.dy());
1075  result.a11() = A11() * right.A11() + A12() * right.A21();
1076  result.a12() = A11() * right.A12() + A12() * right.A22();
1077  result.a21() = A21() * right.A11() + A22() * right.A21();
1078  result.a22() = A21() * right.A12() + A22() * right.A22();
1079  return result;
1080 }
1081 
1082 void GtransfoLin::computeDerivative(const Point &, GtransfoLin &derivative, const double) const {
1083  derivative = *this;
1084  derivative.coeff(0, 0, 0) = 0;
1085  derivative.coeff(0, 0, 1) = 0;
1086 }
1087 
1088 GtransfoLin GtransfoLin::linearApproximation(const Point &, const double) const { return *this; }
1089 
1091  //
1092  // (T1,M1) * (T2,M2) = 1 i.e (0,1) implies
1093  // T1 = -M1 * T2
1094  // M1 = M2^(-1)
1095  //
1096 
1097  double a11 = A11();
1098  double a12 = A12();
1099  double a21 = A21();
1100  double a22 = A22();
1101  double d = (a11 * a22 - a12 * a21);
1102  if (d == 0) {
1103  LOGL_FATAL(_log,
1104  "GtransfoLin::invert singular transformation: transfo contents will be dumped to stderr.");
1105  dump(cerr);
1106  }
1107 
1108  GtransfoLin result(0, 0, a22 / d, -a12 / d, -a21 / d, a11 / d);
1109  double rdx, rdy;
1110  result.apply(Dx(), Dy(), rdx, rdy);
1111  result.dx() = -rdx;
1112  result.dy() = -rdy;
1113  return result;
1114 }
1115 
1118 }
1119 
1121  throw pexExcept::NotFoundError("GTransfoLinRot::fit not implemented! aborting");
1122 }
1123 
1124 double GtransfoLinShift::fit(const StarMatchList &starMatchList) {
1125  int npairs = starMatchList.size();
1126  if (npairs < 3) {
1127  LOGLS_FATAL(_log, "GtransfoLinShift::fit trying to fit a linear transfo with only " << npairs
1128  << " matches.");
1129  return -1;
1130  }
1131 
1132  double sumr2 = 0; /* used to compute chi2 without relooping */
1133  /* loop on pairs and fill */
1134  Eigen::VectorXd B(2);
1135  B.setZero();
1136  Eigen::MatrixXd A(2, 2);
1137  A.setZero();
1138 
1139  for (auto const &it : starMatchList) {
1140  const FatPoint &point1 = it.point1;
1141  const FatPoint &point2 = it.point2;
1142  double deltax = point2.x - point1.x;
1143  double deltay = point2.y - point1.y;
1144  double vxx = point1.vx + point2.vx;
1145  double vyy = point1.vy + point2.vy;
1146  double vxy = point1.vxy + point2.vxy;
1147  double det = vxx * vyy - vxy * vxy;
1148  double wxx = vyy / det;
1149  double wyy = vxx / det;
1150  double wxy = -vxy / det;
1151  B(0) += deltax * wxx + wxy * deltay;
1152  B(1) += deltay * wyy + wxy * deltax;
1153  A(0, 0) += wxx;
1154  A(1, 1) += wyy;
1155  A(0, 1) += wxy;
1156  sumr2 += deltax * deltax * wxx + deltay * deltay * wyy + 2. * wxy * deltax * deltay;
1157  }
1158  double det = A(0, 0) * A(1, 1) - A(0, 1) * A(1, 0);
1159  if (det <= 0) return -1;
1160  double tmp = A(0, 0);
1161  A(0, 0) = A(1, 1) / det;
1162  A(1, 1) = tmp / det;
1163  A(0, 1) = A(1, 0) = -A(0, 1) / det;
1164  Eigen::VectorXd sol = A * B;
1165  (*this) = GtransfoLinShift(sol(0), sol(1));
1166  return (sumr2 - sol.dot(B)); // chi2 compact form
1167 }
1168 
1169 GtransfoLinRot::GtransfoLinRot(const double angleRad, const Point *center, const double scaleFactor) {
1170  double c = scaleFactor * cos(angleRad);
1171  double s = scaleFactor * sin(angleRad);
1172  a11() = a22() = c;
1173  a21() = s;
1174  a12() = -s;
1175 
1176  // we want that the center does not move : gtransfo+M*C = C ==> gtransfo = C - M*C
1177  Point a_point(0., 0.);
1178  if (center) a_point = *center;
1179 
1180  dx() = dy() = 0;
1181  GtransfoPoly::apply(a_point.x, a_point.y, dx(), dy()); // compute M*C
1182  dx() = a_point.x - Dx();
1183  dy() = a_point.y - dy();
1184 }
1185 
1186 static double deg2rad(double degree) { return degree * M_PI / 180.; }
1187 
1188 static double rad2deg(double rad) { return rad * 180. / M_PI; }
1189 
1190 /************* WCS transfo ******************/
1191 /************** LinPix2Tan *******************/
1192 
1193 /* Implementation note : it seemed wise to incorporate
1194  the radians to degrees convertion into the linPix2Tan
1195  part (right in the constructor), and to do the
1196  opposite operation in the LinPart routine.
1197  When I was coding the fit, I realized that it was a
1198  bad idea. then I realized that the fitting routine
1199  itself was probably useless. Finaly, for a persistor,
1200  it seems bizarre that the stored data is different
1201  from what convention (angles in degrees for WCS's)
1202  would expect.
1203  So, no more "automatic" degrees to radians and
1204  radians to degrees conversion. They are explicitely
1205  done in apply (for TanPix2RaDec and TanRaDec2Pix).
1206  This is a minor concern though....
1207 */
1208 BaseTanWcs::BaseTanWcs(const GtransfoLin &pix2Tan, const Point &tangentPoint,
1209  const GtransfoPoly *corrections) {
1210  /* the angles returned by linPix2Tan should be in
1211  degrees. */
1212  linPix2Tan = pix2Tan;
1213  ra0 = deg2rad(tangentPoint.x);
1214  dec0 = deg2rad(tangentPoint.y);
1215  cos0 = cos(dec0);
1216  sin0 = sin(dec0);
1217  corr = nullptr;
1218  if (corrections) corr.reset(new GtransfoPoly(*corrections));
1219 }
1220 
1221 /* with some sort of smart pointer ro handle "corr", we could remove the
1222  copy constructor, the operator = and the destructor */
1223 
1224 // ": Gtransfo" suppresses a warning
1226  corr = nullptr;
1227  *this = original;
1228 }
1229 
1230 void BaseTanWcs::operator=(const BaseTanWcs &original) {
1231  linPix2Tan = original.linPix2Tan;
1232  ra0 = original.ra0;
1233  dec0 = original.dec0;
1234  cos0 = cos(dec0);
1235  sin0 = sin(dec0);
1236  corr = nullptr;
1237  if (original.corr) corr.reset(new GtransfoPoly(*original.corr));
1238 }
1239 
1240 void BaseTanWcs::apply(const double xIn, const double yIn, double &xOut, double &yOut) const {
1241  double l, m; // radians in the tangent plane
1242  pix2TP(xIn, yIn, l, m); // l, m in degrees.
1243  l = deg2rad(l);
1244  m = deg2rad(m); // now in radians
1245  // Code inspired from worldpos.c in wcssubs (ancestor of the wcslib)
1246  /* At variance with wcslib, it collapses the projection to a plane
1247  and expression of sidereal cooordinates into a single set of
1248  operations. */
1249  double dect = cos0 - m * sin0;
1250  if (dect == 0) {
1251  LOGL_WARN(_log, "No sidereal coordinates at pole!");
1252  xOut = 0;
1253  yOut = 0;
1254  return;
1255  }
1256  double rat = ra0 + atan2(l, dect);
1257  dect = atan(cos(rat - ra0) * (m * cos0 + sin0) / dect);
1258  if (rat - ra0 > M_PI) rat -= (2. * M_PI);
1259  if (rat - ra0 < -M_PI) rat += (2. * M_PI);
1260  if (rat < 0.0) rat += (2. * M_PI);
1261  // convert to degree
1262  xOut = rad2deg(rat);
1263  yOut = rad2deg(dect);
1264 }
1265 
1266 Point BaseTanWcs::getTangentPoint() const { return Point(rad2deg(ra0), rad2deg(dec0)); }
1267 
1269 
1271 
1273  /* CRPIX's are defined by:
1274  ( CD1_1 CD1_2 ) (x - crpix1)
1275  transformed = ( ) * ( )
1276  ( CD2_1 CD2_2 ) (y - crpix2)
1277 
1278  so that CrPix is the point which transforms to (0,0)
1279  */
1280  const GtransfoLin inverse = linPix2Tan.invert();
1281  return Point(inverse.Dx(), inverse.Dy());
1282 }
1283 
1285 
1286 
1288 
1289 void GtransfoSkyWcs::apply(const double xIn, const double yIn, double &xOut, double &yOut) const {
1290  auto const outCoord = _skyWcs->pixelToSky(afw::geom::Point2D(xIn, yIn));
1291  xOut = outCoord[0].asDegrees();
1292  yOut = outCoord[1].asDegrees();
1293 }
1294 
1296  stream << "GtransfoSkyWcs(" << *_skyWcs << ")";
1297 }
1298 
1299 double GtransfoSkyWcs::fit(const StarMatchList &starMatchList) {
1300  throw LSST_EXCEPT(pex::exceptions::LogicError, "Not implemented");
1301 }
1302 
1305 }
1306 
1307 /*************************** TanPix2RaDec ***************/
1308 
1309 TanPix2RaDec::TanPix2RaDec(const GtransfoLin &pix2Tan, const Point &tangentPoint,
1310  const GtransfoPoly *corrections)
1311  : BaseTanWcs(pix2Tan, tangentPoint, corrections) {}
1312 
1313 // ": Gtransfo" suppresses a warning
1315 
1317  const GtransfoLin *lin = dynamic_cast<const GtransfoLin *>(right);
1318  if (lin && lin->getDegree() == 1) return std::unique_ptr<Gtransfo>(new TanPix2RaDec((*this) * (*lin)));
1319  return std::unique_ptr<Gtransfo>(nullptr);
1320 }
1321 
1323  TanPix2RaDec result(*this);
1324  result.linPix2Tan = result.linPix2Tan * right;
1325  return result;
1326 }
1327 
1329  if (corr != nullptr) {
1330  LOGL_WARN(_log, "You are inverting a TanPix2RaDec with corrections.");
1331  LOGL_WARN(_log, "The inverse you get ignores the corrections!");
1332  }
1334 }
1335 
1338 }
1339 
1341  if (!corr)
1343  else
1344  return std::unique_ptr<Gtransfo>(new GtransfoInverse(this, precision, region));
1345 }
1346 
1348  if (corr)
1349  return (*corr) * linPix2Tan;
1350  else
1351  return linPix2Tan;
1352 }
1353 
1354 void TanPix2RaDec::pix2TP(double xPixel, double yPixel, double &xTangentPlane, double &yTangentPlane) const {
1355  // xTangentPlane, yTangentPlane in degrees.
1356  linPix2Tan.apply(xPixel, yPixel, xTangentPlane, yTangentPlane);
1357  if (corr) {
1358  double xtmp = xTangentPlane;
1359  double ytmp = yTangentPlane;
1360  corr->apply(xtmp, ytmp, xTangentPlane, yTangentPlane); // still in degrees.
1361  }
1362 }
1363 
1366 }
1367 
1369  stream << " TanPix2RaDec, lin part :" << endl << linPix2Tan;
1370  Point tp = getTangentPoint();
1371  stream << " tangent point " << tp.x << ' ' << tp.y << endl;
1372  Point crpix = getCrPix();
1373  stream << " crpix " << crpix.x << ' ' << crpix.y << endl;
1374  if (corr) stream << "PV correction: " << endl << *corr;
1375 }
1376 
1378  /* OK we could implement this routine, but it is
1379  probably useless since to do the match, we have to
1380  project from sky to tangent plane. When a match is
1381  found, it is easier to carry out the fit in the
1382  tangent plane, rather than going back to the celestial
1383  sphere (and reproject to fit...). Anyway if this
1384  message shows up, we'll think about it.
1385  */
1387  "TanPix2RaDec::fit is NOT implemented (although it is doable)) ");
1388  return -1;
1389 }
1390 
1391 /*************************** TanSipPix2RaDec ***************/
1392 
1393 TanSipPix2RaDec::TanSipPix2RaDec(const GtransfoLin &pix2Tan, const Point &tangentPoint,
1394  const GtransfoPoly *corrections)
1395  : BaseTanWcs(pix2Tan, tangentPoint, corrections) {}
1396 
1397 // ": Gtransfo" suppresses a warning
1399 
1400 /* Would require some checks before cooking up something more efficient
1401  than just a linear approximation */
1402 #if 0
1404 {
1405  if (&region) {}
1407 }
1408 #endif
1409 
1411  const { /* We have not implemented (yet) the reverse corrections available in SIP */
1412  return std::unique_ptr<Gtransfo>(new GtransfoInverse(this, precision, region));
1413 }
1414 
1416  if (corr)
1417  return GtransfoPoly(linPix2Tan) * (*corr);
1418  else
1419  return linPix2Tan;
1420 }
1421 
1422 void TanSipPix2RaDec::pix2TP(double xPixel, double yPixel, double &xTangentPlane,
1423  double &yTangentPlane) const {
1424  // xTangentPlane, yTangentPlane returned in degrees
1425  if (corr) {
1426  double xtmp, ytmp;
1427  corr->apply(xPixel, yPixel, xtmp, ytmp);
1428  linPix2Tan.apply(xtmp, ytmp, xTangentPlane, yTangentPlane);
1429  } else
1430  linPix2Tan.apply(xPixel, yPixel, xTangentPlane, yTangentPlane);
1431 }
1432 
1435 }
1436 
1438  stream << " TanSipPix2RaDec, lin part :" << endl << linPix2Tan;
1439  Point tp = getTangentPoint();
1440  stream << " tangent point " << tp.x << ' ' << tp.y << endl;
1441  Point crpix = getCrPix();
1442  stream << " crpix " << crpix.x << ' ' << crpix.y << endl;
1443  if (corr) stream << "PV correction: " << endl << *corr;
1444 }
1445 
1447  /* OK we could implement this routine, but it is
1448  probably useless since to do the match, we have to
1449  project from sky to tangent plane. When a match is
1450  found, it is easier to carry out the fit in the
1451  tangent plane, rather than going back to the celestial
1452  sphere (and reproject to fit...). Anyway if this
1453  message shows up, we'll think about it.
1454  */
1456  "TanSipPix2RaDec::fit is NOT implemented (although it is doable)) ");
1457  return -1;
1458 }
1459 
1460 /*************** reverse transfo of TanPix2RaDec: TanRaDec2Pix ********/
1461 
1462 TanRaDec2Pix::TanRaDec2Pix(const GtransfoLin &tan2Pix, const Point &tangentPoint) : linTan2Pix(tan2Pix) {
1463  setTangentPoint(tangentPoint);
1464 }
1465 
1466 void TanRaDec2Pix::setTangentPoint(const Point &tangentPoint) {
1467  /* the radian to degrees conversion after projection
1468  is handled in apply */
1469  ra0 = deg2rad(tangentPoint.x);
1470  dec0 = deg2rad(tangentPoint.y);
1471  cos0 = cos(dec0);
1472  sin0 = sin(dec0);
1473 }
1474 
1476  ra0 = dec0 = 0;
1477  cos0 = 1;
1478  sin0 = 0;
1479 }
1480 
1481 Point TanRaDec2Pix::getTangentPoint() const { return Point(rad2deg(ra0), rad2deg(dec0)); }
1482 
1484 
1485 // Use analytic derivatives, computed at the same time as the transform itself
1487  /* this routine is very similar to apply, but also propagates errors.
1488  The deg2rad and rad2deg are ignored for errors because they act as
1489  2 global scalings that cancel each other.
1490  Derivatives were computed using maple:
1491 
1492  l1 := sin(a - a0)*cos(d);
1493  m1 := sin(d)*sin(d0)+cos(d)*cos(d0)*cos(a-a0);
1494  l2 := sin(d)*cos(d0)-cos(d)*sin(d0)*cos(a-a0);
1495  simplify(diff(l1/m1,a));
1496  simplify(diff(l1/m1,d));
1497  simplify(diff(l2/m1,a));
1498  simplify(diff(l2/m1,d));
1499 
1500  Checked against Gtransfo::transformPosAndErrors (dec 09)
1501  */
1502  double ra = deg2rad(in.x);
1503  double dec = deg2rad(in.y);
1504  if (ra - ra0 > M_PI) ra -= (2. * M_PI);
1505  if (ra - ra0 < -M_PI) ra += (2. * M_PI);
1506  // Code inspired from worldpos.c in wcssubs (ancestor of the wcslib)
1507  // The same code is copied in ::apply()
1508 
1509  double coss = cos(dec);
1510  double sins = sin(dec);
1511  double sinda = sin(ra - ra0);
1512  double cosda = cos(ra - ra0);
1513  double l = sinda * coss;
1514  double m = sins * sin0 + coss * cos0 * cosda;
1515  l = l / m;
1516  m = (sins * cos0 - coss * sin0 * cosda) / m;
1517 
1518  // derivatives
1519  double deno =
1520  sq(sin0) - sq(coss) + sq(coss * cos0) * (1 + sq(cosda)) + 2 * sins * sin0 * coss * cos0 * cosda;
1521  double a11 = coss * (cosda * sins * sin0 + coss * cos0) / deno;
1522  double a12 = -sinda * sin0 / deno;
1523  double a21 = coss * sinda * sins / deno;
1524  double a22 = cosda / deno;
1525 
1526  FatPoint tmp;
1527  tmp.vx = a11 * (a11 * in.vx + 2 * a12 * in.vxy) + a12 * a12 * in.vy;
1528  tmp.vy = a21 * a21 * in.vx + a22 * a22 * in.vy + 2. * a21 * a22 * in.vxy;
1529  tmp.vxy = a21 * a11 * in.vx + a22 * a12 * in.vy + (a21 * a12 + a11 * a22) * in.vxy;
1530 
1531  // l and m are now coordinates in the tangent plane, in radians.
1532  tmp.x = rad2deg(l);
1533  tmp.y = rad2deg(m);
1534 
1536 }
1537 
1538 void TanRaDec2Pix::apply(const double xIn, const double yIn, double &xOut, double &yOut) const {
1539  double ra = deg2rad(xIn);
1540  double dec = deg2rad(yIn);
1541  if (ra - ra0 > M_PI) ra -= (2. * M_PI);
1542  if (ra - ra0 < -M_PI) ra += (2. * M_PI);
1543  // Code inspired from worldpos.c in wcssubs (ancestor of the wcslib)
1544  // The same code is copied in ::transformPosAndErrors()
1545  double coss = cos(dec);
1546  double sins = sin(dec);
1547  double l = sin(ra - ra0) * coss;
1548  double m = sins * sin0 + coss * cos0 * cos(ra - ra0);
1549  l = l / m;
1550  m = (sins * cos0 - coss * sin0 * cos(ra - ra0)) / m;
1551  // l and m are now coordinates in the tangent plane, in radians.
1552  l = rad2deg(l);
1553  m = rad2deg(m);
1554  linTan2Pix.apply(l, m, xOut, yOut);
1555 }
1556 
1558 
1560  Point tp = getTangentPoint();
1561  stream << " tan2pix " << linTan2Pix << " tangent point " << tp.x << ' ' << tp.y << endl;
1562 }
1563 
1566 }
1567 
1570 }
1571 
1573  return std::unique_ptr<Gtransfo>(new TanRaDec2Pix(*this));
1574 }
1575 
1578  "TanRaDec2Pix::fit is NOT implemented (although it is doable)) ");
1579  return -1;
1580 }
1581 
1582 /************* a "run-time" transfo, that does not require to
1583 modify this file */
1584 
1585 UserTransfo::UserTransfo(GtransfoFun &userFun, const void *userData)
1586  : _userFun(userFun), _userData(userData) {}
1587 
1588 void UserTransfo::apply(const double xIn, const double yIn, double &xOut, double &yOut) const {
1589  _userFun(xIn, yIn, xOut, yOut, _userData);
1590 }
1591 
1593  stream << "UserTransfo with user function @ " << _userFun << "and userData@ " << _userData << endl;
1594 }
1595 
1598  "UserTransfo::fit is NOT implemented (and will never be)) ");
1599  return -1;
1600 }
1601 
1603  return std::unique_ptr<Gtransfo>(new UserTransfo(*this));
1604 }
1605 
1606 /*************************************************************/
1607 
1609  ifstream s(fileName.c_str());
1610  if (!s)
1611  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, " gtransfoRead : cannot open " + fileName);
1612  try {
1614  s.close();
1615  return res;
1618  std::string(e.what()) + " in file " + fileName);
1619  }
1620 }
1621 
1623  std::string type;
1624  s >> type;
1625  if (s.fail())
1627  "gtransfoRead : could not find a Gtransfotype");
1628  if (type == "GtransfoIdentity") {
1630  res->read(s);
1631  return std::move(res);
1632  } else if (type == "GtransfoPoly") {
1634  res->read(s);
1635  return std::move(res);
1636  } else
1638  " gtransfoRead : No reader for Gtransfo type " + type);
1639 }
1640 } // namespace jointcal
1641 } // namespace lsst
#define LOGLS_WARN(logger, message)
Log a warn-level message using an iostream-based interface.
Definition: Log.h:657
std::unique_ptr< Gtransfo > roughInverse(const Frame &region) const
Overload the "generic routine" (available for all Gtransfo types.
Definition: Gtransfo.cc:1336
void write(std::ostream &s) const
Definition: Gtransfo.cc:395
virtual std::unique_ptr< Gtransfo > clone() const
returns a copy (allocated by new) of the transformation.
Definition: Gtransfo.cc:307
void dump(std::ostream &stream=std::cout) const
dumps the transfo coefficients to stream.
Definition: Gtransfo.cc:1592
implements the linear transformations (6 real coefficients).
Definition: Gtransfo.h:294
TanPix2RaDec invert() const
exact typed inverse:
Definition: Gtransfo.cc:1557
T atan(T... args)
solver_t * s
void apply(const double xIn, const double yIn, double &xOut, double &yOut) const override
Definition: Gtransfo.cc:1289
TanRaDec2Pix invert() const
approximate inverse : it ignores corrections;
Definition: Gtransfo.cc:1328
std::unique_ptr< Gtransfo > inverseTransfo(const double precision, const Frame &region) const
Inverse transfo: returns a TanPix2RaDec.
Definition: Gtransfo.cc:1568
std::unique_ptr< Gtransfo > gtransfoCompose(const Gtransfo *left, const Gtransfo *right)
Returns a pointer to a composition.
Definition: Gtransfo.cc:368
void computeDerivative(const Point &where, GtransfoLin &derivative, const double step=0.01) const
specialised analytic routine
Definition: Gtransfo.cc:509
#define LOG_LOGGER
Definition: Log.h:712
PolyXY(const int degree)
Definition: Gtransfo.cc:861
GtransfoFun * _userFun
Definition: Gtransfo.h:620
void apply(const double xIn, const double yIn, double &xOut, double &yOut) const
Definition: Gtransfo.cc:486
double fit(const StarMatchList &starMatchList)
fits a transfo to a std::list of Point pairs (p1,p2, the Point fields in StarMatch).
Definition: Gtransfo.cc:303
void computeDerivative(const Point &where, GtransfoLin &derivative, const double step=0.01) const
Computes the local Derivative of a transfo, w.r.t.
Definition: Gtransfo.cc:386
std::unique_ptr< Gtransfo > _direct
Definition: Gtransfo.cc:221
A hanger for star associations.
Definition: StarMatch.h:31
A point in a plane.
Definition: Point.h:13
void() GtransfoFun(const double, const double, double &, double &, const void *)
signature of the user-provided routine that actually does the coordinate transfo for UserTransfo...
Definition: Gtransfo.h:601
double getArea() const
Definition: Frame.cc:102
the transformation that handles pix to sideral transfos (Gnomonic, possibly with polynomial distortio...
Definition: Gtransfo.h:480
void setCorrections(std::unique_ptr< GtransfoPoly > corrections)
Assign the correction polynomial (what it means is left to derived classes)
Definition: Gtransfo.cc:1270
long double & coeff(const unsigned powX, const unsigned powY)
Definition: Gtransfo.cc:880
GtransfoLin invert() const
returns the inverse: T1 = T2.invert();
Definition: Gtransfo.cc:1090
T fail(T... args)
std::unique_ptr< Gtransfo > roughInverse(const Frame &) const
Overload the "generic routine".
Definition: Gtransfo.cc:241
FatPoint point2
2 points
Definition: StarMatch.h:37
void apply(const double xIn, const double yIn, double &xOut, double &yOut) const
implements an iterative (Gauss-Newton) solver.
Definition: Gtransfo.cc:276
T endl(T... args)
void paramDerivatives(const Point &where, double *dx, double *dy) const
Derivative w.r.t parameters.
Definition: Gtransfo.cc:683
void apply(const double xIn, const double yIn, double &xOut, double &yOut) const
Definition: Gtransfo.cc:1588
void write(std::ostream &s) const
Definition: Gtransfo.cc:988
void computeMonomials(double xIn, double yIn, double *monomial) const
Definition: Gtransfo.cc:442
bool isIdentity(const Gtransfo *gtransfo)
Shorthand test to tell if a transfo belongs to the GtransfoIdentity class.
Definition: Gtransfo.cc:30
T left(T... args)
int min
Definition: Coord.cc:160
std::unique_ptr< Gtransfo > clone() const override
returns a copy (allocated by new) of the transformation.
Definition: Gtransfo.cc:1303
void apply(const double xIn, const double yIn, double &xOut, double &yOut) const
return second(first(xIn,yIn))
Definition: Gtransfo.cc:342
double computeFit(const StarMatchList &starMatchList, const Gtransfo &InTransfo, const bool UseErrors)
Definition: Gtransfo.cc:758
void apply(const double xIn, const double yIn, double &xOut, double &yOut) const
Transform pixels to ICRS RA, Dec in degrees.
Definition: Gtransfo.cc:1240
STL namespace.
T precision(T... args)
double fit(const StarMatchList &starMatchList)
Not implemented yet, because we do it otherwise.
Definition: Gtransfo.cc:1446
double xMin
coordinate of boundary.
Definition: Frame.h:22
GtransfoLin linearApproximation(const Point &where, const double step=0.01) const
linear (local) approximation.
Definition: Gtransfo.cc:1088
T end(T... args)
#define LOGL_ERROR(logger, message...)
Log a error-level message using a varargs/printf style interface.
Definition: Log.h:561
T floor(T... args)
double paramRef(const int i) const
Definition: Gtransfo.cc:673
table::Key< table::Array< int > > degree
Definition: PsfexPsf.cc:346
void dump(std::ostream &stream) const
dumps the transfo coefficients to stream.
Definition: Gtransfo.cc:1437
Polynomial transformation class.
Definition: Gtransfo.h:195
GtransfoLin normalizeCoordinatesTransfo(const Frame &frame)
Returns the transformation that maps the input frame along both axes to [-1,1].
Definition: Gtransfo.cc:725
GtransfoInverse(const Gtransfo *direct, const double precision, const Frame &region)
Definition: Gtransfo.cc:256
STL class.
GtransfoPoly getPix2TangentPlane() const
the transformation from pixels to tangent plane (degrees)
Definition: Gtransfo.cc:1415
A Point with uncertainties.
Definition: FatPoint.h:11
#define M_PI
Definition: ListMatch.cc:7
std::ostream & operator<<(std::ostream &os, CameraSysPrefix const &detSysPrefix)
Definition: CameraSys.cc:55
double fit(const StarMatchList &starMatchList)
fits a transfo to a std::list of Point pairs (p1,p2, the Point fields in StarMatch).
Definition: Gtransfo.cc:1576
T resize(T... args)
int const step
Definition: BoundedField.cc:97
T atan2(T... args)
STL class.
LSST DM logging module built on log4cxx.
std::unique_ptr< Gtransfo > clone() const
returns a copy (allocated by new) of the transformation.
Definition: Gtransfo.cc:1364
double x
coordinate
Definition: Point.h:18
pairs of points
Include files required for standard LSST Exception handling.
T sin(T... args)
GtransfoComposition(const Gtransfo *second, const Gtransfo *first)
will pipe transfos
Definition: Gtransfo.cc:337
T at(T... args)
std::unique_ptr< Gtransfo > roughInverse(const Frame &region) const
Overload the "generic routine" (available for all Gtransfo types.
Definition: Gtransfo.cc:1564
GtransfoPoly operator*(const GtransfoPoly &right) const
Composition (internal stuff in quadruple precision)
Definition: Gtransfo.cc:944
GtransfoLin()
the default constructor constructs the do-nothing transformation.
Definition: Gtransfo.h:299
bool isIntegerShift(const Gtransfo *gtransfo)
Shorthand test to tell if a transfo is a simple integer shift.
Definition: Gtransfo.cc:34
std::unique_ptr< GtransfoPoly > inversePolyTransfo(const Gtransfo &Direct, const Frame &frame, const double Prec)
approximates the inverse by a polynomial, up to required precision.
Definition: Gtransfo.cc:1013
double getHeight() const
size along y axis
Definition: Frame.h:38
T push_back(T... args)
STL class.
double coeffOrZero(const unsigned powX, const unsigned powY, const unsigned whichCoord) const
read access, zero if beyond degree
Definition: Gtransfo.cc:664
void computeDerivative(const Point &where, GtransfoLin &derivative, const double step=0.01) const
specialised analytic routine
Definition: Gtransfo.cc:1082
#define LOGL_FATAL(logger, message...)
Log a fatal-level message using a varargs/printf style interface.
Definition: Log.h:577
unsigned getDegree() const
Definition: Gtransfo.cc:866
void read(std::istream &s)
Definition: Gtransfo.cc:397
rectangle with sides parallel to axes.
Definition: Frame.h:19
A base class for image defects.
Definition: cameraGeom.dox:3
std::unique_ptr< Gtransfo > clone() const
returns a copy (allocated by new) of the transformation.
Definition: Gtransfo.cc:1572
GtransfoPoly operator-(const GtransfoPoly &right) const
Subtraction.
Definition: Gtransfo.cc:978
Point getCrPix() const
Get the pixel origin of the WCS (CRPIX in FITS WCS terminology, but zero-based)
Definition: Gtransfo.cc:1272
std::unique_ptr< Gtransfo > _roughInverse
Definition: Gtransfo.cc:222
GtransfoLin getLinPart() const
The Linear part (corresponding to CD&#39;s and CRPIX&#39;s)
Definition: Gtransfo.cc:1268
std::unique_ptr< Gtransfo > reduceCompo(const Gtransfo *right) const
to be overloaded by derived classes if they can really "reduce" the composition (e.g.
Definition: Gtransfo.cc:1316
std::unique_ptr< Gtransfo > inverseTransfo(const double precision, const Frame &region) const
returns an inverse transfo. Numerical if not overloaded.
Definition: Gtransfo.cc:1116
std::unique_ptr< Gtransfo > clone() const
returns a copy (allocated by new) of the transformation.
Definition: Gtransfo.cc:1433
double fit(const StarMatchList &starMatchList)
guess what
Definition: Gtransfo.cc:1120
void apply(const double xIn, const double yIn, double &xOut, double &yOut) const
Definition: Gtransfo.cc:1538
int max
Definition: BoundedField.cc:99
void dump(ostream &stream=cout) const
dumps the transfo coefficients to stream.
Definition: Gtransfo.cc:348
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:134
void read(std::istream &s)
Definition: Gtransfo.cc:998
double fit(const StarMatchList &starMatchList)
fits a transfo to a std::list of Point pairs (p1,p2, the Point fields in StarMatch).
Definition: Gtransfo.cc:353
Point getTangentPoint() const
tangent point coordinates (degrees)
Definition: Gtransfo.cc:1481
std::shared_ptr< afw::geom::SkyWcs > getSkyWcs() const
Definition: Gtransfo.h:423
T str(T... args)
double fit(const StarMatchList &starMatchList)
Not implemented yet, because we do it otherwise.
Definition: Gtransfo.cc:1377
void dump(std::ostream &stream) const
dumps the transfo coefficients to stream.
Definition: Gtransfo.cc:1559
std::unique_ptr< Gtransfo > clone() const
returns a copy (allocated by new) of the transformation.
Definition: Gtransfo.cc:358
T reset(T... args)
T cos(T... args)
void dump(std::ostream &stream=std::cout) const
print out of coefficients in a readable form.
Definition: Gtransfo.cc:703
double fit(const StarMatchList &starMatchList)
fits a transfo to a std::list of Point pairs (p1,p2, the Point fields in StarMatch).
Definition: Gtransfo.cc:1596
#define LOGL_WARN(logger, message...)
Log a warn-level message using a varargs/printf style interface.
Definition: Log.h:545
double x
T fabs(T... args)
T max(T... args)
T move(T... args)
double getWidth() const
size along x axis
Definition: Frame.h:35
T count(T... args)
unsigned getDegree() const
returns degree
Definition: Gtransfo.h:218
virtual void transformPosAndErrors(const FatPoint &in, FatPoint &out) const
a mix of apply and Derivative
Definition: Gtransfo.cc:567
std::vector< double > _coeffs
Definition: Gtransfo.h:271
PolyXY(const GtransfoPoly &gtransfoPoly, const unsigned whichCoord)
Definition: Gtransfo.cc:868
T insert(T... args)
Point getCenter() const
Center of the frame.
Definition: Frame.h:41
A do-nothing transformation. It anyway has dummy routines to mimick a Gtransfo.
Definition: Gtransfo.h:152
void setTangentPoint(const Point &tangentPoint)
Resets the projection (or tangent) point.
Definition: Gtransfo.cc:1466
T size(T... args)
#define LSST_EXCEPT(type,...)
Create an exception with a given type and message and optionally other arguments (dependent on the ty...
Definition: Exception.h:46
just here to provide a specialized constructor, and fit.
Definition: Gtransfo.h:358
virtual std::unique_ptr< Gtransfo > reduceCompo(const Gtransfo *right) const
to be overloaded by derived classes if they can really "reduce" the composition (e.g.
Definition: Gtransfo.cc:53
STL class.
std::unique_ptr< Gtransfo > inverseTransfo(const double precision, const Frame &region) const
Inverse transfo: returns a TanRaDec2Pix if there are no corrections, or the iterative solver if there...
Definition: Gtransfo.cc:1340
std::unique_ptr< Gtransfo > _second
Definition: Gtransfo.cc:320
std::unique_ptr< Gtransfo > clone() const
returns a copy (allocated by new) of the transformation.
Definition: Gtransfo.cc:1602
This one is the Tangent Plane (called gnomonic) projection (from celestial sphere to tangent plane) ...
Definition: Gtransfo.h:554
std::unique_ptr< Gtransfo > inverseTransfo(const double precision, const Frame &region) const
Inverse transfo: returns a TanRaDec2Pix if there are no corrections, or the iterative solver if there...
Definition: Gtransfo.cc:1410
T begin(T... args)
friend class GtransfoPoly
Definition: Gtransfo.h:349
void transformPosAndErrors(const FatPoint &in, FatPoint &out) const
transform with analytical derivatives
Definition: Gtransfo.cc:1486
T pow(T... args)
GtransfoPoly operator+(const GtransfoPoly &right) const
Addition.
Definition: Gtransfo.cc:965
virtual char const * what(void) const
Return a character string summarizing this exception.
Definition: Exception.cc:112
GtransfoLin getLinPart() const
The Linear part (corresponding to CD&#39;s and CRPIX&#39;s)
Definition: Gtransfo.cc:1483
just here to provide specialized constructors. GtransfoLin fit routine.
Definition: Gtransfo.h:385
T c_str(T... args)
a virtual (interface) class for geometric transformations.
Definition: Gtransfo.h:41
void operator=(const GtransfoInverse &)
Definition: Gtransfo.cc:270
void dump(std::ostream &stream) const
dumps the transfo coefficients to stream.
Definition: Gtransfo.cc:1368
GtransfoPoly(const unsigned degree=1)
Default transfo : identity for all degrees (>=1 ).
Definition: Gtransfo.cc:409
void setDegree(const unsigned degree)
Definition: Gtransfo.cc:465
Point getTangentPoint() const
Get the sky origin (CRVAL in FITS WCS terminology) in degrees.
Definition: Gtransfo.cc:1266
std::unique_ptr< GtransfoPoly > corr
Definition: Gtransfo.h:472
T dec(T... args)
virtual void pix2TP(double xPixel, double yPixel, double &xTangentPlane, double &yTangentPlane) const
transforms from pixel space to tangent plane (degrees)
Definition: Gtransfo.cc:1422
double coeff(const unsigned powX, const unsigned powY, const unsigned whichCoord) const
access to coefficients (read only)
Definition: Gtransfo.cc:651
table::Key< int > a
Private class to handle Gtransfo compositions (i.e.
Definition: Gtransfo.cc:318
BaseTanWcs(const GtransfoLin &pix2Tan, const Point &tangentPoint, const GtransfoPoly *corrections=nullptr)
Definition: Gtransfo.cc:1208
T sqrt(T... args)
GtransfoPoly getPix2TangentPlane() const
the transformation from pixels to tangent plane (degrees)
Definition: Gtransfo.cc:1347
double fit(const StarMatchList &starMatchList)
guess what
Definition: Gtransfo.cc:1124
virtual GtransfoLin linearApproximation(const Point &where, const double step=0.01) const
linear approximation.
Definition: Gtransfo.cc:390
TanPix2RaDec operator*(const GtransfoLin &right) const
composition with GtransfoLin
Definition: Gtransfo.cc:1322
#define LOGLS_FATAL(logger, message)
Log a fatal-level message using an iostream-based interface.
Definition: Log.h:697
GtransfoSkyWcs(std::shared_ptr< afw::geom::SkyWcs > skyWcs)
Definition: Gtransfo.cc:1287
long double coeff(const unsigned powX, const unsigned powY) const
Definition: Gtransfo.cc:875
#define LOG_GET(logger)
Returns a Log object associated with logger.
Definition: Log.h:83
std::unique_ptr< Gtransfo > reduceCompo(const Gtransfo *right) const
to be overloaded by derived classes if they can really "reduce" the composition (e.g.
Definition: Gtransfo.cc:835
virtual void pix2TP(double xPixel, double yPixel, double &xTangentPlane, double &yTangentPlane) const
transforms from pixel space to tangent plane (degrees)
Definition: Gtransfo.cc:1354
std::unique_ptr< Gtransfo > gtransfoRead(const std::string &fileName)
The virtual constructor from a file.
Definition: Gtransfo.cc:1608
T setprecision(T... args)
virtual std::unique_ptr< Gtransfo > clone() const =0
returns a copy (allocated by new) of the transformation.
double fit(const StarMatchList &starMatchList)
guess what
Definition: Gtransfo.cc:817
virtual void dump(std::ostream &stream=std::cout) const =0
dumps the transfo coefficients to stream.
STL class.
UserTransfo(GtransfoFun &fun, const void *userData)
the transfo routine and extra data that it may need.
Definition: Gtransfo.cc:1585
virtual void pix2TP(double xPixel, double yPixel, double &xTangentPlane, double &yTangentPlane) const =0
Transform from pixels to tangent plane (degrees)
double fit(const StarMatchList &starMatchList) override
Not implemented; throws pex::exceptions::LogicError.
Definition: Gtransfo.cc:1299
vector< long double > coeffs
Definition: Gtransfo.cc:858
STL class.
virtual void apply(const double xIn, const double yIn, double &xOut, double &yOut) const =0
void dump(ostream &stream) const
dumps the transfo coefficients to stream.
Definition: Gtransfo.cc:299
void operator=(const BaseTanWcs &original)
Definition: Gtransfo.cc:1230
T reserve(T... args)
std::unique_ptr< Gtransfo > inverseTransfo(double, const Frame &) const
Inverse transfo: returns the direct one!
Definition: Gtransfo.cc:244
double determinant() const
Definition: Gtransfo.cc:719
GtransfoLin operator*(const GtransfoLin &right) const
enables to combine linear tranformations: T1=T2*T3 is legal.
Definition: Gtransfo.cc:1067
void dump(std::ostream &stream=std::cout) const override
dumps the transfo coefficients to stream.
Definition: Gtransfo.cc:1295
std::shared_ptr< afw::geom::SkyWcs > _skyWcs
Definition: Gtransfo.h:426