Loading [MathJax]/extensions/tex2jax.js
KaliVeda
Toolkit for HIC analysis
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Modules Pages
KVFilterGroupReconstructor.cpp
1 #include "KVFilterGroupReconstructor.h"
2 #include "KVIDZAGrid.h"
3 #include "KVMultiDetArray.h"
4 #include "KVNucleusEvent.h"
5 
6 
11 
13 {
14  // We look for a simulated particle stopped in the same node with the same trajectory.
15  // We use the actual trajectory of the simulated particle to get the right reconstruction trajectory
16 
17  //Info("get_recon_traj","traj=%s node=%s",traj->GetPathString().Data(), node->GetName());
18  KVReconNucTrajectory* Rtraj{nullptr};
19  for (auto& n : EventIterator(fSimEvent.get())) {
20  TString stop = n.GetParameters()->GetTStringValue("STOPPING DETECTOR");
21  //Info("get_recon_traj", "stop=%s", stop.Data());
22  if (stop == node->GetName()) {
24  if (Rtraj) {
25  //Info("get_recon_traj","Rtraj=%s TRAJECTORY=%s",Rtraj->GetPathString().Data(),n.GetParameters()->GetStringValue("TRAJECTORY"));
26  auto traj_string = n.GetParameters()->GetTStringValue("TRAJECTORY");
27  auto traj_in_grp = (KVGeoDNTrajectory*)GetGroup()->GetTrajectories()->FindObject(traj_string);
28  if ((Rtraj->GetPathString() == traj_string) || (traj_in_grp && Rtraj->ContainsTrajectory(traj_in_grp))) {
29  // correspondence recon <-> simu
30  //Info("get_recon_traj","sim particle added to part_correspond");
32  // copy simulated particle parameters to reconstructed particle
33  n.GetParameters()->Copy(*current_nuc_recon->GetParameters());
34  }
35  }
36  }
37  }
38  if (!Rtraj) {
39  Info("get_recon_traj_for_particle", "%p : noRtraj for this: %s %s", this, node->GetName(), traj->GetPathString().Data());
40  if (!fSimEvent->GetMult()) {
41  Info("get_recon_traj_for_particle", "%p : sim event is empty", this);
42  }
43  }
44  return Rtraj;
45 }
46 
47 
48 
54 
56 {
57  // check associated simulated particle passes identification threshold
58  //
59  // if more than one simulated particle stopped in the same detector, we add the Z, A and E of each particle together
60  // and merge the lists of parameters into one.
61 
62  int multihit;
63  if ((multihit = part_correspond[&nuc].GetEntries()) > 1) {
64  KVNucleus sum_part;
65  TIter next(&part_correspond[&nuc]);
66  KVNucleus* N;
68  // the parameter lists are added to q because the KVNucleus operator+ does
69  // not retain any parameters from either of its arguments
70  while ((N = (KVNucleus*)next())) {
71  sum_part += *N;
72  q.Merge(*N->GetParameters());
73  }
74  sum_part.GetParameters()->Merge(q);
75  auto sim_part = (KVNucleus*)part_correspond[&nuc].First();
76  // replace properties of first nucleus in list with summed properties
77  part_correspond[&nuc].Clear();
78  sum_part.Copy(*sim_part);
79  part_correspond[&nuc].Add(sim_part);
80  sim_part->SetParameter("PILEUP", Form("%d particles in %s", multihit, nuc.GetStoppingDetector()->GetName()));
81  // check 'string' parameters (TRAJECTORY,STOPPING DETECTOR,DETECTED)
82  // 'merging' string parameters forms a comma-separated list of individual values
83  // these should be replaced with a single value - unless they are not all the same!?!
84  for (auto& param : *sim_part->GetParameters()) {
85  KVString unique_value;
86  if (param.IsString()) {
87  KVString sparam(param.GetString());
88  sparam.Begin(",");
89  auto next = sparam.Next();
90  if (unique_value.IsNull())
91  unique_value = next;
92  else {
93  if (next != unique_value) {
94  Warning("identify_particle", "different values of %s for %d-particle pileup in %s:%s, %s, ...",
95  param.GetName(), multihit, nuc.GetStoppingDetector()->GetName(), unique_value.Data(), next.Data());
96  }
97  }
98  param.Set(unique_value);
99  }
100  }
101  nuc.GetParameters()->Concatenate(*sim_part->GetParameters());
102  }
103  auto sim_part = (KVNucleus*)part_correspond[&nuc].First();
104 
105  IDR->SetIDType(idt->GetType());
106  IDR->IDattempted = true;
107 
108  // why does this happen???
109  if (!sim_part) {
110  Info("identify_particle", "sim_part=nullptr; multihit=%d", multihit);
111  Info("identify_particle", "sim_event contains:");
112  fSimEvent->Print();
113  Info("identify_particle", "recon_nuc stopping detector is: %s", nuc.GetStoppingDetector()->GetName());
114  nuc.Print();
115  Fatal("identify_particle", "no sim_part for recon_nuc!");
116  }
117 
118  check_identification_threshold(sim_part, idt, IDR);
119 
120  // special case: if particle ends up in a deadzone or punches through all detector layers, having a residual energy,
121  // it would not be possible to identify it correctly.
122  if (sim_part->GetParameters()->HasDoubleParameter("RESIDUAL ENERGY")) {
123  IDR->IDOK = false;
124  IDR->IDcode = GetGroup()->GetParentStructure<KVMultiDetArray>()->GetBadIDCode();
126  IDR->SetComment(Form("particle incompletely detected, DETECTED=%s", sim_part->GetParameters()->GetStringValue("DETECTED")));
127  }
128 }
129 
130 
131 
140 
142 {
143  // Check that identification is possible for the given nucleus with its Z, A and (total) kinetic energy.
144  // The nucleus in question may be from the simulation (KVSimNucleus) or from the reconstruction (KVReconstructedNucleus).
145  // The KVIdentificationResult (identification status of the nucleus) may be changed by this method:
146  // a particle previously thought identified may become unidentified here, as the reconstructed energy is
147  // lower than the simulated energy, and therefore below the experimental threshold, although the "real"
148  // energy of the simulated nucleus permitted its identification. If we don't do this, we end up with the
149  // inconsistent final result of identified particles with energies below the experimental identification threshold.
150 
151  if (fDataQAudit) {
152  // use experimental thresholds etc. to decide what can be identified
153  int A = nuc->GetA();
154  auto status = fDataQAudit->CanIdentify(idt->GetName(), nuc->GetZ(), A, nuc->GetEnergy());
155  std::stringstream comments;
156  comments << status;
157  if (status) {
158  IDR->IDOK = true;
159  IDR->Z = nuc->GetZ();
160  IDR->Zident = true;
161  IDR->A = A; // may have been changed in CanIdentify()
162  IDR->IDcode = idt->GetIDCode();
163  IDR->Aident = false;
169  IDR->Aident = true;
170  }
173  IDR->Aident = true;
174  }
176  IDR->Aident = true;
177  }
178  else {
179  IDR->IDOK = false;
188  )
189  Warning("identify_particle",
190  "%s : %s Z=%d A=%d E=%f", comments.str().c_str(),
191  idt->GetName(), nuc->GetZ(), nuc->GetA(), nuc->GetEnergy());
192  }
193  IDR->SetComment(comments.str().c_str());
194  }
195  else {
196  if (idt->CanIdentify(nuc->GetZ(), nuc->GetA())) {
197  IDR->Z = nuc->GetZ();
198  IDR->A = nuc->GetA();
200  IDR->IDOK = true;
201  IDR->IDcode = idt->GetIDCode();
203  // set mass identification status depending on telescope, Z, A & energy of simulated particle
204  idt->SetIdentificationStatus(IDR, nuc);
205  }
206  else {
207  IDR->IDOK = false;
208  IDR->IDcode = GetGroup()->GetParentStructure<KVMultiDetArray>()->GetIDCodeForParticlesStoppingInFirstStageOfTelescopes();
210  IDR->SetComment("below threshold for identification");
211  }
212  }
213  else {
214  IDR->IDOK = false;
215  }
216  }
217 }
218 
219 
220 
223 
225 {
226  // After first round of identification in group, try to identify remaining particles
227 
228  int num_ident_0, num_ident;
229  int num_unident_0, num_unident;
230  do {
232  num_ident = num_ident_0 = GetNIdentifiedInGroup();
233  num_unident_0 = GetNUnidentifiedInGroup();
234  Reconstruct();
235  num_unident = GetNUnidentifiedInGroup();
236  if (num_unident > num_unident_0) {
237  Identify();
238  num_ident = GetNIdentifiedInGroup();
239  if (num_ident > num_ident_0) Calibrate();
240  }
241  }
242  while (num_ident > num_ident_0); // continue until no more new identifications occur
243 }
244 
245 
246 
248 
250 {
251  current_nuc_recon = part;
252 
254 
256  while (auto Nd = part->GetReconstructionTrajectory()->GetNextNode()) {
257  // energy_loss will contain the sum of energy losses (dE) measured in the *active* layer of each detector
258  // the contribution to the energy of each particle may be greater than this after correcting for
259  // dead layers etc.
260  energy_loss[Nd->GetName()] = Nd->GetDetector()->GetEnergyLoss();
261  ++number_uncalibrated[Nd->GetName()];
262  }
263 }
264 
265 
266 
268 
270 {
272 
273  if (PART.IsIdentified()) {
275  KVGeoDetectorNode* node;
276  while ((node = PART.GetReconstructionTrajectory()->GetNextNode())) {
277  --number_unidentified[node->GetName()];
278  }
279  }
280 }
281 
282 
283 
287 
289 {
290  // Calculate and set the energy of a (previously identified) reconstructed particle,
291  // including an estimate of the energy loss in the target.
292 
293  PART->SetIsCalibrated();
294  PART->SetECode(GetGroup()->GetParentStructure<KVMultiDetArray>()->GetNormalCalibrationCode()); // => general code for calibration with no problems, no calculated energy losses
295  double Einc = 0;
297  while (auto node = PART->GetReconstructionTrajectory()->GetNextNode()) {
298  double edet, dE;
299  auto det = node->GetDetector();
300  //Info("Calib", "det=%s", det->GetName());
301  //Info("Calib", "number_uncalibrated=%d, energy_loss=%f", number_uncalibrated[det->GetName()], energy_loss[det->GetName()]);
302  // deal with pileup in detectors
303  if (number_uncalibrated[det->GetName()] > 1 || (det != PART->GetStoppingDetector() && number_unidentified[det->GetName()] > 0)) {
304  //Info("Calib", "number_uncalib[%s]=%d, Einc=%f", det->GetName(), number_uncalibrated[det->GetName()], Einc);
305  // there are other uncalibrated particles which hit this detector
306  // the contribution for this particle must be calculated from the residual energy (Einc)
307  // deposited in all detectors so far (if any)
308  if (Einc > 0) {
309  // calculate dE in active layer for particle
310  dE = det->GetDeltaEFromERes(PART->GetZ(), PART->GetA(), Einc);
311  if (dE == 0) {
312  //Info("Calib", "dE from Eres gives 0! dead");
313  PART->SetECode(GetGroup()->GetParentStructure<KVMultiDetArray>()->GetNoCalibrationCode());
314  PART->SetIsUncalibrated();
315  break;
316  }
317  det->SetEResAfterDetector(Einc);
318  edet = det->GetCorrectedEnergy(PART, dE);
319  //Info("Calib", "calculated edet=%f from dE=%f", edet, dE);
320  // negative parameter for calculated contribution
321  PART->SetParameter(Form("%s.E%s", GetGroup()->GetParentStructure<KVMultiDetArray>()->GetName(), det->GetLabel()), -edet);
322  PART->SetECode(GetGroup()->GetParentStructure<KVMultiDetArray>()->GetCalculatedCalibrationCode()); // calculated
323  }
324  else {
325  //Info("Calib", "Einc=0, dead");
326  // nothing to do here
327  PART->SetECode(GetGroup()->GetParentStructure<KVMultiDetArray>()->GetNoCalibrationCode());
328  PART->SetIsUncalibrated();
329  break;
330  }
331  }
332  else if (det->GetNHits() > 1) {
333  // other particles hit this detector, but their contributions have already been calculated
334  // and subtracted. use remaining energy calculated in detector.
335  //Info("Calib", "det->nhits>1");
336  dE = energy_loss[det->GetName()];
337  det->SetEResAfterDetector(Einc);
338  edet = det->GetCorrectedEnergy(PART, dE);
339  // negative parameter for calculated contribution
340  PART->SetParameter(Form("%s.E%s", GetGroup()->GetParentStructure<KVMultiDetArray>()->GetName(), det->GetLabel()), -edet);
341  PART->SetECode(GetGroup()->GetParentStructure<KVMultiDetArray>()->GetCalculatedCalibrationCode()); // calculated
342  }
343  else {
344  dE = det->GetEnergyLoss();
345  det->SetEResAfterDetector(Einc);
346  edet = det->GetCorrectedEnergy(PART, -1., (Einc > 0));
347  //Info("Calib", "Simple normal dE=%f edet=%f", dE, edet);
348  PART->SetParameter(Form("%s.E%s", GetGroup()->GetParentStructure<KVMultiDetArray>()->GetName(), node->GetDetector()->GetLabel()), edet);
349  }
350  Einc += edet;
351  --number_uncalibrated[det->GetName()];
352  energy_loss[det->GetName()] -= dE;
353  det->SetEnergyLoss(energy_loss[det->GetName()]);
354  //Info("Calib", "After: number_uncalibrated=%d, energy_loss=%f", number_uncalibrated[det->GetName()], energy_loss[det->GetName()]);
355  //Info("Calib", "After: number_unidentified=%d", number_unidentified[det->GetName()]);
356  }
357  if (PART->GetECode() > 0) {
358  PART->SetEnergy(Einc);
359  // set particle momentum from telescope dimensions (random)
361  //Info("CalibrateParticle","Calibrated particle with %f MeV",Einc);
362  //add correction for target energy loss - moving charged particles only!
363  Double_t E_targ = 0.;
364  if (PART->GetZ() && PART->GetEnergy() > 0) {
365  E_targ = GetTargetEnergyLossCorrection(PART);
366  //Info("CalibrateParticle","Target energy loss %f MeV",E_targ);
367  PART->SetTargetEnergyLoss(E_targ);
368  }
369  Double_t E_tot = PART->GetEnergy() + E_targ;
370  PART->SetEnergy(E_tot);
371  //Info("CalibrateParticle","Total energy now %f MeV",E_tot);
372 
373  // to avoid inconsistencies in reconstructed data, now that we have 'calibrated' the particle,
374  // we re-check that its identification is consistent with its apparent energy if the latter
375  // is lower than the energy of the simulated particle
376  if (E_tot < PART->GetParameters()->GetDoubleValue("SIM:ENERGY")) {
377  //Warning("CalibrateParticle", "Apparent energy lower than real energy. Initial idendtification:");
378  auto idt = PART->GetIdentifyingTelescope();
379  auto IDR = PART->GetIdentificationResult(idt);
380  //std::cout << std::endl; IDR->Print(); std::cout << std::endl;
381  check_identification_threshold(PART, idt, IDR);
382  //Warning("CalibrateParticle", "Revised idendtification:");
383  //std::cout << std::endl; IDR->Print(); std::cout << std::endl;
384  if (IDR->IDOK) {
385  // Initial identification is still valid, but fine details may have changed...
386  PART->SetIdentification(IDR, idt);
387  // in case particle mass number changes, which changes the total (and kinetic) energy:
388  // we keep the same energy as calculated from measured losses in detectors,
389  // to stay coherent with the latter
390  PART->SetEnergy(E_tot);
391  }
392  else {
393  // initial identification is no longer valid. look for another?
394  // set first successful identification as particle identification
395  // as long as the id telescope concerned contains the stopping detector!
396  const KVSeqCollection* idt_list = PART->GetReconstructionTrajectory()->GetIDTelescopes();
397  TIter next(idt_list);
398  Int_t id_no = 1;
399  Bool_t ok = kFALSE;
401  idt = (KVIDTelescope*)next();
402  while (idt && idt->HasDetector(PART->GetStoppingDetector())) {
403  if (pid->IDattempted && pid->IDOK) {
404  ok = kTRUE;
405  partID = *pid;
406  identifying_telescope = idt;
407  break;
408  }
409  ++id_no;
410  pid = PART->GetIdentificationResult(id_no);
411  idt = (KVIDTelescope*)next();
412  }
413  if (ok) { // particle was already identified
415  // in case particle mass number changes, which changes the total (and kinetic) energy:
416  // we keep the same energy as calculated from measured losses in detectors,
417  // to stay coherent with the latter
418  PART->SetEnergy(E_tot);
419  }
420  else {
421  PART->SetIsUnidentified();
422  PART->SetIDCode(GetGroup()->GetParentStructure<KVMultiDetArray>()->GetBadIDCode());
423  }
424  }
425  }
426  }
427 }
428 
429 
431 
432 
433 
int Int_t
bool Bool_t
constexpr Bool_t kFALSE
double Double_t
constexpr Bool_t kTRUE
void GetParameters(TFitEditor::FuncParams_t &pars, TF1 *func)
#define N
float * q
char * Form(const char *fmt,...)
Class for iterating over nuclei in events accessed through base pointer/reference.
virtual const Char_t * GetType() const
Definition: KVBase.h:176
IDStatus CanIdentify(const TString &tel_name, int Z, int &A, double E) const
Reconstruct particles in group of detectors after filtering simulated events.
KVReconstructedNucleus * current_nuc_recon
correspondence between reconstructed and simulated particles
void IdentifyParticle(KVReconstructedNucleus &PART) override
void PerformSecondaryAnalysis()
After first round of identification in group, try to identify remaining particles.
std::unique_ptr< KVEvent > fSimEvent
experimental data on identification thresholds & capabilities
std::unordered_map< std::string, double > energy_loss
temporary, store argument to ReconstructParticle
KVReconNucTrajectory * get_recon_traj_for_particle(const KVGeoDNTrajectory *, const KVGeoDetectorNode *node) override
number of particles hitting detector aas yet unidentified
std::unordered_map< KVReconstructedNucleus *, TList > part_correspond
count simulated particles in stopping detectors
void ReconstructParticle(KVReconstructedNucleus *part, const KVGeoDNTrajectory *traj, const KVGeoDetectorNode *node) override
void check_identification_threshold(KVNucleus *, KVIDTelescope *idt, KVIdentificationResult *IDR)
std::unordered_map< std::string, int > number_uncalibrated
energy losses in detectors
const KVDataQualityAudit * fDataQAudit
void identify_particle(KVIDTelescope *idt, KVIdentificationResult *IDR, KVReconstructedNucleus &nuc) override
std::unordered_map< std::string, int > number_unidentified
number of particles for which the energy contribution of detector has not yet been set
void CalibrateParticle(KVReconstructedNucleus *PART) override
Path taken by particles through multidetector geometry.
KVGeoDetectorNode * GetNextNode() const
KVString GetPathString() const
void IterateFrom(const KVGeoDetectorNode *node0=nullptr) const
const KVSeqCollection * GetIDTelescopes() const
Information on relative positions of detectors & particle trajectories.
const Char_t * GetName() const override
Name of node is same as name of associated detector.
KVGeoStrucElement * GetParentStructure(const Char_t *type, const Char_t *name="") const
KVIDTelescope * identifying_telescope
telescope which identified current particle
virtual void ReconstructParticle(KVReconstructedNucleus *part, const KVGeoDNTrajectory *traj, const KVGeoDetectorNode *node)
KVGroup * GetGroup() const
void Calibrate()
Calculate and set energies of all Z-identified but uncalibrated charged particles in event.
Double_t GetTargetEnergyLossCorrection(KVReconstructedNucleus *ion)
virtual void IdentifyParticle(KVReconstructedNucleus &)
KVIdentificationResult partID
identification to be applied to current particle
const TCollection * GetTrajectories() const
Definition: KVGroup.h:87
const KVGeoDNTrajectory * GetTrajectoryForReconstruction(const KVGeoDNTrajectory *t, const KVGeoDetectorNode *n) const
Definition: KVGroup.h:117
Base class for all detectors or associations of detectors in array which can identify charged particl...
Definition: KVIDTelescope.h:84
virtual Bool_t CheckTheoreticalIdentificationThreshold(KVNucleus *, Double_t=0.0)
virtual Bool_t CanIdentify(Int_t Z, Int_t)
virtual UShort_t GetIDCode()
virtual void SetIdentificationStatus(KVIdentificationResult *IDR, const KVNucleus *)
Full result of one attempted particle identification.
Bool_t IDattempted
=kTRUE if identification was attempted
Bool_t IDOK
general quality of identification, =kTRUE if acceptable identification made
void SetComment(const Char_t *c)
Bool_t Aident
= kTRUE if A of particle established
Int_t A
A of particle found (if Aident==kTRUE)
Int_t Z
Z of particle found (if Zident==kTRUE)
Int_t IDquality
specific quality code returned by identification procedure
Int_t IDcode
a general identification code for this type of identification
void SetIDType(const Char_t *t)
Bool_t Zident
=kTRUE if Z of particle established
Base class for describing the geometry of a detector array.
Handles lists of named parameters with different types, a list of KVNamedParameter objects.
void Merge(const KVNameValueList &)
Description of properties and kinematics of atomic nuclei.
Definition: KVNucleus.h:123
void Copy(TObject &) const override
Copy this KVNucleus into the KVNucleus object referenced by "obj".
Definition: KVNucleus.cpp:827
Int_t GetA() const
Definition: KVNucleus.cpp:792
Int_t GetZ() const
Return the number of proton / atomic number.
Definition: KVNucleus.cpp:763
KVNameValueList * GetParameters() const
Definition: KVParticle.h:818
Double_t GetEnergy() const
Definition: KVParticle.h:624
void SetParameter(const Char_t *name, ValType value) const
Definition: KVParticle.h:822
void SetEnergy(Double_t e)
Definition: KVParticle.h:602
Path through detector array used to reconstruct detected particle.
Nuclei reconstructed from data measured by a detector array .
virtual void SetIDCode(UShort_t s)
virtual Int_t GetECode() const
KVIdentificationResult * GetIdentificationResult(Int_t i)
const KVReconNucTrajectory * GetReconstructionTrajectory() const
void SetIdentification(KVIdentificationResult *, KVIDTelescope *)
KVDetector * GetStoppingDetector() const
void SetDetector(int i, KVDetector *);
virtual void SetTargetEnergyLoss(Double_t e)
virtual void GetAnglesFromReconstructionTrajectory(Option_t *opt="random")
void Print(Option_t *option="") const override
KVIDTelescope * GetIdentifyingTelescope() const
virtual void SetECode(UChar_t s)
KaliVeda extensions to ROOT collection classes.
Extension of ROOT TString class which allows backwards compatibility with ROOT v3....
Definition: KVString.h:73
void Begin(TString delim) const
Definition: KVString.cpp:565
KVString Next(Bool_t strip_whitespace=kFALSE) const
Definition: KVString.cpp:695
TObject * FindObject(const char *name) const override
const char * GetName() const override
virtual void Warning(const char *method, const char *msgfmt,...) const
virtual void Fatal(const char *method, const char *msgfmt,...) const
virtual void Info(const char *method, const char *msgfmt,...) const
const char * Data() const
Bool_t IsNull() const
const Int_t n
ClassImp(TPyArg)