KaliVeda
Toolkit for HIC analysis
KVDataQualityAudit.cpp
1 #include "KVDataQualityAudit.h"
2 #include <algorithm>
3 
4 
7 
9 {
10  // Add this reconstructed nucleus to the audit.
11 
12  auto tel = telescopes.get_object<idtelescope>(N.GetIdentifyingTelescope()->GetName());
13  if (!tel) {
14  tel = new idtelescope(N.GetIdentifyingTelescope()->GetName());
15  telescopes.Add(tel);
16  }
17  tel->add(N);
18 }
19 
20 
21 
23 
25 {
26  for (auto p : telescopes) {
27  p->Print(opt);
28  }
29 }
30 
31 
32 
38 
40 {
41  // Used to merge audit objects in different ROOT files (using hadd).
42  //
43  // This method is called for the object in the first file, the TCollection
44  // contains the objects with the same name in all the other files.
45 
46  TIter next(l);
47  TObject* o;
48  Long64_t nmerge = 0;
49  while ((o = next())) {
50  nmerge += merge(dynamic_cast<KVDataQualityAudit*>(o));
51  }
52  return nmerge;
53 }
54 
55 
56 
67 
68 KVDataQualityAudit::IDStatus KVDataQualityAudit::CanIdentify(const TString& tel_name, int Z, int& A, double E) const
69 {
70  // Call this method to test whether a given particle could be identified in a given identification
71  // telescope according to the data quality audit.
72  //
73  // \param[in] tel_name name of identification telescope
74  // \param[in] Z atomic number \f$Z\f$ of particle
75  // \param[in,out] A mass number \f$A\f$ of particle. May be changed by method.
76  // \param[in] E total incident energy of particle
77  //
78  // \returns IDStatus object which indicates if & how well the identification would proceed
79 
80  if (!HasTelescope(tel_name)) // telescope does not appear in audit, not functioning
82 
83  auto idtel = GetTelescope(tel_name);
84  if (!idtel->HasElement(Z)) // telescope never identifies this Z value
86 
87  auto& elem = idtel->GetElement(Z);
88  if (E < elem.GetIdThreshold()) // no identification for this energy
90 
91  if (!elem.HasIsotopes()) { // telescope does not provide isotopic identification
92  // attribute default mass to particle
93  A = elem.get_default_mass();
95  }
96 
97  if (elem.HasIsotope(A)) {
98  if (E > elem.GetIsotope(A).GetIdThreshold())
100 
101  // telescope can identify isotope, but we are below threshold for full identification
102  int a_min_thresh;
103  if (E < elem.get_minimum_isotopic_threshold(a_min_thresh)) { // no isotopic identification possible
104  // attribute default mass to particle
105  A = elem.get_default_mass();
107  }
108  // look for closest isostope with A'<A with good threshold?
109  // [this is modelled on CsI R/L behaviour, where heavier isotopes have higher thresholds]
110  if (a_min_thresh < A) {
111  int a = A - 1;
112  while (a >= a_min_thresh) {
113  if (elem.HasIsotope(a) && E > elem.GetIsotope(a).GetIdThreshold()) {
114  // attribute isotope mass to particle
115  A = a;
117  }
118  --a;
119  }
120  // we shouldn't arrive here?
122  }
123  // no luck? now look for first isotope with threshold less than particle's energy
124  auto seuil_map = elem.get_isotopes_sorted_by_threshold();
125  int last_a = 0;
126  for (auto& s : seuil_map) {
127  if (s.first > E) {
128  if (last_a > 0) {
129  // use isotopic mass of previous isotope in map, its threshold was <E
130  A = last_a;
132  }
133  else
135  }
136  last_a = s.second;
137  }
138  // we shouldn't arrive here?
140  }
141 
142  // particle's A was never identified by the telescope:
143  // if A > Amax or A < Amin,no identification (in between lines of different Z)
144  // if Amax > A > Amin, look for closest mass in list with good threshold?
145 
146  // start by filling list of candidate masses with OK thresholds
147  auto seuil_map = elem.get_isotopes_sorted_by_threshold();
148  std::map<int, int> ok_masses;
149  for (auto& s : seuil_map) {
150  if (E > s.first) ok_masses[s.second] = 1;
151  else break;
152  }
153  // get largest isotopically resolved mass above threshold
154  auto last = ok_masses.rbegin();
155  auto Amax = (*last).first;
156  // get smallest isotopically resolved mass above threshold
157  auto first = ok_masses.begin();
158  auto Amin = (*first).first;
159  if (A > Amax) {
161  }
162  else if (A < Amin) {
164  }
165  else {
166  int adiff(999), near_a(-1);
167  for (auto& p : ok_masses) {
168  auto diff = std::abs(p.first - A);
169  if (diff < adiff) {
170  adiff = diff;
171  near_a = p.first;
172  }
173  }
174  A = near_a;
176  }
177  // should never get here?
179 }
180 
181 
182 
185 
187 {
188  // Add copy of idtelescope data to this audit
189  telescopes.Add(new idtelescope(*idt));
190 }
191 
192 
193 
197 
199 {
200  // Merge other audit object with this one. Return 1 if merge is successful,
201  // 0 in case of problems.
202  if (!other) return 0; // possibly called for wrong object type
203 
204  TIter next_tel(other->GetTelescopeList());
205  idtelescope* idt;
206  Long64_t nmerge = 0;
207  while ((idt = (idtelescope*)next_tel())) {
208  if (HasTelescope(idt))
209  GetTelescope(idt)->merge(idt);
210  else
211  add(idt);
212  ++nmerge;
213  }
214  return nmerge;
215 }
216 
217 
218 
223 
225 {
226  // add an isotopically identified nucleus
227  //
228  // for calibrated particles, we store the minimum energy (=> threshold)
229  A = N.GetA();
230  ++counts;
231  if (N.IsCalibrated() && ((emin < 0) || (N.GetEnergy() < emin))) emin = N.GetEnergy();
232 }
233 
234 
235 
237 
239 {
240  std::cout << "\t\tA=" << A << "\t\t[E>" << emin << "]" << std::endl;
241 }
242 
243 
244 
251 
253 {
254  // add an element (Z-identified nucleus)
255  //
256  // if isotopically identified, add to list of isotopes
257  //
258  // for calibrated particles, we store the minimum energy (=> threshold)
259  if (N.GetZ() > 0) Z = N.GetZ();
260  ++counts;
261  if (N.IsCalibrated() && ((emin < 0) || (N.GetEnergy() < emin))) emin = N.GetEnergy();
262  if (N.IsAMeasured()) {
263  isotopes[N.GetA()].add(N);
264  }
265  else if (N.GetA() > 0) A = N.GetA(); // default mass for Z-only identification
266 }
267 
268 
269 
271 
273 {
274  std::cout << "\tZ=" << (int)Z << "\t\t[E>" << emin << "]";
275  if (A > 0) std::cout << " default A=" << A;
276  if (!HasIsotopes()) {
277  std::cout << std::endl;
278  return;
279  }
280  std::cout << "\t\tIsotopes: " << GetIsotopeList().AsString() << std::endl;
281  for (auto i : isotopes) i.second.print();
282 }
283 
284 
285 
293 
295 {
296  // Merge the informations in element elem with those in this one:
297  //
298  // - we keep the lower of the two threshold values
299  // - we sum the counts for the element
300  // - we merge the lists of isotopes of the two elements
301  // - we keep the default mass, if it has been set
302 
303  if (emin > 0) {
304  if (elem.emin > 0) emin = std::min(emin, elem.emin);
305  }
306  else if (elem.emin > 0) emin = elem.emin;
307  A = std::max(A, elem.A);
308  counts += elem.counts;
309  // look at isotopes in other's list. if any are not in our list they are added.
310  // if any are in both, they are merged
311  std::for_each(std::begin(elem.isotopes), std::end(elem.isotopes),
312  [&](const std::pair<int, isotope>& isotop) {
313  if (HasIsotope(isotop.first)) {
314  isotopes[isotop.first].merge(isotop.second);
315  }
316  else {
317  isotopes[isotop.first] = isotop.second;
318  }
319  }
320  );
321 }
322 
323 
324 
327 
329 {
330  // calculate and return mean mass of isotopes measured for this element
331 
332  if (isotopes.empty()) return 0;
333  double sum{0}, weight{0};
334  std::for_each(std::begin(isotopes), std::end(isotopes),
335  [&](const std::pair<int, isotope>& count) {
336  sum += count.second.counts;
337  weight += count.first * count.second.counts;
338  }
339  );
340  if (sum > 0) return weight / sum;
341  return 0;
342 }
343 
344 
345 
348 
350 {
351  // return max A of isotopes measured for this element
352 
353  if (isotopes.empty()) return 0;
354  auto last = isotopes.rbegin();
355  return (*last).first;
356 }
357 
358 
359 
362 
364 {
365  // return min A of isotopes measured for this element
366 
367  if (isotopes.empty()) return 0;
368  auto first = isotopes.begin();
369  return (*first).first;
370 }
371 
372 
373 
377 
379 {
380  // \returns the smallest recorded threshold (in MeV/u) for isotopic identification for the element
381  // \param[out] a mass number corresponding to minimum
382  a = -1;
383  if (isotopes.empty()) return -1;
384  double minE = 9999;
385  for (auto& p : isotopes) {
386  double myE = p.second.emin / p.first;
387  if ((myE > 0) && (myE < minE)) {
388  minE = myE;
389  a = p.first;
390  }
391  }
392  if (minE < 9999) return minE;
393  // uncalibrated particles: all thresholds are -1 MeV
394  return -1;
395 }
396 
397 
398 
402 
404 {
405  // \returns the smallest recorded threshold (in MeV) for isotopic identification for the element
406  // \param[out] a mass number corresponding to minimum
407  a = -1;
408  if (isotopes.empty()) return -1;
409  double minE = 9999;
410  for (auto& p : isotopes) {
411  double myE = p.second.emin;
412  if ((myE > 0) && (myE < minE)) {
413  minE = myE;
414  a = p.first;
415  }
416  }
417  if (minE < 9999) return minE;
418  // uncalibrated particles: all thresholds are -1 MeV
419  return -1;
420 }
421 
422 
423 
426 
428 {
429  // \returns a map sorted according to increasing identification threshold of isotope mass numbers
430 
431  std::map<double, int> seuils;
432  for (auto& i : isotopes) {
433  seuils[i.second.GetIdThreshold()] = i.first;
434  }
435  return seuils;
436 }
437 
438 
439 
442 
444 {
445  // \returns probability distribution for each isotope as a map between isotope A and P(A)
446 
447  double sum{0};
448  std::for_each(std::begin(isotopes), std::end(isotopes),
449  [&](const std::pair<int, isotope>& count) {
450  sum += count.second.counts;
451  }
452  );
453  std::map<int, double> proba;
454  for (auto& p : isotopes) {
455  proba[p.first] = p.second.counts / sum;
456  }
457  return proba;
458 }
459 
460 
461 
463 
465 {
466  elements[N.GetZ()].add(N);
467 }
468 
469 
470 
472 
474 {
475  std::cout << GetName() << " :" << std::endl;
476  std::cout << "Elements: " << GetElementList().AsString() << std::endl;
477  for (auto e : elements) e.second.print();
478 }
479 
480 
481 
486 
488 {
489  // Merge data in idtelescope idt with this one
490 
491  // look at elements in other's list. if any are not in our list they are added.
492  // if any are in both, they are merged
493  std::for_each(std::begin(idt->elements), std::end(idt->elements),
494  [&](const std::pair<int, element>& elem) {
495  if (HasElement(elem.first)) {
496  elements[elem.first].merge(elem.second);
497  }
498  else {
499  elements[elem.first] = elem.second;
500  }
501  }
502  );
503 }
504 
505 
506 
509 
511 {
512  // \returns probability distribution for all elements identified by telescope as a map between Z and P(Z)
513 
514  double sum{0};
515  std::for_each(std::begin(elements), std::end(elements),
516  [&](const std::pair<int, element>& count) {
517  sum += count.second.counts;
518  }
519  );
520  std::map<int, double> proba;
521  for (auto& p : elements) {
522  proba[p.first] = p.second.counts / sum;
523  }
524  return proba;
525 }
526 
527 
528 
531 
533 {
534  // \returns mean Z measured in telescope
535  double sum{0}, weight{0};
536  std::for_each(std::begin(elements), std::end(elements),
537  [&](const std::pair<int, element>& count) {
538  sum += count.second.counts;
539  weight += count.second.counts * count.first;
540  }
541  );
542  return weight / sum;
543 }
544 
545 
546 
549 
551 {
552  // \returns maximum Z measured in telescope
553  auto last = elements.rbegin();
554  return (*last).first;
555 }
556 
557 
560 
562 {
563  // \returns maximum Z for which isotopic masses were measured
564  auto it = elements.rbegin();
565  while (it != elements.rend()) {
566  if ((*it).second.HasIsotopes()) return (*it).first;
567  ++it;
568  }
569  return 0;
570 }
571 
572 
575 
577 {
578  // \returns minimum Z measured in telescope
579  auto first = elements.begin();
580  return (*first).first;
581 }
582 
583 
584 
587 
589 {
590  // \returns mean A measured in telescope
591  double sum{0}, weight{0};
592  std::for_each(std::begin(elements), std::end(elements),
593  [&](const std::pair<int, element>& count) {
594  sum += count.second.counts;
595  weight += count.second.counts * count.second.get_mean_isotopic_mass();
596  }
597  );
598  return weight / sum;
599 }
600 
601 
602 
605 
607 {
608  // \returns maximum A measured in telescope
609  int max = 0;
610  for (auto& e : elements) {
611  max = std::max(max, e.second.get_max_isotopic_mass());
612  }
613  return max;
614 }
615 
616 
617 
620 
622 {
623  // \returns smallest A measured in telescope
624  int min = 999;
625  for (auto& e : elements) {
626  if (auto other_A = e.second.get_min_isotopic_mass())
627  min = std::min(min, other_A);
628  }
629  return min;
630 }
631 
632 
633 
634 
636 
637 
638 
#define e(i)
const char Option_t
#define N
winID h TVirtualViewer3D TVirtualGLPainter p
Helper class used by CanIdentify() to test whether particles can be identified.
void Print(Option_t *opt="") const override
void add(const KVReconstructedNucleus &N)
std::map< int, element > elements
void merge(const idtelescope *)
std::map< int, double > get_element_distribution() const
Audit of experimental data identification and calibrations.
Long64_t merge(KVDataQualityAudit *)
void Print(Option_t *opt="") const override
Long64_t Merge(TCollection *)
Bool_t HasTelescope(const TString &tel_name) const
IDStatus CanIdentify(const TString &tel_name, int Z, int &A, double E) const
idtelescope * GetTelescope(const TString &tel_name) const
KVUniqueNameList telescopes
const KVSeqCollection * GetTelescopeList() const
void Add(const KVReconstructedNucleus &N)
Add this reconstructed nucleus to the audit.
void add(const idtelescope *)
Add copy of idtelescope data to this audit.
Nuclei reconstructed from data measured by a detector array .
T * get_object(const TString &name) const
void Add(TObject *obj) override
const char * GetName() const override
virtual void Print(Option_t *option="") const
long long Long64_t
double min(double x, double y)
double max(double x, double y)
constexpr Double_t E()
double get_mean_isotopic_mass() const
calculate and return mean mass of isotopes measured for this element
std::map< double, int > get_isotopes_sorted_by_threshold() const
double get_minimum_isotopic_threshold(int &) const
std::map< int, double > get_isotopic_distribution() const
std::map< int, isotope > isotopes
Double_t counts
watch the alignment !
int get_min_isotopic_mass() const
return min A of isotopes measured for this element
double get_minimum_isotopic_threshold_mev_per_nuc(int &) const
void add(const KVReconstructedNucleus &N)
int get_max_isotopic_mass() const
return max A of isotopes measured for this element
void add(const KVReconstructedNucleus &N)
Double_t counts
watch the alignment !
TLine l
TArc a
ClassImp(TPyArg)