31#include "Eigen/Sparse"
56 double wxx = refStar.
vy /
det;
57 double wyy = refStar.
vx /
det;
58 double wxy = -refStar.
vxy /
det;
59 return wxx *
std::pow(refStar.
x, 2) + 2 * wxy * refStar.
x * refStar.
y + wyy *
std::pow(refStar.
y, 2);
69 _astrometryModel(
std::
move(astrometryModel)),
70 _epoch(_associations->getEpoch()),
79 double deltaYears)
const {
84 fittedStarInTP = sky2TP.
apply(temp);
86 fittedStarInTP = sky2TP.
apply(fittedStar);
88 return fittedStarInTP;
94static void tweakAstromMeasurementErrors(FatPoint &P, MeasuredStar
const &Ms,
double error) {
95 static bool called =
false;
96 static double increment = 0;
107void AstrometryFit::leastSquareDerivativesMeasurement(CcdImage
const &ccdImage, TripletList &tripletList,
108 Eigen::VectorXd &fullGrad,
109 MeasuredStarList
const *msList)
const {
119 if (msList) assert(&(msList->front()->getCcdImage()) == &ccdImage);
122 const AstrometryMapping *mapping = _astrometryModel->getMapping(ccdImage);
124 std::size_t npar_mapping = (_fittingDistortions) ? mapping->getNpar() : 0;
127 std::size_t npar_tot = npar_mapping + npar_pos + npar_pm;
130 if (npar_tot == 0)
return;
132 if (_fittingDistortions) mapping->getMappingIndices(indices);
135 double deltaYears = _epoch - ccdImage.getEpoch();
137 auto sky2TP = _astrometryModel->getSkyToTangentPlane(ccdImage);
139 AstrometryTransformLinear dypdy;
143 Eigen::Matrix2d transW(2, 2);
144 Eigen::Matrix2d alpha(2, 2);
145 Eigen::VectorXd grad(npar_tot);
147 Eigen::Index kTriplets = tripletList.getNextFreeIndex();
148 const MeasuredStarList &catalog = (msList) ? *msList : ccdImage.getCatalogForFit();
150 for (
auto &i : catalog) {
151 const MeasuredStar &ms = *i;
152 if (!ms.isValid())
continue;
155 tweakAstromMeasurementErrors(inPos, ms, _posError);
159 if (_fittingDistortions)
160 mapping->computeTransformAndDerivatives(inPos, outPos, H);
162 mapping->transformPosAndErrors(inPos, outPos);
165 double det = outPos.vx * outPos.vy -
std::pow(outPos.vxy, 2);
166 if (
det <= 0 || outPos.vx <= 0 || outPos.vy <= 0) {
167 LOGLS_WARN(
_log,
"Inconsistent measurement errors: drop measurement at "
168 << Point(ms) <<
" in image " << ccdImage.getName());
171 transW(0, 0) = outPos.vy /
det;
172 transW(1, 1) = outPos.vx /
det;
173 transW(0, 1) = transW(1, 0) = -outPos.vxy /
det;
176 alpha(0, 0) =
sqrt(transW(0, 0));
178 alpha(1, 0) = transW(0, 1) / alpha(0, 0);
181 alpha(1, 1) = 1. /
sqrt(
det * transW(0, 0));
186 Point fittedStarInTP = transformFittedStar(*fs, *sky2TP, deltaYears);
194 H(npar_mapping, 0) = -dypdy.A11();
195 H(npar_mapping + 1, 0) = -dypdy.A12();
196 H(npar_mapping, 1) = -dypdy.A21();
197 H(npar_mapping + 1, 1) = -dypdy.A22();
198 indices[npar_mapping] = fs->getIndexInMatrix();
199 indices.at(npar_mapping + 1) = fs->getIndexInMatrix() + 1;
215 Eigen::Vector2d res(fittedStarInTP.x - outPos.x, fittedStarInTP.y - outPos.y);
223 for (
std::size_t ipar = 0; ipar < npar_tot; ++ipar) {
225 double val = halpha(ipar, ic);
226 if (
val == 0)
continue;
227 tripletList.addTriplet(indices[ipar], kTriplets + ic,
val);
229 fullGrad(indices[ipar]) += grad(ipar);
233 tripletList.setNextFreeIndex(kTriplets);
236void AstrometryFit::leastSquareDerivativesReference(FittedStarList
const &fittedStarList,
237 TripletList &tripletList,
238 Eigen::VectorXd &fullGrad)
const {
247 if (!_fittingPos)
return;
251 Eigen::Matrix2d W(2, 2);
252 Eigen::Matrix2d alpha(2, 2);
253 Eigen::Matrix2d H(2, 2), halpha(2, 2), HW(2, 2);
254 AstrometryTransformLinear der;
255 Eigen::Vector2d res, grad;
256 Eigen::Index indices[2];
257 Eigen::Index kTriplets = tripletList.getNextFreeIndex();
264 TanRaDecToPixel proj(AstrometryTransformLinear(), Point(0., 0.));
265 for (
auto const &i : fittedStarList) {
266 const FittedStar &fs = *i;
267 auto rs = fs.getRefStar();
268 if (rs ==
nullptr)
continue;
269 proj.setTangentPoint(fs);
272 proj.transformPosAndErrors(*rs, rsProj);
274 proj.computeDerivative(fs, der, 1e-4);
276 H(0, 0) = -der.A11();
277 H(1, 0) = -der.A12();
278 H(0, 1) = -der.A21();
279 H(1, 1) = -der.A22();
281 double det = rsProj.vx * rsProj.vy -
std::pow(rsProj.vxy, 2);
282 if (rsProj.vx <= 0 || rsProj.vy <= 0 ||
det <= 0) {
283 LOGLS_WARN(
_log,
"RefStar error matrix not positive definite for: " << *rs);
286 W(0, 0) = rsProj.vy /
det;
287 W(0, 1) = W(1, 0) = -rsProj.vxy /
det;
288 W(1, 1) = rsProj.vx /
det;
291 alpha(0, 0) =
sqrt(W(0, 0));
293 alpha(1, 0) = W(0, 1) / alpha(0, 0);
294 alpha(1, 1) = 1. /
sqrt(
det * W(0, 0));
296 indices[0] = fs.getIndexInMatrix();
297 indices[1] = fs.getIndexInMatrix() + 1;
298 unsigned npar_tot = 2;
314 for (
std::size_t ipar = 0; ipar < npar_tot; ++ipar) {
315 for (
unsigned ic = 0; ic < 2; ++ic) {
316 double val = halpha(ipar, ic);
317 if (
val == 0)
continue;
318 tripletList.addTriplet(indices[ipar], kTriplets + ic,
val);
320 fullGrad(indices[ipar]) += grad(ipar);
324 tripletList.setNextFreeIndex(kTriplets);
327void AstrometryFit::accumulateStatImage(CcdImage
const &ccdImage, Chi2Accumulator &accum)
const {
334 const AstrometryMapping *mapping = _astrometryModel->getMapping(ccdImage);
336 double deltaYears = _epoch - ccdImage.getEpoch();
338 auto sky2TP = _astrometryModel->getSkyToTangentPlane(ccdImage);
340 Eigen::Matrix2Xd transW(2, 2);
342 auto &catalog = ccdImage.getCatalogForFit();
343 for (
auto const &ms : catalog) {
344 if (!ms->isValid())
continue;
346 FatPoint inPos = *ms;
347 tweakAstromMeasurementErrors(inPos, *ms, _posError);
351 mapping->transformPosAndErrors(inPos, outPos);
352 double det = outPos.vx * outPos.vy -
std::pow(outPos.vxy, 2);
353 if (
det <= 0 || outPos.vx <= 0 || outPos.vy <= 0) {
354 LOGLS_WARN(
_log,
" Inconsistent measurement errors :drop measurement at "
355 << Point(*ms) <<
" in image " << ccdImage.getName());
358 transW(0, 0) = outPos.vy /
det;
359 transW(1, 1) = outPos.vx /
det;
360 transW(0, 1) = transW(1, 0) = -outPos.vxy /
det;
363 Point fittedStarInTP = transformFittedStar(*fs, *sky2TP, deltaYears);
365 Eigen::Vector2d res(fittedStarInTP.x - outPos.x, fittedStarInTP.y - outPos.y);
366 double chi2Val = res.transpose() * transW * res;
368 accum.addEntry(chi2Val, 2, ms);
372void AstrometryFit::accumulateStatImageList(
CcdImageList const &ccdImageList, Chi2Accumulator &accum)
const {
373 for (
auto const &ccdImage : ccdImageList) {
374 accumulateStatImage(*ccdImage, accum);
378void AstrometryFit::accumulateStatRefStars(Chi2Accumulator &accum)
const {
386 FittedStarList &fittedStarList =
_associations->fittedStarList;
387 TanRaDecToPixel proj(AstrometryTransformLinear(), Point(0., 0.));
388 for (
auto const &fs : fittedStarList) {
389 auto rs = fs->getRefStar();
390 if (rs ==
nullptr)
continue;
391 proj.setTangentPoint(*fs);
394 proj.transformPosAndErrors(*rs, rsProj);
396 double chi2 = computeProjectedRefStarChi2(rsProj);
397 accum.addEntry(chi2, 2, fs);
404void AstrometryFit::getIndicesOfMeasuredStar(MeasuredStar
const &measuredStar,
IndexVector &indices)
const {
405 if (_fittingDistortions) {
406 const AstrometryMapping *mapping = _astrometryModel->getMapping(measuredStar.getCcdImage());
407 mapping->getMappingIndices(indices);
410 Eigen::Index fsIndex = fs->getIndexInMatrix();
426 _fittingDistortions = (
_whatToFit.
find(
"Distortions") != std::string::npos);
427 _fittingPos = (
_whatToFit.
find(
"Positions") != std::string::npos);
437 for (
auto &fittedStar : fittedStarList) {
457 "AstrometryFit::offsetParams : the provided vector length is not compatible with "
458 "the current whatToFit setting");
459 if (_fittingDistortions) _astrometryModel->offsetParams(delta);
463 for (
auto const &i : fittedStarList) {
469 fs.
x += delta(index);
470 fs.
y += delta(index + 1);
481 const char *what2fit[] = {
"Positions",
"Distortions",
"Positions Distortions"};
483 for (
unsigned k = 0; k <
sizeof(what2fit) /
sizeof(what2fit[0]); ++k) {
490 jacobian.setFromTriplets(tripletList.
begin(), tripletList.
end());
500 ofile <<
"id" << separator <<
"xccd" << separator <<
"yccd " << separator;
501 ofile <<
"rx" << separator <<
"ry" << separator;
502 ofile <<
"xtp" << separator <<
"ytp" << separator;
503 ofile <<
"mag" << separator <<
"deltaYears" << separator;
504 ofile <<
"xErr" << separator <<
"yErr" << separator <<
"xyCov" << separator;
505 ofile <<
"xtpi" << separator <<
"ytpi" << separator;
506 ofile <<
"rxi" << separator <<
"ryi" << separator;
507 ofile <<
"fsindex" << separator;
508 ofile <<
"ra" << separator <<
"dec" << separator;
509 ofile <<
"chi2" << separator <<
"nm" << separator;
510 ofile <<
"detector" << separator <<
"visit" <<
std::endl;
512 ofile <<
"id in source catalog" << separator <<
"coordinates in CCD (pixels)" << separator << separator;
513 ofile <<
"residual on TP (degrees)" << separator << separator;
514 ofile <<
"transformed coordinate in TP (degrees)" << separator << separator;
515 ofile <<
"rough magnitude" << separator <<
"Julian epoch year delta from fit epoch" << separator;
516 ofile <<
"transformed measurement uncertainty (degrees)" << separator << separator << separator;
517 ofile <<
"as-read position on TP (degrees)" << separator << separator;
518 ofile <<
"as-read residual on TP (degrees)" << separator << separator;
519 ofile <<
"unique index of the fittedStar" << separator;
520 ofile <<
"on sky position of fittedStar" << separator << separator;
521 ofile <<
"contribution to chi2 (2D dofs)" << separator <<
"number of measurements of this fittedStar"
523 ofile <<
"detector id" << separator <<
"visit id" <<
std::endl;
526 for (
auto const &ccdImage : ccdImageList) {
529 const auto readTransform = ccdImage->getReadWcs();
531 double deltaYears = _epoch - ccdImage->getEpoch();
532 for (
auto const &ms : cat) {
533 if (!ms->isValid())
continue;
536 tweakAstromMeasurementErrors(inPos, *ms, _posError);
538 auto sky2TP = _astrometryModel->getSkyToTangentPlane(*ccdImage);
540 compose(*sky2TP, *readTransform);
541 FatPoint inputTpPos = readPixToTangentPlane->apply(inPos);
544 Point fittedStarInTP = transformFittedStar(*fs, *sky2TP, deltaYears);
545 Point res = tpPos - fittedStarInTP;
546 Point inputRes = inputTpPos - fittedStarInTP;
548 double wxx = tpPos.
vy /
det;
549 double wyy = tpPos.
vx /
det;
550 double wxy = -tpPos.
vxy /
det;
551 double chi2 = wxx * res.
x * res.
x + wyy * res.
y * res.
y + 2 * wxy * res.
x * res.
y;
554 ofile << ms->getId() << separator << ms->x << separator << ms->y << separator;
555 ofile << res.
x << separator << res.
y << separator;
556 ofile << tpPos.
x << separator << tpPos.
y << separator;
557 ofile << fs->getMag() << separator << deltaYears << separator;
558 ofile << tpPos.
vx << separator << tpPos.
vy << separator << tpPos.
vxy << separator;
559 ofile << inputTpPos.
x << separator << inputTpPos.
y << separator;
560 ofile << inputRes.
x << separator << inputRes.
y << separator;
561 ofile << fs->getIndexInMatrix() << separator;
562 ofile << fs->x << separator << fs->y << separator;
563 ofile << chi2 << separator << fs->getMeasurementCount() << separator;
564 ofile << ccdImage->getCcdId() << separator << ccdImage->getVisit() <<
std::endl;
573 ofile <<
"ra" << separator <<
"dec " << separator;
574 ofile <<
"rx" << separator <<
"ry" << separator;
575 ofile <<
"mag" << separator;
576 ofile <<
"xErr" << separator <<
"yErr" << separator <<
"xyCov" << separator;
577 ofile <<
"fsindex" << separator;
578 ofile <<
"chi2" << separator <<
"nm" <<
std::endl;
580 ofile <<
"coordinates of fittedStar (degrees)" << separator << separator;
581 ofile <<
"residual on TP (degrees)" << separator << separator;
582 ofile <<
"magnitude" << separator;
583 ofile <<
"refStar transformed measurement uncertainty (degrees)" << separator << separator << separator;
584 ofile <<
"unique index of the fittedStar" << separator;
585 ofile <<
"refStar contribution to chi2 (2D dofs)" << separator
586 <<
"number of measurements of this FittedStar" <<
std::endl;
591 for (
auto const &i : fittedStarList) {
594 if (rs ==
nullptr)
continue;
599 double chi2 = computeProjectedRefStarChi2(rsProj);
602 ofile << fs.
x << separator << fs.
y << separator;
603 ofile << rsProj.
x << separator << rsProj.
y << separator;
604 ofile << fs.
getMag() << separator;
605 ofile << rsProj.
vx << separator << rsProj.
vy << separator << rsProj.
vxy << separator;
Eigen::SparseMatrix< double, 0, Eigen::Index > SparseMatrixD
Eigen::Matrix< double, Eigen::Dynamic, 2 > MatrixX2d
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
LSST DM logging module built on log4cxx.
#define LOGLS_WARN(logger, message)
Log a warn-level message using an iostream-based interface.
#define LOG_GET(logger)
Returns a Log object associated with logger.
#define LOGLS_INFO(logger, message)
Log a info-level message using an iostream-based interface.
#define LOGLS_DEBUG(logger, message)
Log a debug-level message using an iostream-based interface.
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.
FittedStars are objects whose position or flux is going to be fitted, and which come from the associa...
void setIndexInMatrix(Eigen::Index const index)
index is a value that a fit can set and reread....
const RefStar * getRefStar() const
Get the astrometric reference star associated with this star.
int getMeasurementCount() const
The number of MeasuredStars currently associated with this FittedStar.
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.
Point applyProperMotion(const Point &star, double timeDeltaYears) const
Apply proper motion correction to the input star, returning a star with PM-corrected coordinates and ...
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
Reports invalid arguments.
std::unique_ptr< AstrometryTransform > compose(AstrometryTransform const &left, AstrometryTransform const &right)
Returns a pointer to a composition of transforms, representing left(right()).
std::list< std::shared_ptr< CcdImage > > CcdImageList
A base class for image defects.
T setprecision(T... args)