Jpp  debug
the software that should make you happy
JFit2D.cc
Go to the documentation of this file.
1 #include <string>
2 #include <iostream>
3 #include <iomanip>
4 #include <vector>
5 #include <algorithm>
6 #include <chrono>
7 
8 #include "TROOT.h"
9 #include "TFile.h"
10 #include "TKey.h"
11 #include "TH2.h"
12 #include "TGraph2D.h"
13 #include "TGraph2DErrors.h"
14 #include "TF2.h"
15 #include "TFitResult.h"
16 #include "TString.h"
17 #include "TRegexp.h"
18 
19 #include "JROOT/JMinimizer.hh"
20 
21 #include "JLang/JType.hh"
22 #include "JLang/JTypeList.hh"
23 #include "JLang/JToken.hh"
24 #include "JTools/JRange.hh"
25 
26 #include "JGizmo/JRootObjectID.hh"
27 #include "JGizmo/JGizmoToolkit.hh"
28 
29 #include "Jeep/JPrint.hh"
30 #include "Jeep/JParser.hh"
31 #include "Jeep/JMessage.hh"
32 
33 
34 namespace {
35 
36  using namespace JPP;
37 
38  const char* const _F2 = ".f2"; //!< extension of name for fit function
39 
40  /**
41  * Auxiliary class for ROOT fit.
42  */
43  struct JFit {
44  /**
45  * Constructor.
46  *
47  * \param object object
48  * \param fcn fcn
49  * \param option option
50  */
51  JFit(TObject& object,
52  TF2* fcn,
53  const std::string& option) :
54  object(object),
55  fcn (fcn),
56  option(option)
57  {}
58 
59 
60  /**
61  * Attempt fit for given data type.
62  *
63  * \param type data type
64  */
65  template<class T>
66  void operator()(const JType<T>& type)
67  {
68  try {
69  result = dynamic_cast<T&>(object).Fit(fcn, option.c_str(), "same");
70  }
71  catch(const std::exception&) {}
72  }
73 
74  TObject& object;
75  TF2* fcn;
76  std::string option;
77  TFitResultPtr result;
78  };
79 }
80 
81 
82 /**
83  * \file
84  * General purpose fit program for 2D ROOT objects.\n
85  * The option <tt>-f</tt> corresponds to <tt><file name>:<object name></tt>.
86  *
87  * The expressions for the fit function, start and fixed values should comply
88  * with ROOT class TFormula.
89  *
90  * In the expressions of the start and fixed values, names of member methods
91  * of corresponding class of the fit object may appear,
92  * such as TH1::GetMaximum, TH1::GetRMS, etc., e.g:
93  * <pre>
94  * -F "[0]*exp(-0.5*x*x/([1]*[1])*exp(-0.5*y*y/([2]*[2])"
95  * -@ "p0 = GetMaximum; p1 = 2*GetRMS(1); .."
96  * -= "p2 = 1"
97  * </pre>
98  * The result of the formulas for the start and fixed values will be evaluated
99  * for each histogram separately.
100  * \author mdejong
101  */
102 int main(int argc, char **argv)
103 {
104  using namespace std;
105  using namespace JPP;
106 
107  typedef JToken<';'> JToken_t;
108  typedef JRange<double> JRange_t;
109 
110  vector<JRootObjectID> inputFile;
111  string outputFile;
112  string formula;
113  vector<JToken_t> startValues;
114  vector<JToken_t> startErrors;
115  vector<JToken_t> fixedValues;
116  vector<JToken_t> limitValues;
117  JRange_t X;
118  JRange_t Y;
119  string option;
120  bool writeFits;
121  int debug;
122 
123  try {
124 
125  JParser<> zap("General purpose fit program for 2D ROOT objects.");
126 
127  zap['f'] = make_field(inputFile, "<input file>:<object name>");
128  zap['o'] = make_field(outputFile, "ROOT file with fit results") = "fit.root";
129  zap['F'] = make_field(formula, "fit formula, e.g: \"[0]+[1]*x\"");
130  zap['@'] = make_field(startValues, "start values, e.g: \"p0 = GetMaximum;\"");
131  zap['E'] = make_field(startErrors, "start errors, e.g: \"p0 = 0.01 * GetMaximum;\"") = JPARSER::initialised();
132  zap['='] = make_field(fixedValues, "fixed values, e.g: \"p0 = GetMaximum;\"") = JPARSER::initialised();
133  zap['R'] = make_field(limitValues, "limit values, e.g: \"p0 = <lower limit> <upper limit>;\"") = JPARSER::initialised();
134  zap['x'] = make_field(X, "abscissa range") = JRange_t();
135  zap['y'] = make_field(Y, "abscissa range") = JRange_t();
136  zap['O'] = make_field(option, "Fit option") = "";
137  zap['w'] = make_field(writeFits, "write fit function(s) to ROOT file " << "(\"<name>" << _F2 << "\")");
138  zap['M'] = make_field(minimizer, "ROOT minimizer type and algorithm [debug]") = JMinimizer();
139  zap['d'] = make_field(debug) = 1;
140 
141  zap(argc, argv);
142  }
143  catch(const exception &error) {
144  FATAL(error.what() << endl);
145  }
146 
147 
148  if (option.find('O') == string::npos) { option += "O"; }
149  if (option.find("R") == string::npos) { option += "R"; }
150  if (option.find("S") == string::npos) { option += "S"; }
151  //if (option.find('N') == string::npos) { option += "N"; }
152  if (debug == 0 && option.find('Q') == string::npos) { option += "Q"; }
153 
154 
155  TFile out(outputFile.c_str(), "recreate");
156 
157 
158  TF2* fcn = new TF2("user", formula.c_str());
159 
160  fcn->SetNpx(1000);
161  fcn->SetNpy(1000);
162 
163  if (fcn->IsZombie()) {
164  FATAL("Function: " << formula << " is zombie." << endl);
165  }
166 
167  for (vector<JRootObjectID>::const_iterator input = inputFile.begin(); input != inputFile.end(); ++input) {
168 
169  DEBUG("Input: " << *input << endl);
170 
171  TDirectory* dir = getDirectory(*input);
172 
173  if (dir == NULL) {
174  ERROR("File: " << input->getFullFilename() << " not opened." << endl);
175  continue;
176  }
177 
178  const TRegexp regexp(input->getObjectName());
179 
180  TIter iter(dir->GetListOfKeys());
181 
182  for (TKey* key; (key = (TKey*) iter.Next()) != NULL; ) {
183 
184  const TString tag(key->GetName());
185 
186  DEBUG("Key: " << tag << " match = " << tag.Contains(regexp) << endl);
187 
188  // option match
189 
190  if (tag.Contains(regexp) && isTObject(key)) {
191 
192  TObject* object = key->ReadObj();
193 
194 
195  // set fit parameters
196 
197  try {
198 
199  for (vector<JToken_t>::const_iterator i = startValues.begin(); i != startValues.end(); ++i) {
200  fcn->SetParameter(getParameter(*i), getValue(*i,object));
201  }
202 
203  for (Int_t i = 0; i != fcn->GetNpar(); ++i) {
204  fcn->SetParError(i, 0.0);
205  }
206 
207  for (vector<JToken_t>::const_iterator i = startErrors.begin(); i != startErrors.end(); ++i) {
208  fcn->SetParError (getParameter(*i), getValue(*i,object));
209  }
210 
211  for (vector<JToken_t>::const_iterator i = fixedValues.begin(); i != fixedValues.end(); ++i) {
212  fcn->FixParameter(getParameter(*i), getValue(*i,object));
213  }
214 
215  for (vector<JToken_t>::const_iterator i = limitValues.begin(); i != limitValues.end(); ++i) {
216  fcn->SetParLimits(getParameter(*i), getValue(*i,0), getValue(*i,1));
217  }
218  }
219  catch(JLANG::JParseError& error) {
220  FATAL(error << endl);
221  }
222 
223  DEBUG("Start values " << object->GetName() << endl);
224 
225  for (int i = 0; i != fcn->GetNpar(); ++i) {
226  DEBUG(left << setw(12) << fcn->GetParName (i) << ' ' <<
227  SCIENTIFIC(12,5) << fcn->GetParameter(i) << endl);
228  }
229 
230  Double_t xmin = numeric_limits<Double_t>::max();
231  Double_t xmax = numeric_limits<Double_t>::lowest();
232  Double_t ymin = numeric_limits<Double_t>::max();
233  Double_t ymax = numeric_limits<Double_t>::lowest();
234 
235  {
236  TH2* h2 = dynamic_cast<TH2*>(object);
237 
238  if (h2 != NULL) {
239 
240  xmin = min(xmin, h2->GetXaxis()->GetXmin());
241  xmax = max(xmax, h2->GetXaxis()->GetXmax());
242  ymin = min(ymin, h2->GetYaxis()->GetXmin());
243  ymax = max(ymax, h2->GetYaxis()->GetXmax());
244 
245  if (X != JRange_t()) { h2->GetXaxis()->SetRangeUser(X.getLowerLimit(), X.getUpperLimit()); }
246  if (Y != JRange_t()) { h2->GetYaxis()->SetRangeUser(Y.getLowerLimit(), Y.getUpperLimit()); }
247  }
248  }
249 
250  {
251  TGraph2D* g2 = dynamic_cast<TGraph2D*>(object);
252 
253  if (g2 != NULL) {
254  for (Int_t i = 0; i != g2->GetN(); ++i) {
255  xmin = min(xmin, g2->GetX()[i]);
256  xmax = max(xmax, g2->GetX()[i]);
257  ymin = min(ymin, g2->GetY()[i]);
258  ymax = max(ymax, g2->GetY()[i]);
259  }
260  }
261  }
262 
263  if (X != JRange_t()) {
264  xmin = X.getLowerLimit();
265  xmax = X.getUpperLimit();
266  }
267 
268  if (Y != JRange_t()) {
269  ymin = Y.getLowerLimit();
270  ymax = Y.getUpperLimit();
271  }
272 
273  fcn->SetRange(xmin, ymin, xmax, ymax);
274 
275 
276  // execute fit
277 
278  const chrono::steady_clock::time_point t0 = chrono::steady_clock::now();
279 
280  JFit fit(*object, fcn, option);
281 
283 
284  const chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
285 
286  if (fit.result != -1) {
287 
288  // output fit results
289 
290  NOTICE("Fit values " << object->GetName() << endl);
291  NOTICE("Fit formula " << formula << endl);
292  NOTICE("chi2/NDF " << FIXED(7,3) << fit.result->Chi2() << '/' << fit.result->Ndf() << ' ' << (fit.result->IsValid() ? "" : "failed") << endl);
293  NOTICE("Number of calls " << fit.result->NCalls() << endl);
294  NOTICE("Elapsed time [us] " << setw(8) << chrono::duration_cast<chrono::microseconds>(t1 - t0).count() << endl);
295 
296  for (int j = 0; j != fcn->GetNpar(); ++j) {
297  NOTICE(left << setw(12) << fcn->GetParName (j) << ' ' <<
298  SCIENTIFIC(12,5) << fcn->GetParameter(j) << " +/- " <<
299  SCIENTIFIC(12,5) << fcn->GetParError (j) << endl);
300  }
301 
302  } else {
303 
304  WARNING("Object: not compatible with ROOT Fit." << endl);
305  }
306 
307  out.cd();
308 
309  object->Write();
310  fcn ->Write();
311 
312  if (writeFits) {
313 
314  TObject* p = object->Clone(MAKE_CSTRING(object->GetName() << _F2));
315 
316  {
317  TH2* h2 = dynamic_cast<TH2*>(p);
318 
319  if (h2 != NULL) {
320  for (Int_t ix = 1; ix <= h2->GetXaxis()->GetNbins(); ++ix) {
321  for (Int_t iy = 1; iy <= h2->GetYaxis()->GetNbins(); ++iy) {
322 
323  const Double_t x = h2->GetXaxis()->GetBinCenter(ix);
324  const Double_t y = h2->GetYaxis()->GetBinCenter(iy);
325 
326  h2->SetBinContent(ix, iy, fcn->Eval(x,y));
327  h2->SetBinError (ix, iy, 0.0);
328  }
329  }
330  }
331  }
332 
333  {
334  TGraph2D* g2 = dynamic_cast<TGraph2D*>(p);
335 
336  if (g2 != NULL) {
337  for (Int_t i = 0; i != g2->GetN(); ++i) {
338 
339  const Double_t x = g2->GetX()[i];
340  const Double_t y = g2->GetY()[i];
341 
342  g2->GetZ()[i] = fcn->Eval(x,y);
343  }
344  }
345  }
346 
347  {
348  TGraph2DErrors* g2 = dynamic_cast<TGraph2DErrors*>(p);
349 
350  if (g2 != NULL) {
351  for (Int_t i = 0; i != g2->GetN(); ++i) {
352  g2->SetPointError(i, 0.0, 0.0, 0.0);
353  }
354  }
355  }
356  }
357  }
358  }
359 
360  dir->Close();
361  }
362 
363  out.Write();
364  out.Close();
365 }
string outputFile
int main(int argc, char **argv)
Definition: JFit2D.cc:102
General purpose messaging.
#define DEBUG(A)
Message macros.
Definition: JMessage.hh:62
#define ERROR(A)
Definition: JMessage.hh:66
#define NOTICE(A)
Definition: JMessage.hh:64
#define FATAL(A)
Definition: JMessage.hh:67
int debug
debug level
Definition: JSirene.cc:69
#define WARNING(A)
Definition: JMessage.hh:65
static JMinimizer minimizer
ROOT minimizer.
Definition: JMinimizer.hh:80
Utility class to parse command line options.
#define make_field(A,...)
macro to convert parameter to JParserTemplateElement object
Definition: JParser.hh:2158
I/O formatting auxiliaries.
#define MAKE_CSTRING(A)
Make C-string.
Definition: JPrint.hh:136
Auxiliary class to define a range between two values.
Exception for parsing value.
Definition: JException.hh:198
Wrapper class around string.
Definition: JToken.hh:26
Utility class to parse command line options.
Definition: JParser.hh:1714
T getLowerLimit() const
Get lower limit.
Definition: JRange.hh:202
T getUpperLimit() const
Get upper limit.
Definition: JRange.hh:213
const double xmax
Definition: JQuadrature.cc:24
const double xmin
Definition: JQuadrature.cc:23
double getValue(const JScale_t scale)
Get numerical value corresponding to scale.
Definition: JScale.hh:47
int getParameter(const std::string &text)
Get parameter number from text string.
TDirectory * getDirectory(const JRootObjectID &id)
Get TDirectory pointer.
bool isTObject(const TKey *key)
Check if given key corresponds to a TObject.
JObject_t & for_each(JObject_t &object, JType< JTypeList< JHead_t, JTail_t > > typelist)
For each data type method.
Definition: JTypeList.hh:415
This name space includes all other name spaces (except KM3NETDAQ, KM3NET and ANTARES).
JRootfit_t< JF1_t > Fit(const TH1 &h1, const JF1_t &f1, const index_list &ls=index_list(), const range_type &X=range_type())
Global fit fuction.
Definition: JRootfit.hh:1247
int j
Definition: JPolint.hh:792
Definition: JSTDTypes.hh:14
Auxiliary data structure for floating point format specification.
Definition: JManip.hh:448
Type definition of range.
Definition: JHead.hh:43
Acoustic single fit.
JFit()
Default constructor.
Type list.
Definition: JTypeList.hh:23
Auxiliary class for a type holder.
Definition: JType.hh:19
Auxiliary data structure to define ROOT minimizer.
Definition: JMinimizer.hh:14
Empty structure for specification of parser element that is initialised (i.e. does not require input)...
Definition: JParser.hh:84
Auxiliary data structure for floating point format specification.
Definition: JManip.hh:488
Definition: JRoot.hh:19