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 AstrometryMapping *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 auto 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));
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 AstrometryMapping *mapping = _astrometryModel->getMapping(ccdImage);
330 double mjd = ccdImage.getMjd() - _JDRef;
332 Point refractionVector = ccdImage.getRefractionVector();
334 auto 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;
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 AstrometryMapping *mapping = _astrometryModel->getMapping(measuredStar.getCcdImage());
411 mapping->getMappingIndices(indices);
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(
_whatToFit, 0);
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 const char *what2fit[] = {
"Positions",
498 "Positions Distortions",
500 "Distortions Refrac",
501 "Positions Distortions Refrac"};
503 const char *what2fit[] = {
"Positions",
"Distortions",
"Positions Distortions"};
505 for (
unsigned k = 0; k <
sizeof(what2fit) /
sizeof(what2fit[0]); ++k) {
512 jacobian.setFromTriplets(tripletList.
begin(), tripletList.
end());
522 ofile <<
"#id" << separator <<
"xccd" << separator <<
"yccd " << separator;
523 ofile <<
"rx" << separator <<
"ry" << separator;
524 ofile <<
"xtp" << separator <<
"ytp" << separator;
525 ofile <<
"mag" << separator <<
"mjd" << separator;
526 ofile <<
"xErr" << separator <<
"yErr" << separator <<
"xyCov" << separator;
527 ofile <<
"xtpi" << separator <<
"ytpi" << separator;
528 ofile <<
"rxi" << separator <<
"ryi" << separator;
529 ofile <<
"color" << separator <<
"fsindex" << separator;
530 ofile <<
"ra" << separator <<
"dec" << separator;
531 ofile <<
"chi2" << separator <<
"nm" << separator;
532 ofile <<
"chip" << separator <<
"visit" <<
std::endl;
534 ofile <<
"#id in source catalog" << separator <<
"coordinates in CCD (pixels)" << separator << separator;
535 ofile <<
"residual on TP (degrees)" << separator << separator;
536 ofile <<
"transformed coordinate in TP (degrees)" << separator << separator;
537 ofile <<
"rough magnitude" << separator <<
"Modified Julian Date of the measurement" << separator;
538 ofile <<
"transformed measurement uncertainty (degrees)" << separator << separator << separator;
539 ofile <<
"as-read position on TP (degrees)" << separator << separator;
540 ofile <<
"as-read residual on TP (degrees)" << separator << separator;
541 ofile <<
"currently unused" << separator <<
"unique index of the fittedStar" << separator;
542 ofile <<
"on sky position of fittedStar" << separator << separator;
543 ofile <<
"contribution to Chi2 (2D dofs)" << separator <<
"number of measurements of this fittedStar" 545 ofile <<
"chip id" << separator <<
"visit id" <<
std::endl;
548 for (
auto const &ccdImage : ccdImageList) {
551 const auto readTransfo = ccdImage->readWCS();
552 const Point &refractionVector = ccdImage->getRefractionVector();
553 double mjd = ccdImage->getMjd() - _JDRef;
554 for (
auto const &ms : cat) {
555 if (!ms->isValid())
continue;
558 tweakAstromMeasurementErrors(inPos, *ms, _posError);
560 auto sky2TP = _astrometryModel->getSky2TP(*ccdImage);
562 FatPoint inputTpPos = readPix2TP->apply(inPos);
565 Point fittedStarInTP =
566 transformFittedStar(*fs, *sky2TP, refractionVector, _refractionCoefficient, mjd);
567 Point res = tpPos - fittedStarInTP;
568 Point inputRes = inputTpPos - fittedStarInTP;
570 double wxx = tpPos.
vy / det;
571 double wyy = tpPos.
vx / det;
572 double wxy = -tpPos.
vxy / det;
573 double chi2 = wxx * res.
x * res.
x + wyy * res.
y * res.
y + 2 * wxy * res.
x * res.
y;
576 ofile << ms->getId() << separator << ms->x << separator << ms->y << separator;
577 ofile << res.
x << separator << res.
y << separator;
578 ofile << tpPos.
x << separator << tpPos.
y << separator;
579 ofile << fs->getMag() << separator << mjd << separator;
580 ofile << tpPos.
vx << separator << tpPos.
vy << separator << tpPos.
vxy << separator;
581 ofile << inputTpPos.
x << separator << inputTpPos.
y << separator;
582 ofile << inputRes.
x << separator << inputRes.
y << separator;
583 ofile << fs->color << separator << fs->getIndexInMatrix() << separator;
584 ofile << fs->x << separator << fs->y << separator;
585 ofile << chi2 << separator << fs->getMeasurementCount() << separator;
586 ofile << ccdImage->getCcdId() << separator << ccdImage->getVisit() <<
std::endl;
595 ofile <<
"#ra" << separator <<
"dec " << separator;
596 ofile <<
"rx" << separator <<
"ry" << separator;
597 ofile <<
"mag" << separator;
598 ofile <<
"xErr" << separator <<
"yErr" << separator <<
"xyCov" << separator;
599 ofile <<
"color" << separator <<
"fsindex" << separator;
600 ofile <<
"chi2" << separator <<
"nm" <<
std::endl;
602 ofile <<
"#coordinates of fittedStar (degrees)" << separator << separator;
603 ofile <<
"residual on TP (degrees)" << separator << separator;
604 ofile <<
"magnitude" << separator;
605 ofile <<
"refStar transformed measurement uncertainty (degrees)" << separator << separator << separator;
606 ofile <<
"currently unused" << separator <<
"unique index of the fittedStar" << separator;
607 ofile <<
"refStar contribution to Chi2 (2D dofs)" << separator
608 <<
"number of measurements of this FittedStar" <<
std::endl;
613 for (
auto const &i : fittedStarList) {
616 if (rs ==
nullptr)
continue;
621 double rx = rsProj.
x;
622 double ry = rsProj.
y;
624 double wxx = rsProj.
vy / det;
625 double wyy = rsProj.
vx / det;
626 double wxy = -rsProj.
vxy / det;
627 double chi2 = wxx *
std::pow(rx, 2) + 2 * wxy * rx * ry + wyy *
std::pow(ry, 2);
630 ofile << fs.
x << separator << fs.
y << separator;
631 ofile << rx << separator << ry << separator;
632 ofile << fs.
getMag() << separator;
633 ofile << 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.
Eigen::SparseMatrix< double > SparseMatrixD
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::createCcdImage.
#define LOGLS_INFO(logger, message)
Class for a simple mapping implementing a generic Gtransfo.
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
#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
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
virtual void transformPosAndErrors(FatPoint const &where, FatPoint &outPoint) const =0
The same as above but without the parameter derivatives (used to evaluate chi^2)
virtual class needed in the abstraction of the distortion model
void setTangentPoint(Point const &tangentPoint)
Resets the projection (or tangent) point.
T setprecision(T... args)
void checkStuff()
DEBUGGING routine.
unsigned getNextFreeIndex() const
The objects which have been measured several times.
#define LOGLS_WARN(logger, message)
std::unique_ptr< Gtransfo > gtransfoCompose(Gtransfo const &left, Gtransfo const &right)
Returns a pointer to a composition of gtransfos, representing left(right()).