LSSTApplications  10.0+286,10.0+36,10.0+46,10.0-2-g4f67435,10.1+152,10.1+37,11.0,11.0+1,11.0-1-g47edd16,11.0-1-g60db491,11.0-1-g7418c06,11.0-2-g04d2804,11.0-2-g68503cd,11.0-2-g818369d,11.0-2-gb8b8ce7
LSSTDataManagementBasePackage
minimize.cc
Go to the documentation of this file.
1 // -*- LSST-C++ -*-
2 
3 /*
4  * LSST Data Management System
5  * Copyright 2008, 2009, 2010 LSST Corporation.
6  *
7  * This product includes software developed by the
8  * LSST Project (http://www.lsst.org/).
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the LSST License Statement and
21  * the GNU General Public License along with this program. If not,
22  * see <http://www.lsstcorp.org/LegalNotices/>.
23  */
24 
37 #include <string>
38 
39 #include "Minuit2/FunctionMinimum.h"
40 #include "Minuit2/MnMigrad.h"
41 #include "Minuit2/MnMinos.h"
42 #include "Minuit2/MnPrint.h"
43 
44 #include "lsst/pex/logging/Trace.h"
45 #include "lsst/afw/math/minimize.h"
46 
47 namespace afwMath = lsst::afw::math;
48 
49 namespace {
50  /*
51  * Minuit wrapper for a function(x)
52  */
53  template<typename ReturnT>
54  class MinimizerFunctionBase1 : public ROOT::Minuit2::FCNBase, public lsst::daf::base::Citizen {
55  public:
56  explicit MinimizerFunctionBase1(
57  afwMath::Function1<ReturnT> const &function,
58  std::vector<double> const &measurementList,
59  std::vector<double> const &varianceList,
60  std::vector<double> const &xPositionList,
61  double errorDef
62  );
63  virtual ~MinimizerFunctionBase1() {};
64  // Required by ROOT::Minuit2::FCNBase
65  virtual double Up() const { return _errorDef; }
66  virtual double operator() (const std::vector<double>&) const;
67 
68 #if 0 // not used
69  inline std::vector<double> getMeasurements() const {return _measurementList;}
70  inline std::vector<double> getVariances() const {return _varianceList;}
71  inline std::vector<double> getPositions() const {return _xPositionList;}
72  inline void setErrorDef(double def) {_errorDef=def;}
73 #endif
74  private:
75  boost::shared_ptr<afwMath::Function1<ReturnT> > _functionPtr;
76  std::vector<double> _measurementList;
77  std::vector<double> _varianceList;
78  std::vector<double> _xPositionList;
79  double _errorDef;
80  };
81 
82  /*
83  * Minuit wrapper for a function(x, y)
84  */
85  template<typename ReturnT>
86  class MinimizerFunctionBase2 : public ROOT::Minuit2::FCNBase, public lsst::daf::base::Citizen {
87  public:
88  explicit MinimizerFunctionBase2(
89  afwMath::Function2<ReturnT> const &function,
90  std::vector<double> const &measurementList,
91  std::vector<double> const &varianceList,
92  std::vector<double> const &xPositionList,
93  std::vector<double> const &yPositionList,
94  double errorDef
95  );
96  virtual ~MinimizerFunctionBase2() {};
97  // Required by ROOT::Minuit2::FCNBase
98  virtual double Up() const { return _errorDef; }
99  virtual double operator() (const std::vector<double>& par) const;
100 
101 #if 0 // not used
102  inline std::vector<double> getMeasurements() const {return _measurementList;}
103  inline std::vector<double> getVariances() const {return _varianceList;}
104  inline std::vector<double> getPosition1() const {return _xPositionList;}
105  inline std::vector<double> getPosition2() const {return _yPositionList;}
106  inline void setErrorDef(double def) {_errorDef=def;}
107 #endif
108  private:
109  boost::shared_ptr<afwMath::Function2<ReturnT> > _functionPtr;
110  std::vector<double> _measurementList;
111  std::vector<double> _varianceList;
112  std::vector<double> _xPositionList;
113  std::vector<double> _yPositionList;
114  double _errorDef;
115  };
116 }
118 template<typename ReturnT>
119 MinimizerFunctionBase1<ReturnT>::MinimizerFunctionBase1(
120  lsst::afw::math::Function1<ReturnT> const &function,
121  std::vector<double> const &measurementList,
122  std::vector<double> const &varianceList,
123  std::vector<double> const &xPositionList,
124  double errorDef)
125 :
126  lsst::daf::base::Citizen(typeid(this)),
127  _functionPtr(function.clone()),
128  _measurementList(measurementList),
129  _varianceList(varianceList),
130  _xPositionList(xPositionList),
131  _errorDef(errorDef)
132 {}
133 
134 template<typename ReturnT>
135 MinimizerFunctionBase2<ReturnT>::MinimizerFunctionBase2(
136  lsst::afw::math::Function2<ReturnT> const &function,
137  std::vector<double> const &measurementList,
138  std::vector<double> const &varianceList,
139  std::vector<double> const &xPositionList,
140  std::vector<double> const &yPositionList,
141  double errorDef)
142 :
143  lsst::daf::base::Citizen(typeid(this)),
144  _functionPtr(function.clone()),
145  _measurementList(measurementList),
146  _varianceList(varianceList),
147  _xPositionList(xPositionList),
148  _yPositionList(yPositionList),
149  _errorDef(errorDef)
150 {}
151 
152 
153 
154 // Only method we need to set up; basically this is a chi^2 routine
155 template<typename ReturnT>
156 double MinimizerFunctionBase1<ReturnT>::operator() (const std::vector<double>& par) const {
157  // Initialize the function with the fit parameters
158  this->_functionPtr->setParameters(par);
159 
160  double chi2 = 0.0;
161  for (unsigned int i = 0; i < this->_measurementList.size(); i++) {
162  double resid = (*(this->_functionPtr))(this->_xPositionList[i]) - this->_measurementList[i];
163  chi2 += resid * resid / this->_varianceList[i];
164  }
165 
166  return chi2;
167 }
168 
169 
170 template<typename ReturnT>
171 double MinimizerFunctionBase2<ReturnT>::operator() (const std::vector<double>& par) const {
172  // Initialize the function with the fit parameters
173  this->_functionPtr->setParameters(par);
174 
175  double chi2 = 0.0;
176  for (unsigned int i = 0; i < this->_measurementList.size(); i++) {
177  double resid = (*(this->_functionPtr))(this->_xPositionList[i],
178  this->_yPositionList[i]) - this->_measurementList[i];
179  chi2 += resid * resid / this->_varianceList[i];
180  }
181 
182  return chi2;
183 }
185 
201 template<typename ReturnT>
203  lsst::afw::math::Function1<ReturnT> const &function,
204  std::vector<double> const &initialParameterList,
205  std::vector<double> const &stepSizeList,
206  std::vector<double> const &measurementList,
207  std::vector<double> const &varianceList,
208  std::vector<double> const &xPositionList,
209  double errorDef
210 ) {
211  unsigned int const nParameters = function.getNParameters();
212  if (initialParameterList.size() != nParameters) {
213  throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
214  "initialParameterList is the wrong length");
215  }
216  if (stepSizeList.size() != nParameters) {
217  throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
218  "stepSizeList is the wrong length");
219  }
220  unsigned int const nMeasurements = measurementList.size();
221  if (varianceList.size() != nMeasurements) {
222  throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
223  "varianceList is the wrong length");
224  }
225  if (xPositionList.size() != nMeasurements) {
226  throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
227  "xPositionList is the wrong length");
228  }
229 
230  MinimizerFunctionBase1<ReturnT> minimizerFunc(
231  function,
232  measurementList,
233  varianceList,
234  xPositionList,
235  errorDef
236  );
237 
238  ROOT::Minuit2::MnUserParameters fitPar;
239  std::vector<std::string> paramNames;
240  for (unsigned int i = 0; i < nParameters; ++i) {
241  paramNames.push_back((boost::format("p%d") % i).str());
242  fitPar.Add(paramNames[i].c_str(), initialParameterList[i], stepSizeList[i]);
243  }
244 
245  ROOT::Minuit2::MnMigrad migrad(minimizerFunc, fitPar);
246  ROOT::Minuit2::FunctionMinimum min = migrad();
247  ROOT::Minuit2::MnMinos minos(minimizerFunc, min);
248 
249  FitResults fitResults;
250  fitResults.chiSq = min.Fval();
251  fitResults.isValid = min.IsValid() && std::isfinite(fitResults.chiSq);
252  if (!fitResults.isValid) {
253  lsst::pex::logging::Trace("lsst::afw::math::minimize", 1, "WARNING : Fit failed to converge");
254  }
255 
256  for (unsigned int i = 0; i < nParameters; ++i) {
257  fitResults.parameterList.push_back(min.UserState().Value(paramNames[i].c_str()));
258  if (fitResults.isValid) {
259  fitResults.parameterErrorList.push_back(minos(i));
260  } else {
261  double e = min.UserState().Error(paramNames[i].c_str());
262  std::pair<double,double> ep(-1 * e, e);
263  fitResults.parameterErrorList.push_back(ep);
264  }
265  }
266  return fitResults;
267 }
268 
269 
285 template<typename ReturnT>
287  lsst::afw::math::Function2<ReturnT> const &function,
288  std::vector<double> const &initialParameterList,
289  std::vector<double> const &stepSizeList,
290  std::vector<double> const &measurementList,
291  std::vector<double> const &varianceList,
292  std::vector<double> const &xPositionList,
293  std::vector<double> const &yPositionList,
294  double errorDef
295 ) {
296  unsigned int const nParameters = function.getNParameters();
297  if (initialParameterList.size() != nParameters) {
298  throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
299  "initialParameterList is the wrong length");
300  }
301  if (stepSizeList.size() != nParameters) {
302  throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
303  "stepSizeList is the wrong length");
304  }
305  unsigned int const nMeasurements = measurementList.size();
306  if (varianceList.size() != nMeasurements) {
307  throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
308  "varianceList is the wrong length");
309  }
310  if (xPositionList.size() != nMeasurements) {
311  throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
312  "xPositionList is the wrong length");
313  }
314  if (yPositionList.size() != nMeasurements) {
315  throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
316  "yPositionList is the wrong length");
317  }
318 
319  MinimizerFunctionBase2<ReturnT> minimizerFunc(
320  function,
321  measurementList,
322  varianceList,
323  xPositionList,
324  yPositionList,
325  errorDef
326  );
327 
328  ROOT::Minuit2::MnUserParameters fitPar;
329  std::vector<std::string> paramNames;
330  for (unsigned int i = 0; i < nParameters; ++i) {
331  paramNames.push_back((boost::format("p%d") % i).str());
332  fitPar.Add(paramNames[i].c_str(), initialParameterList[i], stepSizeList[i]);
333  }
334 
335  ROOT::Minuit2::MnMigrad migrad(minimizerFunc, fitPar);
336  ROOT::Minuit2::FunctionMinimum min = migrad();
337  ROOT::Minuit2::MnMinos minos(minimizerFunc, min);
338 
339  FitResults fitResults;
340  fitResults.chiSq = min.Fval();
341  fitResults.isValid = min.IsValid() && std::isfinite(fitResults.chiSq);
342  if (!fitResults.isValid) {
343  lsst::pex::logging::Trace("lsst::afw::math::minimize", 1, "WARNING : Fit failed to converge");
344  }
345 
346  for (unsigned int i = 0; i < nParameters; ++i) {
347  fitResults.parameterList.push_back(min.UserState().Value(paramNames[i].c_str()));
348  if (fitResults.isValid) {
349  fitResults.parameterErrorList.push_back(minos(i));
350  } else {
351  double e = min.UserState().Error(paramNames[i].c_str());
352  std::pair<double,double> ep(-1 * e, e);
353  fitResults.parameterErrorList.push_back(ep);
354  }
355  }
356  return fitResults;
357 }
358 
359 // Explicit instantiation
361 #define NL /* */
362 #define minimizeFuncs(ReturnT) \
363  template afwMath::FitResults afwMath::minimize( \
364  afwMath::Function1<ReturnT> const &, \
365  std::vector<double> const &, \
366  std::vector<double> const &, \
367  std::vector<double> const &, \
368  std::vector<double> const &, \
369  std::vector<double> const &, \
370  double \
371  ); NL \
372  template afwMath::FitResults afwMath::minimize( \
373  afwMath::Function2<ReturnT> const &, \
374  std::vector<double> const &, \
375  std::vector<double> const &, \
376  std::vector<double> const &, \
377  std::vector<double> const &, \
378  std::vector<double> const &, \
379  std::vector<double> const &, \
380  double \
381  );
382 
383 minimizeFuncs(float)
384 minimizeFuncs(double)
Adaptor for minuit.
definition of the Trace messaging facilities
FitResults minimize(lsst::afw::math::Function1< ReturnT > const &function, std::vector< double > const &initialParameterList, std::vector< double > const &stepSizeList, std::vector< double > const &measurementList, std::vector< double > const &varianceList, std::vector< double > const &xPositionList, double errorDef)
limited backward compatibility to the DC2 run-time trace facilities
Definition: Trace.h:93
A Function taking two arguments.
Definition: Function.h:300
Results from minimizing a function.
Definition: minimize.h:51
A Function taking one argument.
Definition: Function.h:229
int isfinite(T t)
Definition: ieee.h:100
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
Citizen is a class that should be among all LSST classes base classes, and handles basic memory manag...
Definition: Citizen.h:56