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