103{
106
107 typedef JToken<
';'> JToken_t;
109
112 string formula;
119 string option;
120 bool writeFits;
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>");
129 zap[
'F'] =
make_field(formula,
"fit formula, e.g: \"[0]+[1]*x\"");
130 zap[
'@'] =
make_field(startValues,
"start values, e.g: \"p0 = GetMaximum;\"");
136 zap[
'O'] =
make_field(option,
"Fit option") =
"";
137 zap[
'w'] =
make_field(writeFits,
"write fit function(s) to ROOT file " <<
"(\"<name>" << _F2 <<
"\")");
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
152 if (
debug == 0 && option.find(
'Q') == string::npos) { option +=
"Q"; }
153
154
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
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
189
190 if (tag.Contains(regexp) &&
isTObject(key)) {
191
193
194
195
196
197 try {
198
199 for (vector<JToken_t>::const_iterator i = startValues.begin(); i != startValues.end(); ++i) {
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) {
209 }
210
211 for (vector<JToken_t>::const_iterator i = fixedValues.begin(); i != fixedValues.end(); ++i) {
213 }
214
215 for (vector<JToken_t>::const_iterator i = limitValues.begin(); i != limitValues.end(); ++i) {
217 }
218 }
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
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
266 }
267
271 }
272
273 fcn->SetRange(xmin, ymin, xmax, ymax);
274
275
276
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
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) <<
" +/- " <<
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
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}
#define DEBUG(A)
Message macros.
static JMinimizer minimizer
ROOT minimizer.
#define make_field(A,...)
macro to convert parameter to JParserTemplateElement object
#define MAKE_CSTRING(A)
Make C-string.
Exception for parsing value.
Wrapper class around string.
Utility class to parse command line options.
double getValue(const JScale_t scale)
Get numerical value corresponding to scale.
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.
This name space includes all other name spaces (except KM3NETDAQ, KM3NET and ANTARES).
Auxiliary data structure for floating point format specification.
Type definition of range.
Auxiliary class for a type holder.
Auxiliary data structure to define ROOT minimizer.
Empty structure for specification of parser element that is initialised (i.e. does not require input)...
Auxiliary data structure for floating point format specification.