00001 #include "NagFitStrategy.h"
00002 #include <TF1.h>
00003 #include <TH1.h>
00004 #include <TGraphErrors.h>
00005
00006 using namespace Sct;
00007 namespace SctFitter{
00008 NagFitStrategy::NagFitStrategy(string opt) throw()
00009 : FitStrategy(opt), name("NagFitStrategy") {}
00010
00011 NagFitStrategy::~NagFitStrategy() throw() {}
00012
00014
00015 void NagFitStrategy::fitTH1(const TH1& hist, TF1& fit) const throw(LogicError, MathsError) {
00017 TH1& theHist = const_cast<TH1&> (hist);
00018
00019
00020 int firstpoint=1;
00021 const int npoints = getNumberFitPoints(theHist, fit, firstpoint);
00022
00023
00024 Cache* cache = new Cache(hist, npoints, firstpoint, fit);
00025 nagFit(cache, fit, quiet());
00026 delete cache;
00027 }
00028
00029
00030 void NagFitStrategy::fitTGraph(const TGraph& graph, TF1& fit) const throw (LogicError, MathsError) {
00031 TGraph& theGraph = const_cast<TGraph&> (graph);
00032
00033
00034 vector<bool> active;
00035 getFitPoints(theGraph, fit, active);
00036
00037 Cache* cache = new Cache(theGraph, fit, active);
00038 nagFit(cache, fit, quiet());
00039 delete cache;
00040 }
00041
00042 void NagFitStrategy::fitTGraphErrors(const TGraphErrors& graph, TF1& fit) const throw (LogicError, MathsError) {
00043 TGraphErrors& theGraph = const_cast<TGraphErrors&> (graph);
00044
00045
00046 vector<bool> active;
00047 getFitPoints(theGraph, fit, active);
00048
00049 Cache* cache = new Cache(theGraph, fit, active);
00050 nagFit(cache, fit, quiet());
00051 delete cache;
00052 }
00053
00054 void NagFitStrategy::nagFit(Cache* cache, TF1& fit, bool quiet) const throw(MathsError) {
00055 unsigned npoints=cache->m_x.size();
00056 if (npoints==0) return;
00057
00059 static NagError fail, fail2;
00060 Nag_Comm comm;
00061 Nag_E04_Opt nagOptions;
00062
00063
00064 e04xxc(&nagOptions);
00065
00066 if (quiet){
00067 nagOptions.list=false;
00068 fail.print = FALSE;
00069 nagOptions.print_level=Nag_NoPrint;
00070
00071 }
00072 double chiSq=0.;
00073 double fjac[npoints][cache->nVarPars];
00074 double fvec[npoints];
00075
00076 comm.p = (Pointer) cache;
00077
00078
00079 nag_opt_lsq_no_deriv(npoints, cache->nVarPars,
00080 &(this->chiSquaredFunctionForNag),
00081 cache->inPars, &chiSq, fvec,
00082 (double*)fjac, cache->nVarPars, &nagOptions, &comm, &fail);
00083
00084 e04xzc(&nagOptions, "all", &fail2);
00085
00086
00087 if (fail.code != NE_NOERROR && fail.code != NW_COND_MIN){
00088 if (!quiet){
00089 MathsError e("NagFitStrategy NAG ERROR", __FILE__, __LINE__);
00090 e.sendToMrs(MRS_DIAGNOSTIC);
00091 }
00092 } else {
00093 cache->convertPars(cache->inPars);
00094 for (int i=0; i<fit.GetNpar(); ++i){
00095 fit.SetParameter(i,cache->pars[i]);
00096
00097 }
00098 fit.SetChisquare(chiSq);
00099 fit.SetNDF(npoints-fit.GetNpar());
00100 }
00101 }
00102
00103 const string& NagFitStrategy::getName() const throw() {
00104 return name;
00105 }
00106
00107 bool NagFitStrategy::inMap=FitStrategyFactory::instance().addToMap("NagFitStrategy", *new NagFitStrategy("") );
00108
00109 const int NagFitStrategy::getNumberFitPoints(TH1& hist, const TF1& fit,
00110 int& firstpoint) const throw (LogicError) {
00111 if (!ranged()){
00112 firstpoint=1;
00113 return hist.GetNbinsX();
00114 }
00115
00116 int iLastBin;
00118 TF1& theFit = const_cast<TF1&> (fit);
00119 double xmin, xmax;
00120 theFit.GetRange(xmin, xmax);
00121 if (xmin>=xmax) throw InvalidArgumentError("NagFitStrategy TF1 fit min>=max", __FILE__, __LINE__);
00122 TAxis* axis=hist.GetXaxis();
00123
00124 firstpoint = axis->FindFixBin(xmin);
00125 iLastBin = axis->FindFixBin(xmax);
00126 if (firstpoint < 1) firstpoint = 1;
00127 if (iLastBin > axis->GetLast()) iLastBin = axis->GetLast();
00128 return iLastBin - firstpoint;
00129 }
00130
00131 void NagFitStrategy::getFitPoints(TGraph& graph, const TF1& fit, vector<bool>& active) const throw (LogicError) {
00132 active.resize(graph.GetN());
00133
00134 if (!ranged()){
00135 for (int ipoint=0; ipoint<graph.GetN(); ++ipoint){
00136 active[ipoint]=true;
00137 }
00138 return;
00139 }
00140
00142 TF1& theFit = const_cast<TF1&> (fit);
00143 double xmin, xmax, x, y;
00144 theFit.GetRange(xmin, xmax);
00145 if (xmin>=xmax) throw InvalidArgumentError("NagFitStrategy TF1 fit min>=max", __FILE__, __LINE__);
00146 for (int ipoint=0; ipoint<graph.GetN(); ++ipoint){
00147 graph.GetPoint(ipoint,x,y);
00148 active[ipoint] = (x>=xmin && x<=xmax);
00149 }
00150 }
00151
00152 NagFitStrategy::Cache::Cache(const TGraph& graph, TF1& fit, const vector<bool>& active) throw(LogicError, MathsError) {
00153 TGraph& theGraph = const_cast<TGraph&> (graph);
00154 function=&fit;
00155 setupPars(fit);
00156 for ( int ipoint=0; ipoint<graph.GetN(); ++ipoint){
00157 if (active[ipoint]){
00158 double x, y;
00159 theGraph.GetPoint(ipoint,x,y);
00160 m_x.push_back(x);
00161 m_y.push_back(y);
00162 m_ey.push_back(1.);
00163 }
00164 }
00165 }
00166
00167 NagFitStrategy::Cache::Cache(const TGraphErrors& graph, TF1& fit, const vector<bool>& active) throw(LogicError, MathsError) {
00168 TGraphErrors& theGraph=const_cast<TGraphErrors&> (graph);
00169 function=&fit;
00170 setupPars(fit);
00171 for ( int ipoint=0; ipoint<graph.GetN(); ++ipoint){
00172 if (active[ipoint]){
00173 double x, y, err;
00174 theGraph.GetPoint(ipoint,x,y);
00175 err=theGraph.GetErrorY(ipoint);
00176 if (err==0.) throw MathsError("NagFitStrategy::Cache(graph) Error=0", __FILE__, __LINE__);
00177 m_x.push_back(x);
00178 m_y.push_back(y);
00179 m_ey.push_back(err);
00180 }
00181 }
00182 }
00183
00184 NagFitStrategy::Cache::Cache(const TH1& hist, const unsigned npoints,
00185 const unsigned firstpoint, TF1& fit) throw(LogicError, MathsError) {
00186 function=&fit;
00187 setupPars(fit);
00188 for (unsigned i=0; i<npoints; ++i){
00189 double err = hist.GetBinError(i + firstpoint);
00190 if (err==0.) throw MathsError("NagFitStrategy::Cache(TH1) Error=0", __FILE__, __LINE__);
00191 double y=hist.GetBinContent(i + firstpoint);
00192 if (2*err>y) continue;
00193 m_ey.push_back(err);
00194 m_y.push_back(y);
00195 m_x.push_back(hist.GetBinCenter(i + firstpoint));
00196 }
00197 }
00198
00199 NagFitStrategy::Cache::~Cache() throw(){
00200 delete [] pars;
00201 delete [] map;
00202 delete [] inPars;
00203 }
00204
00205 void NagFitStrategy::Cache::convertPars(double inPars[]) {
00206 for (unsigned int i=0; i<nVarPars; ++i) {
00207 pars[map[i]] = inPars[i];
00208 }
00209 }
00210
00211 void NagFitStrategy::Cache::setupPars(TF1& fit) {
00212 map = new int[fit.GetNpar()];
00213 pars = new double[fit.GetNpar()];
00214 inPars = new double[fit.GetNpar()];
00215 nVarPars = 0;
00216 double lowLim, highLim;
00217
00218 for (unsigned int i=0; i<fit.GetNpar(); ++i) {
00219 fit.GetParLimits(i, lowLim, highLim);
00220 if (lowLim == highLim && lowLim != 0) {
00221 pars[i] = lowLim;
00222
00223 } else {
00224 map[nVarPars] = i;
00225 inPars[nVarPars] = fit.GetParameter(i);
00226
00227 ++nVarPars;
00228 }
00229 }
00230
00231 }
00232
00233
00235 void NagFitStrategy::chiSquaredFunctionForNag(Integer nresid, Integer nvar, double x_pars[],
00236 double fvec[], Nag_Comm *comm) throw() {
00237 Cache* cache = (Cache*) comm->p;
00238 cache->convertPars(x_pars);
00239 for (int i=0; i < nresid; ++i){
00240 double resid = cache->function->EvalPar( &(cache->m_x[i]) , cache->pars)
00241 - cache->m_y[i];
00242 fvec[i] = (resid) / (cache->m_ey[i]);
00243 }
00244 }
00245
00246 bool NagFitStrategy::quiet() const throw() {
00247 return ( getOptions().find('Q')!=string::npos ||
00248 getOptions().find('q')!=string::npos );
00249 }
00250
00251 bool NagFitStrategy::ranged() const throw() {
00252 return ( getOptions().find('R')!=string::npos ||
00253 getOptions().find('r')!=string::npos );
00254 }
00255
00256 }
00257