30 #include "Eigen/Sparse"
49 _astrometryModel(astrometryModel),
50 _refractionCoefficient(0),
51 _nParRefrac(_associations->getNFilters()),
62 _referenceColor += i->color;
67 _referenceColor /= double(
count);
70 LOGLS_INFO(
_log,
"Reference Color: " << _referenceColor <<
" sig " << _sigCol);
78 Point AstrometryFit::transformFittedStar(FittedStar
const &fittedStar, AstrometryTransform
const &sky2TP,
79 Point
const &refractionVector,
double refractionCoeff,
81 Point fittedStarInTP = sky2TP.apply(fittedStar);
82 if (fittedStar.mightMove) {
83 fittedStarInTP.x += fittedStar.pmx * mjd;
84 fittedStarInTP.y += fittedStar.pmy * mjd;
89 double color = fittedStar.color - _referenceColor;
90 fittedStarInTP.x += refractionVector.x * color * refractionCoeff;
91 fittedStarInTP.y += refractionVector.y * color * refractionCoeff;
92 return fittedStarInTP;
98 static void tweakAstromMeasurementErrors(FatPoint &P, MeasuredStar
const &Ms,
double error) {
99 static bool called =
false;
100 static double increment = 0;
111 void AstrometryFit::leastSquareDerivativesMeasurement(CcdImage
const &ccdImage, TripletList &tripletList,
112 Eigen::VectorXd &fullGrad,
113 MeasuredStarList
const *msList)
const {
123 if (msList) assert(&(msList->front()->getCcdImage()) == &ccdImage);
126 const AstrometryMapping *mapping = _astrometryModel->getMapping(ccdImage);
128 std::size_t npar_mapping = (_fittingDistortions) ? mapping->getNpar() : 0;
130 std::size_t npar_refrac = (_fittingRefrac) ? 1 : 0;
132 std::size_t npar_tot = npar_mapping + npar_pos + npar_refrac + npar_pm;
135 if (npar_tot == 0)
return;
137 if (_fittingDistortions) mapping->getMappingIndices(indices);
140 double mjd = ccdImage.getMjd() - _JDRef;
142 Point refractionVector = ccdImage.getRefractionVector();
144 auto sky2TP = _astrometryModel->getSkyToTangentPlane(ccdImage);
146 AstrometryTransformLinear dypdy;
150 Eigen::Matrix2d transW(2, 2);
151 Eigen::Matrix2d alpha(2, 2);
152 Eigen::VectorXd grad(npar_tot);
154 Eigen::Index kTriplets = tripletList.getNextFreeIndex();
155 const MeasuredStarList &catalog = (msList) ? *msList : ccdImage.getCatalogForFit();
157 for (
auto &i : catalog) {
158 const MeasuredStar &ms = *i;
159 if (!ms.isValid())
continue;
162 tweakAstromMeasurementErrors(inPos, ms, _posError);
166 if (_fittingDistortions)
167 mapping->computeTransformAndDerivatives(inPos, outPos, H);
169 mapping->transformPosAndErrors(inPos, outPos);
172 double det = outPos.vx * outPos.vy -
std::pow(outPos.vxy, 2);
173 if (det <= 0 || outPos.vx <= 0 || outPos.vy <= 0) {
174 LOGLS_WARN(
_log,
"Inconsistent measurement errors: drop measurement at "
175 << Point(ms) <<
" in image " << ccdImage.getName());
178 transW(0, 0) = outPos.vy / det;
179 transW(1, 1) = outPos.vx / det;
180 transW(0, 1) = transW(1, 0) = -outPos.vxy / det;
183 alpha(0, 0) =
sqrt(transW(0, 0));
185 alpha(1, 0) = transW(0, 1) / alpha(0, 0);
188 alpha(1, 1) = 1. /
sqrt(det * transW(0, 0));
193 Point fittedStarInTP =
194 transformFittedStar(*fs, *sky2TP, refractionVector, _refractionCoefficient, mjd);
199 sky2TP->computeDerivative(*fs, dypdy, 1e-3);
202 H(npar_mapping, 0) = -dypdy.A11();
203 H(npar_mapping + 1, 0) = -dypdy.A12();
204 H(npar_mapping, 1) = -dypdy.A21();
205 H(npar_mapping + 1, 1) = -dypdy.A22();
206 indices[npar_mapping] = fs->getIndexInMatrix();
207 indices.at(npar_mapping + 1) = fs->getIndexInMatrix() + 1;
212 if (_fittingPM && fs->mightMove) {
214 H(ipar + 1, 1) = -mjd;
215 indices[ipar] = fs->getIndexInMatrix() + 2;
216 indices[ipar + 1] = fs->getIndexInMatrix() + 3;
219 if (_fittingRefrac) {
222 double color = fs->color - _referenceColor;
224 H(ipar, 0) = -refractionVector.x * color;
225 H(ipar, 1) = -refractionVector.y * color;
226 indices[ipar] = _refracPosInMatrix;
231 Eigen::Vector2d res(fittedStarInTP.x - outPos.x, fittedStarInTP.y - outPos.y);
239 for (
std::size_t ipar = 0; ipar < npar_tot; ++ipar) {
241 double val = halpha(ipar, ic);
242 if (val == 0)
continue;
243 tripletList.addTriplet(indices[ipar], kTriplets + ic, val);
245 fullGrad(indices[ipar]) += grad(ipar);
249 tripletList.setNextFreeIndex(kTriplets);
252 void AstrometryFit::leastSquareDerivativesReference(FittedStarList
const &fittedStarList,
253 TripletList &tripletList,
254 Eigen::VectorXd &fullGrad)
const {
263 if (!_fittingPos)
return;
267 Eigen::Matrix2d W(2, 2);
268 Eigen::Matrix2d alpha(2, 2);
269 Eigen::Matrix2d H(2, 2), halpha(2, 2), HW(2, 2);
270 AstrometryTransformLinear der;
271 Eigen::Vector2d res, grad;
272 Eigen::Index indices[2 +
NPAR_PM];
273 Eigen::Index kTriplets = tripletList.getNextFreeIndex();
280 TanRaDecToPixel proj(AstrometryTransformLinear(), Point(0., 0.));
281 for (
auto const &i : fittedStarList) {
282 const FittedStar &fs = *i;
283 const RefStar *rs = fs.getRefStar();
284 if (rs ==
nullptr)
continue;
285 proj.setTangentPoint(fs);
288 proj.transformPosAndErrors(*rs, rsProj);
290 proj.computeDerivative(fs, der, 1e-4);
292 H(0, 0) = -der.A11();
293 H(1, 0) = -der.A12();
294 H(0, 1) = -der.A21();
295 H(1, 1) = -der.A22();
297 double det = rsProj.vx * rsProj.vy -
std::pow(rsProj.vxy, 2);
298 if (rsProj.vx <= 0 || rsProj.vy <= 0 || det <= 0) {
299 LOGLS_WARN(
_log,
"RefStar error matrix not positive definite for: " << *rs);
302 W(0, 0) = rsProj.vy / det;
303 W(0, 1) = W(1, 0) = -rsProj.vxy / det;
304 W(1, 1) = rsProj.vx / det;
307 alpha(0, 0) =
sqrt(W(0, 0));
309 alpha(1, 0) = W(0, 1) / alpha(0, 0);
310 alpha(1, 1) = 1. /
sqrt(det * W(0, 0));
312 indices[0] = fs.getIndexInMatrix();
313 indices[1] = fs.getIndexInMatrix() + 1;
314 unsigned npar_tot = 2;
330 for (
std::size_t ipar = 0; ipar < npar_tot; ++ipar) {
331 for (
unsigned ic = 0; ic < 2; ++ic) {
332 double val = halpha(ipar, ic);
333 if (val == 0)
continue;
334 tripletList.addTriplet(indices[ipar], kTriplets + ic, val);
336 fullGrad(indices[ipar]) += grad(ipar);
340 tripletList.setNextFreeIndex(kTriplets);
343 void AstrometryFit::accumulateStatImage(CcdImage
const &ccdImage, Chi2Accumulator &accum)
const {
350 const AstrometryMapping *mapping = _astrometryModel->getMapping(ccdImage);
352 double mjd = ccdImage.getMjd() - _JDRef;
354 Point refractionVector = ccdImage.getRefractionVector();
356 auto sky2TP = _astrometryModel->getSkyToTangentPlane(ccdImage);
358 Eigen::Matrix2Xd transW(2, 2);
360 auto &catalog = ccdImage.getCatalogForFit();
361 for (
auto const &ms : catalog) {
362 if (!ms->isValid())
continue;
364 FatPoint inPos = *ms;
365 tweakAstromMeasurementErrors(inPos, *ms, _posError);
369 mapping->transformPosAndErrors(inPos, outPos);
370 double det = outPos.vx * outPos.vy -
std::pow(outPos.vxy, 2);
371 if (det <= 0 || outPos.vx <= 0 || outPos.vy <= 0) {
372 LOGLS_WARN(
_log,
" Inconsistent measurement errors :drop measurement at "
373 << Point(*ms) <<
" in image " << ccdImage.getName());
376 transW(0, 0) = outPos.vy / det;
377 transW(1, 1) = outPos.vx / det;
378 transW(0, 1) = transW(1, 0) = -outPos.vxy / det;
381 Point fittedStarInTP =
382 transformFittedStar(*fs, *sky2TP, refractionVector, _refractionCoefficient, mjd);
384 Eigen::Vector2d res(fittedStarInTP.x - outPos.x, fittedStarInTP.y - outPos.y);
385 double chi2Val = res.transpose() * transW * res;
387 accum.addEntry(chi2Val, 2, ms);
391 void AstrometryFit::accumulateStatImageList(
CcdImageList const &ccdImageList, Chi2Accumulator &accum)
const {
392 for (
auto const &ccdImage : ccdImageList) {
393 accumulateStatImage(*ccdImage, accum);
397 void AstrometryFit::accumulateStatRefStars(Chi2Accumulator &accum)
const {
405 FittedStarList &fittedStarList =
_associations->fittedStarList;
406 TanRaDecToPixel proj(AstrometryTransformLinear(), Point(0., 0.));
407 for (
auto const &fs : fittedStarList) {
408 const RefStar *rs = fs->getRefStar();
409 if (rs ==
nullptr)
continue;
410 proj.setTangentPoint(*fs);
413 proj.transformPosAndErrors(*rs, rsProj);
415 double rx = rsProj.x;
416 double ry = rsProj.y;
417 double det = rsProj.vx * rsProj.vy -
std::pow(rsProj.vxy, 2);
418 double wxx = rsProj.vy / det;
419 double wyy = rsProj.vx / det;
420 double wxy = -rsProj.vxy / det;
421 double chi2 = wxx *
std::pow(rx, 2) + 2 * wxy * rx * ry + wyy *
std::pow(ry, 2);
422 accum.addEntry(chi2, 2, fs);
429 void AstrometryFit::getIndicesOfMeasuredStar(MeasuredStar
const &measuredStar,
IndexVector &indices)
const {
430 if (_fittingDistortions) {
431 const AstrometryMapping *mapping = _astrometryModel->getMapping(measuredStar.getCcdImage());
432 mapping->getMappingIndices(indices);
435 Eigen::Index fsIndex = fs->getIndexInMatrix();
451 _fittingDistortions = (
_whatToFit.
find(
"Distortions") != std::string::npos);
452 _fittingPos = (
_whatToFit.
find(
"Positions") != std::string::npos);
453 _fittingRefrac = (
_whatToFit.
find(
"Refrac") != std::string::npos);
454 if (_sigCol == 0 && _fittingRefrac) {
456 "Cannot fit refraction coefficients without a color lever arm. Ignoring refraction.");
457 _fittingRefrac =
false;
468 for (
auto &fittedStar : fittedStarList) {
473 fittedStar->setIndexInMatrix(ipar);
475 if ((_fittingPM)&fittedStar->mightMove) ipar +=
NPAR_PM;
479 if (_fittingRefrac) {
480 _refracPosInMatrix = ipar;
491 "AstrometryFit::offsetParams : the provided vector length is not compatible with "
492 "the current whatToFit setting");
493 if (_fittingDistortions) _astrometryModel->offsetParams(delta);
497 for (
auto const &i : fittedStarList) {
503 fs.
x += delta(index);
504 fs.
y += delta(index + 1);
506 fs.
pmx += delta(index + 2);
507 fs.
pmy += delta(index + 3);
511 if (_fittingRefrac) {
512 _refractionCoefficient += delta(_refracPosInMatrix);
518 const char *what2fit[] = {
"Positions",
521 "Positions Distortions",
523 "Distortions Refrac",
524 "Positions Distortions Refrac"};
526 const char *what2fit[] = {
"Positions",
"Distortions",
"Positions Distortions"};
528 for (
unsigned k = 0; k <
sizeof(what2fit) /
sizeof(what2fit[0]); ++k) {
535 jacobian.setFromTriplets(tripletList.
begin(), tripletList.
end());
545 ofile <<
"#id" << separator <<
"xccd" << separator <<
"yccd " << separator;
546 ofile <<
"rx" << separator <<
"ry" << separator;
547 ofile <<
"xtp" << separator <<
"ytp" << separator;
548 ofile <<
"mag" << separator <<
"mjd" << separator;
549 ofile <<
"xErr" << separator <<
"yErr" << separator <<
"xyCov" << separator;
550 ofile <<
"xtpi" << separator <<
"ytpi" << separator;
551 ofile <<
"rxi" << separator <<
"ryi" << separator;
552 ofile <<
"color" << separator <<
"fsindex" << separator;
553 ofile <<
"ra" << separator <<
"dec" << separator;
554 ofile <<
"chi2" << separator <<
"nm" << separator;
555 ofile <<
"chip" << separator <<
"visit" <<
std::endl;
557 ofile <<
"#id in source catalog" << separator <<
"coordinates in CCD (pixels)" << separator << separator;
558 ofile <<
"residual on TP (degrees)" << separator << separator;
559 ofile <<
"transformed coordinate in TP (degrees)" << separator << separator;
560 ofile <<
"rough magnitude" << separator <<
"Modified Julian Date of the measurement" << separator;
561 ofile <<
"transformed measurement uncertainty (degrees)" << separator << separator << separator;
562 ofile <<
"as-read position on TP (degrees)" << separator << separator;
563 ofile <<
"as-read residual on TP (degrees)" << separator << separator;
564 ofile <<
"currently unused" << separator <<
"unique index of the fittedStar" << separator;
565 ofile <<
"on sky position of fittedStar" << separator << separator;
566 ofile <<
"contribution to Chi2 (2D dofs)" << separator <<
"number of measurements of this fittedStar"
568 ofile <<
"chip id" << separator <<
"visit id" <<
std::endl;
571 for (
auto const &ccdImage : ccdImageList) {
574 const auto readTransform = ccdImage->getReadWcs();
575 const Point &refractionVector = ccdImage->getRefractionVector();
576 double mjd = ccdImage->getMjd() - _JDRef;
577 for (
auto const &ms : cat) {
578 if (!ms->isValid())
continue;
581 tweakAstromMeasurementErrors(inPos, *ms, _posError);
583 auto sky2TP = _astrometryModel->getSkyToTangentPlane(*ccdImage);
585 compose(*sky2TP, *readTransform);
586 FatPoint inputTpPos = readPixToTangentPlane->apply(inPos);
589 Point fittedStarInTP =
590 transformFittedStar(*fs, *sky2TP, refractionVector, _refractionCoefficient, mjd);
591 Point res = tpPos - fittedStarInTP;
592 Point inputRes = inputTpPos - fittedStarInTP;
594 double wxx = tpPos.
vy / det;
595 double wyy = tpPos.
vx / det;
596 double wxy = -tpPos.
vxy / det;
597 double chi2 = wxx * res.
x * res.
x + wyy * res.
y * res.
y + 2 * wxy * res.
x * res.
y;
600 ofile << ms->getId() << separator << ms->x << separator << ms->y << separator;
601 ofile << res.
x << separator << res.
y << separator;
602 ofile << tpPos.
x << separator << tpPos.
y << separator;
603 ofile << fs->getMag() << separator << mjd << separator;
604 ofile << tpPos.
vx << separator << tpPos.
vy << separator << tpPos.
vxy << separator;
605 ofile << inputTpPos.
x << separator << inputTpPos.
y << separator;
606 ofile << inputRes.
x << separator << inputRes.
y << separator;
607 ofile << fs->color << separator << fs->getIndexInMatrix() << separator;
608 ofile << fs->x << separator << fs->y << separator;
609 ofile << chi2 << separator << fs->getMeasurementCount() << separator;
610 ofile << ccdImage->getCcdId() << separator << ccdImage->getVisit() <<
std::endl;
619 ofile <<
"#ra" << separator <<
"dec " << separator;
620 ofile <<
"rx" << separator <<
"ry" << separator;
621 ofile <<
"mag" << separator;
622 ofile <<
"xErr" << separator <<
"yErr" << separator <<
"xyCov" << separator;
623 ofile <<
"color" << separator <<
"fsindex" << separator;
624 ofile <<
"chi2" << separator <<
"nm" <<
std::endl;
626 ofile <<
"#coordinates of fittedStar (degrees)" << separator << separator;
627 ofile <<
"residual on TP (degrees)" << separator << separator;
628 ofile <<
"magnitude" << separator;
629 ofile <<
"refStar transformed measurement uncertainty (degrees)" << separator << separator << separator;
630 ofile <<
"currently unused" << separator <<
"unique index of the fittedStar" << separator;
631 ofile <<
"refStar contribution to Chi2 (2D dofs)" << separator
632 <<
"number of measurements of this FittedStar" <<
std::endl;
637 for (
auto const &i : fittedStarList) {
640 if (rs ==
nullptr)
continue;
645 double rx = rsProj.
x;
646 double ry = rsProj.
y;
648 double wxx = rsProj.
vy / det;
649 double wyy = rsProj.
vx / det;
650 double wxy = -rsProj.
vxy / det;
651 double chi2 = wxx *
std::pow(rx, 2) + 2 * wxy * rx * ry + wyy *
std::pow(ry, 2);
654 ofile << fs.
x << separator << fs.
y << separator;
655 ofile << rx << separator << ry << separator;
656 ofile << fs.
getMag() << separator;
657 ofile << rsProj.
vx << separator << rsProj.
vy << separator << rsProj.
vxy << separator;
Eigen::Matrix< double, Eigen::Dynamic, 2 > MatrixX2d
Eigen::SparseMatrix< double, 0, Eigen::Index > SparseMatrixD
#define LSST_EXCEPT(type,...)
#define LOGLS_WARN(logger, message)
#define LOGLS_INFO(logger, message)
#define LOGLS_DEBUG(logger, message)
void checkStuff()
DEBUGGING routine.
void saveChi2RefContributions(std::string const &filename) const override
Save a CSV file containing residuals of reference terms.
void offsetParams(Eigen::VectorXd const &delta) override
Offset the parameters by the requested quantities.
AstrometryFit(std::shared_ptr< Associations > associations, std::shared_ptr< AstrometryModel > astrometryModel, double posError)
this is the only constructor
void assignIndices(std::string const &whatToFit) override
Set parameters to fit and assign indices in the big matrix.
void saveChi2MeasContributions(std::string const &filename) const override
Save a CSV file containing residuals of measurement terms.
virtual class needed in the abstraction of the distortion model
virtual void transformPosAndErrors(FatPoint const &where, FatPoint &outPoint) const =0
The same as above but without the parameter derivatives (used to evaluate chi^2)
A Point with uncertainties.
The objects which have been measured several times.
const RefStar * getRefStar() const
Get the astrometric reference star associated with this star.
int getMeasurementCount() const
Eigen::Index getIndexInMatrix() const
A list of FittedStar s. Such a list is typically constructed by Associations.
void leastSquareDerivatives(TripletList &tripletList, Eigen::VectorXd &grad) const
Evaluates the chI^2 derivatives (Jacobian and gradient) for the current whatToFit setting.
Eigen::Index _nModelParams
std::shared_ptr< Associations > _associations
Eigen::Index _nStarParams
A list of MeasuredStar. They are usually filled in Associations::createCcdImage.
Objects used as position anchors, typically USNO stars.
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
void setTangentPoint(Point const &tangentPoint)
Resets the projection (or tangent) point.
Eigen::Index getNextFreeIndex() const
std::list< std::shared_ptr< CcdImage > > CcdImageList
std::unique_ptr< AstrometryTransform > compose(AstrometryTransform const &left, AstrometryTransform const &right)
Returns a pointer to a composition of transforms, representing left(right()).
Class for a simple mapping implementing a generic AstrometryTransform.
T setprecision(T... args)