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