LSST Applications g0f08755f38+9c285cab97,g1635faa6d4+bcae251498,g1653933729+a8ce1bb630,g1a0ca8cf93+bf6eb00ceb,g28da252d5a+0829b12dee,g29321ee8c0+18ecbd06b3,g2bbee38e9b+9634bc57db,g2bc492864f+9634bc57db,g2cdde0e794+c2c89b37c4,g3156d2b45e+41e33cbcdc,g347aa1857d+9634bc57db,g35bb328faa+a8ce1bb630,g3a166c0a6a+9634bc57db,g3e281a1b8c+9f2c4e2fc3,g414038480c+077ccc18e7,g41af890bb2+fde0dd39b6,g5fbc88fb19+17cd334064,g7642f7d749+9c285cab97,g781aacb6e4+a8ce1bb630,g80478fca09+55a9465950,g82479be7b0+ed77629bff,g858d7b2824+9c285cab97,g9125e01d80+a8ce1bb630,g9726552aa6+10f999ec6a,ga5288a1d22+2a84bb7594,gacf8899fa4+c69c5206e8,gae0086650b+a8ce1bb630,gb58c049af0+d64f4d3760,gbd46683f8f+1c79523530,gc28159a63d+9634bc57db,gcf0d15dbbd+4b7d09cae4,gda3e153d99+9c285cab97,gda6a2b7d83+4b7d09cae4,gdaeeff99f8+1711a396fd,ge2409df99d+dfd3d5294a,ge79ae78c31+9634bc57db,gf0baf85859+147a0692ba,gf3967379c6+02b11634a5,w.2024.46
LSST Data Management Base Package
Loading...
Searching...
No Matches
Public Member Functions | Protected Member Functions | Protected Attributes | Private Member Functions | List of all members
lsst::jointcal::PhotometryFit Class Reference

Class that handles the photometric least squares problem. More...

#include <PhotometryFit.h>

Inheritance diagram for lsst::jointcal::PhotometryFit:
lsst::jointcal::FitterBase

Public Member Functions

 PhotometryFit (std::shared_ptr< Associations > associations, std::shared_ptr< PhotometryModel > photometryModel)
 Construct a photometry fitter.
 
 PhotometryFit (PhotometryFit const &)=delete
 No copy or move: there is only ever one fitter of a given type.
 
 PhotometryFit (PhotometryFit &&)=delete
 
PhotometryFitoperator= (PhotometryFit const &)=delete
 
PhotometryFitoperator= (PhotometryFit &&)=delete
 
void assignIndices (std::string const &whatToFit) override
 Set parameters to fit and assign indices in the big matrix.
 
void offsetParams (Eigen::VectorXd const &delta) override
 Offset the parameters by the requested quantities.
 
std::shared_ptr< PhotometryModelgetModel () const
 Return the model being fit.
 
MinimizeResult minimize (std::string const &whatToFit, double nSigmaCut=0, double sigmaRelativeTolerance=0, bool doRankUpdate=true, bool doLineSearch=false, std::string const &dumpMatrixFile="")
 Does a 1 step minimization, assuming a linear model.
 
Chi2Statistic computeChi2 () const
 Returns the chi2 for the current state.
 
void leastSquareDerivatives (TripletList &tripletList, Eigen::VectorXd &grad) const
 Evaluates the chI^2 derivatives (Jacobian and gradient) for the current whatToFit setting.
 
virtual void saveChi2Contributions (std::string const &baseName) const
 Save the full chi2 term per star that was used in the minimization, for debugging.
 

Protected Member Functions

void saveChi2MeasContributions (std::string const &filename) const override
 Save a CSV file containing residuals of measurement terms.
 
void saveChi2RefContributions (std::string const &filename) const override
 Save a CSV file containing residuals of reference terms.
 
std::size_t findOutliers (double nSigmaCut, MeasuredStarList &msOutliers, FittedStarList &fsOutliers, double &cut) const
 Find Measurements and references contributing more than a cut, computed as.
 
void outliersContributions (MeasuredStarList &msOutliers, FittedStarList &fsOutliers, TripletList &tripletList, Eigen::VectorXd &grad)
 Contributions to derivatives from (presumably) outlier terms.
 
void removeMeasOutliers (MeasuredStarList &outliers)
 Remove measuredStar outliers from the fit. No Refit done.
 
void removeRefOutliers (FittedStarList &outliers)
 Remove refStar outliers from the fit. No Refit done.
 

Protected Attributes

std::shared_ptr< Associations_associations
 
std::string _whatToFit
 
Eigen::Index _lastNTrip
 
Eigen::Index _nTotal
 
Eigen::Index _nModelParams
 
Eigen::Index _nStarParams
 
LOG_LOGGER _log
 

Private Member Functions

void accumulateStatImageList (CcdImageList const &ccdImageList, Chi2Accumulator &accum) const override
 Compute the chi2 (per star or total, depending on which Chi2Accumulator is used) for measurements.
 
void accumulateStatRefStars (Chi2Accumulator &accum) const override
 Compute the chi2 (per star or total, depending on which Chi2Accumulator is used) for RefStars.
 
void getIndicesOfMeasuredStar (MeasuredStar const &measuredStar, IndexVector &indices) const override
 this routine is to be used only in the framework of outlier removal
 
void leastSquareDerivativesMeasurement (CcdImage const &ccdImage, TripletList &tripletList, Eigen::VectorXd &grad, MeasuredStarList const *measuredStarList=nullptr) const override
 Compute the derivatives of the measured stars and model for one CcdImage.
 
void leastSquareDerivativesReference (FittedStarList const &fittedStarList, TripletList &tripletList, Eigen::VectorXd &grad) const override
 Compute the derivatives of the reference terms.
 

Detailed Description

Class that handles the photometric least squares problem.

Definition at line 46 of file PhotometryFit.h.

Constructor & Destructor Documentation

◆ PhotometryFit() [1/3]

lsst::jointcal::PhotometryFit::PhotometryFit ( std::shared_ptr< Associations > associations,
std::shared_ptr< PhotometryModel > photometryModel )
inline

Construct a photometry fitter.

Parameters
associationsThe associations catalog to use in the fitter.
photometryModelThe model to build the fitter for.

Definition at line 54 of file PhotometryFit.h.

56 : FitterBase(std::move(associations)),
57 _fittingModel(false),
58 _fittingFluxes(false),
59 _photometryModel(std::move(photometryModel)) {
60 _log = LOG_GET("lsst.jointcal.PhotometryFit");
61 }
#define LOG_GET(logger)
Returns a Log object associated with logger.
Definition Log.h:75
FitterBase(std::shared_ptr< Associations > associations)
Definition FitterBase.h:57
T move(T... args)

◆ PhotometryFit() [2/3]

lsst::jointcal::PhotometryFit::PhotometryFit ( PhotometryFit const & )
delete

No copy or move: there is only ever one fitter of a given type.

◆ PhotometryFit() [3/3]

lsst::jointcal::PhotometryFit::PhotometryFit ( PhotometryFit && )
delete

Member Function Documentation

◆ accumulateStatImageList()

void lsst::jointcal::PhotometryFit::accumulateStatImageList ( CcdImageList const & ccdImageList,
Chi2Accumulator & accum ) const
overrideprivatevirtual

Compute the chi2 (per star or total, depending on which Chi2Accumulator is used) for measurements.

Note
the math in this method and leastSquareDerivativesMeasurement() must be kept consistent, in terms of +/- convention, definition of model, etc.

Implements lsst::jointcal::FitterBase.

Definition at line 134 of file PhotometryFit.cc.

134 {
135 /**********************************************************************/
138 /**********************************************************************/
139 for (auto const &ccdImage : ccdImageList) {
140 auto &catalog = ccdImage->getCatalogForFit();
141
142 for (auto const &measuredStar : catalog) {
143 if (!measuredStar->isValid()) continue;
144 double sigma = _photometryModel->transformError(*ccdImage, *measuredStar);
145 double residual = _photometryModel->computeResidual(*ccdImage, *measuredStar);
146
147 double chi2Val = std::pow(residual / sigma, 2);
148 accum.addEntry(chi2Val, 1, measuredStar);
149 } // end loop on measurements
150 }
151}
afw::table::Key< double > sigma
T pow(T... args)

◆ accumulateStatRefStars()

void lsst::jointcal::PhotometryFit::accumulateStatRefStars ( Chi2Accumulator & accum) const
overrideprivatevirtual

Compute the chi2 (per star or total, depending on which Chi2Accumulator is used) for RefStars.

Note
the math in this method and leastSquareDerivativesReference() must be kept consistent, in terms of +/- convention, definition of model, etc.

Implements lsst::jointcal::FitterBase.

Definition at line 153 of file PhotometryFit.cc.

153 {
154 /**********************************************************************/
157 /**********************************************************************/
158
159 FittedStarList &fittedStarList = _associations->fittedStarList;
160 for (auto const &fittedStar : fittedStarList) {
161 auto refStar = fittedStar->getRefStar();
162 if (refStar == nullptr) continue;
163 double sigma = _photometryModel->getRefError(*refStar);
164 double residual = _photometryModel->computeRefResidual(*fittedStar, *refStar);
165 double chi2 = std::pow(residual / sigma, 2);
166 accum.addEntry(chi2, 1, fittedStar);
167 }
168}
std::shared_ptr< Associations > _associations
Definition FitterBase.h:165

◆ assignIndices()

void lsst::jointcal::PhotometryFit::assignIndices ( std::string const & whatToFit)
overridevirtual

Set parameters to fit and assign indices in the big matrix.

Parameters
[in]whatToFitValid strings : "Model", "Fluxes", which define which parameter sets are going to be fitted. whatToFit="Model Fluxes" will set both parameter sets variable when computing derivatives. Provided it contains "Model", whatToFit is passed over to the PhotometryModel, and can hence be used to control more finely which subsets of the photometric model are being fitted, if the the actual PhotometryModel implements such a possibility.

Implements lsst::jointcal::FitterBase.

Definition at line 185 of file PhotometryFit.cc.

185 {
186 _whatToFit = whatToFit;
187 LOGLS_INFO(_log, "assignIndices: now fitting: " << whatToFit);
188 _fittingModel = (_whatToFit.find("Model") != std::string::npos);
189 _fittingFluxes = (_whatToFit.find("Fluxes") != std::string::npos);
190 // When entering here, we assume that whatToFit has already been interpreted.
191
192 _nModelParams = (_fittingModel) ? _photometryModel->assignIndices(whatToFit, 0) : 0;
194
195 if (_fittingFluxes) {
196 for (auto &fittedStar : _associations->fittedStarList) {
197 // the parameter layout here is used also
198 // - when filling the derivatives
199 // - when updating (offsetParams())
200 // - in getIndicesOfMeasuredStar
201 fittedStar->setIndexInMatrix(ipar);
202 ipar += 1;
203 }
204 }
206 _nTotal = ipar;
207 LOGLS_DEBUG(_log, "nParameters total: " << _nTotal << " model: " << _nModelParams
208 << " fluxes: " << _nStarParams);
209}
#define LOGLS_INFO(logger, message)
Log a info-level message using an iostream-based interface.
Definition Log.h:639
#define LOGLS_DEBUG(logger, message)
Log a debug-level message using an iostream-based interface.
Definition Log.h:619
T find(T... args)

◆ computeChi2()

Chi2Statistic lsst::jointcal::FitterBase::computeChi2 ( ) const
inherited

Returns the chi2 for the current state.

Definition at line 43 of file FitterBase.cc.

43 {
44 Chi2Statistic chi2;
45 accumulateStatImageList(_associations->getCcdImageList(), chi2);
47 // chi2.ndof contains the number of squares.
48 // So subtract the number of parameters.
49 chi2.ndof -= _nTotal;
50 return chi2;
51}
virtual void accumulateStatRefStars(Chi2Accumulator &accum) const =0
Compute the chi2 (per star or total, depending on which Chi2Accumulator is used) for RefStars.
virtual void accumulateStatImageList(CcdImageList const &ccdImageList, Chi2Accumulator &accum) const =0
Compute the chi2 (per star or total, depending on which Chi2Accumulator is used) for measurements.

◆ findOutliers()

std::size_t lsst::jointcal::FitterBase::findOutliers ( double nSigmaCut,
MeasuredStarList & msOutliers,
FittedStarList & fsOutliers,
double & cut ) const
protectedinherited

Find Measurements and references contributing more than a cut, computed as.

\[ <chi2> + nSigmaCut + rms(chi2). \]

The outliers are NOT removed, and no refit is done.

After returning from here, there are still measurements that contribute above the cut, but their contribution should be evaluated after a refit before discarding them.

Parameters
[in]nSigmaCutNumber of sigma to select on.
[out]msOutlierslist of MeasuredStar outliers to populate
[out]fsOutlierslist of FittedStar outliers to populate
[out]cutvalue of chi2 that defines which objects are outliers
Returns
Total number of outliers that were removed.

Definition at line 53 of file FitterBase.cc.

54 {
55 // collect chi2 contributions
56 Chi2List chi2List;
57 chi2List.reserve(_associations->getMaxMeasuredStars() + _associations->refStarList.size());
58 // contributions from measurement terms:
59 accumulateStatImageList(_associations->ccdImageList, chi2List);
60 // and from reference terms
61 accumulateStatRefStars(chi2List);
62
63 // compute some statistics
64 size_t nval = chi2List.size();
65 if (nval == 0) return 0;
66 sort(chi2List.begin(), chi2List.end());
67 double median = (nval & 1) ? chi2List[nval / 2].chi2
68 : 0.5 * (chi2List[nval / 2 - 1].chi2 + chi2List[nval / 2].chi2);
69 auto averageAndSigma = chi2List.computeAverageAndSigma();
70 LOGLS_DEBUG(_log, "findOutliers chi2 stat: mean/median/sigma " << averageAndSigma.first << '/' << median
71 << '/' << averageAndSigma.second);
72 cut = averageAndSigma.first + nSigmaCut * averageAndSigma.second;
73 /* For each of the parameters, we will not remove more than 1
74 measurement that contributes to constraining it. Keep track using
75 of what we are touching using an integer vector. This is the
76 trick that Marc Betoule came up to for outlier removals in "star
77 flats" fits. */
78 Eigen::VectorXi affectedParams(_nTotal);
79 affectedParams.setZero();
80
81 std::size_t nOutliers = 0; // returned to the caller
82 // start from the strongest outliers.
83 for (auto chi2 = chi2List.rbegin(); chi2 != chi2List.rend(); ++chi2) {
84 if (chi2->chi2 < cut) break; // because the array is sorted.
85 IndexVector indices;
86 /* now, we want to get the indices of the parameters this chi2
87 term depends on. We have to figure out which kind of term it
88 is; we use for that the type of the star attached to the Chi2Star. */
89 auto measuredStar = std::dynamic_pointer_cast<MeasuredStar>(chi2->star);
90 std::shared_ptr<FittedStar> fittedStar; // To add to fsOutliers if it is a reference outlier.
91 if (measuredStar == nullptr) {
92 // it is a reference outlier
93 fittedStar = std::dynamic_pointer_cast<FittedStar>(chi2->star);
94 if (fittedStar->getMeasurementCount() == 0) {
95 LOGLS_WARN(_log, "FittedStar with no measuredStars found as an outlier: "
96 << *fittedStar << " chi2: " << chi2->chi2);
97 continue;
98 }
99 if (_nStarParams == 0) {
101 "RefStar is outlier but not removed when not fitting FittedStar-RefStar values: "
102 << *(fittedStar->getRefStar()) << " chi2: " << chi2->chi2);
103 continue;
104 }
105 // NOTE: Stars contribute twice to astrometry (x,y), but once to photometry (flux),
106 // NOTE: but we only need to mark one index here because both will be removed with that star.
107 indices.push_back(fittedStar->getIndexInMatrix());
108 LOGLS_TRACE(_log, "Removing refStar " << *(fittedStar->getRefStar()) << " chi2: " << chi2->chi2);
109 /* One might think it would be useful to account for PM
110 parameters here, but it is just useless */
111 } else {
112 // it is a measurement outlier
113 auto tempFittedStar = measuredStar->getFittedStar();
114 if (tempFittedStar->getMeasurementCount() == 1 && tempFittedStar->getRefStar() == nullptr) {
115 LOGLS_WARN(_log, "FittedStar with 1 measuredStar and no refStar found as an outlier: "
116 << *tempFittedStar);
117 continue;
118 }
119 getIndicesOfMeasuredStar(*measuredStar, indices);
120 LOGLS_TRACE(_log, "Removing measStar " << *measuredStar << " chi2: " << chi2->chi2);
121 }
122
123 /* Find out if we already discarded a stronger outlier
124 constraining some parameter this one constrains as well. If
125 yes, we keep this one, because this stronger outlier could be
126 causing the large chi2 we have in hand. */
127 bool drop_it = true;
128 for (auto const &i : indices) {
129 if (affectedParams(i) != 0) {
130 drop_it = false;
131 }
132 }
133
134 if (drop_it) // store the outlier in one of the lists:
135 {
136 if (measuredStar == nullptr) {
137 // reference term
138 fsOutliers.push_back(fittedStar);
139 } else {
140 // measurement term
141 msOutliers.push_back(measuredStar);
142 }
143 // mark the parameters as directly changed when we discard this chi2 term.
144 for (auto const &i : indices) {
145 affectedParams(i)++;
146 }
147 nOutliers++;
148 }
149 } // end loop on measurements/references
150 LOGLS_DEBUG(_log, "findOutliers: found " << msOutliers.size() << " meas outliers and "
151 << fsOutliers.size() << " ref outliers ");
152
153 return nOutliers;
154}
#define LOGLS_WARN(logger, message)
Log a warn-level message using an iostream-based interface.
Definition Log.h:659
#define LOGLS_TRACE(logger, message)
Log a trace-level message using an iostream-based interface.
Definition Log.h:599
virtual void getIndicesOfMeasuredStar(MeasuredStar const &measuredStar, IndexVector &indices) const =0
Set the indices of a measured star from the full matrix, for outlier removal.
T push_back(T... args)
T sort(T... args)

◆ getIndicesOfMeasuredStar()

void lsst::jointcal::PhotometryFit::getIndicesOfMeasuredStar ( MeasuredStar const & measuredStar,
IndexVector & indices ) const
overrideprivatevirtual

this routine is to be used only in the framework of outlier removal

it fills the array of indices of parameters that a Measured star constrains. Not really all of them if you check.

Implements lsst::jointcal::FitterBase.

Definition at line 173 of file PhotometryFit.cc.

173 {
174 indices.clear();
175 if (_fittingModel) {
176 _photometryModel->getMappingIndices(measuredStar.getCcdImage(), indices);
177 }
178 if (_fittingFluxes) {
179 std::shared_ptr<FittedStar const> const fs = measuredStar.getFittedStar();
180 Eigen::Index fsIndex = fs->getIndexInMatrix();
181 indices.push_back(fsIndex);
182 }
183}
T clear(T... args)

◆ getModel()

std::shared_ptr< PhotometryModel > lsst::jointcal::PhotometryFit::getModel ( ) const
inline

Return the model being fit.

Definition at line 87 of file PhotometryFit.h.

87{ return _photometryModel; }

◆ leastSquareDerivatives()

void lsst::jointcal::FitterBase::leastSquareDerivatives ( TripletList & tripletList,
Eigen::VectorXd & grad ) const
inherited

Evaluates the chI^2 derivatives (Jacobian and gradient) for the current whatToFit setting.

The Jacobian is given as triplets in a sparse matrix, the gradient as a dense vector. The parameters which vary, and their indices, are to be set using assignIndices.

Parameters
tripletListtripletList of (row,col,value) representing the Jacobian of the chi2.
gradThe gradient of the chi2.

Definition at line 347 of file FitterBase.cc.

347 {
348 auto ccdImageList = _associations->getCcdImageList();
349 for (auto const &ccdImage : ccdImageList) {
350 leastSquareDerivativesMeasurement(*ccdImage, tripletList, grad);
351 }
352 leastSquareDerivativesReference(_associations->fittedStarList, tripletList, grad);
353}
virtual void leastSquareDerivativesReference(FittedStarList const &fittedStarList, TripletList &tripletList, Eigen::VectorXd &grad) const =0
Compute the derivatives of the reference terms.
virtual void leastSquareDerivativesMeasurement(CcdImage const &ccdImage, TripletList &tripletList, Eigen::VectorXd &grad, MeasuredStarList const *measuredStarList=nullptr) const =0
Compute the derivatives of the measured stars and model for one CcdImage.

◆ leastSquareDerivativesMeasurement()

void lsst::jointcal::PhotometryFit::leastSquareDerivativesMeasurement ( CcdImage const & ccdImage,
TripletList & tripletList,
Eigen::VectorXd & grad,
MeasuredStarList const * measuredStarList = nullptr ) const
overrideprivatevirtual

Compute the derivatives of the measured stars and model for one CcdImage.

The last argument will process a sub-list for outlier removal.

Implements lsst::jointcal::FitterBase.

Definition at line 45 of file PhotometryFit.cc.

47 {
48 /**********************************************************************/
49 /* @note the math in this method and accumulateStatImageList() must be kept consistent,
50 * in terms of +/- convention, definition of model, etc. */
51 /**********************************************************************/
52
53 /* this routine works in two different ways: either providing the
54 Ccd, of providing the MeasuredStarList. In the latter case, the
55 Ccd should match the one(s) in the list. */
56 if (measuredStarList) assert(&(measuredStarList->front()->getCcdImage()) == &ccdImage);
57
58 std::size_t nparModel = (_fittingModel) ? _photometryModel->getNpar(ccdImage) : 0;
59 std::size_t nparFlux = (_fittingFluxes) ? 1 : 0;
60 std::size_t nparTotal = nparModel + nparFlux;
61 IndexVector indices(nparModel, -1);
62 if (_fittingModel) _photometryModel->getMappingIndices(ccdImage, indices);
63
64 Eigen::VectorXd H(nparTotal); // derivative matrix
65 // current position in the Jacobian
66 Eigen::Index kTriplets = tripletList.getNextFreeIndex();
67 const MeasuredStarList &catalog = (measuredStarList) ? *measuredStarList : ccdImage.getCatalogForFit();
68
69 for (auto const &measuredStar : catalog) {
70 if (!measuredStar->isValid()) continue;
71 H.setZero(); // we cannot be sure that all entries will be overwritten.
72
73 double residual = _photometryModel->computeResidual(ccdImage, *measuredStar);
74 double inverseSigma = 1.0 / _photometryModel->transformError(ccdImage, *measuredStar);
75 double W = std::pow(inverseSigma, 2);
76
77 if (_fittingModel) {
78 _photometryModel->computeParameterDerivatives(*measuredStar, ccdImage, H);
79 for (std::size_t k = 0; k < indices.size(); k++) {
80 Eigen::Index l = indices[k];
81 tripletList.addTriplet(l, kTriplets, H[k] * inverseSigma);
82 grad[l] += H[k] * W * residual;
83 }
84 }
85 if (_fittingFluxes) {
86 Eigen::Index index = measuredStar->getFittedStar()->getIndexInMatrix();
87 // Note: H = dR/dFittedStarFlux == -1
88 tripletList.addTriplet(index, kTriplets, -1.0 * inverseSigma);
89 grad[index] += -1.0 * W * residual;
90 }
91 kTriplets += 1; // each measurement contributes 1 column in the Jacobian
92 }
93
94 tripletList.setNextFreeIndex(kTriplets);
95}

◆ leastSquareDerivativesReference()

void lsst::jointcal::PhotometryFit::leastSquareDerivativesReference ( FittedStarList const & fittedStarList,
TripletList & tripletList,
Eigen::VectorXd & grad ) const
overrideprivatevirtual

Compute the derivatives of the reference terms.

Note
the math in this method and accumulateStatReference() must be kept consistent, in terms of +/- convention, definition of model, etc.

Implements lsst::jointcal::FitterBase.

Definition at line 97 of file PhotometryFit.cc.

98 {
99 /**********************************************************************/
102 /**********************************************************************/
103
104 // Derivatives of terms involving fitted and refstars only contribute if we are fitting fluxes.
105 if (!_fittingFluxes) return;
106 // Can't compute anything if there are no refStars.
107 if (_associations->refStarList.empty()) return;
108
109 Eigen::Index kTriplets = tripletList.getNextFreeIndex();
110
111 for (auto const &fittedStar : fittedStarList) {
112 auto refStar = fittedStar->getRefStar();
113 if (refStar == nullptr) continue; // no contribution if no associated refstar
114 // TODO: Can we actually work with multiple filters at a time in this scheme?
115 // TODO: I feel we might only be able to fit one filter at a time, because these terms are
116 // independent of the ccdImage, so we don't have a specific filter.
117 // filter = ccdImage.getFilter();
118
119 // W == inverseSigma^2
120
121 double inverseSigma = 1.0 / _photometryModel->getRefError(*refStar);
122 // Residual is fittedStar - refStar for consistency with measurement terms.
123 double residual = _photometryModel->computeRefResidual(*fittedStar, *refStar);
124
125 Eigen::Index index = fittedStar->getIndexInMatrix();
126 // Note: H = dR/dFittedStar == 1
127 tripletList.addTriplet(index, kTriplets, 1.0 * inverseSigma);
128 grad(index) += 1.0 * std::pow(inverseSigma, 2) * residual;
129 kTriplets += 1;
130 }
131 tripletList.setNextFreeIndex(kTriplets);
132}

◆ minimize()

MinimizeResult lsst::jointcal::FitterBase::minimize ( std::string const & whatToFit,
double nSigmaCut = 0,
double sigmaRelativeTolerance = 0,
bool doRankUpdate = true,
bool doLineSearch = false,
std::string const & dumpMatrixFile = "" )
inherited

Does a 1 step minimization, assuming a linear model.

This is a complete Newton Raphson step. Compute first and second derivatives, solve for the step and apply it, with an optional line search.

It calls assignIndices, leastSquareDerivatives, solves the linear system and calls offsetParams, then removes outliers in a loop if requested. Relies on sparse linear algebra via Eigen's CholmodSupport package.

Parameters
[in]whatToFitSee child method assignIndices for valid string values.
[in]nSigmaCutHow many sigma to reject outliers at. Outlier rejection ignored for nSigmaCut=0.
[in]sigmaRelativeTolerancePercentage change in the chi2 cut for outliers tolerated for termination. If value is zero, minimization iterations will continue until there are no outliers.
[in]doRankUpdateUse CholmodSimplicialLDLT2.update() to do a fast rank update after outlier removal; otherwise do a slower full recomputation of the matrix. Only matters if nSigmaCut != 0.
[in]doLineSearchUse boost's brent_find_minima to perform a line search after the gradient solution is found, and apply the scale factor to the computed offsets. The line search is done in the domain [-1, 2], but if the scale factor is far from 1.0, then the problem is likely in a significantly non-linear regime.
[in]dumpMatrixFileWrite the pre-fit Hessian matrix and gradient to the files with "-mat.txt" and "-grad.txt". Be aware, this requires a large increase in memory usage to create a dense matrix before writing it; the output file may be large. Writing the matrix can be helpful for debugging bad fits. Read it and compute the real eigenvalues (recall that the Hessian is symmetric by construction) with numpy:
hessian = np.matrix(np.loadtxt("dumpMatrixFile-mat.txt"))
values, vectors = np.linalg.eigh(hessian)
Returns
Return code describing success/failure of fit.
Note
When fitting one parameter set by itself (e.g. "Model"), the system is purely linear (assuming there are no cross-terms in the derivatives, e.g. the SimpleAstrometryModel), which should result in the optimal chi2 after a single step. This can be used to debug the fitter by fitting that parameter set twice in a row: the second run with the same "whatToFit" will produce no change in the fitted parameters, if the calculations and indices are defined correctly.

Definition at line 179 of file FitterBase.cc.

181 {
182 assignIndices(whatToFit);
183
184 MinimizeResult returnCode = MinimizeResult::Converged;
185
186 // For the initial vector size, use all measured stars + all fitted stars, which should give the
187 // maximum possible number of triplets.
188 std::size_t nTrip = (_lastNTrip)
189 ? _lastNTrip
190 : _associations->getMaxMeasuredStars() + _associations->fittedStarList.size();
191 TripletList tripletList(nTrip);
192 Eigen::VectorXd grad(_nTotal);
193 grad.setZero();
194 double scale = 1.0;
195
196 // Fill the triplets
197 leastSquareDerivatives(tripletList, grad);
198 _lastNTrip = tripletList.size();
199
200 LOGLS_DEBUG(_log, "End of triplet filling, ntrip = " << tripletList.size());
201
202 SparseMatrixD hessian = createHessian(_nTotal, tripletList);
203 tripletList.clear(); // we don't need it any more after we have the hessian.
204
205 LOGLS_DEBUG(_log, "Starting factorization, hessian: dim="
206 << hessian.rows() << " non-zeros=" << hessian.nonZeros()
207 << " filling-frac = " << hessian.nonZeros() / std::pow(hessian.rows(), 2));
208
209 if (dumpMatrixFile != "") {
210 if (hessian.rows() * hessian.cols() > 2e8) {
211 LOGLS_WARN(_log, "Hessian matrix is too big to dump to file, with rows, columns: "
212 << hessian.rows() << ", " << hessian.cols());
213 } else {
214 dumpMatrixAndGradient(hessian, grad, dumpMatrixFile, _log);
215 }
216 }
217
219 if (chol.info() != Eigen::Success) {
220 LOGLS_ERROR(_log, "minimize: factorization failed ");
222 }
223
224 std::size_t totalMeasOutliers = 0;
225 std::size_t totalRefOutliers = 0;
226 double oldChi2 = computeChi2().chi2;
227 double oldSigmaCut = 0.;
228 double sigmaCut = 0.;
229
230 while (true) {
231 Eigen::VectorXd delta = chol.solve(grad);
232 if (doLineSearch) {
233 scale = _lineSearch(delta);
234 }
235 offsetParams(scale * delta);
236 Chi2Statistic currentChi2(computeChi2());
237 LOGLS_DEBUG(_log, currentChi2);
238 if (!isfinite(currentChi2.chi2)) {
239 LOGL_ERROR(_log, "chi2 is not finite. Aborting outlier rejection.");
240 returnCode = MinimizeResult::NonFinite;
241 break;
242 }
243 if (currentChi2.chi2 > oldChi2 && totalMeasOutliers + totalRefOutliers != 0) {
244 LOGL_WARN(_log, "chi2 went up, skipping outlier rejection loop");
246 break;
247 }
248 oldChi2 = currentChi2.chi2;
249
250 if (nSigmaCut == 0) break; // no rejection step to perform
251 MeasuredStarList msOutliers;
252 FittedStarList fsOutliers;
253 // keep nOutliers so we don't have to sum msOutliers.size()+fsOutliers.size() twice below.
254 std::size_t nOutliers = findOutliers(nSigmaCut, msOutliers, fsOutliers, sigmaCut);
255 double relChange = 0.;
256 if(oldSigmaCut!=0.) relChange = (1 - sigmaCut / oldSigmaCut);
257
258 LOGLS_DEBUG(_log, "findOutliers chi2 cut level: " << sigmaCut << ", relative change: " << relChange);
259 // If sigmaRelativeTolerance is set and at least one iteration has been done, break loop when the
260 // fractional change in sigmaCut levels is less than the sigmaRelativeTolerance parameter.
261 if ((sigmaRelativeTolerance > 0) && (oldSigmaCut > 0 && relChange < sigmaRelativeTolerance)) {
262 LOGLS_INFO(_log, "Iterations stopped with chi2 cut at " << sigmaCut << " and relative change of "
263 << relChange);
264 break;
265 }
266 totalMeasOutliers += msOutliers.size();
267 totalRefOutliers += fsOutliers.size();
268 oldSigmaCut = sigmaCut;
269 if (nOutliers == 0) break;
270 TripletList outlierTriplets(nOutliers);
271 grad.setZero(); // recycle the gradient
272 // compute the contributions of outliers to derivatives
273 outliersContributions(msOutliers, fsOutliers, outlierTriplets, grad);
274 // Remove significant outliers
275 removeMeasOutliers(msOutliers);
276 removeRefOutliers(fsOutliers);
277 if (doRankUpdate) {
278 // convert triplet list to eigen internal format
279 SparseMatrixD H(_nTotal, outlierTriplets.getNextFreeIndex());
280 H.setFromTriplets(outlierTriplets.begin(), outlierTriplets.end());
281 chol.update(H, false /* means downdate */);
282 // The contribution of outliers to the gradient is the opposite
283 // of the contribution of all other terms, because they add up to 0
284 grad *= -1;
285 } else {
286 // don't reuse tripletList because we want a new nextFreeIndex.
287 TripletList nextTripletList(_lastNTrip);
288 grad.setZero();
289 // Rebuild the matrix and gradient
290 leastSquareDerivatives(nextTripletList, grad);
291 _lastNTrip = nextTripletList.size();
292 LOGLS_DEBUG(_log, "Triplets recomputed, ntrip = " << nextTripletList.size());
293
294 hessian = createHessian(_nTotal, nextTripletList);
295 nextTripletList.clear(); // we don't need it any more after we have the hessian.
296
298 "Restarting factorization, hessian: dim="
299 << hessian.rows() << " non-zeros=" << hessian.nonZeros()
300 << " filling-frac = " << hessian.nonZeros() / std::pow(hessian.rows(), 2));
301 chol.compute(hessian);
302 if (chol.info() != Eigen::Success) {
303 LOGLS_ERROR(_log, "minimize: factorization failed ");
305 }
306 }
307 }
308
309 if (totalMeasOutliers + totalRefOutliers > 0) {
310 _associations->cleanFittedStars();
311 }
312
313 // only print the outlier summary if outlier rejection was turned on.
314 if (nSigmaCut != 0) {
315 LOGLS_INFO(_log, "Number of outliers (Measured + Reference = Total): "
316 << totalMeasOutliers << " + " << totalRefOutliers << " = "
317 << totalMeasOutliers + totalRefOutliers);
318 }
319 return returnCode;
320}
Eigen::SparseMatrix< double, 0, Eigen::Index > SparseMatrixD
Definition Eigenstuff.h:35
#define LOGL_WARN(logger, message...)
Log a warn-level message using a varargs/printf style interface.
Definition Log.h:547
#define LOGLS_ERROR(logger, message)
Log a error-level message using an iostream-based interface.
Definition Log.h:679
#define LOGL_ERROR(logger, message...)
Log a error-level message using a varargs/printf style interface.
Definition Log.h:563
void leastSquareDerivatives(TripletList &tripletList, Eigen::VectorXd &grad) const
Evaluates the chI^2 derivatives (Jacobian and gradient) for the current whatToFit setting.
void removeRefOutliers(FittedStarList &outliers)
Remove refStar outliers from the fit. No Refit done.
Chi2Statistic computeChi2() const
Returns the chi2 for the current state.
Definition FitterBase.cc:43
virtual void assignIndices(std::string const &whatToFit)=0
Set parameters to fit and assign indices in the big matrix.
virtual void offsetParams(Eigen::VectorXd const &delta)=0
Offset the parameters by the requested quantities.
void outliersContributions(MeasuredStarList &msOutliers, FittedStarList &fsOutliers, TripletList &tripletList, Eigen::VectorXd &grad)
Contributions to derivatives from (presumably) outlier terms.
std::size_t findOutliers(double nSigmaCut, MeasuredStarList &msOutliers, FittedStarList &fsOutliers, double &cut) const
Find Measurements and references contributing more than a cut, computed as.
Definition FitterBase.cc:53
void removeMeasOutliers(MeasuredStarList &outliers)
Remove measuredStar outliers from the fit. No Refit done.
T isfinite(T... args)
scale(algorithm, min, max=None, frame=None)
Definition ds9.py:108

◆ offsetParams()

void lsst::jointcal::PhotometryFit::offsetParams ( Eigen::VectorXd const & delta)
overridevirtual

Offset the parameters by the requested quantities.

The used parameter layout is the one from the last call to assignIndices or minimize(). There is no easy way to check that the current setting of whatToFit and the provided Delta vector are compatible: we can only test the size.

Parameters
[in]deltavector of offsets to apply

Implements lsst::jointcal::FitterBase.

Definition at line 211 of file PhotometryFit.cc.

211 {
212 if (delta.size() != _nTotal)
213 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
214 "PhotometryFit::offsetParams : the provided vector length is not compatible with "
215 "the current whatToFit setting");
216 if (_fittingModel) _photometryModel->offsetParams(delta);
217
218 if (_fittingFluxes) {
219 for (auto &fittedStar : _associations->fittedStarList) {
220 // the parameter layout here is used also
221 // - when filling the derivatives
222 // - when assigning indices (assignIndices())
223 Eigen::Index index = fittedStar->getIndexInMatrix();
224 _photometryModel->offsetFittedStar(*fittedStar, delta(index));
225 }
226 }
227}
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition Exception.h:48

◆ operator=() [1/2]

PhotometryFit & lsst::jointcal::PhotometryFit::operator= ( PhotometryFit && )
delete

◆ operator=() [2/2]

PhotometryFit & lsst::jointcal::PhotometryFit::operator= ( PhotometryFit const & )
delete

◆ outliersContributions()

void lsst::jointcal::FitterBase::outliersContributions ( MeasuredStarList & msOutliers,
FittedStarList & fsOutliers,
TripletList & tripletList,
Eigen::VectorXd & grad )
protectedinherited

Contributions to derivatives from (presumably) outlier terms.

No discarding done.

Definition at line 322 of file FitterBase.cc.

323 {
324 for (auto &outlier : msOutliers) {
325 MeasuredStarList tmp;
326 tmp.push_back(outlier);
327 const CcdImage &ccdImage = outlier->getCcdImage();
328 leastSquareDerivativesMeasurement(ccdImage, tripletList, grad, &tmp);
329 }
330 leastSquareDerivativesReference(fsOutliers, tripletList, grad);
331}

◆ removeMeasOutliers()

void lsst::jointcal::FitterBase::removeMeasOutliers ( MeasuredStarList & outliers)
protectedinherited

Remove measuredStar outliers from the fit. No Refit done.

Definition at line 333 of file FitterBase.cc.

333 {
334 for (auto &measuredStar : outliers) {
335 auto fittedStar = measuredStar->getFittedStar();
336 measuredStar->setValid(false);
337 fittedStar->getMeasurementCount()--; // could be put in setValid
338 }
339}

◆ removeRefOutliers()

void lsst::jointcal::FitterBase::removeRefOutliers ( FittedStarList & outliers)
protectedinherited

Remove refStar outliers from the fit. No Refit done.

Definition at line 341 of file FitterBase.cc.

341 {
342 for (auto &fittedStar : outliers) {
343 fittedStar->setRefStar(nullptr);
344 }
345}

◆ saveChi2Contributions()

void lsst::jointcal::FitterBase::saveChi2Contributions ( std::string const & baseName) const
virtualinherited

Save the full chi2 term per star that was used in the minimization, for debugging.

Saves results to text files "baseName-meas.csv" and "baseName-ref.csv" for the MeasuredStar and RefStar contributions, respectively. This method is mostly useful for debugging: we will probably want to create a better persistence system for jointcal's internal representations in the future (see DM-12446).

Definition at line 355 of file FitterBase.cc.

355 {
356 std::string replaceStr = "{type}";
357 auto pos = baseName.find(replaceStr);
358 std::string measFilename(baseName);
359 measFilename.replace(pos, replaceStr.size(), "-meas.csv");
360 std::string refFilename(baseName);
361 refFilename.replace(pos, replaceStr.size(), "-ref.csv");
362 saveChi2MeasContributions(measFilename);
363 saveChi2RefContributions(refFilename);
364}
virtual void saveChi2MeasContributions(std::string const &filename) const =0
Save a CSV file containing residuals of measurement terms.
virtual void saveChi2RefContributions(std::string const &filename) const =0
Save a CSV file containing residuals of reference terms.
T size(T... args)

◆ saveChi2MeasContributions()

void lsst::jointcal::PhotometryFit::saveChi2MeasContributions ( std::string const & filename) const
overrideprotectedvirtual

Save a CSV file containing residuals of measurement terms.

Implements lsst::jointcal::FitterBase.

Definition at line 229 of file PhotometryFit.cc.

229 {
230 std::ofstream ofile(filename.c_str());
231 std::string separator = "\t";
232
233 ofile << "id" << separator << "xccd" << separator << "yccd" << separator;
234 ofile << "mag" << separator << "instMag" << separator << "instMagErr" << separator;
235 ofile << "instFlux" << separator << "instFluxErr" << separator;
236 ofile << "inputFlux" << separator << "inputFluxErr" << separator;
237 ofile << "transformedFlux" << separator << "transformedFluxErr" << separator;
238 ofile << "fittedFlux" << separator;
239 ofile << "epoch" << separator;
240 ofile << "fsindex" << separator;
241 ofile << "ra" << separator << "dec" << separator;
242 ofile << "chi2" << separator << "nm" << separator;
243 ofile << "detector" << separator << "visit" << separator << std::endl;
244
245 ofile << "id in source catalog" << separator << "coordinates in CCD" << separator << separator;
246 ofile << "fitted magnitude" << separator << "measured magnitude" << separator
247 << "measured magnitude error" << separator;
248 ofile << "measured instrumental flux (ADU)" << separator << "measured instrument flux error" << separator;
249 ofile << "measured flux (nJy)" << separator << "measured flux error" << separator;
250 ofile << separator << separator;
251 ofile << "fitted flux (nJy)" << separator;
252 ofile << "Julian Epoch Year of the measurement" << separator;
253 ofile << "unique index of the fittedStar" << separator;
254 ofile << "on-sky position of fitted star" << separator << separator;
255 ofile << "contribution to chi2 (1 dof)" << separator << "number of measurements of this FittedStar"
256 << separator;
257 ofile << "detector id" << separator << "visit id" << std::endl;
258
259 const CcdImageList &ccdImageList = _associations->getCcdImageList();
260 for (auto const &ccdImage : ccdImageList) {
261 const MeasuredStarList &cat = ccdImage->getCatalogForFit();
262 for (auto const &measuredStar : cat) {
263 if (!measuredStar->isValid()) continue;
264
265 double instFluxErr = _photometryModel->tweakFluxError(*measuredStar);
266 double flux = _photometryModel->transform(*ccdImage, *measuredStar);
267 double fluxErr = _photometryModel->transformError(*ccdImage, *measuredStar);
268 std::shared_ptr<FittedStar const> const fittedStar = measuredStar->getFittedStar();
269 double residual = _photometryModel->computeResidual(*ccdImage, *measuredStar);
270 double chi2Val = std::pow(residual / fluxErr, 2);
271
272 ofile << std::setprecision(9);
273 ofile << measuredStar->getId() << separator << measuredStar->x << separator << measuredStar->y
274 << separator;
275 ofile << fittedStar->getMag() << separator << measuredStar->getInstMag() << separator
276 << measuredStar->getInstMagErr() << separator;
277 ofile << measuredStar->getInstFlux() << separator << instFluxErr << separator;
278 ofile << measuredStar->getFlux() << separator << measuredStar->getFluxErr() << separator;
279 ofile << flux << separator << fluxErr << separator << fittedStar->getFlux() << separator;
280 ofile << ccdImage->getEpoch() << separator;
281 ofile << fittedStar->getIndexInMatrix() << separator;
282 ofile << fittedStar->x << separator << fittedStar->y << separator;
283 ofile << chi2Val << separator << fittedStar->getMeasurementCount() << separator;
284 ofile << ccdImage->getCcdId() << separator << ccdImage->getVisit() << std::endl;
285 } // loop on measurements in image
286 } // loop on images
287}
T endl(T... args)
std::list< std::shared_ptr< CcdImage > > CcdImageList
Definition CcdImage.h:46
T setprecision(T... args)

◆ saveChi2RefContributions()

void lsst::jointcal::PhotometryFit::saveChi2RefContributions ( std::string const & filename) const
overrideprotectedvirtual

Save a CSV file containing residuals of reference terms.

Implements lsst::jointcal::FitterBase.

Definition at line 289 of file PhotometryFit.cc.

289 {
290 std::ofstream ofile(filename.c_str());
291 std::string separator = "\t";
292
293 ofile << "ra" << separator << "dec " << separator;
294 ofile << "mag" << separator;
295 ofile << "refFlux" << separator << "refFluxErr" << separator;
296 ofile << "fittedFlux" << separator << "fittedFluxErr" << separator;
297 ofile << "fsindex" << separator << "chi2" << separator << "nm" << std::endl;
298
299 ofile << "coordinates of fittedStar" << separator << separator;
300 ofile << "magnitude" << separator;
301 ofile << "refStar flux (nJy)" << separator << "refStar fluxErr" << separator;
302 ofile << "fittedStar flux (nJy)" << separator << "fittedStar fluxErr" << separator;
303 ofile << "unique index of the fittedStar" << separator << "refStar contribution to chi2 (1 dof)"
304 << separator << "number of measurements of this FittedStar" << std::endl;
305
306 // The following loop is heavily inspired from PhotometryFit::computeChi2()
307 const FittedStarList &fittedStarList = _associations->fittedStarList;
308 for (auto const &fittedStar : fittedStarList) {
309 const RefStar *refStar = fittedStar->getRefStar();
310 if (refStar == nullptr) continue;
311
312 double chi2 = std::pow(((fittedStar->getFlux() - refStar->getFlux()) / refStar->getFluxErr()), 2);
313
314 ofile << std::setprecision(9);
315 ofile << fittedStar->x << separator << fittedStar->y << separator;
316 ofile << fittedStar->getMag() << separator;
317 ofile << refStar->getFlux() << separator << refStar->getFluxErr() << separator;
318 ofile << fittedStar->getFlux() << separator << fittedStar->getFluxErr() << separator;
319 ofile << fittedStar->getIndexInMatrix() << separator << chi2 << separator
320 << fittedStar->getMeasurementCount() << std::endl;
321 } // loop on FittedStars
322}

Member Data Documentation

◆ _associations

std::shared_ptr<Associations> lsst::jointcal::FitterBase::_associations
protectedinherited

Definition at line 165 of file FitterBase.h.

◆ _lastNTrip

Eigen::Index lsst::jointcal::FitterBase::_lastNTrip
protectedinherited

Definition at line 168 of file FitterBase.h.

◆ _log

LOG_LOGGER lsst::jointcal::FitterBase::_log
protectedinherited

Definition at line 174 of file FitterBase.h.

◆ _nModelParams

Eigen::Index lsst::jointcal::FitterBase::_nModelParams
protectedinherited

Definition at line 170 of file FitterBase.h.

◆ _nStarParams

Eigen::Index lsst::jointcal::FitterBase::_nStarParams
protectedinherited

Definition at line 171 of file FitterBase.h.

◆ _nTotal

Eigen::Index lsst::jointcal::FitterBase::_nTotal
protectedinherited

Definition at line 169 of file FitterBase.h.

◆ _whatToFit

std::string lsst::jointcal::FitterBase::_whatToFit
protectedinherited

Definition at line 166 of file FitterBase.h.


The documentation for this class was generated from the following files: