00001 #ifndef PhisycsTools_Utilities_RootMinuit_h
00002 #define PhisycsTools_Utilities_RootMinuit_h
00003
00006 #include "PhysicsTools/Utilities/interface/Parameter.h"
00007 #include "PhysicsTools/Utilities/interface/ParameterMap.h"
00008 #include "PhysicsTools/Utilities/interface/RootMinuitResultPrinter.h"
00009 #include "PhysicsTools/Utilities/interface/RootMinuitFuncEvaluator.h"
00010 #include "FWCore/Utilities/interface/EDMException.h"
00011 #include "TMinuit.h"
00012 #include "Math/SMatrix.h"
00013 #include <boost/shared_ptr.hpp>
00014 #include <vector>
00015 #include <string>
00016 #include <memory>
00017
00018 namespace fit {
00019
00020 template<class Function>
00021 class RootMinuit {
00022 public:
00023 RootMinuit(Function f, bool verbose = false) :
00024 initialized_(false), minValue_(0), verbose_(verbose) {
00025 f_ = f;
00026 }
00027 void addParameter(const std::string & name, boost::shared_ptr<double> val, double err, double min, double max) {
00028 if(initialized_)
00029 throw edm::Exception(edm::errors::Configuration)
00030 << "RootMinuit: can't add parameter " << name
00031 << " after minuit initialization\n";
00032 pars_.push_back(val);
00033 parameter_t par;
00034 par.val = *val;
00035 par.err = err;
00036 par.min = min;
00037 par.max = max;
00038 par.fixed = false;
00039 parMap_.push_back(std::make_pair(name, par));
00040 size_t s = parIndices_.size();
00041 parIndices_[name] = s;
00042 }
00043 void addParameter(const funct::Parameter & par, double err, double min, double max) {
00044 return addParameter(par.name(), par, err, min, max);
00045 }
00046 double getParameter(const std::string & name, double & err) {
00047 double val;
00048 init();
00049 minuit_->GetParameter(parameterIndex(name), val, err);
00050 return val;
00051 }
00052 double getParameter(const std::string & name) {
00053 double val, err;
00054 init();
00055 minuit_->GetParameter(parameterIndex(name), val, err);
00056 return val;
00057 }
00058 double getParameterError(const std::string & name, double & val) {
00059 double err;
00060 init();
00061 minuit_->GetParameter(parameterIndex(name), val, err);
00062 return err;
00063 }
00064 double getParameterError(const std::string & name) {
00065 double val, err;
00066 init();
00067 minuit_->GetParameter(parameterIndex(name), val, err);
00068 return err;
00069 }
00070 template<unsigned int N>
00071 void getErrorMatrix(ROOT::Math::SMatrix<double, N, N, ROOT::Math::MatRepSym<double, N> > & err) {
00072 init();
00073 if(N != numberOfParameters())
00074 throw edm::Exception(edm::errors::Configuration)
00075 << "RootMinuit: can't call getErrorMatrix passing an SMatrix of dimension " << N
00076 << " while the number of parameters is " << numberOfParameters() << "\n";
00077 double * e = new double[N*N];
00078 minuit_->mnemat(e, numberOfParameters());
00079 for(size_t i = 0; i < N; ++i) {
00080 for(size_t j = 0; j <= i; ++j) {
00081 err(i, j) = e[i + N*j];
00082 }
00083 }
00084 delete [] e;
00085 setParameters();
00086 }
00087 void fixParameter(const std::string & name) {
00088 size_t i = parameterIndex(name);
00089 parMap_[i].second.fixed = true;
00090 if(initialized_) {
00091 minuit_->FixParameter(i);
00092 }
00093 }
00094 void releaseParameter(const std::string & name) {
00095 size_t i = parameterIndex(name);
00096 parMap_[i].second.fixed = false;
00097 if(initialized_) {
00098 minuit_->Release(i);
00099 }
00100 }
00101 void setParameter(const std::string & name, double val) {
00102 size_t i = parameterIndex(name);
00103 parameter_t & par = parMap_[i].second;
00104 par.val = val;
00105 if(initialized_) {
00106 int ierflg = 0;
00107 minuit_->mnparm(i, name, par.val, par.err, par.min, par.max, ierflg);
00108 if(ierflg != 0)
00109 throw edm::Exception(edm::errors::Configuration)
00110 << "RootMinuit: error in setting parameter " << i
00111 << " value = " << par.val << " error = " << par.err
00112 << " range = [" << par.min << ", " << par.max << "]\n";
00113 }
00114 }
00115 void setParameters() {
00116 std::map<std::string, size_t>::const_iterator i = parIndices_.begin(), end = parIndices_.end();
00117 double val, err;
00118 for(; i != end; ++i) {
00119 size_t index = i->second;
00120 minuit_->GetParameter(index, val, err);
00121 *pars_[index] = val;
00122 }
00123 }
00124 int numberOfParameters() {
00125 init();
00126 return minuit_->GetNumPars();
00127 }
00128 int numberOfFreeParameters() {
00129 init();
00130 return minuit_->GetNumFreePars();
00131 }
00132 double minimize() {
00133 init();
00134 double arglist[10];
00135 arglist[0] = 5000;
00136 arglist[1] = 0.1;
00137 int ierflag;
00138 minuit_->mnexcm("MINIMIZE", arglist, 2, ierflag);
00139 if ( ierflag != 0 ) std::cerr << "ERROR in minimize!!" << std::endl;
00140 if(verbose_) minuit_->mnmatu(1);
00141 double m = minValue();
00142 if(verbose_) minuit_->mnprin(3, m);
00143 setParameters();
00144 return m;
00145 }
00146 double migrad() {
00147 init();
00148 double arglist[10];
00149 arglist[0] = 5000;
00150 arglist[1] = 0.1;
00151 int ierflag;
00152 minuit_->mnexcm("MIGRAD", arglist, 2, ierflag);
00153 if ( ierflag != 0 ) std::cerr << "ERROR in migrad!!" << std::endl;
00154 if(verbose_) minuit_->mnmatu(1);
00155 double m = minValue();
00156 if(verbose_) minuit_->mnprin(3, m);
00157 setParameters();
00158 return m;
00159 }
00160 double minValue() {
00161 init();
00162 int ierflag;
00163 double edm, errdef;
00164 int nvpar, nparx;
00165 minuit_->mnstat(minValue_, edm, errdef, nvpar, nparx, ierflag);
00166 return minValue_;
00167 }
00168 void printParameters(std::ostream& cout = std::cout) {
00169 std::map<std::string, size_t>::const_iterator i = parIndices_.begin(), end = parIndices_.end();
00170 for(; i != end; ++i) {
00171 cout << i->first << " = " << *pars_[i->second]
00172 << " +/- " << getParameterError(i->first) << std::endl;
00173 }
00174 }
00175 void printFitResults(std::ostream& cout = std::cout) {
00176 RootMinuitResultPrinter<Function>::print(minValue(), numberOfFreeParameters(), f_);
00177 printParameters(cout);
00178 }
00179 private:
00180 parameterVector_t parMap_;
00181 std::map<std::string, size_t> parIndices_;
00182 bool initialized_;
00183 double minValue_;
00184 std::auto_ptr<TMinuit> minuit_;
00185 std::vector<boost::shared_ptr<double> > pars_;
00186 static std::vector<boost::shared_ptr<double> > *fPars_;
00187 bool verbose_;
00188 static Function f_;
00189 static void fcn_(int &, double *, double &f, double *par, int) {
00190 size_t size = fPars_->size();
00191 for(size_t i = 0; i < size; ++i)
00192 *((*fPars_)[i]) = par[i];
00193 f = RootMinuitFuncEvaluator<Function>::evaluate(f_);
00194 }
00195 size_t parameterIndex(const std::string &name) const {
00196 typename std::map<std::string, size_t>::const_iterator p = parIndices_.find(name);
00197 if(p == parIndices_.end())
00198 throw edm::Exception(edm::errors::Configuration)
00199 << "RootMinuit: can't find parameter " << name << "\n";
00200 return p->second;
00201 }
00202 void init() {
00203 if(initialized_) return;
00204 minuit_.reset(new TMinuit(parMap_.size()));
00205 double arglist[10];
00206 int ierflg = 0;
00207 if (! verbose_) {
00208 arglist[0] = -1;
00209 minuit_->mnexcm("SET PRINT", arglist, 1, ierflg);
00210 if (ierflg != 0)
00211 throw edm::Exception(edm::errors::Configuration)
00212 << "RootMinuit: error in calling SET PRINT\n";
00213 }
00214 arglist[0] = 1;
00215 minuit_->mnexcm("SET ERR", arglist, 1, ierflg);
00216 if (ierflg != 0)
00217 throw edm::Exception(edm::errors::Configuration)
00218 << "RootMinuit: error in calling SET ERR\n";
00219
00220 size_t i = 0;
00221 typename parameterVector_t::const_iterator p = parMap_.begin(), end = parMap_.end();
00222 for(; p != end; ++p, ++i) {
00223 const std::string & name = p->first;
00224 const parameter_t & par = p->second;
00225 minuit_->mnparm(i, name, par.val, par.err, par.min, par.max, ierflg);
00226 if(ierflg != 0)
00227 throw edm::Exception(edm::errors::Configuration)
00228 << "RootMinuit: error in setting parameter " << i
00229 << " value = " << par.val << " error = " << par.err
00230 << " range = [" << par.min << ", " << par.max << "]\n";
00231 }
00232 initialized_ = true;
00233 for(i = 0, p = parMap_.begin(); p != end; ++p, ++i)
00234 if(p->second.fixed)
00235 minuit_->FixParameter(i);
00236 fPars_= & pars_;
00237 minuit_->SetFCN(fcn_);
00238 }
00239 };
00240
00241 template<class Function>
00242 Function RootMinuit<Function>::f_;
00243
00244 template<class Function>
00245 std::vector<boost::shared_ptr<double> > * RootMinuit<Function>::fPars_ = 0;
00246 }
00247
00248 #endif