lsst.jointcal  14.0-19-g0e46020+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  auto 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  /* If we think the some coordinate on the focal plane is relevant in
218  the ntuple, because thmodel relies on it, then we have to add
219  some function to the model that returns this relevant
220  coordinate. */
221  std::string separator = "\t";
222  ofile << "#id" << separator << "#xccd" << separator << "yccd" << separator << "mag" << separator
223  << "instFlux" << separator << "instFluxError" << separator << "flux" << separator << "fluxError"
224  << separator << "transformedFlux" << separator << "transformedFluxErr" << separator << "fflux"
225  << separator << "mjd" << separator << "color" << separator << "fsindex" << separator << "ra"
226  << separator << "dec" << separator << "chi2" << separator << "nm" << separator << "chip"
227  << separator << "visit" << separator << std::endl;
228  ofile << "#id in source catalog" << separator << "#coordinates in CCD" << separator << separator
229  << "rough mag" << separator << "measured instrument flux" << separator
230  << "measured instrument flux error" << separator << "measured flux" << separator
231  << "measured flux error" << separator << separator << separator << "fitted flux" << separator
232  << "modified Julian date of the measurement" << separator << "currently unused" << separator
233  << "unique index of the fittedStar" << separator << "pos of fitted star" << separator << separator
234  << "contribution to Chi2 (1 dof)" << separator << "number of measurements of this FittedStar"
235  << separator << "chip id" << separator << "visit id" << std::endl;
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  double sigma = _photometryModel->transformError(*ccdImage, *measuredStar,
242  measuredStar->getInstFluxErr());
243 #ifdef FUTURE
244  tweakPhotomMeasurementErrors(inPos, measuredStar, _fluxError);
245 #endif
246  double flux = _photometryModel->transform(*ccdImage, *measuredStar, measuredStar->getInstFlux());
247  double fluxErr = _photometryModel->transformError(*ccdImage, *measuredStar,
248  measuredStar->getInstFluxErr());
249  double jd = ccdImage->getMjd();
250  auto fittedStar = measuredStar->getFittedStar();
251  double residual = flux - fittedStar->getFlux();
252  double chi2Val = std::pow(residual / sigma, 2);
253 
254  ofile << measuredStar->getId() << separator << measuredStar->x << separator << measuredStar->y
255  << separator << fittedStar->getMag() << separator << measuredStar->getInstFlux()
256  << separator << measuredStar->getInstFluxErr() << separator << measuredStar->getFlux()
257  << separator << measuredStar->getFluxErr() << separator << flux << separator << fluxErr
258  << separator << fittedStar->getFlux() << separator << jd << separator << fittedStar->color
259  << separator << fittedStar->getIndexInMatrix() << separator << fittedStar->x << separator
260  << fittedStar->y << separator << chi2Val << separator << fittedStar->getMeasurementCount()
261  << separator << ccdImage->getCcdId() << separator << ccdImage->getVisit() << std::endl;
262  } // loop on measurements in image
263  } // loop on images
264 }
265 
267  std::ofstream ofile(baseName.c_str());
268  std::string separator = "\t";
269  ofile << "#ra" << separator << "dec " << separator << "mag" << separator << "color" << separator
270  << "refFlux" << separator << "refFluxErr" << separator << "fittedFlux" << separator
271  << "fittedFluxErr" << separator << "fsindex" << separator << "chi2" << separator << "nm"
272  << std::endl;
273  ofile << "#coordinates of fittedStar" << separator << separator << "magnitude" << separator
274  << "currently unused" << separator << "default refStar flux" << separator
275  << "default refStar fluxErr" << separator << "fittedStar flux" << separator << "fittedStar fluxErr"
276  << separator << "unique index of the fittedStar" << separator
277  << "refStar contribution to Chi2 (2D dofs)" << separator
278  << "number of measurements of this FittedStar" << std::endl;
279  // The following loop is heavily inspired from AstrometryFit::computeChi2()
280  const FittedStarList &fittedStarList = _associations->fittedStarList;
281  for (auto const &fittedStar : fittedStarList) {
282  const RefStar *refStar = fittedStar->getRefStar();
283  if (refStar == nullptr) continue;
284 
285  double chi2 = std::pow(((fittedStar->getFlux() - refStar->getFlux()) / refStar->getFluxErr()), 2);
286 
287  ofile << std::setprecision(9);
288  ofile << fittedStar->x << separator << fittedStar->y << separator << fittedStar->getMag() << separator
289  << fittedStar->color << separator << refStar->getFlux() << separator << refStar->getFluxErr()
290  << separator << fittedStar->getFlux() << separator << fittedStar->getFluxErr() << separator
291  << fittedStar->getIndexInMatrix() << separator << chi2 << separator
292  << fittedStar->getMeasurementCount() << std::endl;
293  } // loop on FittedStars
294 }
295 
296 } // namespace jointcal
297 } // 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::AddImage.
Definition: MeasuredStar.h:111
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:121
T clear(T... args)
std::shared_ptr< Associations > _associations
Definition: FitterBase.h:114
#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.