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  // if ok_masses is empty, the particle's energy is below all isotopic thresholds
154  if(ok_masses.empty())
155  {
157  }
158  // get largest isotopically resolved mass above threshold
159  auto last = ok_masses.rbegin();
160  int Amax;
161  if(last != ok_masses.rend())
162  Amax = (*last).first;
163  else
164  {
165  Error("CanIdentify", "problem with ok_masses map...: tel=%s Z=%d A=%d E=%f", tel_name.Data(), Z, A, E);
166  std::cout << "contents of seuil_map:\n";
167  for(auto& p : seuil_map)
168  {
169  std::cout << "seuil_map[" << p.first << "] = " << p.second << std::endl;
170  }
172  }
173  // get smallest isotopically resolved mass above threshold
174  auto first = ok_masses.begin();
175  auto Amin = (*first).first;
176  if (A > Amax) {
178  }
179  else if (A < Amin) {
181  }
182  else {
183  int adiff(999), near_a(-1);
184  for (auto& p : ok_masses) {
185  auto diff = std::abs(p.first - A);
186  if (diff < adiff) {
187  adiff = diff;
188  near_a = p.first;
189  }
190  }
191  A = near_a;
193  }
194  // should never get here?
196 }
197 
198 
199 
202 
204 {
205  // Add copy of idtelescope data to this audit
206  telescopes.Add(new idtelescope(*idt));
207 }
208 
209 
210 
214 
216 {
217  // Merge other audit object with this one. Return 1 if merge is successful,
218  // 0 in case of problems.
219  if (!other) return 0; // possibly called for wrong object type
220 
221  TIter next_tel(other->GetTelescopeList());
222  idtelescope* idt;
223  Long64_t nmerge = 0;
224  while ((idt = (idtelescope*)next_tel())) {
225  if (HasTelescope(idt))
226  GetTelescope(idt)->merge(idt);
227  else
228  add(idt);
229  ++nmerge;
230  }
231  return nmerge;
232 }
233 
234 
235 
240 
242 {
243  // add an isotopically identified nucleus
244  //
245  // for calibrated particles, we store the minimum energy (=> threshold)
246  A = N.GetA();
247  ++counts;
248  if (N.IsCalibrated() && ((emin < 0) || (N.GetEnergy() < emin))) emin = N.GetEnergy();
249 }
250 
251 
252 
254 
256 {
257  std::cout << "\t\tA=" << A << "\t\t[E>" << emin << "]" << std::endl;
258 }
259 
260 
261 
268 
270 {
271  // add an element (Z-identified nucleus)
272  //
273  // if isotopically identified, add to list of isotopes
274  //
275  // for calibrated particles, we store the minimum energy (=> threshold)
276  if (N.GetZ() > 0) Z = N.GetZ();
277  ++counts;
278  if (N.IsCalibrated() && ((emin < 0) || (N.GetEnergy() < emin))) emin = N.GetEnergy();
279  if (N.IsAMeasured()) {
280  isotopes[N.GetA()].add(N);
281  }
282  else if (N.GetA() > 0) A = N.GetA(); // default mass for Z-only identification
283 }
284 
285 
286 
288 
290 {
291  std::cout << "\tZ=" << (int)Z << "\t\t[E>" << emin << "]";
292  if (A > 0) std::cout << " default A=" << A;
293  if (!HasIsotopes()) {
294  std::cout << std::endl;
295  return;
296  }
297  std::cout << "\t\tIsotopes: " << GetIsotopeList().AsString() << std::endl;
298  for (auto i : isotopes) i.second.print();
299 }
300 
301 
302 
310 
312 {
313  // Merge the informations in element elem with those in this one:
314  //
315  // - we keep the lower of the two threshold values
316  // - we sum the counts for the element
317  // - we merge the lists of isotopes of the two elements
318  // - we keep the default mass, if it has been set
319 
320  if (emin > 0) {
321  if (elem.emin > 0) emin = std::min(emin, elem.emin);
322  }
323  else if (elem.emin > 0) emin = elem.emin;
324  A = std::max(A, elem.A);
325  counts += elem.counts;
326  // look at isotopes in other's list. if any are not in our list they are added.
327  // if any are in both, they are merged
328  std::for_each(std::begin(elem.isotopes), std::end(elem.isotopes),
329  [&](const std::pair<int, isotope>& isotop) {
330  if (HasIsotope(isotop.first)) {
331  isotopes[isotop.first].merge(isotop.second);
332  }
333  else {
334  isotopes[isotop.first] = isotop.second;
335  }
336  }
337  );
338 }
339 
340 
341 
344 
346 {
347  // calculate and return mean mass of isotopes measured for this element
348 
349  if (isotopes.empty()) return 0;
350  double sum{0}, weight{0};
351  std::for_each(std::begin(isotopes), std::end(isotopes),
352  [&](const std::pair<int, isotope>& count) {
353  sum += count.second.counts;
354  weight += count.first * count.second.counts;
355  }
356  );
357  if (sum > 0) return weight / sum;
358  return 0;
359 }
360 
361 
362 
365 
367 {
368  // return max A of isotopes measured for this element
369 
370  if (isotopes.empty()) return 0;
371  auto last = isotopes.rbegin();
372  return (*last).first;
373 }
374 
375 
376 
379 
381 {
382  // return min A of isotopes measured for this element
383 
384  if (isotopes.empty()) return 0;
385  auto first = isotopes.begin();
386  return (*first).first;
387 }
388 
389 
390 
394 
396 {
397  // \returns the smallest recorded threshold (in MeV/u) for isotopic identification for the element
398  // \param[out] a mass number corresponding to minimum
399  a = -1;
400  if (isotopes.empty()) return -1;
401  double minE = 9999;
402  for (auto& p : isotopes) {
403  double myE = p.second.emin / p.first;
404  if ((myE > 0) && (myE < minE)) {
405  minE = myE;
406  a = p.first;
407  }
408  }
409  if (minE < 9999) return minE;
410  // uncalibrated particles: all thresholds are -1 MeV
411  return -1;
412 }
413 
414 
415 
419 
421 {
422  // \returns the smallest recorded threshold (in MeV) for isotopic identification for the element
423  // \param[out] a mass number corresponding to minimum
424  a = -1;
425  if (isotopes.empty()) return -1;
426  double minE = 9999;
427  for (auto& p : isotopes) {
428  double myE = p.second.emin;
429  if ((myE > 0) && (myE < minE)) {
430  minE = myE;
431  a = p.first;
432  }
433  }
434  if (minE < 9999) return minE;
435  // uncalibrated particles: all thresholds are -1 MeV
436  return -1;
437 }
438 
439 
440 
443 
445 {
446  // \returns a map sorted according to increasing identification threshold of isotope mass numbers
447 
448  std::map<double, int> seuils;
449  for (auto& i : isotopes) {
450  seuils[i.second.GetIdThreshold()] = i.first;
451  }
452  return seuils;
453 }
454 
455 
456 
459 
461 {
462  // \returns probability distribution for each isotope as a map between isotope A and P(A)
463 
464  double sum{0};
465  std::for_each(std::begin(isotopes), std::end(isotopes),
466  [&](const std::pair<int, isotope>& count) {
467  sum += count.second.counts;
468  }
469  );
470  std::map<int, double> proba;
471  for (auto& p : isotopes) {
472  proba[p.first] = p.second.counts / sum;
473  }
474  return proba;
475 }
476 
477 
478 
480 
482 {
483  elements[N.GetZ()].add(N);
484 }
485 
486 
487 
489 
491 {
492  std::cout << GetName() << " :" << std::endl;
493  std::cout << "Elements: " << GetElementList().AsString() << std::endl;
494  for (auto e : elements) e.second.print();
495 }
496 
497 
498 
503 
505 {
506  // Merge data in idtelescope idt with this one
507 
508  // look at elements in other's list. if any are not in our list they are added.
509  // if any are in both, they are merged
510  std::for_each(std::begin(idt->elements), std::end(idt->elements),
511  [&](const std::pair<int, element>& elem) {
512  if (HasElement(elem.first)) {
513  elements[elem.first].merge(elem.second);
514  }
515  else {
516  elements[elem.first] = elem.second;
517  }
518  }
519  );
520 }
521 
522 
523 
526 
528 {
529  // \returns probability distribution for all elements identified by telescope as a map between Z and P(Z)
530 
531  double sum{0};
532  std::for_each(std::begin(elements), std::end(elements),
533  [&](const std::pair<int, element>& count) {
534  sum += count.second.counts;
535  }
536  );
537  std::map<int, double> proba;
538  for (auto& p : elements) {
539  proba[p.first] = p.second.counts / sum;
540  }
541  return proba;
542 }
543 
544 
545 
548 
550 {
551  // \returns mean Z measured in telescope
552  double sum{0}, weight{0};
553  std::for_each(std::begin(elements), std::end(elements),
554  [&](const std::pair<int, element>& count) {
555  sum += count.second.counts;
556  weight += count.second.counts * count.first;
557  }
558  );
559  return weight / sum;
560 }
561 
562 
563 
566 
568 {
569  // \returns maximum Z measured in telescope
570  auto last = elements.rbegin();
571  return (*last).first;
572 }
573 
574 
577 
579 {
580  // \returns maximum Z for which isotopic masses were measured
581  auto it = elements.rbegin();
582  while (it != elements.rend()) {
583  if ((*it).second.HasIsotopes()) return (*it).first;
584  ++it;
585  }
586  return 0;
587 }
588 
589 
592 
594 {
595  // \returns minimum Z measured in telescope
596  auto first = elements.begin();
597  return (*first).first;
598 }
599 
600 
601 
604 
606 {
607  // \returns mean A measured in telescope
608  double sum{0}, weight{0};
609  std::for_each(std::begin(elements), std::end(elements),
610  [&](const std::pair<int, element>& count) {
611  sum += count.second.counts;
612  weight += count.second.counts * count.second.get_mean_isotopic_mass();
613  }
614  );
615  return weight / sum;
616 }
617 
618 
619 
622 
624 {
625  // \returns maximum A measured in telescope
626  int max = 0;
627  for (auto& e : elements) {
628  max = std::max(max, e.second.get_max_isotopic_mass());
629  }
630  return max;
631 }
632 
633 
634 
637 
639 {
640  // \returns smallest A measured in telescope
641  int min = 999;
642  for (auto& e : elements) {
643  if (auto other_A = e.second.get_min_isotopic_mass())
644  min = std::min(min, other_A);
645  }
646  return min;
647 }
648 
649 
650 
651 
653 
654 
655 
#define e(i)
const char Option_t
#define N
winID h TVirtualViewer3D TVirtualGLPainter p
void Error(const char *method, const char *msgfmt,...) const override
Definition: KVBase.cpp:1666
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
const char * Data() 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)