Jpp
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
JDomino.cc
Go to the documentation of this file.
1 
2 #include <string>
3 #include <iostream>
4 #include <iomanip>
5 #include <map>
6 #include <sstream>
7 
8 #include "TROOT.h"
9 #include "TFile.h"
10 #include "TH1D.h"
11 #include "TH2D.h"
12 #include "TProfile.h"
13 
14 #include "evt/Head.hh"
15 #include "evt/Evt.hh"
16 
17 #include "JAAnet/JHead.hh"
18 #include "JAAnet/JHeadToolkit.hh"
19 #include "JAAnet/JAAnetToolkit.hh"
20 
21 #include "JDetector/JDetector.hh"
23 #include "JDetector/JPMTRouter.hh"
25 
28 #include "JSupport/JSupport.hh"
29 
30 #include "JGizmo/JManager.hh"
31 #include "JGizmo/JGizmoToolkit.hh"
32 #include "JTools/JWeight.hh"
33 #include "JROOT/JRootToolkit.hh"
34 #include "JPhysics/JPDFToolkit.hh"
35 
36 #include "JLang/JException.hh"
37 #include "JLang/JPredicate.hh"
38 #include "JLang/JLangToolkit.hh"
39 
40 #include "Jeep/JPrint.hh"
41 #include "Jeep/JParser.hh"
42 #include "Jeep/JMessage.hh"
43 
44 
45 namespace {
46 
47  /**
48  * Get weight for hits from muon.
49  *
50  * \param E muon energy [GeV]
51  * \param npe number of photo-electrons
52  * \return weight
53  */
54  inline double getMuonWeight(const double E,
55  const double npe)
56  {
57  using namespace JPP;
58 
59  return npe / (1.0 + gWater.getB() * E * geanc());
60  }
61 
62 
63  /**
64  * Get weight for hits from muon.
65  *
66  * \param E muon energy [GeV]
67  * \param R minimal distance of approach [m]
68  * \param npe number of photo-electrons
69  * \return weight
70  */
71  inline double getMuonWeight(const double E,
72  const double R,
73  const double npe)
74  {
75  using namespace JPP;
76 
77  static const double l_att = 45.0 * getSinThetaC(); // [m]
78 
79  return R * exp(+R/l_att) * getMuonWeight(E, npe);
80  }
81 
82 
83  /**
84  * Get weight for hits from vertex.
85  *
86  * \param E neutrino energy [GeV]
87  * \param npe number of photo-electrons
88  * \return weight
89  */
90  inline double getNeutrinoWeight(const double E,
91  const double npe)
92  {
93  return npe / E;
94  }
95 
96 
97  /**
98  * Get weight for hits from vertex.
99  *
100  * \param E neutrino energy [GeV]
101  * \param D distance [m]
102  * \param npe number of photo-electrons
103  * \return weight
104  */
105  inline double getNeutrinoWeight(const double E,
106  const double D,
107  const double npe)
108  {
109  static const double l_att = 45.0; // [m]
110 
111  return D*D * exp(+D/l_att) * getNeutrinoWeight(E, npe);
112  }
113 
114 
115  /**
116  * Function that returns true if second element of first pair is larger than second element of second pair.
117  *
118  * Implemented to provide sort functionality for function `makeSortedH1`
119  *
120  * \param first first instance of a pair
121  * \param second second instance of a pair
122  * \return first.second > second.second
123  */
124  inline bool compare(std::pair<Double_t, Double_t> const& first, std::pair<Int_t, Double_t> const& second)
125  {
126  return first.second > second.second;
127  }
128 
129 
130  /**
131  * Function to sort input histogram in order of decreasing bin contents.
132  *
133  * \param in pointer to input histogram
134  * \param name name of sorted histogram
135  * \return pointer to sorted histogram
136  */
137  inline TH1D* makeSortedH1(TH1D* in, const TString& name)
138  {
139  using namespace std;
140  using namespace JPP;
141 
142  // read bin contents to a vector
143 
145 
146  for (Int_t ix = 1; ix <= in->GetXaxis()->GetNbins(); ++ix) {
147 
148  const Int_t x = (Int_t) in->GetXaxis()->GetBinCenter(ix);
149  const Double_t y = in->GetBinContent(ix);
150 
151  if (y > 0.0) {
152  data.push_back(make_pair(x, y));
153  }
154  }
155 
156  // sort
157 
158  sort(data.begin(), data.end(), compare);
159 
160  // create a histogram
161 
162  TH1D* out = new TH1D(name, NULL, data.size(), -0.5, data.size() - 0.5);
163 
164  for (Int_t i = 0; i < (Int_t) data.size(); i++) {
165 
166  const Int_t ix = i + 1;
167 
168  out->GetXaxis()->SetBinLabel(ix, MAKE_CSTRING(fixed << setprecision(0) << data[i].first));
169  out->SetBinContent(ix, data[i].second);
170  }
171 
172  return out;
173  }
174 }
175 
176 
177 /**
178  * \file
179  *
180  * Example program to verify Monte Carlo data.
181  * \author mdejong
182  */
183 int main(int argc, char **argv)
184 {
185  using namespace std;
186  using namespace JPP;
187 
188  //-------------------------------------------------------------------------
189  // command-line arguments
190  //-------------------------------------------------------------------------
191 
192  JMultipleFileScanner<Evt> inputFile;
193  JLimit_t& numberOfEvents = inputFile.getLimit();
194  string outputFile;
195  string detectorFile;
196  set<int> hit_types;
197  int debug;
198 
199  try {
200 
201  JParser<> zap("Example program to verify Monte Carlo data.");
202 
203  zap['f'] = make_field(inputFile);
204  zap['n'] = make_field(numberOfEvents) = JLimit::max();
205  zap['o'] = make_field(outputFile) = "domino.root";
206  zap['a'] = make_field(detectorFile) = "";
207  zap['T'] = make_field(hit_types) = JPARSER::initialised();
208  zap['d'] = make_field(debug) = 2;
209 
210  zap(argc, argv);
211  }
212  catch(const exception &error) {
213  FATAL(error.what() << endl);
214  }
215 
216  cout.tie(&cerr);
217 
218 
219  //-------------------------------------------------------------------------
220  // load detector file
221  //-------------------------------------------------------------------------
222 
223  JDetector detector;
224 
225  if (detectorFile != "") {
226 
227  try {
228  load(detectorFile, detector);
229  }
230  catch(const JException& error) {
231  FATAL(error);
232  }
233  }
234 
235  const JPMTRouter router(detector);
236 
237  const JHead header = getHeader(inputFile);
238 
239 
240  //-------------------------------------------------------------------------
241  // try to determine coordinate origin
242  //-------------------------------------------------------------------------
243 
244  JPosition3D center = get<JPosition3D>(header);
245 
246  NOTICE("Apply detector offset " << center << endl);
247 
248  detector -= center;
249 
250 
251  //-------------------------------------------------------------------------
252  // calculate instrumented volume
253  //-------------------------------------------------------------------------
254 
255  JCylinder3D inst_vol(detector.begin(), detector.end());
256 
257  NOTICE("JDomino: Instrumented volume dimensions (x, y, r, zmin, zmax): " << inst_vol << endl);
258 
259 
260  //-------------------------------------------------------------------------
261  // histogram binning
262  //-------------------------------------------------------------------------
263 
264  typedef map<int, JWeight> map_type;
265 
266  const double xmin = log10(header.cut_nu.Emin);
267  const double xmax = log10(header.cut_nu.Emax);
268  const int nx = (int) ((xmax - xmin) / 0.1);
269 
270  const Double_t T[] = { -50.0, -20.0, -10.0, -5.0, -2.0, 0.0, +2.0, +5.0, +10.0, +15.0, +20.0, +30.0, +40.0, +50.0,
271  +75.0, +100.0, +150.0, +200.0, +250.0, +300.0, +400.0, +500.0, 1000.0 }; // [ns]
272 
273  //-------------------------------------------------------------------------
274  // histograms for events
275  //-------------------------------------------------------------------------
276 
277  TH1D hits("hits", NULL, 100, 0.0, 8.0); // number of mc_hits per event
278  TH1D trks("trks", NULL, 10001, -5000.5, 5000.5); // number of track_in type's per event
279  TH1D job ("job" , NULL, 10001, -5000.5, 5000.5); // number of photo-electrons by track_in type
280 
281  TProfile hits_per_E_in ("hits_per_E_in", "average number of hits per E_{#nu} inside instrumented volume", nx, xmin, xmax);
282  TProfile hits_per_E_out("hits_per_E_out", "average number of hits per E_{#nu} outside instrumented volume", nx, xmin, xmax);
283 
284  typedef JManager<int, TH1D> JManager_t;
285 
286  JManager_t npe_per_type(new TH1D("npe[%]", NULL, 5000, 0.5, 5000.5), '%', ios::fmtflags(ios::showpos));
287 
288  TH1D npe_per_pmt ("pmt", NULL, 100001, -0.5, 100000.5); // number of photo-electrons per PMT
289 
290 
291  //-------------------------------------------------------------------------
292  // histograms for neutrino
293  //-------------------------------------------------------------------------
294 
295  TH2D nuExD("nuExD", NULL, nx, xmin, xmax, 100, 0.0, 1000.0); // Enu versus distance between vertex and PMT
296  TH2D* nuExD_tmp = (TH2D*) nuExD.Clone("nuExD.tmp"); // normalisation
297 
298  TH2D nuExc("nuExc", NULL, nx, xmin, xmax, 100, -1.0, +1.0); // Enu versus emission angle
299  TH2D* nuExc_tmp = (TH2D*) nuExc.Clone("nuExc.tmp"); // normalisation
300 
301  TH2D nuDxc("nuDxc", NULL, 50, 0.0, 1000.0, 100, -1.0, +1.0); // distance between vertex and PMT versus emission angle
302  TH2D* nuDxc_tmp = (TH2D*) nuDxc.Clone("nuDxc.tmp"); // normalisation
303 
304  TH2D nuDxU("nuDxU", NULL, 50, 0.0, 1000.0, 100, -1.0, +1.0); // distance between vertex and PMT versus incidence angle
305  TH2D* nuDxU_tmp = (TH2D*) nuDxU.Clone("nuDxU.tmp"); // normalisation
306 
307  TH2D nuDxT("nuDxT", NULL, 50, 0.0, 1000.0, getSize(T) - 1, T); // distance between vertex and PMT versus time residual
308  TH2D* nuDxT_tmp = (TH2D*) nuDxT.Clone("nuDxT.tmp"); // normalisation
309 
310  nuExD.Sumw2();
311  nuExc.Sumw2();
312  nuDxc.Sumw2();
313  nuDxU.Sumw2();
314  nuDxT.Sumw2();
315 
316 
317  //-------------------------------------------------------------------------
318  // histograms for muon
319  //-------------------------------------------------------------------------
320 
321  TH2D muExR("muExR", NULL, nx, xmin, xmax, 30, 0.0, 300.0); // Emu versus distance between muon and PMT
322  TH2D* muExR_tmp = (TH2D*) muExR.Clone("muExR.tmp"); // normalisation
323 
324  TH2D muRxU("muRxU", NULL, 15, 0.0, 300.0, 100, -1.0, +1.0); // distance between muon and PMT versus incidence angle
325  TH2D* muRxU_tmp = (TH2D*) muRxU.Clone("muRxU.tmp"); // normalisation
326 
327  TH2D muRxT("muRxT", NULL, 15, 0.0, 300.0, getSize(T) - 1, T); // distance between muon and PMT versus time residual
328  TH2D* muRxT_tmp = (TH2D*) muRxT.Clone("muRxT.tmp"); // normalisation
329 
330  muExR.Sumw2();
331  muRxU.Sumw2();
332  muRxT.Sumw2();
333 
334 
335  //-------------------------------------------------------------------------
336  // loop over events
337  //-------------------------------------------------------------------------
338 
339  while (inputFile.hasNext()) {
340 
341  STATUS("event: " << setw(10) << inputFile.getCounter() << '\r'); DEBUG(endl);
342 
343  const Evt* event = inputFile.next();
344 
345  double NPE = 0.0;
346 
347  for (vector<Hit>::const_iterator hit = event->mc_hits.begin(); hit != event->mc_hits.end(); ++hit) {
348  NPE += hit->pure_a;
349  }
350 
351  hits.Fill(log10((Double_t) event->mc_hits.size()));
352 
353  for (vector<Trk>::const_iterator track = event->mc_trks.begin(); track != event->mc_trks.end(); ++track) {
354  trks.Fill(track->type);
355  }
356 
357  JTrack3E neutrino;
358 
359  if (has_neutrino(*event)) {
360  neutrino = getTrack(get_neutrino(*event));
361  }
362 
363  const JVertex3D vertex = neutrino.getVertex();
364 
365  map_type npe_pmt; // temporary buffer to accumulate total npe's by individual PMTs
366  map_type npe_type; // temporary buffer to accumulate total npe's by hit origin track
367 
368 
369  //-------------------------------------------------------------------------
370  // loop over hits
371  //-------------------------------------------------------------------------
372 
373  for (vector<Hit>::const_iterator hit = event->mc_hits.begin(); hit != event->mc_hits.end(); ++hit) {
374 
375  const int type = hit->type;
376  const double t1 = hit->pure_t;
377  const double npe = hit->pure_a;
378 
379  npe_pmt[hit->pmt_id].put(npe);
380 
381  npe_type[0] .put(npe);
382  npe_type[type].put(npe);
383 
384  if (hit_types.empty() || hit_types.count(type) != 0) {
385 
386  vector<Trk>::const_iterator track = find_if(event->mc_trks.begin(),
387  event->mc_trks.end(),
388  make_predicate(&Trk::id, hit->origin));
389 
390  if (track == event->mc_trks.end()) {
391  ERROR("Hit " << *hit << " has no origin." << endl);
392  continue;
393  }
394 
395  if (count_if(event->mc_trks.begin(),
396  event->mc_trks.end(),
397  make_predicate(&Trk::id, hit->origin)) > 1) {
398  ERROR("Hit " << *hit << " has ambiguous origin." << endl);
399  continue;
400  }
401 
402  job.Fill((double) track->type, npe);
403 
404  if (router.hasPMT(hit->pmt_id)) {
405 
406  const JPMT& pmt = router.getPMT(hit->pmt_id);
407 
408  if (is_muon(*track)) {
409 
410  const JTrack3E muon = getTrack(*track);
411 
412  const double E = muon.getE();
413  const double x = log10(E);
414  const double R = muon.getDistance(pmt);
415  const double t0 = muon.getT (pmt);
416  const double ct1 = muon.getDot (pmt);
417 
418  muExR.Fill(x, R, getMuonWeight(E, npe));
419  muRxU.Fill(R, ct1, getMuonWeight(E, R, npe));
420  muRxT.Fill(R, t1 - t0, getMuonWeight(E, R, npe));
421 
422  } else if (has_neutrino(*event)) {
423 
424  const double E = neutrino.getE();
425  const double x = log10(E);
426  const double D = vertex.getDistance(pmt);
427  const double t0 = vertex.getT(pmt);
428  const double ct0 = neutrino.getDot(pmt.getPosition());
429  const double ct1 = vertex.getDot(pmt);
430 
431  nuExD.Fill(x, D, getNeutrinoWeight(E, npe));
432  nuExc.Fill(x, ct0, getNeutrinoWeight(E, npe));
433  nuDxc.Fill(D, ct0, getNeutrinoWeight(E, D, npe));
434  nuDxU.Fill(D, ct1, getNeutrinoWeight(E, D, npe));
435  nuDxT.Fill(D, t1 - t0, getNeutrinoWeight(E, D, npe));
436  }
437  }
438  } // end if PMT of hit found in PMT router
439  } // end loop over hits
440 
441 
442  //-------------------------------------------------------------------------
443  // continue with logic for event, fill histograms common to all input files
444  //-------------------------------------------------------------------------
445 
446  for (map_type::const_iterator i = npe_pmt.begin(); i != npe_pmt.end(); ++i) {
447  npe_per_pmt.Fill(i->second.getTotal()); // npe / PMT
448  }
449 
450  for (map_type::const_iterator i = npe_type.begin(); i != npe_type.end(); ++i) {
451  npe_per_type[i->first]->Fill(i->second.getTotal()); // npe / type
452  }
453 
454 
455  //-------------------------------------------------------------------------
456  // normalisation of muon histograms
457  //-------------------------------------------------------------------------
458 
459  for (vector<Trk>::const_iterator track = event->mc_trks.begin(); track != event->mc_trks.end(); ++track) {
460 
461  if (is_muon(*track)) {
462 
463  const JTrack3E muon = getTrack(*track);
464 
465  const double E = muon.getE();
466  const double x = log10(E);
467 
468  for (JDetector::const_iterator module = detector.begin(); module != detector.end(); ++module) {
469 
470  const double R = muon.getDistance(*module);
471 
472  muExR_tmp->Fill(x, R, module->size());
473 
474  if (R < muRxU.GetXaxis()->GetXmax()) {
475  for (JModule::const_iterator pmt = module->begin(); pmt != module->end(); ++pmt) {
476  muRxU_tmp->Fill(R, muon.getDot(*pmt));
477  }
478  }
479 
480  if (R < muRxT.GetXaxis()->GetXmax()) {
481  for (Int_t iy = 1; iy <= muRxT_tmp->GetYaxis()->GetNbins(); ++iy) {
482  muRxT_tmp->Fill(R, muRxT_tmp->GetYaxis()->GetBinCenter(iy), muRxT_tmp->GetYaxis()->GetBinWidth(iy));
483  }
484  }
485  }
486  }
487  }
488 
489 
490  //-------------------------------------------------------------------------
491  // normalisation of neutrino histograms
492  //-------------------------------------------------------------------------
493 
494  if (has_neutrino(*event)) {
495 
496  const double E = neutrino.getE();
497  const double x = log10(E);
498 
499  if (inst_vol.is_inside(vertex))
500  hits_per_E_in .Fill(x, NPE);
501  else
502  hits_per_E_out.Fill(x, NPE);
503 
504  for (JDetector::const_iterator module = detector.begin(); module != detector.end(); ++module) {
505 
506  const double D = vertex.getDistance(*module);
507  const double ct0 = neutrino.getDot(module->getPosition());
508 
509  nuExD_tmp->Fill(x, D, module->size());
510  nuExc_tmp->Fill(x, ct0, module->size());
511  nuDxc_tmp->Fill(D, ct0, module->size());
512 
513  if (D < nuDxU.GetXaxis()->GetXmax()) {
514  for (JModule::const_iterator pmt = module->begin(); pmt != module->end(); ++pmt) {
515  nuDxU_tmp->Fill(D, neutrino.getDot(*pmt));
516  }
517  }
518 
519  if (D < nuDxT.GetXaxis()->GetXmax()) {
520  for (Int_t iy = 1; iy <= nuDxT_tmp->GetYaxis()->GetNbins(); ++iy) {
521  nuDxT_tmp->Fill(D, nuDxT_tmp->GetYaxis()->GetBinCenter(iy), nuDxT_tmp->GetYaxis()->GetBinWidth(iy));
522  }
523  }
524  }
525  }
526  } // end loop over events
527 
528  STATUS(endl);
529 
530 
531  //-------------------------------------------------------------------------
532  // normalisation of histograms
533  //-------------------------------------------------------------------------
534 
535  TH1D *job_sorted = makeSortedH1(&job, "hits_by_pdg"); // hits by track_in particles (PDG codes) per event, sorted
536  TH1D *trks_sorted = makeSortedH1(&trks, "trks_sorted"); // track_in particles (PDG codes) per event, sorted
537 
538  if (inputFile.getCounter() != 0) {
539 
540  const Double_t W = 1.0 / ((Double_t) inputFile.getCounter());
541 
542  for (TH1D* buffer[] = { &hits, &npe_per_pmt, &job, &trks, job_sorted, trks_sorted, NULL }, **i = buffer; *i != NULL; ++i) {
543  (*i)->Scale(W);
544  }
545 
546  for (JManager_t::iterator i = npe_per_type.begin(); i != npe_per_type.end(); ++i) {
547  i->second->Scale(W);
548  }
549 
550  nuExD.Divide(nuExD_tmp);
551  nuExc.Divide(nuExc_tmp);
552  nuDxc.Divide(nuDxc_tmp);
553  nuDxU.Divide(nuDxU_tmp);
554  nuDxT.Divide(nuDxT_tmp);
555 
556  muExR.Divide(muExR_tmp);
557  muRxU.Divide(muRxU_tmp);
558  muRxT.Divide(muRxT_tmp);
559  }
560 
561 
562  //-------------------------------------------------------------------------
563  // output
564  //-------------------------------------------------------------------------
565 
566  TFile out(outputFile.c_str(), "recreate");
567 
568  out << hits << job << *job_sorted << trks << *trks_sorted << hits_per_E_in << hits_per_E_out << npe_per_type << npe_per_pmt;
569 
570  out << nuExD << nuExc << nuDxc << nuDxU << nuDxT;
571  out << muExR << muRxU << muRxT;
572 
573  out.Write();
574  out.Close();
575 }
Utility class to parse command line options.
Definition: JParser.hh:1410
Exceptions.
static const JGeane gWater(2.67e-1 *JTOOLS::DENSITY_SEA_WATER, 3.4e-4 *JTOOLS::DENSITY_SEA_WATER)
Function object for Energy loss of muon in sea water.
JPredicate< JResult_t T::*, JComparison::eq > make_predicate(JResult_t T::*member, const JResult_t value)
Helper method to create predicate for data member.
Definition: JPredicate.hh:128
Auxiliary methods for PDF calculations.
JTrack3E getTrack(const Trk &track)
Get track.
double geanc()
Equivalent muon track length per unit shower energy.
Definition: JGeane.hh:23
Auxiliary class to manage set of histograms.
#define STATUS(A)
Definition: JMessage.hh:61
bool has_neutrino(const Evt &evt)
Test whether given event has an incoming neutrino.
bool is_muon(const Trk &track)
Test whether given track is a (anti-)muon.
double getB() const
Get energy loss constant.
Definition: JGeane.hh:68
Structure to store the ToT mean and standard deviation of the hits produced by a nanobeacon in a sour...
#define MAKE_CSTRING(A)
Make C-string.
Definition: JPrint.hh:611
Empty structure for specification of parser element that is initialised (i.e.
Definition: JParser.hh:64
Dynamic ROOT object management.
string outputFile
size_t getSize(T(&array)[N])
Get size of c-array.
Definition: JLangToolkit.hh:32
Data structure for detector geometry and calibration.
Head getHeader(const JMultipleFileScanner_t &file_list)
Get Monte Carlo header.
JLimit JLimit_t
Type definition of limit.
Definition: JLimit.hh:214
double getSinThetaC()
Get average sine of Cherenkov angle of water.
Definition: JConstants.hh:144
I/O formatting auxiliaries.
#define make_field(A,...)
macro to convert parameter to JParserTemplateElement object
Definition: JParser.hh:1836
Definition of hit and track types and auxiliary methods for handling Monte Carlo data.
#define NOTICE(A)
Definition: JMessage.hh:62
#define ERROR(A)
Definition: JMessage.hh:64
void load(const JString &file_name, JDetector &detector)
Load detector from input file.
Direct access to PMT in detector data structure.
int debug
debug level
Definition: JSirene.cc:59
General purpose messaging.
Monte Carlo run header.
Definition: JHead.hh:727
#define FATAL(A)
Definition: JMessage.hh:65
Scanning of objects from multiple files according a format that follows from the extension of each fi...
Utility class to parse command line options.
ROOT TTree parameter settings.
const JLimit & getLimit() const
Get limit.
Definition: JLimit.hh:72
const Trk & get_neutrino(const Evt &evt)
Get incoming neutrino.
#define DEBUG(A)
Message macros.
Definition: JMessage.hh:60
int main(int argc, char *argv[])
Definition: Main.cpp:15