REST-for-Physics  v2.3
Rare Event Searches ToolKit for Physics
TRestDetectorHits3DReconstructionProcess.cxx
1 
12 #include "TRestDetectorHits3DReconstructionProcess.h"
13 
14 #include "TFunction.h"
15 #include "TLine.h"
16 #include "TMarker.h"
17 
18 using namespace std;
19 #define XWidth 96.7
20 #define YWidth 96.3
21 #define PITCH 6.2
22 #define PlaneMaxX 800
23 #define PlaneMaxY 800
24 struct regionhit {
25  double x = 0;
26  double y = 0;
27  double e = 0;
28  bool iszombie() const { return e == 0; }
29  void add(const regionhit& h) {
30  x = (x * e + h.x * h.e) / (e + h.e);
31  y = (y * e + h.y * h.e) / (e + h.e);
32  e += h.e;
33  }
34  static double dist(const regionhit& h1, const regionhit& h2) {
35  return sqrt((h1.x - h2.x) * (h1.x - h2.x) + (h1.y - h2.y) * (h1.y - h2.y));
36  }
37 };
38 
39 struct stripehit {
40  double x1 = 0;
41  double x2 = 0;
42  double y1 = 0;
43  double y2 = 0;
44  double e = 0;
45  REST_HitType type;
46 
47  void Print() { cout << "x1: " << x1 << ", x2: " << x2 << ", y1: " << y1 << ", y2: " << y2 << endl; }
48 
49  bool iszombie() const { return e == 0; }
50 
51  static bool IsRectCross(const stripehit& s1, const stripehit& s2) {
52  bool ret = min(s1.x1, s1.x2) <= max(s2.x1, s2.x2) && min(s2.x1, s2.x2) <= max(s1.x1, s1.x2) &&
53  min(s1.y1, s1.y2) <= max(s2.y1, s2.y2) && min(s2.y1, s2.y2) <= max(s1.y1, s1.y2);
54  return ret;
55  }
56 
57  static bool IsLineSegmentCross(const stripehit& s1, const stripehit& s2) {
58  if (((s2.x1 - s1.x1) * (s2.y1 - s2.y2) - (s2.y1 - s1.y1) * (s2.x1 - s2.x2)) *
59  ((s2.x1 - s1.x2) * (s2.y1 - s2.y2) - (s2.y1 - s1.y2) * (s2.x1 - s2.x2)) <
60  0 ||
61  ((s1.x1 - s2.x1) * (s1.y1 - s1.y2) - (s1.y1 - s2.y1) * (s1.x1 - s1.x2)) *
62  ((s1.x1 - s2.x2) * (s1.y1 - s1.y2) - (s1.y1 - s2.y2) * (s1.x1 - s1.x2)) <
63  0)
64  return true;
65  else
66  return false;
67  }
68 
69  static bool GetCrossPoint(const stripehit& s1, const stripehit& s2, double& x, double& y) {
70  if (IsRectCross(s1, s2)) {
71  if (IsLineSegmentCross(s1, s2)) {
72  long tmpLeft, tmpRight;
73  tmpLeft = (s2.x2 - s2.x1) * (s1.y1 - s1.y2) - (s1.x2 - s1.x1) * (s2.y1 - s2.y2);
74  tmpRight = (s1.y1 - s2.y1) * (s1.x2 - s1.x1) * (s2.x2 - s2.x1) +
75  s2.x1 * (s2.y2 - s2.y1) * (s1.x2 - s1.x1) -
76  s1.x1 * (s1.y2 - s1.y1) * (s2.x2 - s2.x1);
77 
78  x = (int)((double)tmpRight / (double)tmpLeft);
79 
80  tmpLeft = (s1.x1 - s1.x2) * (s2.y2 - s2.y1) - (s1.y2 - s1.y1) * (s2.x1 - s2.x2);
81  tmpRight = s1.y2 * (s1.x1 - s1.x2) * (s2.y2 - s2.y1) +
82  (s2.x2 - s1.x2) * (s2.y2 - s2.y1) * (s1.y1 - s1.y2) -
83  s2.y2 * (s2.x1 - s2.x2) * (s1.y2 - s1.y1);
84  y = (int)((double)tmpRight / (double)tmpLeft);
85  return true;
86  }
87  }
88  return false;
89  }
90 
91  static double dist(const stripehit& h1, const stripehit& h2) {
92  if (IsRectCross(h1, h2) && IsLineSegmentCross(h1, h2)) {
93  return 0;
94  } else {
95  double x = h1.x1;
96  double y = h1.y1;
97  double d1 = abs(((x - h2.x1) * (h2.y2 - h2.y1) - (h2.x2 - h2.x1) * (y - h2.y1)) /
98  sqrt((h2.x2 - h2.x1) * (h2.x2 - h2.x1) + (h2.y2 - h2.y1) * (h2.y2 - h2.y1)));
99 
100  x = h1.x2;
101  y = h1.y2;
102  double d2 = abs(((x - h2.x1) * (h2.y2 - h2.y1) - (h2.x2 - h2.x1) * (y - h2.y1)) /
103  sqrt((h2.x2 - h2.x1) * (h2.x2 - h2.x1) + (h2.y2 - h2.y1) * (h2.y2 - h2.y1)));
104 
105  x = h2.x1;
106  y = h2.y1;
107  double d3 = abs(((x - h1.x1) * (h1.y2 - h1.y1) - (h1.x2 - h1.x1) * (y - h1.y1)) /
108  sqrt((h1.x2 - h1.x1) * (h1.x2 - h1.x1) + (h1.y2 - h1.y1) * (h1.y2 - h1.y1)));
109 
110  x = h2.x2;
111  y = h2.y2;
112  double d4 = abs(((x - h1.x1) * (h1.y2 - h1.y1) - (h1.x2 - h1.x1) * (y - h1.y1)) /
113  sqrt((h1.x2 - h1.x1) * (h1.x2 - h1.x1) + (h1.y2 - h1.y1) * (h1.y2 - h1.y1)));
114 
115  return min({d1, d2, d3, d4});
116  }
117  }
118 
119  friend regionhit operator&(const stripehit& s1, const stripehit& s2) {
120  if (s1.type * s2.type == XZ * YZ) {
121  if (!s1.iszombie() && !s2.iszombie()) {
122  double x;
123  double y;
124  if (stripehit::GetCrossPoint(s1, s2, x, y)) {
125  regionhit hit;
126  hit.x = x;
127  hit.y = y;
128  hit.e = s1.e + s2.e;
129  return hit;
130  }
131  }
132  }
133  return regionhit();
134  }
135 
136  stripehit(TRestHits* hits, int i) {
137  type = hits->GetType(i);
138  if (type == XZ) {
139  y1 = hits->GetY(i) - YWidth;
140  y2 = hits->GetY(i) + YWidth;
141  x1 = hits->GetX(i);
142  x2 = hits->GetX(i);
143  } else if (type == YZ) {
144  y1 = hits->GetY(i);
145  y2 = hits->GetY(i);
146  x1 = hits->GetX(i) - XWidth;
147  x2 = hits->GetX(i) + XWidth;
148  } else {
149  return;
150  }
151  e = hits->GetEnergy(i);
152  }
153 
154  stripehit(double x1, double x2, double y1, double y2, double e = 0, REST_HitType type = unknown) {
155  this->x1 = x1;
156  this->x2 = x2;
157  this->y1 = y1;
158  this->y2 = y2;
159  this->e = e;
160  this->type = type;
161  }
162 };
163 
165 
166  TRestDetectorHits3DReconstructionProcess::TRestDetectorHits3DReconstructionProcess() {
167  Initialize();
168 }
169 
170 TRestDetectorHits3DReconstructionProcess::~TRestDetectorHits3DReconstructionProcess() {
171  delete fOutputHitsEvent;
172 }
173 
175  SetSectionName(this->ClassName());
176  SetLibraryVersion(LIBRARY_VERSION);
177 
178  fInputHitsEvent = nullptr;
179  fOutputHitsEvent = new TRestDetectorHitsEvent();
180 }
181 
183  BeginPrintProcess();
185  // write here the information to print
186 
188  EndPrintProcess();
189 }
190 
192  if (fDraw) {
193  htemp = new TH2D("hhits", "hhits", 100, -PlaneMaxX, PlaneMaxX, 100, -PlaneMaxY, PlaneMaxY);
194  CreateCanvas();
195  }
196 #ifdef REST_Geant4Lib
197  fCompareProc = GetFriendLive("TRestGeant4ToDetectorHitsProcess");
198 #endif
199 }
200 
202  fInputHitsEvent = (TRestDetectorHitsEvent*)inputEvent;
203 
204  // sort with z from small to large
205  fInputHitsEvent->Sort();
206 
207  double lastz = 0;
208  double totalambiguity = 0;
209  double Nlayers = 0;
210  for (unsigned int n = 0; n < fInputHitsEvent->GetNumberOfHits(); n++) {
211  double z = fInputHitsEvent->GetZ(n);
212  if (z == lastz) continue;
213 
214  lastz = z;
215 
216  // find the hits near this z slice
217  map<int, double> ids; //[id, weight]
218  ids[n] = 1;
219  for (int i = n - 1; i >= 0; i--) {
220  if (abs(fInputHitsEvent->GetZ(i) - z) < fZRange * 2) {
221  ids[i] = TMath::Gaus(abs(fInputHitsEvent->GetZ(i) - z), 0, fZRange);
222  } else {
223  break;
224  }
225  }
226  for (unsigned int i = n + 1; i < fInputHitsEvent->GetNumberOfHits(); i++) {
227  if (abs(fInputHitsEvent->GetZ(i) - z) < fZRange * 2) {
228  ids[i] = TMath::Gaus(abs(fInputHitsEvent->GetZ(i) - z), 0, fZRange);
229  } else {
230  break;
231  }
232  }
233 
234  // extract stripe hits
235  vector<stripehit> stripehits;
236  for (auto i : ids) {
237  stripehit h = stripehit(fInputHitsEvent->GetHits(), i.first);
238  h.e *= i.second;
239  if (!h.iszombie()) {
240  if (stripehits.size() > 0) {
241  for (unsigned int k = 0; k < stripehits.size(); k++) {
242  stripehit& _h = stripehits[k];
243  if (_h.x1 == h.x1 && _h.x2 == h.x2 && _h.y1 == h.y1 && _h.y2 == h.y2) {
244  _h.e += h.e;
245  break;
246  } else if (k == stripehits.size() - 1) {
247  stripehits.push_back(h);
248  }
249  }
250  } else {
251  stripehits.push_back(h);
252  }
253  }
254  }
255 
256  if (stripehits.size() > 50) {
257  RESTWarning << "(TRestDetectorHits3DReconstructionProcess) event id: " << fInputHitsEvent->GetID()
258  << ", z: " << z << ", bad frame, too much hits! (" << stripehits.size() << ")"
259  << RESTendl;
260  continue;
261  }
262 
264  cout << "stripehits: ";
265  for (auto h : stripehits) {
266  cout << h.x1 << "," << h.y1 << "," << h.x2 << "," << h.y2 << "," << h.e << " ";
267  }
268  cout << endl;
269  }
270 
271  // find all the crossing points of stripe hits
272  vector<regionhit> regionhits;
273  double layerambiguity = 0;
274  set<int> ambcalculatedstripes;
275  for (unsigned int i = 0; i < stripehits.size(); i++) {
276  vector<int> crossedids;
277  double crossedsumenergy = 0;
278  for (unsigned int j = 0; j < stripehits.size(); j++) {
279  if (i == j) continue;
280  if (stripehit::IsRectCross(stripehits[i], stripehits[j])) {
281  crossedids.push_back(j);
282  crossedsumenergy += stripehits[j].e;
283  }
284  }
285 
286  for (int id : crossedids) {
287  regionhit rh = stripehits[i] & stripehits[id];
288  rh.e = stripehits[i].e * stripehits[id].e / crossedsumenergy;
289 
290  if (regionhits.size() > 0) {
291  for (unsigned int k = 0; k < regionhits.size(); k++) {
292  regionhit& _rh = regionhits[k];
293  if (_rh.x == rh.x && _rh.y == rh.y) {
294  _rh.e += rh.e;
295  break;
296  } else if (k == regionhits.size() - 1) {
297  regionhits.push_back(rh);
298  }
299  }
300  } else {
301  regionhits.push_back(rh);
302  }
303  }
304 
305  // calculate ambiguouity
306  if (ambcalculatedstripes.count(i) == 0 && crossedids.size() > 0) {
307  for (int id : crossedids) {
308  ambcalculatedstripes.insert(id);
309  }
310 
311  auto line = stripehits[i];
312  auto newline = stripehits[crossedids[0]];
313  vector<int> crossedids_newline;
314  for (unsigned int j = 0; j < stripehits.size(); j++) {
315  if (j == (unsigned int)crossedids[0]) continue;
316  if (stripehit::IsRectCross(stripehits[j], newline)) {
317  crossedids_newline.push_back(j);
318  }
319  }
320  for (int id : crossedids_newline) {
321  ambcalculatedstripes.insert(id);
322  }
323 
324  vector<pair<double, double>> V_PosE;
325  vector<pair<double, double>> H_PosE;
326 
327  if (line.x1 == line.x2) {
328  // cout << "adding H from crossed lines of first crossed line(" << crossedids[0]
329  // << ") of line: " << i << endl;
330  for (int id : crossedids_newline) {
331  H_PosE.push_back({stripehits[id].x1, stripehits[id].e});
332  }
333  } else if (line.y1 == line.y2) {
334  // cout << "adding V from crossed lines of first crossed line(" << crossedids[0]
335  // << ") of line: " << i << endl;
336  for (int id : crossedids_newline) {
337  V_PosE.push_back({stripehits[id].y1, stripehits[id].e});
338  }
339  }
340 
341  if (newline.x1 == newline.x2) {
342  // cout << "adding H from crossed lines of line: " << i << endl;
343  for (int id : crossedids) {
344  H_PosE.push_back({stripehits[id].x1, stripehits[id].e});
345  }
346  } else if (newline.y1 == newline.y2) {
347  // cout << "adding V from crossed lines of line: " << i << endl;
348  for (int id : crossedids) {
349  V_PosE.push_back({stripehits[id].y1, stripehits[id].e});
350  }
351  }
352 
353  // sort with position form small to large
354  auto comp = [](const pair<double, double>& p1, const pair<double, double>& p2) -> bool {
355  return p1.first < p2.first;
356  };
357  sort(V_PosE.begin(), V_PosE.end(), comp);
358  sort(H_PosE.begin(), H_PosE.end(), comp);
359 
360  for (unsigned int j = 1; j < V_PosE.size(); j++) {
361  if (V_PosE[j].first - V_PosE[j - 1].first > PITCH) {
362  V_PosE.insert(V_PosE.begin() + j, {(V_PosE[j].first + V_PosE[j - 1].first) / 2, 0});
363  j++;
364  }
365  }
366  V_PosE.insert(V_PosE.begin(), {(*V_PosE.begin()).first - 1, 0});
367  V_PosE.insert(V_PosE.end(), {(*(V_PosE.end() - 1)).first + 1, 0});
368 
369  for (unsigned int j = 1; j < H_PosE.size(); j++) {
370  if (H_PosE[j].first - H_PosE[j - 1].first > PITCH) {
371  H_PosE.insert(H_PosE.begin() + j, {(H_PosE[j].first + H_PosE[j - 1].first) / 2, 0});
372  j++;
373  }
374  }
375  H_PosE.insert(H_PosE.begin(), {(*H_PosE.begin()).first - 1, 0});
376  H_PosE.insert(H_PosE.end(), {(*(H_PosE.end() - 1)).first + 1, 0});
377 
379  cout << "V: ";
380  for (auto pose : V_PosE) {
381  cout << pose.first << "," << pose.second << " ";
382  }
383  cout << endl;
384 
385  cout << "H: ";
386  for (auto pose : H_PosE) {
387  cout << pose.first << "," << pose.second << " ";
388  }
389  cout << endl;
390  }
391 
392  int Vsegs = 0;
393  int Hsegs = 0;
394 
395  for (unsigned int j = 1; j < V_PosE.size() - 1; j++) {
396  if (V_PosE[j].second > V_PosE[j - 1].second && V_PosE[j].second > V_PosE[j + 1].second) {
397  Vsegs++;
398  }
399  }
400 
401  for (unsigned int j = 1; j < H_PosE.size() - 1; j++) {
402  if (H_PosE[j].second > H_PosE[j - 1].second && H_PosE[j].second > H_PosE[j + 1].second) {
403  Hsegs++;
404  }
405  }
406 
408  cout << i << " z: " << z << " " << Vsegs << " " << Hsegs << " -> "
409  << LogAmbiguity(Vsegs, Hsegs) << endl;
410  cout << endl;
411  }
412 
413  if (Vsegs == 0) Vsegs = 1;
414  if (Hsegs == 0) Hsegs = 1;
415 
416  layerambiguity += LogAmbiguity(Vsegs, Hsegs);
417  }
418  }
419  // cout << "z: " << z << ", amb: " << layerambiguity << endl;
420  totalambiguity += layerambiguity;
421 
422  // merge the cossing points
423  vector<regionhit> regionhits_merged;
424  set<int> mergeflag_all;
425  while (mergeflag_all.size() < regionhits.size()) {
426  // find the initial point(with max energy)
427  double max = 0;
428  int maxposition;
429  for (unsigned int i = 0; i < regionhits.size(); i++) {
430  if (mergeflag_all.count(i) == 0) {
431  if (regionhits[i].e > max) {
432  max = regionhits[i].e;
433  maxposition = i;
434  }
435  }
436  }
437  set<int> mergeflag;
438  mergeflag.insert(maxposition);
439 
440  // loop over regionhits to find any hits that is **connected** to the initial point
441  for (auto _i = mergeflag.begin(); _i != mergeflag.end();) {
442  int i = *_i;
443 
444  // cout << i << ": ";
445  // for (auto __i : mergeflag) cout << __i << " ";
446  // cout << endl;
447 
448  bool inserted = false;
449  for (unsigned int j = 0; j < regionhits.size(); j++) {
450  if (regionhit::dist(regionhits[i], regionhits[j]) < PITCH &&
451  regionhits[i].e > regionhits[j].e && mergeflag_all.count(j) == 0) {
452  auto insertresult = mergeflag.insert(j);
453  inserted += insertresult.second;
454  }
455  }
456  // if inserted, we go back to the begin incase it is inserted to the former
457  if (inserted)
458  _i = mergeflag.begin();
459  else
460  _i++;
461  }
462 
463  // cout << z << " " << regionhits.size() << " " << mergeflag.size() << endl;
464  // cout << endl;
465 
466  // the collection of all the connected hits are merged
467  regionhit h;
468  for (auto i : mergeflag) {
469  mergeflag_all.insert(i);
470  h.add(regionhits[i]);
471  }
472  regionhits_merged.push_back(h);
473  }
474  if (regionhits_merged.size() > 0) Nlayers++;
475 
476  if (fDraw && (layerambiguity > fDrawThres)) {
477  if (regionhits.size() == 0) continue;
478  double maxenergyofregionhits =
479  (*min_element(regionhits.begin(), regionhits.end(),
480  [](const regionhit& h1, const regionhit& h2) -> bool { return h1.e > h2.e; }))
481  .e;
482 
483  fCanvas->Clear();
484  htemp->SetStats(false);
485  htemp->SetTitle(Form("event id %i, z = %.1f", fInputHitsEvent->GetID(), z));
486  htemp->Draw();
487  vector<TLine*> lines;
488  vector<TMarker*> markers;
489  for (auto h : stripehits) {
490  TLine* line = new TLine(h.x1, h.y1, h.x2, h.y2);
491  line->Draw();
492  lines.push_back(line);
493  }
494  for (auto rh : regionhits) {
495  TMarker* marker = new TMarker(rh.x, rh.y, kFullDotLarge);
496  marker->SetMarkerColor(kGreen);
497  marker->SetMarkerSize(rh.e / maxenergyofregionhits);
498  marker->Draw();
499  markers.push_back(marker);
500  }
501  for (auto rhm : regionhits_merged) {
502  TMarker* marker = new TMarker(rhm.x, rhm.y, kFullDotLarge);
503  marker->SetMarkerColor(kRed);
504  marker->Draw();
505  markers.push_back(marker);
506  }
507 
508  fCanvas->Update();
509  GetChar();
510  for (auto l : lines) {
511  delete l;
512  }
513  for (auto m : markers) {
514  delete m;
515  }
516  }
517 
518  // for (auto rh : regionhits) {
519  for (auto rh : regionhits_merged) {
520  fOutputHitsEvent->AddHit(rh.x, rh.y, z, rh.e, 0, XYZ);
521  }
522  }
523 
524  // scale the total energy
525  if (fDoEnergyScaling) {
526  double e1 = fInputHitsEvent->GetTotalEnergy();
527  double e2 = fOutputHitsEvent->GetTotalEnergy();
528  for (auto h : *fOutputHitsEvent->GetHits()) {
529  h.e() = h.e() / e2 * e1;
530  }
531  }
532 
533  SetObservableValue("MeanAmbiguity", totalambiguity / Nlayers);
534  SetObservableValue("DiffRecon", numeric_limits<double>::quiet_NaN());
535  if (fCompareProc != nullptr && fOutputHitsEvent->GetNumberOfHits() > 0 &&
536  (fObservablesDefined.count("DiffRecon") != 0 || fDynamicObs)) {
537  TRestDetectorHitsEvent* reference = (TRestDetectorHitsEvent*)fCompareProc->GetOutputEvent();
538  auto hits1 = *fOutputHitsEvent->GetHits();
539  auto hits2 = *reference->GetHits();
540 
541  double maxz1 = (*min_element(hits1.begin(), hits1.end(),
542  [](const TRestHits::iterator& h1,
543  const TRestHits::iterator& h2) -> bool { return h1.z() > h2.z(); }))
544  .z();
545  double maxz2 = (*min_element(hits2.begin(), hits2.end(),
546  [](const TRestHits::iterator& h1,
547  const TRestHits::iterator& h2) -> bool { return h1.z() > h2.z(); }))
548  .z();
549  double dz = maxz2 - maxz1;
550 
551  double mindistmean = 1e9;
552  for (double i = -fZRange * 2; i <= fZRange * 2; i += fZRange / 2) {
553  double distsum2 = 0;
554  for (auto hit : hits1) {
555  auto pos = TVector3(hit.x(), hit.y(), hit.z() + dz);
556  int n = hits2.GetClosestHit(pos);
557  auto dist2 = (pos - hits2.GetPosition(n)).Mag2();
558  distsum2 += dist2;
559  }
560  double distmean = sqrt(distsum2) / fOutputHitsEvent->GetNumberOfHits();
561  if (distmean < mindistmean) {
562  mindistmean = distmean;
563  }
564  }
565  SetObservableValue("DiffRecon", mindistmean);
566  }
567 
568  return fOutputHitsEvent;
569 }
570 
571 int TRestDetectorHits3DReconstructionProcess::Ambiguity(const int& n, const int& m) {
572  if (n <= 0 || m <= 0) return 0;
573  if (n == 1 || m == 1) return 1;
574  if (n > 5 && m > 5) return 1e9;
575  if (n > 8 || m > 8) return 1e9;
576 
577  int N = min({n, m});
578  int M = max({n, m});
579 
580  int ambiguity = pow(N, M);
581  for (int i = N - 1; i > 0; i--) {
582  // value of nC(n-i)
583  int combinations = Factorial(N) / Factorial(N - i) / Factorial(i);
584  ambiguity -= Ambiguity(i, M) * combinations;
585  }
586  return ambiguity;
587 }
588 
589 int TRestDetectorHits3DReconstructionProcess::Factorial(const int& n) {
590  int result = n;
591  int N = n;
592  while (N > 1) result *= (--N);
593  return result;
594 }
595 
597  if (fDraw) {
598  delete htemp;
599  delete fCanvas;
600  }
601 }
602 
604  fZRange = StringToDouble(GetParameter("zRange", "5"));
605  fDraw = StringToBool(GetParameter("draw", "false"));
606  if (fDraw) fSingleThreadOnly = true;
607  fDrawThres = StringToDouble(GetParameter("drawThreshold", "3"));
608  fDoEnergyScaling = StringToBool(GetParameter("scaleE", "true"));
609 
610  fCanvasSize = StringTo2DVector(GetParameter("canvasSize", "(800,600)"));
611 }
void InitFromConfigFile() override
To make settings from rml file. This method must be implemented in the derived class.
void PrintMetadata() override
Implemented it in the derived metadata class to print out specific metadata information.
void InitProcess() override
To be executed at the beginning of the run (outside event loop)
TRestEvent * ProcessEvent(TRestEvent *inputEvent) override
Process one event.
void EndProcess() override
To be executed at the end of the run (outside event loop)
A base class for any REST event.
Definition: TRestEvent.h:38
It saves a 3-coordinate position and an energy for each punctual deposition.
Definition: TRestHits.h:39
@ REST_Debug
+show the defined debug messages
Int_t GetChar(std::string hint="Press a KEY to continue ...")
Helps to pause the program, printing a message before pausing.
Double_t StringToDouble(std::string in)
Gets a double from a string.
TVector2 StringTo2DVector(std::string in)
Gets a 2D-vector from a string.