6 #include "Eigen/Sparse" 25 _astrometryModel(astrometryModel),
26 _refractionCoefficient(0),
29 _nParRefrac(_associations->getNFilters()),
40 _referenceColor += i->color;
45 _referenceColor /= double(count);
46 if (_sigCol > 0) _sigCol =
sqrt(_sigCol / count -
std::pow(_referenceColor, 2));
48 LOGLS_INFO(
_log,
"Reference Color: " << _referenceColor <<
" sig " << _sigCol);
56 Point AstrometryFit::transformFittedStar(FittedStar
const &fittedStar, Gtransfo
const *sky2TP,
57 Point
const &refractionVector,
double refractionCoeff,
59 Point fittedStarInTP = sky2TP->apply(fittedStar);
60 if (fittedStar.mightMove) {
61 fittedStarInTP.x += fittedStar.pmx * mjd;
62 fittedStarInTP.y += fittedStar.pmy * mjd;
67 double color = fittedStar.color - _referenceColor;
68 fittedStarInTP.x += refractionVector.x * color * refractionCoeff;
69 fittedStarInTP.y += refractionVector.y * color * refractionCoeff;
70 return fittedStarInTP;
76 static void tweakAstromMeasurementErrors(FatPoint &P, MeasuredStar
const &Ms,
double error) {
77 static bool called =
false;
78 static double increment = 0;
89 void AstrometryFit::leastSquareDerivativesMeasurement(CcdImage
const &
ccdImage, TripletList &tripletList,
90 Eigen::VectorXd &fullGrad,
91 MeasuredStarList
const *msList)
const {
101 if (msList) assert(&(msList->front()->getCcdImage()) == &ccdImage);
104 const Mapping *mapping = _astrometryModel->getMapping(ccdImage);
106 unsigned npar_mapping = (_fittingDistortions) ? mapping->getNpar() : 0;
107 unsigned npar_pos = (_fittingPos) ? 2 : 0;
108 unsigned npar_refrac = (_fittingRefrac) ? 1 : 0;
109 unsigned npar_pm = (_fittingPM) ?
NPAR_PM : 0;
110 unsigned npar_tot = npar_mapping + npar_pos + npar_refrac + npar_pm;
113 if (npar_tot == 0)
return;
115 if (_fittingDistortions) mapping->getMappingIndices(indices);
118 double mjd = ccdImage.getMjd() - _JDRef;
120 Point refractionVector = ccdImage.getRefractionVector();
122 const Gtransfo *sky2TP = _astrometryModel->getSky2TP(ccdImage);
128 Eigen::Matrix2d transW(2, 2);
129 Eigen::Matrix2d
alpha(2, 2);
130 Eigen::VectorXd grad(npar_tot);
132 unsigned kTriplets = tripletList.getNextFreeIndex();
133 const MeasuredStarList &catalog = (msList) ? *msList : ccdImage.getCatalogForFit();
135 for (
auto &i : catalog) {
136 const MeasuredStar &ms = *i;
137 if (!ms.isValid())
continue;
140 tweakAstromMeasurementErrors(inPos, ms, _posError);
144 if (_fittingDistortions)
145 mapping->computeTransformAndDerivatives(inPos, outPos, H);
147 mapping->transformPosAndErrors(inPos, outPos);
149 unsigned ipar = npar_mapping;
150 double det = outPos.vx * outPos.vy -
std::pow(outPos.vxy, 2);
151 if (det <= 0 || outPos.vx <= 0 || outPos.vy <= 0) {
152 LOGLS_WARN(
_log,
"Inconsistent measurement errors: drop measurement at " 153 << Point(ms) <<
" in image " << ccdImage.getName());
156 transW(0, 0) = outPos.vy / det;
157 transW(1, 1) = outPos.vx / det;
158 transW(0, 1) = transW(1, 0) = -outPos.vxy / det;
161 alpha(0, 0) = sqrt(transW(0, 0));
163 alpha(1, 0) = transW(0, 1) / alpha(0, 0);
166 alpha(1, 1) = 1. / sqrt(det * transW(0, 0));
169 auto fs = ms.getFittedStar();
171 Point fittedStarInTP =
172 transformFittedStar(*fs, sky2TP, refractionVector, _refractionCoefficient, mjd);
177 sky2TP->computeDerivative(*fs, dypdy, 1e-3);
180 H(npar_mapping, 0) = -dypdy.A11();
181 H(npar_mapping + 1, 0) = -dypdy.A12();
182 H(npar_mapping, 1) = -dypdy.A21();
183 H(npar_mapping + 1, 1) = -dypdy.A22();
184 indices[npar_mapping] = fs->getIndexInMatrix();
185 indices.
at(npar_mapping + 1) = fs->getIndexInMatrix() + 1;
190 if (_fittingPM && fs->mightMove) {
192 H(ipar + 1, 1) = -mjd;
193 indices[ipar] = fs->getIndexInMatrix() + 2;
194 indices[ipar + 1] = fs->getIndexInMatrix() + 3;
197 if (_fittingRefrac) {
200 double color = fs->color - _referenceColor;
202 H(ipar, 0) = -refractionVector.x * color;
203 H(ipar, 1) = -refractionVector.y * color;
204 indices[ipar] = _refracPosInMatrix;
209 Eigen::Vector2d res(fittedStarInTP.x - outPos.x, fittedStarInTP.y - outPos.y);
217 for (
unsigned ipar = 0; ipar < npar_tot; ++ipar) {
218 for (
unsigned ic = 0; ic < 2; ++ic) {
219 double val = halpha(ipar, ic);
220 if (val == 0)
continue;
221 tripletList.addTriplet(indices[ipar], kTriplets + ic, val);
223 fullGrad(indices[ipar]) += grad(ipar);
227 tripletList.setNextFreeIndex(kTriplets);
230 void AstrometryFit::leastSquareDerivativesReference(FittedStarList
const &fittedStarList,
231 TripletList &tripletList,
232 Eigen::VectorXd &fullGrad)
const {
241 if (!_fittingPos)
return;
245 Eigen::Matrix2d W(2, 2);
246 Eigen::Matrix2d
alpha(2, 2);
247 Eigen::Matrix2d H(2, 2), halpha(2, 2), HW(2, 2);
249 Eigen::Vector2d res, grad;
251 unsigned kTriplets = tripletList.getNextFreeIndex();
258 TanRaDec2Pix proj(GtransfoLin(), Point(0., 0.));
259 for (
auto const &i : fittedStarList) {
260 const FittedStar &fs = *i;
261 const RefStar *rs = fs.getRefStar();
262 if (rs ==
nullptr)
continue;
263 proj.setTangentPoint(fs);
266 proj.transformPosAndErrors(*rs, rsProj);
268 proj.computeDerivative(fs, der, 1e-4);
270 H(0, 0) = -der.A11();
271 H(1, 0) = -der.A12();
272 H(0, 1) = -der.A21();
273 H(1, 1) = -der.A22();
275 double det = rsProj.vx * rsProj.vy -
std::pow(rsProj.vxy, 2);
276 if (rsProj.vx <= 0 || rsProj.vy <= 0 || det <= 0) {
277 LOGLS_WARN(
_log,
"RefStar error matrix not positive definite for: " << *rs);
280 W(0, 0) = rsProj.vy / det;
281 W(0, 1) = W(1, 0) = -rsProj.vxy / det;
282 W(1, 1) = rsProj.vx / det;
285 alpha(0, 0) = sqrt(W(0, 0));
287 alpha(1, 0) = W(0, 1) / alpha(0, 0);
288 alpha(1, 1) = 1. / sqrt(det * W(0, 0));
290 indices[0] = fs.getIndexInMatrix();
291 indices[1] = fs.getIndexInMatrix() + 1;
292 unsigned npar_tot = 2;
308 for (
unsigned ipar = 0; ipar < npar_tot; ++ipar) {
309 for (
unsigned ic = 0; ic < 2; ++ic) {
310 double val = halpha(ipar, ic);
311 if (val == 0)
continue;
312 tripletList.addTriplet(indices[ipar], kTriplets + ic, val);
314 fullGrad(indices[ipar]) += grad(ipar);
318 tripletList.setNextFreeIndex(kTriplets);
321 void AstrometryFit::accumulateStatImage(CcdImage
const &ccdImage, Chi2Accumulator &accum)
const {
328 const Mapping *mapping = _astrometryModel->getMapping(ccdImage);
330 double mjd = ccdImage.getMjd() - _JDRef;
332 Point refractionVector = ccdImage.getRefractionVector();
334 const Gtransfo *sky2TP = _astrometryModel->getSky2TP(ccdImage);
336 Eigen::Matrix2Xd transW(2, 2);
338 auto &catalog = ccdImage.getCatalogForFit();
339 for (
auto const &ms : catalog) {
340 if (!ms->isValid())
continue;
342 FatPoint inPos = *ms;
343 tweakAstromMeasurementErrors(inPos, *ms, _posError);
347 mapping->transformPosAndErrors(inPos, outPos);
348 double det = outPos.vx * outPos.vy -
std::pow(outPos.vxy, 2);
349 if (det <= 0 || outPos.vx <= 0 || outPos.vy <= 0) {
350 LOGLS_WARN(
_log,
" Inconsistent measurement errors :drop measurement at " 351 << Point(*ms) <<
" in image " << ccdImage.getName());
354 transW(0, 0) = outPos.vy / det;
355 transW(1, 1) = outPos.vx / det;
356 transW(0, 1) = transW(1, 0) = -outPos.vxy / det;
358 auto fs = ms->getFittedStar();
359 Point fittedStarInTP =
360 transformFittedStar(*fs, sky2TP, refractionVector, _refractionCoefficient, mjd);
362 Eigen::Vector2d res(fittedStarInTP.x - outPos.x, fittedStarInTP.y - outPos.y);
363 double chi2Val = res.transpose() * transW * res;
365 accum.addEntry(chi2Val, 2, ms);
369 void AstrometryFit::accumulateStatImageList(
CcdImageList const &ccdImageList, Chi2Accumulator &accum)
const {
370 for (
auto const &ccdImage : ccdImageList) {
371 accumulateStatImage(*ccdImage, accum);
375 void AstrometryFit::accumulateStatRefStars(Chi2Accumulator &accum)
const {
383 FittedStarList &fittedStarList =
_associations->fittedStarList;
384 TanRaDec2Pix proj(GtransfoLin(), Point(0., 0.));
385 for (
auto const &fs : fittedStarList) {
386 const RefStar *rs = fs->getRefStar();
387 if (rs ==
nullptr)
continue;
388 proj.setTangentPoint(*fs);
391 proj.transformPosAndErrors(*rs, rsProj);
393 double rx = rsProj.x;
394 double ry = rsProj.y;
395 double det = rsProj.vx * rsProj.vy -
std::pow(rsProj.vxy, 2);
396 double wxx = rsProj.vy / det;
397 double wyy = rsProj.vx / det;
398 double wxy = -rsProj.vxy / det;
399 double chi2 = wxx *
std::pow(rx, 2) + 2 * wxy * rx * ry + wyy *
std::pow(ry, 2);
400 accum.addEntry(chi2, 2, fs);
407 void AstrometryFit::getIndicesOfMeasuredStar(MeasuredStar
const &measuredStar,
409 if (_fittingDistortions) {
410 const Mapping *mapping = _astrometryModel->getMapping(measuredStar.getCcdImage());
411 mapping->getMappingIndices(indices);
413 auto fs = measuredStar.getFittedStar();
414 unsigned fsIndex = fs->getIndexInMatrix();
430 _fittingDistortions = (
_whatToFit.
find(
"Distortions") != std::string::npos);
431 _fittingPos = (
_whatToFit.
find(
"Positions") != std::string::npos);
432 _fittingRefrac = (
_whatToFit.
find(
"Refrac") != std::string::npos);
433 if (_sigCol == 0 && _fittingRefrac) {
435 "Cannot fit refraction coefficients without a color lever arm. Ignoring refraction.");
436 _fittingRefrac =
false;
441 _nParDistortions = 0;
442 if (_fittingDistortions) _nParDistortions = _astrometryModel->assignIndices(0,
_whatToFit);
443 unsigned ipar = _nParDistortions;
447 for (
auto &fittedStar : fittedStarList) {
452 fittedStar->setIndexInMatrix(ipar);
454 if ((_fittingPM)&fittedStar->mightMove) ipar +=
NPAR_PM;
457 _nParPositions = ipar - _nParDistortions;
458 if (_fittingRefrac) {
459 _refracPosInMatrix = ipar;
468 "AstrometryFit::offsetParams : the provided vector length is not compatible with " 469 "the current whatToFit setting");
470 if (_fittingDistortions) _astrometryModel->offsetParams(delta);
474 for (
auto const &i : fittedStarList) {
480 fs.
x += delta(index);
481 fs.
y += delta(index + 1);
483 fs.
pmx += delta(index + 2);
484 fs.
pmy += delta(index + 3);
488 if (_fittingRefrac) {
489 _refractionCoefficient += delta(_refracPosInMatrix);
495 static void write_sparse_matrix_in_fits(
SpMat const &mat,
std::string const &fitsName) {
496 if (mat.rows() * mat.cols() > 2e8) {
498 "write_sparse_matrix_in_fits: yout matrix is too large. " << fitsName <<
" not generated");
501 Mat
m(mat.rows(), mat.cols());
502 for (
int k = 0; k < mat.outerSize(); ++k)
503 for (SpMat::InnerIterator it(mat, k); it; ++it) {
504 m(it.row(), it.col()) = it.value();
506 m.writeFits(fitsName);
509 static void write_vect_in_fits(Eigen::VectorXd
const &vectorXd,
std::string const &fitsName) {
510 Vect v(vectorXd.size());
511 for (
int k = 0; k < vectorXd.size(); ++k) v(k) = V(k);
512 Mat(v).writeFits(fitsName);
519 const char *what2fit[] = {
"Positions",
522 "Positions Distortions",
524 "Distortions Refrac",
525 "Positions Distortions Refrac"};
527 const char *what2fit[] = {
"Positions",
"Distortions",
"Positions Distortions"};
529 for (
unsigned k = 0; k <
sizeof(what2fit) /
sizeof(what2fit[0]); ++k) {
536 jacobian.setFromTriplets(tripletList.
begin(), tripletList.
end());
537 SpMat hessian = jacobian * jacobian.transpose();
541 write_sparse_matrix_in_fits(hessian, name);
543 write_vect_in_fits(grad, name);
552 ofile <<
"#id" << separator <<
"xccd" << separator <<
"yccd " << separator <<
"rx" << separator <<
"ry" 553 << separator <<
"xtp" << separator <<
"ytp" << separator <<
"mag" << separator <<
"mjd" << separator
554 <<
"rvx" << separator <<
"rvy" << separator <<
"rvxy" << separator <<
"color" << separator
555 <<
"fsindex" << separator <<
"ra" << separator <<
"dec" << separator <<
"chi2" << separator <<
"nm" 556 << separator <<
"chip" << separator <<
"visit" <<
std::endl;
557 ofile <<
"#id in source catalog" << separator <<
"coordinates in CCD" << separator << separator
558 <<
"residual in degrees in TP" << separator << separator <<
"transformed coordinate in TP" 559 << separator << separator <<
"rough mag" << separator <<
"Modified Julian date of the measurement" 560 << separator <<
"transformed measurement uncertainty" << separator << separator << separator
561 <<
"currently unused" << separator <<
"unique index of the fittedStar" << separator
562 <<
"on sky position of fittedStar" << separator << separator <<
"contribution to Chi2 (2D dofs)" 563 << separator <<
"number of measurements of this fittedStar" << separator <<
"chip id" << separator
566 for (
auto const &ccdImage : ccdImageList) {
568 const Mapping *mapping = _astrometryModel->getMapping(*ccdImage);
569 const Point &refractionVector = ccdImage->getRefractionVector();
570 double mjd = ccdImage->getMjd() - _JDRef;
571 for (
auto const &ms : cat) {
572 if (!ms->isValid())
continue;
575 tweakAstromMeasurementErrors(inPos, *ms, _posError);
577 const Gtransfo *sky2TP = _astrometryModel->getSky2TP(*ccdImage);
578 auto fs = ms->getFittedStar();
580 Point fittedStarInTP =
581 transformFittedStar(*fs, sky2TP, refractionVector, _refractionCoefficient, mjd);
582 Point res = tpPos - fittedStarInTP;
584 double wxx = tpPos.
vy / det;
585 double wyy = tpPos.
vx / det;
586 double wxy = -tpPos.
vxy / det;
587 double chi2 = wxx * res.
x * res.
x + wyy * res.
y * res.
y + 2 * wxy * res.
x * res.
y;
589 ofile << ms->getId() << separator << ms->x << separator << ms->y << separator << res.
x 590 << separator << res.
y << separator << tpPos.
x << separator << tpPos.
y << separator
591 << fs->getMag() << separator << mjd << separator << tpPos.
vx << separator << tpPos.
vy 592 << separator << tpPos.
vxy << separator << fs->color << separator << fs->getIndexInMatrix()
593 << separator << fs->x << separator << fs->y << separator << chi2 << separator
594 << fs->getMeasurementCount() << separator << ccdImage->getCcdId() << separator
603 ofile <<
"#ra" << separator <<
"dec " << separator <<
"rx" << separator <<
"ry" << separator <<
"mag" 604 << separator <<
"rvx" << separator <<
"rvy" << separator <<
"rvxy" << separator <<
"color" 605 << separator <<
"fsindex" << separator <<
"chi2" << separator <<
"nm" <<
std::endl;
606 ofile <<
"#coordinates of fittedStar" << separator << separator <<
"residual in degrees in TP" 607 << separator << separator <<
"magnitude" << separator
608 <<
"refStar transformed measurement uncertainty" << separator << separator << separator
609 <<
"currently unused" << separator <<
"unique index of the fittedStar" << separator
610 <<
"refStar contribution to Chi2 (2D dofs)" << separator
611 <<
"number of measurements of this FittedStar" <<
std::endl;
615 for (
auto const &i : fittedStarList) {
618 if (rs ==
nullptr)
continue;
623 double rx = rsProj.
x;
624 double ry = rsProj.
y;
626 double wxx = rsProj.
vy / det;
627 double wyy = rsProj.
vx / det;
628 double wxy = -rsProj.
vxy / det;
629 double chi2 = wxx *
std::pow(rx, 2) + 2 * wxy * rx * ry + wyy *
std::pow(ry, 2);
631 ofile << fs.
x << separator << fs.
y << separator << rx << separator << ry << separator << fs.
getMag()
632 << separator << rsProj.
vx << separator << rsProj.
vy << separator << rsProj.
vxy << separator
Objects used as position anchors, typically USNO stars.
implements the linear transformations (6 real coefficients).
void saveChi2RefContributions(std::string const &baseName) const override
Save a CSV file containing residuals of reference terms.
virtual class needed in the abstraction of the distortion model
int getMeasurementCount() const
void saveChi2MeasContributions(std::string const &baseName) const override
Save a CSV file containing residuals of measurement terms.
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.
A list of MeasuredStar. They are usually filled in Associations::AddImage.
#define LOGLS_INFO(logger, message)
Class for a simple mapping implementing a generic Gtransfo.
Eigen::SparseMatrix< double > SpMat
A list of FittedStar s. Such a list is typically constructed by Associations.
void offsetParams(Eigen::VectorXd const &delta) override
Offset the parameters by the requested quantities.
std::shared_ptr< Associations > _associations
Eigen::Matrix< double, Eigen::Dynamic, 2 > MatrixX2d
void setTangentPoint(const Point &tangentPoint)
Resets the projection (or tangent) point.
#define LSST_EXCEPT(type,...)
This one is the Tangent Plane (called gnomonic) projection (from celestial sphere to tangent plane) ...
void transformPosAndErrors(const FatPoint &in, FatPoint &out) const
transform with analytical derivatives
a virtual (interface) class for geometric transformations.
const RefStar * getRefStar() const
Get the astrometric reference star associated with this star.
#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...
int getIndexInMatrix() const
std::list< std::shared_ptr< CcdImage > > CcdImageList
double getMag() const
derived using available zero points in input images. In the absence ofZP, ZP= 0.
T setprecision(T... args)
void checkStuff()
DEBUGGING routine.
unsigned getNextFreeIndex() const
The objects which have been measured several times.
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)