lsst.jointcal  15.0-11-gda8ddd7+2
PhotometryFit.cc
Go to the documentation of this file.
1 #include <iostream>
2 #include <iomanip>
3 #include <algorithm>
4 #include <fstream>
5 
6 #include "Eigen/Sparse"
7 
8 #include "lsst/log/Log.h"
9 #include "lsst/pex/exceptions.h"
12 #include "lsst/jointcal/Chi2.h"
14 #include "lsst/jointcal/Gtransfo.h"
16 
17 namespace lsst {
18 namespace jointcal {
19 
20 void PhotometryFit::leastSquareDerivativesMeasurement(CcdImage const &ccdImage, TripletList &tripletList,
21  Eigen::VectorXd &grad,
22  MeasuredStarList const *measuredStarList) const {
23  /**********************************************************************/
24  /* @note the math in this method and accumulateStatImageList() must be kept consistent,
25  * in terms of +/- convention, definition of model, etc. */
26  /**********************************************************************/
27 
28  /* this routine works in two different ways: either providing the
29  Ccd, of providing the MeasuredStarList. In the latter case, the
30  Ccd should match the one(s) in the list. */
31  if (measuredStarList) assert(&(measuredStarList->front()->getCcdImage()) == &ccdImage);
32 
33  unsigned nparModel = (_fittingModel) ? _photometryModel->getNpar(ccdImage) : 0;
34  unsigned nparFlux = (_fittingFluxes) ? 1 : 0;
35  unsigned nparTotal = nparModel + nparFlux;
36  std::vector<unsigned> indices(nparModel, -1);
37  if (_fittingModel) _photometryModel->getMappingIndices(ccdImage, indices);
38 
39  Eigen::VectorXd H(nparTotal); // derivative matrix
40  // current position in the Jacobian
41  unsigned kTriplets = tripletList.getNextFreeIndex();
42  const MeasuredStarList &catalog = (measuredStarList) ? *measuredStarList : ccdImage.getCatalogForFit();
43 
44  for (auto const &measuredStar : catalog) {
45  if (!measuredStar->isValid()) continue;
46 // tweak the measurement errors
47 #ifdef FUTURE
48  TweakPhotomMeasurementErrors(inPos, *measuredStar, _fluxError);
49 #endif
50  H.setZero(); // we cannot be sure that all entries will be overwritten.
51 
52  double residual = _photometryModel->transform(ccdImage, *measuredStar, measuredStar->getInstFlux()) -
53  measuredStar->getFittedStar()->getFlux();
54 
55  double inverseSigma = 1.0 / _photometryModel->transformError(ccdImage, *measuredStar,
56  measuredStar->getInstFluxErr());
57  double W = std::pow(inverseSigma, 2);
58 
59  if (_fittingModel) {
60  _photometryModel->computeParameterDerivatives(*measuredStar, ccdImage, H);
61  for (unsigned k = 0; k < indices.size(); k++) {
62  unsigned l = indices[k];
63  tripletList.addTriplet(l, kTriplets, H[k] * inverseSigma);
64  grad[l] += H[k] * W * residual;
65  }
66  }
67  if (_fittingFluxes) {
68  unsigned index = measuredStar->getFittedStar()->getIndexInMatrix();
69  // Note: H = dR/dFittedStarFlux == -1
70  tripletList.addTriplet(index, kTriplets, -1.0 * inverseSigma);
71  grad[index] += -1.0 * W * residual;
72  }
73  kTriplets += 1; // each measurement contributes 1 column in the Jacobian
74  }
75 
76  tripletList.setNextFreeIndex(kTriplets);
77 }
78 
79 void PhotometryFit::leastSquareDerivativesReference(FittedStarList const &fittedStarList,
80  TripletList &tripletList, Eigen::VectorXd &grad) const {
81  /**********************************************************************/
84  /**********************************************************************/
85 
86  // Derivatives of terms involving fitted and refstars only contribute if we are fitting fluxes.
87  if (!_fittingFluxes) return;
88  // Can't compute anything if there are no refStars.
89  if (_associations->refStarList.size() == 0) return;
90 
91  unsigned kTriplets = tripletList.getNextFreeIndex();
92 
93  for (auto const &fittedStar : fittedStarList) {
94  auto refStar = fittedStar->getRefStar();
95  if (refStar == nullptr) continue; // no contribution if no associated refstar
96  // TODO: Can we actually work with multiple filters at a time in this scheme?
97  // TODO: I feel we might only be able to fit one filter at a time, because these terms are
98  // independent of the ccdImage, so we don't have a specific filter.
99  // filter = ccdImage.getFilter();
100 
101  // W == inverseSigma^2
102  double inverseSigma = 1.0 / refStar->getFluxErr();
103  // Residual is fittedStar.flux - refStar.flux for consistency with measurement terms.
104  double residual = fittedStar->getFlux() - refStar->getFlux();
105 
106  unsigned index = fittedStar->getIndexInMatrix();
107  // Note: H = dR/dFittedStar == 1
108  tripletList.addTriplet(index, kTriplets, 1.0 * inverseSigma);
109  grad(index) += 1.0 * std::pow(inverseSigma, 2) * residual;
110  kTriplets += 1;
111  }
112  tripletList.setNextFreeIndex(kTriplets);
113 }
114 
115 void PhotometryFit::accumulateStatImageList(CcdImageList const &ccdImageList, Chi2Accumulator &accum) const {
116  /**********************************************************************/
119  /**********************************************************************/
120  for (auto const &ccdImage : ccdImageList) {
121  auto &catalog = ccdImage->getCatalogForFit();
122 
123  for (auto const &measuredStar : catalog) {
124  if (!measuredStar->isValid()) continue;
125  double sigma = _photometryModel->transformError(*ccdImage, *measuredStar,
126  measuredStar->getInstFluxErr());
127 #ifdef FUTURE
128  TweakPhotomMeasurementErrors(inPos, measuredStar, _fluxError);
129 #endif
130  double residual =
131  _photometryModel->transform(*ccdImage, *measuredStar, measuredStar->getInstFlux()) -
132  measuredStar->getFittedStar()->getFlux();
133 
134  double chi2Val = std::pow(residual / sigma, 2);
135  accum.addEntry(chi2Val, 1, measuredStar);
136  } // end loop on measurements
137  }
138 }
139 
140 void PhotometryFit::accumulateStatRefStars(Chi2Accumulator &accum) const {
141  /**********************************************************************/
144  /**********************************************************************/
145 
146  FittedStarList &fittedStarList = _associations->fittedStarList;
147  for (auto const &fittedStar : fittedStarList) {
148  auto refStar = fittedStar->getRefStar();
149  if (refStar == nullptr) continue;
150  double chi2 = std::pow(((fittedStar->getFlux() - refStar->getFlux()) / refStar->getFluxErr()), 2);
151  accum.addEntry(chi2, 1, fittedStar);
152  }
153 }
154 
156 
158 void PhotometryFit::getIndicesOfMeasuredStar(MeasuredStar const &measuredStar,
159  std::vector<unsigned> &indices) const {
160  indices.clear();
161  if (_fittingModel) {
162  _photometryModel->getMappingIndices(measuredStar.getCcdImage(), indices);
163  }
164  if (_fittingFluxes) {
165  std::shared_ptr<FittedStar const> const fs = measuredStar.getFittedStar();
166  unsigned fsIndex = fs->getIndexInMatrix();
167  indices.push_back(fsIndex);
168  }
169 }
170 
172  _whatToFit = whatToFit;
173  LOGLS_INFO(_log, "assignIndices: now fitting: " << whatToFit);
174  _fittingModel = (_whatToFit.find("Model") != std::string::npos);
175  _fittingFluxes = (_whatToFit.find("Fluxes") != std::string::npos);
176  // When entering here, we assume that whatToFit has already been interpreted.
177 
178  _nParModel = (_fittingModel) ? _photometryModel->assignIndices(whatToFit, 0) : 0;
179  unsigned ipar = _nParModel;
180 
181  if (_fittingFluxes) {
182  for (auto &fittedStar : _associations->fittedStarList) {
183  // the parameter layout here is used also
184  // - when filling the derivatives
185  // - when updating (offsetParams())
186  // - in getIndicesOfMeasuredStar
187  fittedStar->setIndexInMatrix(ipar);
188  ipar += 1;
189  }
190  }
191  _nParFluxes = ipar - _nParModel;
192  _nParTot = ipar;
194  "nParameters total: " << _nParTot << " model: " << _nParModel << " fluxes: " << _nParFluxes);
195 }
196 
197 void PhotometryFit::offsetParams(Eigen::VectorXd const &delta) {
198  if (delta.size() != _nParTot)
200  "PhotometryFit::offsetParams : the provided vector length is not compatible with "
201  "the current whatToFit setting");
202  if (_fittingModel) _photometryModel->offsetParams(delta);
203 
204  if (_fittingFluxes) {
205  for (auto &fittedStar : _associations->fittedStarList) {
206  // the parameter layout here is used also
207  // - when filling the derivatives
208  // - when assigning indices (assignIndices())
209  unsigned index = fittedStar->getIndexInMatrix();
210  fittedStar->getFlux() -= delta(index);
211  }
212  }
213 }
214 
216  std::ofstream ofile(baseName.c_str());
217  std::string separator = "\t";
218 
219  ofile << "#id" << separator << "xccd" << separator << "yccd" << separator;
220  ofile << "mag" << separator;
221  ofile << "instFlux" << separator << "instFluxErr" << separator;
222  ofile << "inputFlux" << separator << "inputFluxErr" << separator;
223  ofile << "transformedFlux" << separator << "transformedFluxErr" << separator;
224  ofile << "fittedFlux" << separator;
225  ofile << "mjd" << separator << "color" << separator;
226  ofile << "fsindex" << separator;
227  ofile << "ra" << separator << "dec" << separator;
228  ofile << "chi2" << separator << "nm" << separator;
229  ofile << "chip" << separator << "visit" << separator << std::endl;
230 
231  ofile << "#id in source catalog" << separator << "coordinates in CCD" << separator << separator;
232  ofile << "rough mag" << separator;
233  ofile << "measured instrument flux (ADU)" << separator << "measured instrument flux error" << separator;
234  ofile << "measured flux (maggies)" << separator << "measured flux error" << separator;
235  ofile << separator << separator;
236  ofile << "fitted flux (maggies)" << separator;
237  ofile << "modified Julian date of the measurement" << separator << "currently unused" << separator;
238  ofile << "unique index of the fittedStar" << separator;
239  ofile << "on-sky position of fitted star" << separator << separator;
240  ofile << "contribution to Chi2 (1 dof)" << separator << "number of measurements of this FittedStar"
241  << separator;
242  ofile << "chip id" << separator << "visit id" << std::endl;
243 
244  const CcdImageList &ccdImageList = _associations->getCcdImageList();
245  for (auto const &ccdImage : ccdImageList) {
246  const MeasuredStarList &cat = ccdImage->getCatalogForFit();
247  for (auto const &measuredStar : cat) {
248  if (!measuredStar->isValid()) continue;
249  double sigma = _photometryModel->transformError(*ccdImage, *measuredStar,
250  measuredStar->getInstFluxErr());
251 #ifdef FUTURE
252  tweakPhotomMeasurementErrors(inPos, measuredStar, _fluxError);
253 #endif
254  double flux = _photometryModel->transform(*ccdImage, *measuredStar, measuredStar->getInstFlux());
255  double fluxErr = _photometryModel->transformError(*ccdImage, *measuredStar,
256  measuredStar->getInstFluxErr());
257  double jd = ccdImage->getMjd();
258  std::shared_ptr<FittedStar const> const fittedStar = measuredStar->getFittedStar();
259  double residual = flux - fittedStar->getFlux();
260  double chi2Val = std::pow(residual / sigma, 2);
261 
262  ofile << std::setprecision(9);
263  ofile << measuredStar->getId() << separator << measuredStar->x << separator << measuredStar->y
264  << separator;
265  ofile << fittedStar->getMag() << separator;
266  ofile << measuredStar->getInstFlux() << separator << measuredStar->getInstFluxErr() << separator;
267  ofile << measuredStar->getFlux() << separator << measuredStar->getFluxErr() << separator;
268  ofile << flux << separator << fluxErr << separator << fittedStar->getFlux() << separator;
269  ofile << jd << separator << fittedStar->color << separator;
270  ofile << fittedStar->getIndexInMatrix() << separator;
271  ofile << fittedStar->x << separator << fittedStar->y << separator;
272  ofile << chi2Val << separator << fittedStar->getMeasurementCount() << separator;
273  ofile << ccdImage->getCcdId() << separator << ccdImage->getVisit() << std::endl;
274  } // loop on measurements in image
275  } // loop on images
276 }
277 
279  std::ofstream ofile(baseName.c_str());
280  std::string separator = "\t";
281 
282  ofile << "#ra" << separator << "dec " << separator;
283  ofile << "mag" << separator << "color" << separator;
284  ofile << "refFlux" << separator << "refFluxErr" << separator;
285  ofile << "fittedFlux" << separator << "fittedFluxErr" << separator;
286  ofile << "fsindex" << separator << "chi2" << separator << "nm" << std::endl;
287 
288  ofile << "#coordinates of fittedStar" << separator << separator;
289  ofile << "magnitude" << separator << "currently unused" << separator;
290  ofile << "refStar flux (maggies)" << separator << "refStar fluxErr" << separator;
291  ofile << "fittedStar flux (maggies)" << separator << "fittedStar fluxErr" << separator;
292  ofile << "unique index of the fittedStar" << separator << "refStar contribution to Chi2 (1 dof)"
293  << separator << "number of measurements of this FittedStar" << std::endl;
294 
295  // The following loop is heavily inspired from PhotometryFit::computeChi2()
296  const FittedStarList &fittedStarList = _associations->fittedStarList;
297  for (auto const &fittedStar : fittedStarList) {
298  const RefStar *refStar = fittedStar->getRefStar();
299  if (refStar == nullptr) continue;
300 
301  double chi2 = std::pow(((fittedStar->getFlux() - refStar->getFlux()) / refStar->getFluxErr()), 2);
302 
303  ofile << std::setprecision(9);
304  ofile << fittedStar->x << separator << fittedStar->y << separator;
305  ofile << fittedStar->getMag() << separator << fittedStar->color << separator;
306  ofile << refStar->getFlux() << separator << refStar->getFluxErr() << separator;
307  ofile << fittedStar->getFlux() << separator << fittedStar->getFluxErr() << separator;
308  ofile << fittedStar->getIndexInMatrix() << separator << chi2 << separator
309  << fittedStar->getMeasurementCount() << std::endl;
310  } // loop on FittedStars
311 }
312 
313 } // namespace jointcal
314 } // namespace lsst
Objects used as position anchors, typically USNO stars.
Definition: RefStar.h:16
double getFluxErr(size_t filter) const
reference fluxErr in a given filter
Definition: RefStar.h:44
void saveChi2RefContributions(std::string const &baseName) const override
Save a CSV file containing residuals of reference terms.
T endl(T... args)
A list of MeasuredStar. They are usually filled in Associations::createCcdImage.
Definition: MeasuredStar.h:113
afw::table::Key< double > sigma
#define LOGLS_INFO(logger, message)
STL class.
T push_back(T... args)
STL class.
void offsetParams(Eigen::VectorXd const &delta) override
Offset the parameters by the requested quantities.
Class for a simple mapping implementing a generic Gtransfo.
A list of FittedStar s. Such a list is typically constructed by Associations.
Definition: FittedStar.h:121
T clear(T... args)
std::shared_ptr< Associations > _associations
Definition: FitterBase.h:114
void assignIndices(std::string const &whatToFit) override
Set parameters to fit and assign indices in the big matrix.
T find(T... args)
#define LSST_EXCEPT(type,...)
T pow(T... args)
T c_str(T... args)
#define LOGLS_DEBUG(logger, message)
double getFlux(size_t filter) const
reference flux in a given filter
Definition: RefStar.h:42
std::list< std::shared_ptr< CcdImage > > CcdImageList
Definition: CcdImage.h:23
T setprecision(T... args)
void saveChi2MeasContributions(std::string const &baseName) const override
Save a CSV file containing residuals of measurement terms.