Jpp test-rotations-new
the software that should make you happy
Loading...
Searching...
No Matches
JFit.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 "TH1.h"
12#include "TGraph.h"
13#include "TProfile.h"
14#include "TF1.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
28
29#include "Jeep/JPrint.hh"
30#include "Jeep/JParser.hh"
31#include "Jeep/JMessage.hh"
32
33
34namespace {
35
36 using namespace JPP;
37
38 /**
39 * Auxiliary class for ROOT fit.
40 */
41 struct JFit {
42 /**
43 * Constructor.
44 *
45 * \param object object
46 * \param fcn fcn
47 * \param option option
48 */
49 JFit(TObject& object,
50 TF1* fcn,
51 const std::string& option) :
52 object(object),
53 fcn (fcn),
54 option(option)
55 {}
56
57
58 /**
59 * Attempt fit for given data type.
60 *
61 * \param type data type
62 */
63 template<class T>
64 void operator()(const JType<T>& type)
65 {
66 try {
67 result = dynamic_cast<T&>(object).Fit(fcn, option.c_str(), "same");
68 }
69 catch(const std::exception&) {}
70 }
71
72 TObject& object;
73 TF1* fcn;
74 std::string option;
75 TFitResultPtr result;
76 };
77}
78
79
80/**
81 * \file
82 * General purpose fit program for 1D ROOT objects.\n
83 * The option <tt>-f</tt> corresponds to <tt><file name>:<object name></tt>.
84 *
85 * The expressions for the fit function, start and fixed values should comply
86 * with ROOT class TFormula.
87 *
88 * In the expressions of the start and fixed values, names of member methods
89 * of corresponding class of the fit object may appear,
90 * such as TH1::GetMaximum, TH1::GetRMS, etc., e.g:
91 * <pre>
92 * -F "[0]*exp(x/[1])+[2]"
93 * -@ "p0 = GetMaximum; p1 = 2*GetRMS"
94 * -= "p2 = 0"
95 * </pre>
96 * The result of the formulas for the start and fixed values will be evaluated
97 * for each histogram separately.
98 * \author mdejong
99 */
100int main(int argc, char **argv)
101{
102 using namespace std;
103 using namespace JPP;
104
105 typedef JToken<';'> JToken_t;
106 typedef JRange<double> JRange_t;
107
108 vector<JRootObjectID> inputFile;
109 string outputFile;
110 string formula;
111 vector<JToken_t> startValues;
112 vector<JToken_t> startErrors;
113 vector<JToken_t> fixedValues;
114 vector<JToken_t> limitValues;
115 JRange_t X;
116 JRange_t Y;
117 char project;
118 string option;
119 int debug;
120
121 try {
122
123 JParser<> zap("General purpose fit program for 1D ROOT objects.");
124
125 zap['f'] = make_field(inputFile, "<input file>:<object name>");
126 zap['o'] = make_field(outputFile, "ROOT file with fit results") = "fit.root";
127 zap['F'] = make_field(formula, "fit formula, e.g: \"[0]+[1]*x\"");
128 zap['@'] = make_field(startValues, "start values, e.g: \"p0 = GetMaximum;\"");
129 zap['E'] = make_field(startErrors, "start errors, e.g: \"p0 = 0.01 * GetMaximum;\"") = JPARSER::initialised();
130 zap['='] = make_field(fixedValues, "fixed values, e.g: \"p0 = GetMaximum;\"") = JPARSER::initialised();
131 zap['R'] = make_field(limitValues, "limit values, e.g: \"p0 = <lower limit> <upper limit>;\"") = JPARSER::initialised();
132 zap['x'] = make_field(X, "abscissa range") = JRange_t();
133 zap['y'] = make_field(Y, "ordinate range") = JRange_t();
134 zap['P'] = make_field(project, "projection") = '\0', 'x', 'X', 'y', 'Y';
135 zap['O'] = make_field(option, "Fit option") = "";
136 zap['M'] = make_field(minimizer, "ROOT minimizer type and algorithm [debug]") = JMinimizer();
137 zap['d'] = make_field(debug) = 1;
138
139 zap(argc, argv);
140 }
141 catch(const exception &error) {
142 FATAL(error.what() << endl);
143 }
144
145
146 if (option.find('O') == string::npos) { option += "O"; }
147 if (option.find("R") == string::npos) { option += "R"; }
148 if (option.find("S") == string::npos) { option += "S"; }
149 //if (option.find('N') == string::npos) { option += "N"; }
150 if (debug == 0 && option.find('Q') == string::npos) { option += "Q"; }
151
152 bool px = (project == 'x' || project == 'X'); // projection on x-axis
153 bool py = (project == 'y' || project == 'Y'); // projection on y-axis
154
155 if (py) {
156 swap(Y, X); // Y becomes x-axis range and X becomes y-axis range
157 }
158
159
160 TFile out(outputFile.c_str(), "recreate");
161
162
163 TF1* fcn = new TF1("user", formula.c_str());
164
165 fcn->SetNpx(1000);
166
167 if (fcn->IsZombie()) {
168 FATAL("Function: " << formula << " is zombie." << endl);
169 }
170
171 for (vector<JRootObjectID>::const_iterator input = inputFile.begin(); input != inputFile.end(); ++input) {
172
173 DEBUG("Input: " << *input << endl);
174
175 TDirectory* dir = getDirectory(*input);
176
177 if (dir == NULL) {
178 ERROR("File: " << input->getFullFilename() << " not opened." << endl);
179 continue;
180 }
181
182 const TRegexp regexp(input->getObjectName());
183
184 TIter iter(dir->GetListOfKeys());
185
186 for (TKey* key; (key = (TKey*) iter.Next()) != NULL; ) {
187
188 const TString tag(key->GetName());
189
190 DEBUG("Key: " << tag << " match = " << tag.Contains(regexp) << endl);
191
192 // option match
193
194 if (tag.Contains(regexp) && isTObject(key)) {
195
196 TObject* object = key->ReadObj();
197
198 try {
199
200 TProfile& h1 = dynamic_cast<TProfile&>(*object);
201
202 object = h1.ProjectionX();
203 }
204 catch(exception&) {}
205
206 try {
207
208 TH2& h2 = dynamic_cast<TH2&>(*object);
209
210 if (px) {
211
212 object = h2.ProjectionX("_px",
213 h2.GetYaxis()->FindBin(Y.getLowerLimit()),
214 h2.GetYaxis()->FindBin(Y.getUpperLimit()));
215
216 } else if (py) {
217
218 object = h2.ProjectionY("_py",
219 h2.GetXaxis()->FindBin(Y.getLowerLimit()),
220 h2.GetXaxis()->FindBin(Y.getUpperLimit()));
221
222 } else {
223
224 ERROR("For 2D histograms, use option option -P for projections." << endl);
225
226 continue;
227 }
228 }
229 catch(exception&) {}
230
231
232 // set fit parameters
233
234 try {
235
236 for (vector<JToken_t>::const_iterator i = startValues.begin(); i != startValues.end(); ++i) {
237 fcn->SetParameter(getParameter(*i), getValue(*i,object));
238 }
239
240 for (Int_t i = 0; i != fcn->GetNpar(); ++i) {
241 fcn->SetParError (i, 0.0);
242 }
243
244 for (vector<JToken_t>::const_iterator i = startErrors.begin(); i != startErrors.end(); ++i) {
245 fcn->SetParError (getParameter(*i), getValue(*i,object));
246 }
247
248 for (vector<JToken_t>::const_iterator i = fixedValues.begin(); i != fixedValues.end(); ++i) {
249 fcn->FixParameter(getParameter(*i), getValue(*i,object));
250 }
251
252 for (vector<JToken_t>::const_iterator i = limitValues.begin(); i != limitValues.end(); ++i) {
253 fcn->SetParLimits(getParameter(*i), getValue(*i,0), getValue(*i,1));
254 }
255 }
256 catch(JLANG::JParseError& error) {
257 FATAL(error << endl);
258 }
259
260 DEBUG("Start values " << object->GetName() << endl);
261
262 for (int j = 0; j != fcn->GetNpar(); ++j) {
263 DEBUG(left << setw(12) << fcn->GetParName (j) << ' ' <<
264 SCIENTIFIC(12,5) << fcn->GetParameter(j) << endl);
265 }
266
267 Double_t xmin = numeric_limits<Double_t>::max();
268 Double_t xmax = numeric_limits<Double_t>::lowest();
269
270 {
271 TH1* h1 = dynamic_cast<TH1*>(object);
272
273 if (h1 != NULL) {
274 xmin = min(xmin, h1->GetXaxis()->GetXmin());
275 xmax = max(xmax, h1->GetXaxis()->GetXmax());
276 }
277 }
278
279 {
280 TGraph* g1 = dynamic_cast<TGraph*>(object);
281
282 if (g1 != NULL) {
283 for (Int_t i = 0; i != g1->GetN(); ++i) {
284 xmin = min(xmin, g1->GetX()[i]);
285 xmax = max(xmax, g1->GetX()[i]);
286 }
287 }
288 }
289
290 if (X != JRange_t()) {
291 xmin = X.getLowerLimit();
292 xmax = X.getUpperLimit();
293 }
294
295 fcn->SetRange(xmin, xmax);
296
297
298 // execute fit
299
300 const chrono::steady_clock::time_point t0 = chrono::steady_clock::now();
301
302 JFit fit(*object, fcn, option);
303
305
306 const chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
307
308 if (fit.result != -1) {
309
310 // output fit results
311
312 NOTICE("Fit values " << object->GetName() << endl);
313 NOTICE("Fit formula " << formula << endl);
314 NOTICE("chi2/NDF " << FIXED(7,3) << fit.result->Chi2() << '/' << fit.result->Ndf() << ' ' << (fit.result->IsValid() ? "" : "failed") << endl);
315 NOTICE("Number of calls " << fit.result->NCalls() << endl);
316 NOTICE("Elapsed time [us] " << setw(8) << chrono::duration_cast<chrono::microseconds>(t1 - t0).count() << endl);
317
318 for (int j = 0; j != fcn->GetNpar(); ++j) {
319 NOTICE(left << setw(12) << fcn->GetParName (j) << ' ' <<
320 SCIENTIFIC(12,5) << fcn->GetParameter(j) << " +/- " <<
321 SCIENTIFIC(12,5) << fcn->GetParError (j) << endl);
322 }
323
324 } else {
325
326 WARNING("Object: not compatible with ROOT Fit." << endl);
327 }
328
329 out.cd();
330
331 object->Write();
332 }
333 }
334
335 dir->Close();
336 }
337
338 out.Write();
339 out.Close();
340}
string outputFile
int main(int argc, char **argv)
Definition JFit.cc:100
General purpose messaging.
#define DEBUG(A)
Message macros.
Definition JMessage.hh:62
#define NOTICE(A)
Definition JMessage.hh:64
#define FATAL(A)
Definition JMessage.hh:67
int debug
debug level
Definition JSirene.cc:72
#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:2142
I/O formatting auxiliaries.
Double_t g1(const Double_t x)
Function.
Definition JQuantiles.cc:25
Auxiliary class to define a range between two values.
Exception for parsing value.
Wrapper class around string.
Definition JToken.hh:26
Utility class to parse command line options.
Definition JParser.hh:1698
Range of values.
Definition JRange.hh:42
T getLowerLimit() const
Get lower limit.
Definition JRange.hh:202
T getUpperLimit() const
Get upper limit.
Definition JRange.hh:213
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.
void for_each(JObject_t &object, JType< JTypeList< JHead_t, JTail_t > > typelist)
For each data type method.
Definition JTypeList.hh:414
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
return result
Definition JPolint.hh:862
int j
Definition JPolint.hh:801
Auxiliary data structure for floating point format specification.
Definition JManip.hh:448
Type definition of range.
Definition JHead.hh:43
Acoustic single fit.
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:68
Auxiliary data structure for floating point format specification.
Definition JManip.hh:488