lsst.jointcal  master-gc7bdbdc8f0
AstrometryFit.cc
Go to the documentation of this file.
1 #include <iostream>
2 #include <iomanip>
3 #include <algorithm>
4 #include <fstream>
5 
6 #include "Eigen/Sparse"
7 
8 #include "lsst/log/Log.h"
9 #include "lsst/pex/exceptions.h"
12 #include "lsst/jointcal/Chi2.h"
15 #include "lsst/jointcal/Mapping.h"
16 #include "lsst/jointcal/Gtransfo.h"
18 
19 namespace {
20 LOG_LOGGER _log = LOG_GET("jointcal.AstrometryFit");
21 }
22 
23 namespace lsst {
24 namespace jointcal {
25 
27  std::shared_ptr<AstrometryModel> astrometryModel, double posError)
28  : FitterBase(associations),
29  _astrometryModel(astrometryModel),
30  _refractionCoefficient(0),
31  _nParDistortions(0),
32  _nParPositions(0),
33  _nParRefrac(_associations->getNFilters()),
34  _posError(posError) {
35  _JDRef = 0;
36 
37  _posError = posError;
38 
39  _referenceColor = 0;
40  _sigCol = 0;
41  unsigned count = 0;
42  for (auto const &i : _associations->fittedStarList) {
43  _referenceColor += i->color;
44  _sigCol += std::pow(i->color, 2);
45  count++;
46  }
47  if (count) {
48  _referenceColor /= double(count);
49  if (_sigCol > 0) _sigCol = sqrt(_sigCol / count - std::pow(_referenceColor, 2));
50  }
51  LOGLS_INFO(_log, "Reference Color: " << _referenceColor << " sig " << _sigCol);
52 }
53 
54 #define NPAR_PM 2
55 
56 /* ! this routine is used in 3 instances: when computing
57 the derivatives, when computing the Chi2, when filling a tuple.
58 */
59 Point AstrometryFit::transformFittedStar(FittedStar const &fittedStar, Gtransfo const *sky2TP,
60  Point const &refractionVector, double refractionCoeff,
61  double mjd) const {
62  Point fittedStarInTP = sky2TP->apply(fittedStar);
63  if (fittedStar.mightMove) {
64  fittedStarInTP.x += fittedStar.pmx * mjd;
65  fittedStarInTP.y += fittedStar.pmy * mjd;
66  }
67  // account for atmospheric refraction: does nothing if color
68  // have not been assigned
69  // the color definition shouldbe the same when computing derivatives
70  double color = fittedStar.color - _referenceColor;
71  fittedStarInTP.x += refractionVector.x * color * refractionCoeff;
72  fittedStarInTP.y += refractionVector.y * color * refractionCoeff;
73  return fittedStarInTP;
74 }
75 
79 static void tweakAstromMeasurementErrors(FatPoint &P, MeasuredStar const &Ms, double error) {
80  static bool called = false;
81  static double increment = 0;
82  if (!called) {
83  increment = std::pow(error, 2); // was in Preferences
84  called = true;
85  }
86  P.vx += increment;
87  P.vy += increment;
88 }
89 
90 // we could consider computing the chi2 here.
91 // (although it is not extremely useful)
92 void AstrometryFit::leastSquareDerivativesMeasurement(CcdImage const &ccdImage, TripletList &tripletList,
93  Eigen::VectorXd &fullGrad,
94  MeasuredStarList const *msList) const {
95  /**********************************************************************/
96  /* @note the math in this method and accumulateStatImage() must be kept consistent,
97  * in terms of +/- convention, definition of model, etc. */
98  /**********************************************************************/
99 
100  /* Setup */
101  /* this routine works in two different ways: either providing the
102  ccdImage, of providing the MeasuredStarList. In the latter case, the
103  ccdImage should match the one(s) in the list. */
104  if (msList) assert(&(msList->front()->getCcdImage()) == &ccdImage);
105 
106  // get the Mapping
107  const Mapping *mapping = _astrometryModel->getMapping(ccdImage);
108  // count parameters
109  unsigned npar_mapping = (_fittingDistortions) ? mapping->getNpar() : 0;
110  unsigned npar_pos = (_fittingPos) ? 2 : 0;
111  unsigned npar_refrac = (_fittingRefrac) ? 1 : 0;
112  unsigned npar_pm = (_fittingPM) ? NPAR_PM : 0;
113  unsigned npar_tot = npar_mapping + npar_pos + npar_refrac + npar_pm;
114  // if (npar_tot == 0) this CcdImage does not contribute
115  // any constraint to the fit, so :
116  if (npar_tot == 0) return;
117  std::vector<unsigned> indices(npar_tot, -1);
118  if (_fittingDistortions) mapping->getMappingIndices(indices);
119 
120  // proper motion stuff
121  double mjd = ccdImage.getMjd() - _JDRef;
122  // refraction stuff
123  Point refractionVector = ccdImage.getRefractionVector();
124  // transformation from sky to TP
125  const Gtransfo *sky2TP = _astrometryModel->getSky2TP(ccdImage);
126  // reserve matrices once for all measurements
127  GtransfoLin dypdy;
128  // the shape of H (et al) is required this way in order to be able to
129  // separate derivatives along x and y as vectors.
130  Eigen::MatrixX2d H(npar_tot, 2), halpha(npar_tot, 2), HW(npar_tot, 2);
131  Eigen::Matrix2d transW(2, 2);
132  Eigen::Matrix2d alpha(2, 2);
133  Eigen::VectorXd grad(npar_tot);
134  // current position in the Jacobian
135  unsigned kTriplets = tripletList.getNextFreeIndex();
136  const MeasuredStarList &catalog = (msList) ? *msList : ccdImage.getCatalogForFit();
137 
138  for (auto &i : catalog) {
139  const MeasuredStar &ms = *i;
140  if (!ms.isValid()) continue;
141  // tweak the measurement errors
142  FatPoint inPos = ms;
143  tweakAstromMeasurementErrors(inPos, ms, _posError);
144  H.setZero(); // we cannot be sure that all entries will be overwritten.
145  FatPoint outPos;
146  // should *not* fill H if whatToFit excludes mapping parameters.
147  if (_fittingDistortions)
148  mapping->computeTransformAndDerivatives(inPos, outPos, H);
149  else
150  mapping->transformPosAndErrors(inPos, outPos);
151 
152  unsigned ipar = npar_mapping;
153  double det = outPos.vx * outPos.vy - std::pow(outPos.vxy, 2);
154  if (det <= 0 || outPos.vx <= 0 || outPos.vy <= 0) {
155  LOGLS_WARN(_log, "Inconsistent measurement errors: drop measurement at "
156  << Point(ms) << " in image " << ccdImage.getName());
157  continue;
158  }
159  transW(0, 0) = outPos.vy / det;
160  transW(1, 1) = outPos.vx / det;
161  transW(0, 1) = transW(1, 0) = -outPos.vxy / det;
162  // compute alpha, a triangular square root
163  // of transW (i.e. a Cholesky factor)
164  alpha(0, 0) = sqrt(transW(0, 0));
165  // checked that alpha*alphaT = transW
166  alpha(1, 0) = transW(0, 1) / alpha(0, 0);
167  // DB - I think that the next line is equivalent to : alpha(1,1) = 1./sqrt(outPos.vy)
168  // PA - seems correct !
169  alpha(1, 1) = 1. / sqrt(det * transW(0, 0));
170  alpha(0, 1) = 0;
171 
172  auto fs = ms.getFittedStar();
173 
174  Point fittedStarInTP =
175  transformFittedStar(*fs, sky2TP, refractionVector, _refractionCoefficient, mjd);
176 
177  // compute derivative of TP position w.r.t sky position ....
178  if (npar_pos > 0) // ... if actually fitting FittedStar position
179  {
180  sky2TP->computeDerivative(*fs, dypdy, 1e-3);
181  // sign checked
182  // TODO Still have to check with non trivial non-diagonal terms
183  H(npar_mapping, 0) = -dypdy.A11();
184  H(npar_mapping + 1, 0) = -dypdy.A12();
185  H(npar_mapping, 1) = -dypdy.A21();
186  H(npar_mapping + 1, 1) = -dypdy.A22();
187  indices[npar_mapping] = fs->getIndexInMatrix();
188  indices.at(npar_mapping + 1) = fs->getIndexInMatrix() + 1;
189  ipar += npar_pos;
190  }
191  /* only consider proper motions of objects allowed to move,
192  unless the fit is going to be degenerate */
193  if (_fittingPM && fs->mightMove) {
194  H(ipar, 0) = -mjd; // Sign unchecked but consistent with above
195  H(ipar + 1, 1) = -mjd;
196  indices[ipar] = fs->getIndexInMatrix() + 2;
197  indices[ipar + 1] = fs->getIndexInMatrix() + 3;
198  ipar += npar_pm;
199  }
200  if (_fittingRefrac) {
201  /* if the definition of color changes, it has to remain
202  consistent with transformFittedStar */
203  double color = fs->color - _referenceColor;
204  // sign checked
205  H(ipar, 0) = -refractionVector.x * color;
206  H(ipar, 1) = -refractionVector.y * color;
207  indices[ipar] = _refracPosInMatrix;
208  ipar += 1;
209  }
210 
211  // We can now compute the residual
212  Eigen::Vector2d res(fittedStarInTP.x - outPos.x, fittedStarInTP.y - outPos.y);
213 
214  // do not write grad = H*transW*res to avoid
215  // dynamic allocation of a temporary
216  halpha = H * alpha;
217  HW = H * transW;
218  grad = HW * res;
219  // now feed in triplets and fullGrad
220  for (unsigned ipar = 0; ipar < npar_tot; ++ipar) {
221  for (unsigned ic = 0; ic < 2; ++ic) {
222  double val = halpha(ipar, ic);
223  if (val == 0) continue;
224  tripletList.addTriplet(indices[ipar], kTriplets + ic, val);
225  }
226  fullGrad(indices[ipar]) += grad(ipar);
227  }
228  kTriplets += 2; // each measurement contributes 2 columns in the Jacobian
229  } // end loop on measurements
230  tripletList.setNextFreeIndex(kTriplets);
231 }
232 
233 void AstrometryFit::leastSquareDerivativesReference(FittedStarList const &fittedStarList,
234  TripletList &tripletList,
235  Eigen::VectorXd &fullGrad) const {
236  /**********************************************************************/
237  /* @note the math in this method and accumulateStatRefStars() must be kept consistent,
238  * in terms of +/- convention, definition of model, etc. */
239  /**********************************************************************/
240 
241  /* We compute here the derivatives of the terms involving fitted
242  stars and reference stars. They only provide contributions if we
243  are fitting positions: */
244  if (!_fittingPos) return;
245  /* the other case where the accumulation of derivatives stops
246  here is when there are no RefStars */
247  if (_associations->refStarList.size() == 0) return;
248  Eigen::Matrix2d W(2, 2);
249  Eigen::Matrix2d alpha(2, 2);
250  Eigen::Matrix2d H(2, 2), halpha(2, 2), HW(2, 2);
251  GtransfoLin der;
252  Eigen::Vector2d res, grad;
253  unsigned indices[2 + NPAR_PM];
254  unsigned kTriplets = tripletList.getNextFreeIndex();
255  /* We cannot use the spherical coordinates directly to evaluate
256  Euclidean distances, we have to use a projector on some plane in
257  order to express least squares. Not projecting could lead to a
258  disaster around the poles or across alpha=0. So we need a
259  projector. We construct a projector and will change its
260  projection point at every object */
261  TanRaDec2Pix proj(GtransfoLin(), Point(0., 0.));
262  for (auto const &i : fittedStarList) {
263  const FittedStar &fs = *i;
264  const RefStar *rs = fs.getRefStar();
265  if (rs == nullptr) continue;
266  proj.setTangentPoint(fs);
267  // fs projects to (0,0), no need to compute its transform.
268  FatPoint rsProj;
269  proj.transformPosAndErrors(*rs, rsProj);
270  // Compute the derivative of the projector to incorporate its effects on the errors.
271  proj.computeDerivative(fs, der, 1e-4);
272  // sign checked. TODO check that the off-diagonal terms are OK.
273  H(0, 0) = -der.A11();
274  H(1, 0) = -der.A12();
275  H(0, 1) = -der.A21();
276  H(1, 1) = -der.A22();
277  // TO DO : account for proper motions.
278  double det = rsProj.vx * rsProj.vy - std::pow(rsProj.vxy, 2);
279  if (rsProj.vx <= 0 || rsProj.vy <= 0 || det <= 0) {
280  LOGLS_WARN(_log, "RefStar error matrix not positive definite for: " << *rs);
281  continue;
282  }
283  W(0, 0) = rsProj.vy / det;
284  W(0, 1) = W(1, 0) = -rsProj.vxy / det;
285  W(1, 1) = rsProj.vx / det;
286  // compute alpha, a triangular square root
287  // of W (i.e. a Cholesky factor)
288  alpha(0, 0) = sqrt(W(0, 0));
289  // checked that alpha*alphaT = transW
290  alpha(1, 0) = W(0, 1) / alpha(0, 0);
291  alpha(1, 1) = 1. / sqrt(det * W(0, 0));
292  alpha(0, 1) = 0;
293  indices[0] = fs.getIndexInMatrix();
294  indices[1] = fs.getIndexInMatrix() + 1;
295  unsigned npar_tot = 2;
296  /* TODO: account here for proper motions in the reference
297  catalog. We can code the effect and set the value to 0. Most
298  (all?) catalogs do not even come with a reference epoch. Gaia
299  will change that. When refraction enters into the game, one should
300  pay attention to the orientation of the frame */
301 
302  /* The residual should be Proj(fs)-Proj(*rs) in order to be consistent
303  with the measurement terms. Since P(fs) = 0, we have: */
304  res[0] = -rsProj.x;
305  res[1] = -rsProj.y;
306  halpha = H * alpha;
307  // grad = H*W*res
308  HW = H * W;
309  grad = HW * res;
310  // now feed in triplets and fullGrad
311  for (unsigned ipar = 0; ipar < npar_tot; ++ipar) {
312  for (unsigned ic = 0; ic < 2; ++ic) {
313  double val = halpha(ipar, ic);
314  if (val == 0) continue;
315  tripletList.addTriplet(indices[ipar], kTriplets + ic, val);
316  }
317  fullGrad(indices[ipar]) += grad(ipar);
318  }
319  kTriplets += 2; // each measurement contributes 2 columns in the Jacobian
320  }
321  tripletList.setNextFreeIndex(kTriplets);
322 }
323 
324 void AstrometryFit::accumulateStatImage(CcdImage const &ccdImage, Chi2Accumulator &accum) const {
325  /**********************************************************************/
328  /**********************************************************************/
329  /* Setup */
330  // 1 : get the Mapping's
331  const Mapping *mapping = _astrometryModel->getMapping(ccdImage);
332  // proper motion stuff
333  double mjd = ccdImage.getMjd() - _JDRef;
334  // refraction stuff
335  Point refractionVector = ccdImage.getRefractionVector();
336  // transformation from sky to TP
337  const Gtransfo *sky2TP = _astrometryModel->getSky2TP(ccdImage);
338  // reserve matrix once for all measurements
339  Eigen::Matrix2Xd transW(2, 2);
340 
341  auto &catalog = ccdImage.getCatalogForFit();
342  for (auto const &ms : catalog) {
343  if (!ms->isValid()) continue;
344  // tweak the measurement errors
345  FatPoint inPos = *ms;
346  tweakAstromMeasurementErrors(inPos, *ms, _posError);
347 
348  FatPoint outPos;
349  // should *not* fill H if whatToFit excludes mapping parameters.
350  mapping->transformPosAndErrors(inPos, outPos);
351  double det = outPos.vx * outPos.vy - std::pow(outPos.vxy, 2);
352  if (det <= 0 || outPos.vx <= 0 || outPos.vy <= 0) {
353  LOGLS_WARN(_log, " Inconsistent measurement errors :drop measurement at "
354  << Point(*ms) << " in image " << ccdImage.getName());
355  continue;
356  }
357  transW(0, 0) = outPos.vy / det;
358  transW(1, 1) = outPos.vx / det;
359  transW(0, 1) = transW(1, 0) = -outPos.vxy / det;
360 
361  auto fs = ms->getFittedStar();
362  Point fittedStarInTP =
363  transformFittedStar(*fs, sky2TP, refractionVector, _refractionCoefficient, mjd);
364 
365  Eigen::Vector2d res(fittedStarInTP.x - outPos.x, fittedStarInTP.y - outPos.y);
366  double chi2Val = res.transpose() * transW * res;
367 
368  accum.addEntry(chi2Val, 2, ms);
369  } // end of loop on measurements
370 }
371 
372 void AstrometryFit::accumulateStatImageList(CcdImageList const &ccdImageList, Chi2Accumulator &accum) const {
373  for (auto const &ccdImage : ccdImageList) {
374  accumulateStatImage(*ccdImage, accum);
375  }
376 }
377 
378 void AstrometryFit::accumulateStatRefStars(Chi2Accumulator &accum) const {
379  /**********************************************************************/
382  /**********************************************************************/
383 
384  /* If you wonder why we project here, read comments in
385  AstrometryFit::leastSquareDerivativesReference(TripletList &TList, Eigen::VectorXd &Rhs) */
386  FittedStarList &fittedStarList = _associations->fittedStarList;
387  TanRaDec2Pix proj(GtransfoLin(), Point(0., 0.));
388  for (auto const &fs : fittedStarList) {
389  const RefStar *rs = fs->getRefStar();
390  if (rs == nullptr) continue;
391  proj.setTangentPoint(*fs);
392  // fs projects to (0,0), no need to compute its transform.
393  FatPoint rsProj;
394  proj.transformPosAndErrors(*rs, rsProj);
395  // TO DO : account for proper motions.
396  double rx = rsProj.x; // -fsProj.x (which is 0)
397  double ry = rsProj.y;
398  double det = rsProj.vx * rsProj.vy - std::pow(rsProj.vxy, 2);
399  double wxx = rsProj.vy / det;
400  double wyy = rsProj.vx / det;
401  double wxy = -rsProj.vxy / det;
402  accum.addEntry(wxx * std::pow(rx, 2) + 2 * wxy * rx * ry + wyy * std::pow(ry, 2), 2, fs);
403  }
404 }
405 
407 
409 void AstrometryFit::getIndicesOfMeasuredStar(MeasuredStar const &measuredStar,
410  std::vector<unsigned> &indices) const {
411  if (_fittingDistortions) {
412  const Mapping *mapping = _astrometryModel->getMapping(measuredStar.getCcdImage());
413  mapping->getMappingIndices(indices);
414  }
415  auto fs = measuredStar.getFittedStar();
416  unsigned fsIndex = fs->getIndexInMatrix();
417  if (_fittingPos) {
418  indices.push_back(fsIndex);
419  indices.push_back(fsIndex + 1);
420  }
421  // For securing the outlier removal, the next block is just useless
422  if (_fittingPM) {
423  for (unsigned k = 0; k < NPAR_PM; ++k) indices.push_back(fsIndex + 2 + k);
424  }
425  /* Should not put the index of refaction stuff or we will not be
426  able to remove more than 1 star at a time. */
427 }
428 
430  _whatToFit = whatToFit;
431  LOGLS_INFO(_log, "assignIndices: Now fitting " << whatToFit);
432  _fittingDistortions = (_whatToFit.find("Distortions") != std::string::npos);
433  _fittingPos = (_whatToFit.find("Positions") != std::string::npos);
434  _fittingRefrac = (_whatToFit.find("Refrac") != std::string::npos);
435  if (_sigCol == 0 && _fittingRefrac) {
436  LOGLS_WARN(_log,
437  "Cannot fit refraction coefficients without a color lever arm. Ignoring refraction.");
438  _fittingRefrac = false;
439  }
440  _fittingPM = (_whatToFit.find("PM") != std::string::npos);
441  // When entering here, we assume that whatToFit has already been interpreted.
442 
443  _nParDistortions = 0;
444  if (_fittingDistortions) _nParDistortions = _astrometryModel->assignIndices(0, _whatToFit);
445  unsigned ipar = _nParDistortions;
446 
447  if (_fittingPos) {
448  FittedStarList &fittedStarList = _associations->fittedStarList;
449  for (auto &fittedStar : fittedStarList) {
450  // the parameter layout here is used also
451  // - when filling the derivatives
452  // - when updating (offsetParams())
453  // - in GetMeasuredStarIndices
454  fittedStar->setIndexInMatrix(ipar);
455  ipar += 2;
456  if ((_fittingPM)&fittedStar->mightMove) ipar += NPAR_PM;
457  }
458  }
459  _nParPositions = ipar - _nParDistortions;
460  if (_fittingRefrac) {
461  _refracPosInMatrix = ipar;
462  ipar += _nParRefrac;
463  }
464  _nParTot = ipar;
465 }
466 
467 void AstrometryFit::offsetParams(Eigen::VectorXd const &delta) {
468  if (delta.size() != _nParTot)
470  "AstrometryFit::offsetParams : the provided vector length is not compatible with "
471  "the current whatToFit setting");
472  if (_fittingDistortions) _astrometryModel->offsetParams(delta);
473 
474  if (_fittingPos) {
475  FittedStarList &fittedStarList = _associations->fittedStarList;
476  for (auto const &i : fittedStarList) {
477  FittedStar &fs = *i;
478  // the parameter layout here is used also
479  // - when filling the derivatives
480  // - when assigning indices (assignIndices())
481  unsigned index = fs.getIndexInMatrix();
482  fs.x += delta(index);
483  fs.y += delta(index + 1);
484  if ((_fittingPM)&fs.mightMove) {
485  fs.pmx += delta(index + 2);
486  fs.pmy += delta(index + 3);
487  }
488  }
489  }
490  if (_fittingRefrac) {
491  _refractionCoefficient += delta(_refracPosInMatrix);
492  }
493 }
494 
495 // should not be too large !
496 #ifdef STORAGE
497 static void write_sparse_matrix_in_fits(SpMat const &mat, std::string const &fitsName) {
498  if (mat.rows() * mat.cols() > 2e8) {
499  LOGLS_WARN(_log,
500  "write_sparse_matrix_in_fits: yout matrix is too large. " << fitsName << " not generated");
501  return;
502  }
503  Mat m(mat.rows(), mat.cols());
504  for (int k = 0; k < mat.outerSize(); ++k)
505  for (SpMat::InnerIterator it(mat, k); it; ++it) {
506  m(it.row(), it.col()) = it.value();
507  }
508  m.writeFits(fitsName);
509 }
510 
511 static void write_vect_in_fits(Eigen::VectorXd const &vectorXd, std::string const &fitsName) {
512  Vect v(vectorXd.size());
513  for (int k = 0; k < vectorXd.size(); ++k) v(k) = V(k);
514  Mat(v).writeFits(fitsName);
515 }
516 
517 #endif
518 
520 #if (0)
521  const char *what2fit[] = {"Positions",
522  "Distortions",
523  "Refrac",
524  "Positions Distortions",
525  "Positions Refrac",
526  "Distortions Refrac",
527  "Positions Distortions Refrac"};
528 #endif
529  const char *what2fit[] = {"Positions", "Distortions", "Positions Distortions"};
530  // DEBUG
531  for (unsigned k = 0; k < sizeof(what2fit) / sizeof(what2fit[0]); ++k) {
532  assignIndices(what2fit[k]);
533  TripletList tripletList(10000);
534  Eigen::VectorXd grad(_nParTot);
535  grad.setZero();
536  leastSquareDerivatives(tripletList, grad);
537  SpMat jacobian(_nParTot, tripletList.getNextFreeIndex());
538  jacobian.setFromTriplets(tripletList.begin(), tripletList.end());
539  SpMat hessian = jacobian * jacobian.transpose();
540 #ifdef STORAGE
541  char name[24];
542  sprintf(name, "H%d.fits", k);
543  write_sparse_matrix_in_fits(hessian, name);
544  sprintf(name, "g%d.fits", k);
545  write_vect_in_fits(grad, name);
546 #endif
547  LOGLS_DEBUG(_log, "npar : " << _nParTot << ' ' << _nParDistortions);
548  }
549 }
550 
551 void AstrometryFit::saveResultTuples(std::string const &tupleName) const {
552  /* cook-up 2 different file names by inserting something just before
553  the dot (if any), and within the actual file name. */
554  size_t dot = tupleName.rfind('.');
555  size_t slash = tupleName.rfind('/');
556  if (dot == std::string::npos || (slash != std::string::npos && dot < slash)) dot = tupleName.size();
557  std::string meas_tuple(tupleName);
558  meas_tuple.insert(dot, "-meas");
559  makeMeasResTuple(meas_tuple);
560  std::string ref_tuple(tupleName);
561  ref_tuple.insert(dot, "-ref");
562  makeRefResTuple(ref_tuple);
563 }
564 
565 void AstrometryFit::makeMeasResTuple(std::string const &tupleName) const {
566  std::ofstream tuple(tupleName.c_str());
567  tuple << "#xccd: coordinate in CCD" << std::endl
568  << "#yccd: " << std::endl
569  << "#rx: residual in degrees in TP" << std::endl
570  << "#ry:" << std::endl
571  << "#xtp: transformed coordinate in TP " << std::endl
572  << "#ytp:" << std::endl
573  << "#mag: rough mag" << std::endl
574  << "#jd: Julian date of the measurement" << std::endl
575  << "#rvx: transformed measurement uncertainty " << std::endl
576  << "#rvy:" << std::endl
577  << "#rvxy:" << std::endl
578  << "#color : " << std::endl
579  << "#fsindex: some unique index of the object" << std::endl
580  << "#ra: pos of fitted star" << std::endl
581  << "#dec: pos of fitted star" << std::endl
582  << "#chi2: contribution to Chi2 (2D dofs)" << std::endl
583  << "#nm: number of measurements of this FittedStar" << std::endl
584  << "#chip: chip number" << std::endl
585  << "#visit: visit id" << std::endl
586  << "#end" << std::endl;
587  const CcdImageList &L = _associations->getCcdImageList();
588  for (auto const &i : L) {
589  const CcdImage &im = *i;
590  const MeasuredStarList &cat = im.getCatalogForFit();
591  const Mapping *mapping = _astrometryModel->getMapping(im);
592  const Point &refractionVector = im.getRefractionVector();
593  double mjd = im.getMjd() - _JDRef;
594  for (auto const &is : cat) {
595  const MeasuredStar &ms = *is;
596  if (!ms.isValid()) continue;
597  FatPoint tpPos;
598  FatPoint inPos = ms;
599  tweakAstromMeasurementErrors(inPos, ms, _posError);
600  mapping->transformPosAndErrors(inPos, tpPos);
601  const Gtransfo *sky2TP = _astrometryModel->getSky2TP(im);
602  auto fs = ms.getFittedStar();
603 
604  Point fittedStarInTP =
605  transformFittedStar(*fs, sky2TP, refractionVector, _refractionCoefficient, mjd);
606  Point res = tpPos - fittedStarInTP;
607  double det = tpPos.vx * tpPos.vy - std::pow(tpPos.vxy, 2);
608  double wxx = tpPos.vy / det;
609  double wyy = tpPos.vx / det;
610  double wxy = -tpPos.vxy / det;
611  // double chi2 = rx*(wxx*rx+wxy*ry)+ry*(wxy*rx+wyy*ry);
612  double chi2 = wxx * res.x * res.x + wyy * res.y * res.y + 2 * wxy * res.x * res.y;
613  tuple << std::setprecision(9);
614  tuple << ms.x << ' ' << ms.y << ' ' << res.x << ' ' << res.y << ' ' << tpPos.x << ' ' << tpPos.y
615  << ' ' << fs->getMag() << ' ' << mjd << ' ' << tpPos.vx << ' ' << tpPos.vy << ' '
616  << tpPos.vxy << ' ' << fs->color << ' ' << fs->getIndexInMatrix() << ' ' << fs->x << ' '
617  << fs->y << ' ' << chi2 << ' ' << fs->getMeasurementCount() << ' ' << im.getCcdId() << ' '
618  << im.getVisit() << std::endl;
619  } // loop on measurements in image
620  } // loop on images
621 }
622 
623 void AstrometryFit::makeRefResTuple(std::string const &tupleName) const {
624  std::ofstream tuple(tupleName.c_str());
625  tuple << "#ra: coordinates of FittedStar" << std::endl
626  << "#dec: " << std::endl
627  << "#rx: residual in degrees in TP" << std::endl
628  << "#ry:" << std::endl
629  << "#mag: mag" << std::endl
630  << "#rvx: transformed measurement uncertainty " << std::endl
631  << "#rvy:" << std::endl
632  << "#rvxy:" << std::endl
633  << "#color : " << std::endl
634  << "#fsindex: some unique index of the object" << std::endl
635  << "#chi2: contribution to Chi2 (2D dofs)" << std::endl
636  << "#nm: number of measurements of this FittedStar" << std::endl
637  << "#end" << std::endl;
638  // The following loop is heavily inspired from AstrometryFit::computeChi2()
639  const FittedStarList &fittedStarList = _associations->fittedStarList;
640  TanRaDec2Pix proj(GtransfoLin(), Point(0., 0.));
641  for (auto const &i : fittedStarList) {
642  const FittedStar &fs = *i;
643  const RefStar *rs = fs.getRefStar();
644  if (rs == nullptr) continue;
645  proj.setTangentPoint(fs);
646  // fs projects to (0,0), no need to compute its transform.
647  FatPoint rsProj;
648  proj.transformPosAndErrors(*rs, rsProj);
649  double rx = rsProj.x; // -fsProj.x (which is 0)
650  double ry = rsProj.y;
651  double det = rsProj.vx * rsProj.vy - std::pow(rsProj.vxy, 2);
652  double wxx = rsProj.vy / det;
653  double wyy = rsProj.vx / det;
654  double wxy = -rsProj.vxy / det;
655  double chi2 = wxx * std::pow(rx, 2) + 2 * wxy * rx * ry + wyy * std::pow(ry, 2);
656  tuple << std::setprecision(9);
657  tuple << fs.x << ' ' << fs.y << ' ' << rx << ' ' << ry << ' ' << fs.getMag() << ' ' << rsProj.vx
658  << ' ' << rsProj.vy << ' ' << rsProj.vxy << ' ' << fs.color << ' ' << fs.getIndexInMatrix()
659  << ' ' << chi2 << ' ' << fs.getMeasurementCount() << std::endl;
660  } // loop on FittedStars
661 }
662 } // namespace jointcal
663 } // namespace lsst
Objects used as position anchors, typically USNO stars.
Definition: RefStar.h:16
VisitIdType getVisit() const
returns visit ID
Definition: CcdImage.h:101
implements the linear transformations (6 real coefficients).
Definition: Gtransfo.h:292
Base class for fitters.
Definition: FitterBase.h:28
virtual class needed in the abstraction of the distortion model
Definition: Mapping.h:15
A point in a plane.
Definition: Point.h:13
int getMeasurementCount() const
Definition: FittedStar.h:82
T rfind(T... args)
double getMjd() const
Julian Date.
Definition: CcdImage.h:111
T endl(T... args)
void makeRefResTuple(std::string const &tupleName) const
Produces a tuple containing residuals of reference terms.
T end(T... args)
CcdIdType getCcdId() const
returns ccd ID
Definition: CcdImage.h:98
void assignIndices(std::string const &whatToFit) override
Set parameters to fit and assign indices in the big matrix.
AstrometryFit(std::shared_ptr< Associations > associations, std::shared_ptr< AstrometryModel > astrometryModel, double posError)
this is the only constructor
A Point with uncertainties.
Definition: FatPoint.h:11
A list of MeasuredStar. They are usually filled in Associations::AddImage.
Definition: MeasuredStar.h:111
string name
Matrix alpha
#define LOGLS_INFO(logger, message)
def dot(symb, c, r, frame=None, size=2, ctype=None, origin=afwImage.PARENT, args, kwargs)
STL class.
double x
coordinate
Definition: Point.h:18
T at(T... args)
T push_back(T... args)
STL class.
Class for a simple mapping implementing a generic Gtransfo.
Eigen::SparseMatrix< double > SpMat
Definition: Eigenstuff.h:11
A list of FittedStar s. Such a list is typically constructed by Associations.
Definition: FittedStar.h:121
objects measured on actual images.
Definition: MeasuredStar.h:18
void makeMeasResTuple(std::string const &tupleName) const
Produces a tuple containing residuals of measurement terms.
void offsetParams(Eigen::VectorXd const &delta) override
Offset the parameters by the requested quantities.
std::shared_ptr< Associations > _associations
Definition: FitterBase.h:107
Eigen::Matrix< double, Eigen::Dynamic, 2 > MatrixX2d
Definition: Eigenstuff.h:9
T count(T... args)
#define NPAR_PM
T insert(T... args)
T find(T... args)
void setTangentPoint(const Point &tangentPoint)
Resets the projection (or tangent) point.
Definition: Gtransfo.cc:1444
T size(T... args)
#define LSST_EXCEPT(type,...)
void saveResultTuples(std::string const &tupleName) const override
Save the full chi2 term per star that was used in the minimization, for debugging.
std::shared_ptr< const FittedStar > getFittedStar() const
Definition: MeasuredStar.h:83
This one is the Tangent Plane (called gnomonic) projection (from celestial sphere to tangent plane) ...
Definition: Gtransfo.h:517
T begin(T... args)
void transformPosAndErrors(const FatPoint &in, FatPoint &out) const
transform with analytical derivatives
Definition: Gtransfo.cc:1464
T pow(T... args)
Point getRefractionVector() const
Definition: CcdImage.h:134
MeasuredStarList const & getCatalogForFit() const
Gets the catalog to be used for fitting, which may have been cleaned-up.
Definition: CcdImage.h:64
T c_str(T... args)
a virtual (interface) class for geometric transformations.
Definition: Gtransfo.h:39
const RefStar * getRefStar() const
Get the astrometric reference star associated with this star.
Definition: FittedStar.h:105
#define LOGLS_DEBUG(logger, message)
void leastSquareDerivatives(TripletList &tripletList, Eigen::VectorXd &grad) const
Evaluates the chI^2 derivatives (Jacobian and gradient) for the current whatToFit setting...
Definition: FitterBase.cc:215
int getIndexInMatrix() const
Definition: FittedStar.h:99
std::list< std::shared_ptr< CcdImage > > CcdImageList
Definition: CcdImage.h:23
T sqrt(T... args)
double getMag() const
derived using available zero points in input images. In the absence ofZP, ZP= 0.
Definition: FittedStar.h:86
m
Handler of an actual image from a single CCD.
Definition: CcdImage.h:34
T setprecision(T... args)
bool isValid() const
Fits may use that to discard outliers.
Definition: MeasuredStar.h:90
void checkStuff()
DEBUGGING routine.
T sprintf(T... args)
ImageT val
unsigned getNextFreeIndex() const
Definition: Tripletlist.h:22
#define LOG_GET(logger)
The objects which have been measured several times.
Definition: FittedStar.h:37
virtual void transformPosAndErrors(FatPoint const &where, FatPoint &outPoint) const =0
The same as above but without the parameter derivatives (used to evaluate chi^2)
#define LOGLS_WARN(logger, message)