Jpp
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
JHobbit.cc
Go to the documentation of this file.
1 #include <string>
2 #include <iostream>
3 #include <iomanip>
4 #include <vector>
5 #include <map>
6 
7 #include "TROOT.h"
8 #include "TFile.h"
9 #include "TH1D.h"
10 #include "TH2D.h"
11 #include "TF1.h"
12 #include "TMath.h"
13 #include "TFitResult.h"
14 
15 #include "JLang/JLangToolkit.hh"
16 #include "JSupport/JMeta.hh"
17 
18 #include "JDetector/JDetector.hh"
20 #include "JDetector/JTimeRange.hh"
21 
22 #include "Jeep/JPrint.hh"
23 #include "Jeep/JParser.hh"
24 #include "Jeep/JMessage.hh"
25 
26 namespace {
27 
28  /**
29  * Name of histogram with fit results from JCalibrateMuon.cc.
30  */
31  const char* h2_t = "h2";
32 
33  const char* gauss_t = "Gauss"; //!< Gaussian
34  const char* landau_t = "Landau"; //!< Landau
35  const char* emg_t = "EMG"; //!< Exponentially Modified Gaussian
36  const char* breitwigner_t = "BreitWigner"; //!< Breit-Wigner
37 }
38 
39 
40 /**
41  * \file
42  * Fit time-residuals histogram in output of JGandalf.cc in calibration mode.
43  * \author mdejong
44  */
45 int main(int argc, char **argv)
46 {
47  using namespace std;
48  using namespace JPP;
49 
50  vector<string> inputFile;
51  string outputFile;
52  string detectorFile;
53  bool overwriteDetector;
54  string function;
55  JTimeRange T_ns;
56  string option;
57  JTimeRange E_ns;
58  double WMin;
59  int debug;
60 
61  try {
62 
63  JParser<> zap("Program to fit time-residuals histogram in output of JCalibrateMuon.cc.");
64 
65  zap['f'] = make_field(inputFile, "input files (output from JCalibrateMuon).");
66  zap['o'] = make_field(outputFile, "output file.") = "hobbit.root";
67  zap['a'] = make_field(detectorFile, "detector file.");
68  zap['A'] = make_field(overwriteDetector, "overwrite detector file provided through '-a' with correct time offsets.");
69  zap['F'] = make_field(function, "fit function") = gauss_t, landau_t, emg_t, breitwigner_t;
70  zap['T'] = make_field(T_ns, "ROOT fit range around maximum [ns].") = JTimeRange(-7.5,+5.0);
71  zap['O'] = make_field(option, "ROOT fit option, see TH1::Fit.") = "";
72  zap['E'] = make_field(E_ns, "validity range of t0 uncertainty [ns].") = JTimeRange( 0.0, 0.3);
73  zap['W'] = make_field(WMin, "minimal histogram contents.") = 100.0;
74  zap['d'] = make_field(debug) = 1;
75 
76  zap(argc, argv);
77  }
78  catch(const exception &error) {
79  FATAL(error.what() << endl);
80  }
81 
82 
83  cout.tie(&cerr);
84 
85  if (!T_ns.is_valid()) {
86  FATAL("Invalid fit range [ns] " << T_ns << endl);
87  }
88 
90 
91  try {
92  load(detectorFile, detector);
93  }
94  catch(const JException& error) {
95  FATAL(error);
96  }
97 
98  if (option.find('S') == string::npos) { option += 'S'; }
99  if (option.find('Q') == string::npos && debug < JEEP::debug_t) { option += 'Q'; }
100 
101 
102  TH2D* h2 = NULL;
103 
104  for (vector<string>::const_iterator i = inputFile.begin(); i != inputFile.end(); ++i) {
105 
106  NOTICE("Processing " << *i << endl);
107 
108  TFile in(i->c_str(), "exist");
109 
110  if (!in.IsOpen()) {
111  FATAL("File " << *i << " not opened." << endl);
112  }
113 
114  TH2D* p = dynamic_cast<TH2D*>(in.Get(h2_t));
115 
116  if (p == NULL) {
117  FATAL("File " << *i << " has no histogram <" << h2_t << ">." << endl);
118  }
119 
120  if (h2 == NULL)
121  h2 = (TH2D*) p->Clone();
122  else
123  h2->Add(p);
124 
125  h2->SetDirectory(0);
126 
127  in.Close();
128  }
129 
130  if (h2 == NULL) {
131  FATAL("No histogram <" << h2_t << ">." << endl);
132  }
133 
134  // auxiliary data structure for fit result
135 
136  struct result_type {
137 
138  result_type() :
139  value(0.0),
140  error(0.0)
141  {}
142 
143  result_type(double value,
144  double error) :
145  value(value),
146  error(error)
147  {}
148 
149  double value;
150  double error;
151  };
152 
153  typedef map<int, result_type> map_type; // module index -> fit result
154 
155  map_type zmap;
156 
157 
158  // histogram fit results
159 
160  const TAxis* x_axis = h2->GetXaxis();
161  const TAxis* y_axis = h2->GetYaxis();
162 
163  TH1D h0("h0", NULL, x_axis->GetNbins(), -0.5, x_axis->GetNbins() - 0.5);
164  TH1D hc("hc", NULL, x_axis->GetNbins(), -0.5, x_axis->GetNbins() - 0.5);
165  TH1D hq("hq", NULL, x_axis->GetNbins(), -0.5, x_axis->GetNbins() - 0.5);
166 
167 
168  TFile out(outputFile.c_str(), "recreate");
169 
170  for (int ix = 1; ix <= x_axis->GetNbins(); ++ix) {
171 
172  TH1D h1(MAKE_CSTRING((detector.empty() ? ix : detector[ix - 1].getID()) << ".1D"), NULL, y_axis->GetNbins(), y_axis->GetXmin(), y_axis->GetXmax());
173 
174  // start values
175 
176  Double_t ymax = 0.0;
177  Double_t x0 = 0.0; // [ns]
178  Double_t sigma = 4.5; // [ns]
179  Double_t W = 0.0;
180 
181  for (int iy = 1; iy <= y_axis->GetNbins(); ++iy) {
182 
183  h1.SetBinContent(iy, h2->GetBinContent(ix,iy));
184  h1.SetBinError (iy, sqrt(h2->GetBinContent(ix,iy)));
185 
186  const Double_t x = h1.GetBinCenter (iy);
187  const Double_t y = h1.GetBinContent(iy);
188 
189  W += y;
190 
191  if (y > ymax) {
192  ymax = y;
193  x0 = x;
194  }
195  }
196 
197  if (W <= WMin) {
198 
199  WARNING("Not enough entries for slice " << ix << ' ' << W << "; skip fit." << endl);
200 
201  continue;
202  }
203 
204 
205  const Double_t xmin = x0 + T_ns.getLowerLimit();
206  const Double_t xmax = x0 + T_ns.getUpperLimit();
207 
208 
209  TF1* f1 = NULL;
210 
211  if (function == gauss_t) {
212 
213  f1 = new TF1(function.c_str(), "[0]*TMath::Gaus(x,[1],[2])");
214 
215  f1->SetParameter(0, ymax);
216  f1->SetParameter(1, x0);
217  f1->SetParameter(2, sigma);
218 
219  } else if (function == landau_t) {
220 
221  f1 = new TF1(function.c_str(), "[0]*TMath::Landau(x,[1],[2])");
222 
223  f1->SetParameter(0, ymax);
224  f1->SetParameter(1, x0);
225  f1->SetParameter(2, sigma);
226 
227  } else if (function == emg_t) {
228 
229  f1 = new TF1(function.c_str(), "[0]*TMath::Exp(0.5*[3]*(2.0*[1]+[3]*[2]*[2]-2.0*x))*TMath::Erfc(([1]+[3]*[2]*[2]-x)/(TMath::Sqrt(2.0)*[2]))");
230 
231  f1->SetParameter(0, ymax);
232  f1->SetParameter(1, x0 - sigma);
233  f1->SetParameter(2, sigma);
234  f1->SetParameter(3, 0.04);
235 
236  } else if (function == breitwigner_t) {
237 
238  f1 = new TF1(function.c_str(), "(x <= [1])*[0]*[2]*TMath::BreitWigner(x,[1],[2])+(x > [1])*[0]*[3]*TMath::BreitWigner(x,[1],[3])");
239 
240  f1->SetParameter(0, ymax);
241  f1->SetParameter(1, x0);
242  f1->SetParameter(2, 15.0);
243  f1->SetParameter(3, 25.0);
244 
245  } else {
246 
247  FATAL("Unknown fit function " << function << endl);
248  }
249 
250 
251  DEBUG("Start values:" << endl);
252 
253  for (int i = 0; i != f1->GetNpar(); ++i) {
254  DEBUG(left << setw(12) << f1->GetParName (i) << ' ' <<
255  SCIENTIFIC(12,5) << f1->GetParameter(i) << endl);
256  }
257 
258  // fit
259 
260  TFitResultPtr result = h1.Fit(f1, option.c_str(), "same", xmin, xmax);
261 
262  if (debug >= notice_t || !result->IsValid()) {
263  cout << "Slice: "
264  << setw(4) << ix << ' '
265  << setw(16) << h1.GetName() << ' '
266  << FIXED(7,3) << f1->GetParameter(1) << " +/- "
267  << FIXED(7,3) << f1->GetParError(1) << ' '
268  << FIXED(7,3) << result->Chi2() << '/'
269  << result->Ndf() << ' '
270  << (result->IsValid() ? "" : "failed") << endl;
271  }
272 
273  if (result->IsValid()) {
274  zmap[ix] = result_type(f1->GetParameter(1), f1->GetParError (1));
275  }
276 
277  if (result->Ndf() > 0) {
278  hc.SetBinContent(ix, result->Chi2() / result->Ndf());
279  }
280  hq.SetBinContent(ix, result->IsValid() ? 1.0 : 0.0);
281 
282  h1.Write();
283 
284  delete f1;
285  }
286 
287 
288  if (!zmap.empty()) {
289 
290  // average time offset
291 
292  double t0 = 0.0;
293 
294  for (map_type::const_iterator i = zmap.begin(); i != zmap.end(); ++i) {
295  t0 += i->second.value;
296  }
297 
298  t0 /= zmap.size();
299 
300  NOTICE("Average time offset [ns] " << FIXED(7,2) << t0 << endl);
301 
302  for (map_type::iterator i = zmap.begin(); i != zmap.end(); ++i) {
303  i->second.value -= t0;
304  }
305 
306  for (map_type::const_iterator i = zmap.begin(); i != zmap.end(); ++i) {
307  h0.SetBinContent(i->first, i->second.value);
308  h0.SetBinError (i->first, i->second.error);
309  }
310 
311  if (!detector.empty()) {
312 
313  const JRange<int> string(detector.begin(), detector.end(), &JModule::getString);
314  const JRange<int> floor (detector.begin(), detector.end(), &JModule::getFloor);
315 
316  TH2D hi("hi", NULL,
317  string.getLength() + 1,
318  string.getLowerLimit() - 0.5,
319  string.getUpperLimit() + 0.5,
320  floor.getLength() + 1,
321  floor.getLowerLimit() - 0.5,
322  floor.getUpperLimit() + 0.5);
323 
324  for (map_type::const_iterator i = zmap.begin(); i != zmap.end(); ++i) {
325  hi.SetBinContent(detector[i->first - 1].getString(),
326  detector[i->first - 1].getFloor(),
327  i->second.value);
328  }
329 
330  hi.Write();
331  }
332 
333 
334  if (overwriteDetector) {
335 
336  NOTICE("Store calibration data on file " << detectorFile << endl);
337 
338  detector.comment.add(JMeta(argc, argv));
339 
340  for (map_type::const_iterator i = zmap.begin(); i != zmap.end(); ++i) {
341 
342  if (E_ns(i->second.error))
343  detector[i->first - 1].sub(i->second.value);
344  else
345  ERROR("Slice " << setw(4) << i->first << " fit uncertainty " << FIXED(5,2) << i->second.error << " outside specified range (option -E <E_ns>)" << endl);
346  }
347 
348  store(detectorFile, detector);
349  }
350 
351  } else {
352 
353  NOTICE("No calibration results." << endl);
354  }
355 
356  h0 .Write();
357  hc .Write();
358  hq .Write();
359  h2->Write();
360 
361  out.Close();
362 }
Auxiliary class for ROOT I/O of application specific meta data.
Definition: JMeta.hh:71
Utility class to parse command line options.
Definition: JParser.hh:1493
General exception.
Definition: JException.hh:23
#define WARNING(A)
Definition: JMessage.hh:65
debug
Definition: JMessage.hh:29
Detector data structure.
Definition: JDetector.hh:80
esac print_variable DETECTOR INPUT_FILE OUTPUT_FILE CDF for TYPE in
Definition: JSirene.sh:45
notice
Definition: JMessage.hh:32
#define MAKE_CSTRING(A)
Make C-string.
Definition: JPrint.hh:708
then for HISTOGRAM in h0 h1
Definition: JMatrixNZ.sh:69
Auxiliary data structure for floating point format specification.
Definition: JPrint.hh:481
string outputFile
Data structure for detector geometry and calibration.
JRange< double > JTimeRange
Type definition for time range.
I/O formatting auxiliaries.
Detector file.
Definition: JHead.hh:130
#define make_field(A,...)
macro to convert parameter to JParserTemplateElement object
Definition: JParser.hh:1954
return result
Definition: JPolint.hh:695
ROOT I/O of application specific meta data.
#define NOTICE(A)
Definition: JMessage.hh:64
#define ERROR(A)
Definition: JMessage.hh:66
void load(const JString &file_name, JDetector &detector)
Load detector from input file.
int debug
debug level
Definition: JSirene.cc:61
General purpose messaging.
#define FATAL(A)
Definition: JMessage.hh:67
Utility class to parse command line options.
void store(const JString &file_name, const JDetector &detector)
Store detector to output file.
Auxiliary data structure for floating point format specification.
Definition: JPrint.hh:518
#define DEBUG(A)
Message macros.
Definition: JMessage.hh:62
int main(int argc, char *argv[])
Definition: Main.cpp:15