5 #include "lsst/log/Log.h"
9 #include "Eigen/Sparse"
11 #include "lsst/pex/exceptions.h"
15 typedef Eigen::SparseMatrix<double>
SpMat;
19 static double sqr(
double x) {
return x * x; }
22 LOG_LOGGER _log = LOG_GET(
"jointcal.PhotometryFit");
29 : _associations(associations),
30 _photometryModel(photometryModel),
40 for (
auto const &im : ccdImageList) {
53 if (measuredStarList) assert(&(measuredStarList->front()->getCcdImage()) == &ccdImage);
55 unsigned npar_max = 100;
56 vector<unsigned> indices(npar_max, -1);
58 Eigen::VectorXd h(npar_max);
59 Eigen::VectorXd grad(npar_max);
64 for (
auto const &i : catalog) {
66 if (!measuredStar.
isValid())
continue;
68 double sigma = measuredStar.
eflux;
70 TweakPhotomMeasurementErrors(inPos, measuredStar, _fluxError);
74 double pf = _photometryModel->
photomFactor(ccdImage, measuredStar);
77 double res = measuredStar.
getFlux() - pf * fs->getFlux();
81 for (
unsigned k = 0; k < indices.size(); k++) {
82 unsigned l = indices[k];
83 tripletList.
addTriplet(l, kTriplets, h[k] * fs->getFlux() / sigma);
84 rhs[l] += h[k] * res / sqr(sigma);
88 unsigned index = fs->getIndexInMatrix();
89 tripletList.
addTriplet(index, kTriplets, pf / sigma);
90 rhs[index] += res * pf / sqr(sigma);
103 template <
class ListType,
class Accum>
104 void PhotometryFit::accumulateStat(ListType &listType, Accum &accum)
const {
105 for (
auto &im : listType) {
109 auto &ccdIMage = *im;
110 auto &catalog = ccdIMage.getCatalogForFit();
112 for (
auto const &measuredStar : catalog) {
113 if (!measuredStar->isValid())
continue;
115 double sigma = measuredStar->eflux;
117 TweakPhotomMeasurementErrors(inPos, measuredStar, _fluxError);
120 double pf = _photometryModel->
photomFactor(ccdIMage, *measuredStar);
121 auto fs = measuredStar->getFittedStar();
122 double res = measuredStar->getFlux() - pf * fs->getFlux();
123 double chi2Val = sqr(res / sigma);
124 accum.addEntry(chi2Val, 1, measuredStar);
135 chi2.
ndof -= _nParTot;
140 Eigen::VectorXd &grad) {
141 for (
auto &outlier : outliers) {
143 tmp.push_back(outlier);
144 const CcdImage &ccdImage = outlier->getCcdImage();
146 outlier->setValid(
false);
147 auto fs = std::const_pointer_cast<
FittedStar>(outlier->getFittedStar());
166 struct Chi2Vect :
public vector<Chi2Entry> {
167 void addEntry(
double Chi2Val,
unsigned ndof, std::shared_ptr<MeasuredStar> measuredStar) {
168 push_back(
Chi2Entry(Chi2Val, std::move(measuredStar)));
175 void PhotometryFit::getMeasuredStarIndices(
const MeasuredStar &measuredStar,
176 std::vector<unsigned> &indices)
const {
179 Eigen::VectorXd h(100);
182 if (_fittingFluxes) {
183 auto fs = measuredStar.getFittedStar();
184 unsigned fsIndex = fs->getIndexInMatrix();
185 indices.push_back(fsIndex);
189 void PhotometryFit::findOutliers(
double nSigCut, MeasuredStarList &outliers)
const {
198 unsigned nval = chi2s.size();
199 if (nval == 0)
return;
200 sort(chi2s.begin(), chi2s.end());
202 (nval & 1) ? chi2s[nval / 2].chi2 : 0.5 * (chi2s[nval / 2 - 1].chi2 + chi2s[nval / 2].chi2);
206 for (
auto const &i : chi2s) {
210 double average = sum / nval;
211 double sigma = sqrt(sum2 / nval - sqr(average));
213 "findOutliers chi2 stat: mean/median/sigma " << average <<
'/' << median <<
'/' << sigma);
214 double cut = average + nSigCut * sigma;
220 Eigen::VectorXi affectedParams(_nParTot);
221 affectedParams.setZero();
224 for (
auto i = chi2s.rbegin(); i != chi2s.rend(); ++i) {
225 if (i->chi2 < cut)
break;
226 vector<unsigned> indices;
227 getMeasuredStarIndices(*(i->measuredStar), indices);
231 for (
auto const &i : indices)
232 if (affectedParams(i) != 0) drop_it =
false;
235 for (
auto const &i : indices) affectedParams(i)++;
236 outliers.push_back(i->measuredStar);
239 LOGLS_INFO(_log,
"findMeasOutliers: found " << outliers.size() <<
" outliers");
243 _whatToFit = whatToFit;
244 LOGLS_INFO(_log,
"assignIndices: now fitting: " << whatToFit);
245 _fittingModel = (_whatToFit.find(
"Model") != string::npos);
246 _fittingFluxes = (_whatToFit.find(
"Fluxes") != string::npos);
249 _nParModel = (_fittingModel) ? _photometryModel->
assignIndices(whatToFit, 0) : 0;
250 unsigned ipar = _nParModel;
252 if (_fittingFluxes) {
254 for (
auto &i : fsl) {
268 if (delta.size() != _nParTot)
269 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
270 "PhotometryFit::offsetParams : the provided vector length is not compatible with "
271 "the current whatToFit setting");
272 if (_fittingModel) _photometryModel->
offsetParams(delta);
274 if (_fittingFluxes) {
276 for (
auto &i : fsl) {
291 unsigned nTrip = (_lastNTrip) ? _lastNTrip : 1e6;
293 Eigen::VectorXd grad(_nParTot);
298 _lastNTrip = tripletList.size();
303 jacobian.setFromTriplets(tripletList.begin(), tripletList.end());
306 hessian = jacobian * jacobian.transpose();
309 LOGLS_DEBUG(_log,
"Starting factorization, hessian: dim="
310 << hessian.rows() <<
" nnz=" << hessian.nonZeros()
311 <<
" filling-frac = " << hessian.nonZeros() / sqr(hessian.rows()));
313 Eigen::SimplicialLDLT<SpMat> chol(hessian);
314 if (chol.info() != Eigen::Success) {
315 LOGLS_ERROR(_log,
"minimize: factorization failed ");
319 Eigen::VectorXd delta = chol.solve(grad);
326 std::ofstream tuple(tupleName.c_str());
331 tuple <<
"#xccd: coordinate in CCD" << endl
333 <<
"#mag: rough mag" << endl
334 <<
"#flux : measured flux" << endl
335 <<
"#eflux : measured flux erro" << endl
336 <<
"#fflux : fitted flux" << endl
337 <<
"#phot_factor:" << endl
338 <<
"#jd: Julian date of the measurement" << endl
339 <<
"#color : " << endl
340 <<
"#fsindex: some unique index of the object" << endl
341 <<
"#ra: pos of fitted star" << endl
342 <<
"#dec: pos of fitted star" << endl
343 <<
"#chi2: contribution to Chi2 (1 dof)" << endl
344 <<
"#nm: number of measurements of this FittedStar" << endl
345 <<
"#chip: chip number" << endl
346 <<
"#visit: visit id" << endl
349 for (
auto const &i : ccdImageList) {
352 for (
auto const &is : cat) {
355 double sigma = ms.
eflux;
357 tweakPhotomMeasurementErrors(inPos, ms, _fluxError);
362 double res = ms.
getFlux() - pf * fs->getFlux();
363 double chi2Val = sqr(res / sigma);
364 tuple << ms.
x <<
' ' << ms.
y <<
' ' << fs->getMag() <<
' ' << ms.
getFlux() <<
' ' << ms.
eflux
365 <<
' ' << fs->getFlux() <<
' ' << pf <<
' ' << jd <<
' ' << fs->color <<
' '
366 << fs->getIndexInMatrix() <<
' ' << fs->x <<
' ' << fs->y <<
' ' << chi2Val <<
' '
367 << fs->getMeasurementCount() <<
' ' << im.
getCcdId() <<
' ' << im.
getVisit() << endl;
Chi2 computeChi2() const
Returns a chi2 for the current state.
double getMjd() const
Julian Date.
a class to accumulate chi2 contributions together with pointers to the contributors.
void LSDerivatives(TripletList &tripletList, Eigen::VectorXd &rhs) const
Derivatives of the Chi2.
bool minimize(const std::string &whatToFit)
Does a 1 step minimization, assuming a linear model.
virtual double photomFactor(const CcdImage &ccdImage, const Point &where) const =0
Return the "photometric factor" at a given location on a ccdImage.
std::shared_ptr< const FittedStar > getFittedStar() const
void addEntry(double Chi2Val, unsigned ndof, std::shared_ptr< MeasuredStar > measuredStar)
CcdImageList ccdImageList
The class that implements the relations between MeasuredStar and FittedStar.
A list of MeasuredStar. They are usually filled in Associations::AddImage.
void assignIndices(const std::string &whatToFit)
Set parameter groups fixed or variable and assign indices to each parameter in the big matrix (which ...
virtual void offsetParams(const Eigen::VectorXd &delta)=0
Offset the parameters by the provided amounts.
Simple structure to accumulate Chi2 and Ndof.
const CcdImageList & getCcdImageList() const
bool operator<(const Chi2Entry &right) const
void setIndexInMatrix(const unsigned &index)
index is a value that a fit can set and reread....
int getIndexInMatrix() const
void addTriplet(const unsigned i, const unsigned j, double val)
A list of FittedStar s. Such a list is typically constructed by Associations.
objects measured on actual images.
const MeasuredStarList & getCatalogForFit() const
Gets the catalog to be used for fitting, which may have been cleaned-up.
virtual void getIndicesAndDerivatives(const MeasuredStar &measuredStar, const CcdImage &ccdImage, std::vector< unsigned > &indices, Eigen::VectorXd &D)=0
number of parameters to be read in indices.size()
unsigned getNextFreeIndex() const
Interface class for PhotometryFit.
Chi2Entry(double chi2, std::shared_ptr< MeasuredStar > star)
int getMeasurementCount() const
std::shared_ptr< MeasuredStar > measuredStar
virtual unsigned assignIndices(const std::string &whatToFit, unsigned firstIndex)=0
Assign indices to parameters involved in mappings, starting at firstIndex.
std::list< std::shared_ptr< CcdImage > > CcdImageList
void makeResTuple(const std::string &tupleName) const
Produces an ntuple.
Handler of an actual image from a single CCD.
Eigen::SparseMatrix< double > SpMat
bool isValid() const
Fits may use that to discard outliers.
void offsetParams(const Eigen::VectorXd &delta)
Offset the parameters by the requested quantities.
The objects which have been measured several times.
void setNextFreeIndex(unsigned index)
VisitIdType getVisit() const
returns visit ID
int getCcdId() const
returns ccd ID
FittedStarList fittedStarList