KaliVeda
Toolkit for HIC analysis
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  if (fDataQAudit) {
119  // use experimental thresholds etc. to decide what can be identified
120  int simA = sim_part->GetA();
121  auto status = fDataQAudit->CanIdentify(idt->GetName(), sim_part->GetZ(), simA, sim_part->GetEnergy());
122  std::stringstream comments;
123  comments << status;
124  if (status) {
125  IDR->IDOK = true;
126  IDR->Z = sim_part->GetZ();
127  IDR->Zident = true;
128  IDR->A = simA; // may have been changed in CanIdentify()
129  IDR->IDcode = idt->GetIDCode();
135  IDR->Aident = true;
136  }
139  IDR->Aident = true;
140  }
142  IDR->Aident = true;
143  }
144  else {
145  IDR->IDOK = false;
154  )
155  Warning("identify_particle",
156  "%s : %s Z=%d A=%d E=%f", comments.str().c_str(),
157  idt->GetName(), sim_part->GetZ(), sim_part->GetA(), sim_part->GetEnergy());
158  }
159  IDR->SetComment(comments.str().c_str());
160  }
161  else {
162  if (idt->CanIdentify(sim_part->GetZ(), sim_part->GetA())) {
163  IDR->Z = sim_part->GetZ();
164  IDR->A = sim_part->GetA();
165  if (idt->CheckTheoreticalIdentificationThreshold((KVNucleus*)sim_part)) {
166  IDR->IDOK = true;
167  IDR->IDcode = idt->GetIDCode();
169  // set mass identification status depending on telescope, Z, A & energy of simulated particle
170  idt->SetIdentificationStatus(IDR, sim_part);
171  }
172  else {
173  IDR->IDOK = false;
174  IDR->IDcode = GetGroup()->GetParentStructure<KVMultiDetArray>()->GetIDCodeForParticlesStoppingInFirstStageOfTelescopes();
176  IDR->SetComment("below threshold for identification");
177  }
178  }
179  else {
180  IDR->IDOK = false;
181  }
182  }
183 
184  // special case: if particle ends up in a deadzone or punches through all detector layers, having a residual energy,
185  // it would not be possible to identify it correctly.
186  if (sim_part->GetParameters()->HasDoubleParameter("RESIDUAL ENERGY")) {
187  IDR->IDOK = false;
188  IDR->IDcode = GetGroup()->GetParentStructure<KVMultiDetArray>()->GetBadIDCode();
190  IDR->SetComment(Form("particle incompletely detected, DETECTED=%s", sim_part->GetParameters()->GetStringValue("DETECTED")));
191  }
192 }
193 
194 
195 
198 
200 {
201  // After first round of identification in group, try to identify remaining particles
202 
203  int num_ident_0, num_ident;
204  int num_unident_0, num_unident;
205  do {
207  num_ident = num_ident_0 = GetNIdentifiedInGroup();
208  num_unident_0 = GetNUnidentifiedInGroup();
209  Reconstruct();
210  num_unident = GetNUnidentifiedInGroup();
211  if (num_unident > num_unident_0) {
212  Identify();
213  num_ident = GetNIdentifiedInGroup();
214  if (num_ident > num_ident_0) Calibrate();
215  }
216  }
217  while (num_ident > num_ident_0); // continue until no more new identifications occur
218 }
219 
220 
221 
223 
225 {
226  current_nuc_recon = part;
227 
229 
231  while (auto Nd = part->GetReconstructionTrajectory()->GetNextNode()) {
232  // energy_loss will contain the sum of energy losses (dE) measured in the *active* layer of each detector
233  // the contribution to the energy of each particle may be greater than this after correcting for
234  // dead layers etc.
235  energy_loss[Nd->GetName()] = Nd->GetDetector()->GetEnergyLoss();
236  ++number_uncalibrated[Nd->GetName()];
237  }
238 }
239 
240 
241 
243 
245 {
247 
248  if (PART.IsIdentified()) {
250  KVGeoDetectorNode* node;
251  while ((node = PART.GetReconstructionTrajectory()->GetNextNode())) {
252  --number_unidentified[node->GetName()];
253  }
254  }
255 }
256 
257 
258 
262 
264 {
265  // Calculate and set the energy of a (previously identified) reconstructed particle,
266  // including an estimate of the energy loss in the target.
267 
268  PART->SetIsCalibrated();
269  PART->SetECode(GetGroup()->GetParentStructure<KVMultiDetArray>()->GetNormalCalibrationCode()); // => general code for calibration with no problems, no calculated energy losses
270  double Einc = 0;
272  while (auto node = PART->GetReconstructionTrajectory()->GetNextNode()) {
273  double edet, dE;
274  auto det = node->GetDetector();
275  //Info("Calib", "det=%s", det->GetName());
276  //Info("Calib", "number_uncalibrated=%d, energy_loss=%f", number_uncalibrated[det->GetName()], energy_loss[det->GetName()]);
277  // deal with pileup in detectors
278  if (number_uncalibrated[det->GetName()] > 1 || (det != PART->GetStoppingDetector() && number_unidentified[det->GetName()] > 0)) {
279  //Info("Calib", "number_uncalib[%s]=%d, Einc=%f", det->GetName(), number_uncalibrated[det->GetName()], Einc);
280  // there are other uncalibrated particles which hit this detector
281  // the contribution for this particle must be calculated from the residual energy (Einc)
282  // deposited in all detectors so far (if any)
283  if (Einc > 0) {
284  // calculate dE in active layer for particle
285  dE = det->GetDeltaEFromERes(PART->GetZ(), PART->GetA(), Einc);
286  if (dE == 0) {
287  //Info("Calib", "dE from Eres gives 0! dead");
288  PART->SetECode(GetGroup()->GetParentStructure<KVMultiDetArray>()->GetNoCalibrationCode());
289  PART->SetIsUncalibrated();
290  break;
291  }
292  det->SetEResAfterDetector(Einc);
293  edet = det->GetCorrectedEnergy(PART, dE);
294  //Info("Calib", "calculated edet=%f from dE=%f", edet, dE);
295  // negative parameter for calculated contribution
296  PART->SetParameter(Form("%s.E%s", GetGroup()->GetParentStructure<KVMultiDetArray>()->GetName(), det->GetLabel()), -edet);
297  PART->SetECode(GetGroup()->GetParentStructure<KVMultiDetArray>()->GetCalculatedCalibrationCode()); // calculated
298  }
299  else {
300  //Info("Calib", "Einc=0, dead");
301  // nothing to do here
302  PART->SetECode(GetGroup()->GetParentStructure<KVMultiDetArray>()->GetNoCalibrationCode());
303  PART->SetIsUncalibrated();
304  break;
305  }
306  }
307  else if (det->GetNHits() > 1) {
308  // other particles hit this detector, but their contributions have already been calculated
309  // and subtracted. use remaining energy calculated in detector.
310  //Info("Calib", "det->nhits>1");
311  dE = energy_loss[det->GetName()];
312  det->SetEResAfterDetector(Einc);
313  edet = det->GetCorrectedEnergy(PART, dE);
314  // negative parameter for calculated contribution
315  PART->SetParameter(Form("%s.E%s", GetGroup()->GetParentStructure<KVMultiDetArray>()->GetName(), det->GetLabel()), -edet);
316  PART->SetECode(GetGroup()->GetParentStructure<KVMultiDetArray>()->GetCalculatedCalibrationCode()); // calculated
317  }
318  else {
319  dE = det->GetEnergyLoss();
320  det->SetEResAfterDetector(Einc);
321  edet = det->GetCorrectedEnergy(PART, -1., (Einc > 0));
322  //Info("Calib", "Simple normal dE=%f edet=%f", dE, edet);
323  PART->SetParameter(Form("%s.E%s", GetGroup()->GetParentStructure<KVMultiDetArray>()->GetName(), node->GetDetector()->GetLabel()), edet);
324  }
325  Einc += edet;
326  --number_uncalibrated[det->GetName()];
327  energy_loss[det->GetName()] -= dE;
328  det->SetEnergyLoss(energy_loss[det->GetName()]);
329  //Info("Calib", "After: number_uncalibrated=%d, energy_loss=%f", number_uncalibrated[det->GetName()], energy_loss[det->GetName()]);
330  //Info("Calib", "After: number_unidentified=%d", number_unidentified[det->GetName()]);
331  }
332  if (PART->GetECode() > 0) {
333  PART->SetEnergy(Einc);
334  // set particle momentum from telescope dimensions (random)
336  //Info("CalibrateParticle","Calibrated particle with %f MeV",Einc);
337  //add correction for target energy loss - moving charged particles only!
338  Double_t E_targ = 0.;
339  if (PART->GetZ() && PART->GetEnergy() > 0) {
340  E_targ = GetTargetEnergyLossCorrection(PART);
341  //Info("CalibrateParticle","Target energy loss %f MeV",E_targ);
342  PART->SetTargetEnergyLoss(E_targ);
343  }
344  Double_t E_tot = PART->GetEnergy() + E_targ;
345  PART->SetEnergy(E_tot);
346  //Info("CalibrateParticle","Total energy now %f MeV",E_tot);
347  }
348 }
349 
350 
352 
353 
354 
double Double_t
#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
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
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
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 &)
const TCollection * GetTrajectories() const
Definition: KVGroup.h:68
const KVGeoDNTrajectory * GetTrajectoryForReconstruction(const KVGeoDNTrajectory *t, const KVGeoDetectorNode *n) const
Definition: KVGroup.h:98
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 Int_t GetECode() const
const KVReconNucTrajectory * GetReconstructionTrajectory() const
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
virtual void SetECode(UChar_t s)
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)