KaliVeda
Toolkit for HIC analysis
KVGroupReconstructor.cpp
1 #include "KVGroupReconstructor.h"
2 #include "KVMultiDetArray.h"
3 #include "KVTarget.h"
4 
5 #include <TPluginManager.h>
6 using std::cout;
7 using std::endl;
8 
10 
13 
14 
17 
19  : KVBase("KVGroupReconstructor", "Reconstruction of particles in detector groups"),
20  fGrpEvent(nullptr)
21 {
22  // Default constructor
23  SetGroup(g);
24 }
25 
26 
27 
30 
32 {
33  // Destructor
34 
36 }
37 
38 
39 
44 
46 {
47  // Set the group to be reconstructed
48  //
49  // Set condition for seeding reconstructed particles
50  fGroup = const_cast<KVGroup*>(g);
52 }
53 
54 
55 
58 
60 {
61  // Instantiate event fragment object
62 
63  if (!fGrpEvent) fGrpEvent = (KVReconstructedEvent*)c->New();
64 }
65 
66 
67 
72 
74 {
75  // Create a new object of a class derived from KVGroupReconstructor defined by a plugin
76  //
77  // If plugin="" this is just a new KVGroupReconstructor instance
78 
79  if (plugin == "") return new KVGroupReconstructor(g);
80  TPluginHandler* ph = LoadPlugin("KVGroupReconstructor", plugin);
81  if (ph) {
82  return (KVGroupReconstructor*)ph->ExecPlugin(1, g);
83  }
84  return nullptr;
85 }
86 
87 
88 
96 
98 {
99  // Perform full reconstruction of particles detected in group.
100  //
101  // This will call in order Reconstruct(), Identify(), Calibrate() and AddCoherencyParticles()
102  //
103  // - identification can be inhibited (for all groups) by calling KVGroupReconstructor::SetDoIdentification(false);
104  // - calibration can be inhibited (for all groups) by calling KVGroupReconstructor::SetDoCalibration(false);
105 
106  nfireddets = 0;
107  coherency_particles.clear();
108  Reconstruct();
109  if (GetEventFragment()->GetMult() == 0) {
110  return;
111  }
113  if (fDoCalibration) {
114  Calibrate();
116  }
117 }
118 
119 
120 
129 
131 {
132  // Reconstruct the particles in the group from hit trajectories
133  //
134  // We work our way along each trajectory, starting from the furthest detector from the target,
135  // and start reconstruction of a new detected particle depending on decision made in ReconstructTrajectory()
136  // for each detector we try (normally just the first fired detector we find).
137  //
138  // The reconstruction is then handled by ReconstructParticle().
139 
140  TIter nxt_traj(GetGroup()->GetTrajectories());
141  KVGeoDNTrajectory* traj;
142 
143  auto old_mult = GetEventFragment()->GetMult();
144 
145  // loop over trajectories
146  while ((traj = (KVGeoDNTrajectory*)nxt_traj())) {
147 
148  // Work our way along the trajectory, starting from furthest detector from target,
149  // start reconstruction of new detected particle from first fired detector.
150  traj->IterateFrom();
151  KVGeoDetectorNode* node;
152  while ((node = traj->GetNextNode())) {
153 
155  if ((kvdp = ReconstructTrajectory(traj, node))) {
156  ReconstructParticle(kvdp, traj, node);
157  break; //start next trajectory
158  }
159 
160  }
161 
162  }
163 
164  if (GetEventFragment()->GetMult() > old_mult) {
167  }
168 }
169 
170 
171 
176 
178 {
179  // This method will be called after reconstruction and first-order coherency analysis
180  // of all particles in the group (if there are any reconstructed particles).
181  // By default it does nothing.
182 }
183 
184 
185 
195 
197 {
198  // \param traj trajectory currently being scanned
199  // \param node current detector on trajectory to test
200  // \returns pointer to a new reconstructed particle added to this group's event; nullptr if nothing is to be done
201  //
202  // The condition which must be fulfilled for us to begin the reconstruction of a new particle starting from
203  // a fired detector on the trajectory is either:
204  // - the trajectory is the only one which passes through this detector; or
205  // - the detector directly in front of this one on this trajectory also fired.
206 
207  KVDetector* d = node->GetDetector();
208  nfireddets += d->Fired();
209  // if d has fired, has not been used to seed a reconstructed particle (IsAnalysed),
210  // is not on the trajectory of a reconstructed particle (GetHits()->GetEntries()),
211  // and only if the detector belongs to a unique trajectory (i.e. neither multiple trajectories
212  // arrive from behind nor continue in front)
213  if (
214  !d->IsAnalysed() && d->Fired(GetPartSeedCond())
215  && (!d->GetHits() || !d->GetHits()->GetEntries())
216  && (node->GetNTrajForwards() <= 1 && node->GetNTrajBackwards() <= 1)
217  )
218  return GetEventFragment()->AddParticle();
219 
220  return nullptr;
221 }
222 
223 
224 
226 
228 {
230 }
231 
232 
233 
245 
247 {
248  // Reconstruction of a detected nucleus from the successive energy losses
249  // measured in a series of detectors/telescopes along a given trajectory.
250  //
251  // The particle is associated with a reconstruction trajectory which starts from the detector in
252  // which the particle stopped and leads up through the detection layers towards the target.
253  // These can be accessed in later analysis using the two methods
254  // - KVReconstructedNucleus::GetStoppingDetector()
255  // - KVReconstructedNucleus::GetReconstructionTrajectory()
256  //
257  // \sa KVReconNucTrajectory
258 
259  auto Rtraj = get_recon_traj_for_particle(traj, node);
260  if (!Rtraj) {
261  Info("ReconstructParticle", "%s fired=%d energy=%f", node->GetName(), node->GetDetector()->Fired(GetPartSeedCond()), node->GetDetector()->GetEnergyLoss());
262  throw std::runtime_error(Form("<KVGroupReconstructor::ReconstructParticle>: Failed to obtain reconstruction trajectory for node %s on trajectory %s",
263  node->GetName(), traj->GetPathString().Data()));
264  }
265  part->SetReconstructionTrajectory(Rtraj);
266  part->SetParameter("ARRAY", GetGroup()->GetParentStructure<KVMultiDetArray>()->GetName());
267  // only the stopping detector is set 'analysed' (to stop any new particles
268  // being reconstructed starting from it) in case other particles stopped
269  // in other detectors further up the reconstruction trajectory
270  part->GetStoppingDetector()->SetAnalysed();
271  Rtraj->IterateFrom();// iterate over trajectory
273  while ((n = Rtraj->GetNextNode())) {
274 
275  KVDetector* d = n->GetDetector();
276  d->AddHit(part); // add particle to list of particles hitting detector
277  }
278 
279 }
280 
281 
282 
291 
293 {
294  // Analyse and set status of reconstructed particles in group, to decide whether they can be identified
295  // and further treated straight away.
296  //
297  // If there is more than one reconstructed particle in the group on different trajectories which
298  // have a detector in common, then it may be necessary to identify one of the particles before the
299  // others in order to try to subtract its contribution from the common detector and allow the
300  // identification of the other particles.
301 
302  if (GetNUnidentifiedInGroup() > 1) { //if there is more than one unidentified particle in the group
303 
304  Int_t n_nseg_1 = 0;
305  //loop over particles counting up different cases
306  for (KVReconstructedEvent::Iterator it = GetEventFragment()->begin(); it != GetEventFragment()->end(); ++it) {
307  KVReconstructedNucleus* nuc = it.get_pointer();
308  //ignore identified particles
309  if (nuc->IsIdentified())
310  continue;
311  // The condition for a particle to be identifiable straight away is that the first
312  // identification method that will be used must be independent
314  && ((KVIDTelescope*)nuc->GetReconstructionTrajectory()->GetIDTelescopes()->First())->IsIndependent()) {
315  //all particles whose first identification telescope is independent are fine
317  }
319  //no independent identification telescope => depends on what's in the rest of the group
320  ++n_nseg_1;
321  }
322  else {
323  //no identification available
325  }
326  }
327  //loop again, setting status
328  for (KVReconstructedEvent::Iterator it = GetEventFragment()->begin(); it != GetEventFragment()->end(); ++it) {
329  KVReconstructedNucleus* nuc = it.get_pointer();
330  if (nuc->IsIdentified())
331  continue; //ignore identified particles
332 
334  && ((KVIDTelescope*)nuc->GetReconstructionTrajectory()->GetIDTelescopes()->First())->IsIndependent())
336  //particles with no independent identification possibility
337  if (n_nseg_1 == 1) {
338  //just the one ? then we can get it no problem
339  //after identifying the others and subtracting their calculated
340  //energy losses from the other detectors
342  }
343  else {
344  //more than one ? then we can make some wild guess by sharing the
345  //contribution between them, but I wouldn't trust it as far as I can spit
347  }
348  //one possibility remains: the particle may actually have stopped e.g.
349  //in the DE detector of a DE-E telescope
351  //no ID telescopes with which to identify particle
353  }
354  }
355  }
356  }
357  else if (GetNUnidentifiedInGroup() == 1) {
358  //only one unidentified particle in group: just need an idtelescope which works
359 
360  //loop over particles looking for the unidentified one
361  KVReconstructedNucleus* nuc(nullptr);
362  for (KVReconstructedEvent::Iterator it = GetEventFragment()->begin(); it != GetEventFragment()->end(); ++it) {
363  nuc = it.get_pointer();
364  if (!nuc->IsIdentified()) break;
365  }
366  //cout << "nuc->GetNSegDet()=" << nuc->GetNSegDet() << endl;
368  //OK no problem
370  }
371  else {
372  //dead in the water
374  }
375  }
376 }
377 
378 
379 
396 
398 {
399  // Try to identify this nucleus by calling the KVIDTelescope::Identify() method of each
400  // identification telescope on its reconstruction trajectory, starting with the telescope
401  // where the particle stopped (i.e. containing its stopping detector), in order.
402  //
403  // Only identifications which have been correctly initialised for the current run are used,
404  // i.e. those for which KVIDTelescope::IsReadyForID() returns kTRUE.
405  //
406  // Note that *all* identifications along the trajectory are tried, even those far in front
407  // of the detector where the particle stopped. The results of all identifications (KVIdentificationResult)
408  // are stored with the particle (they can be retrieved later using KVReconstructedNucleus::GetIdentificationResult() ).
409  // They are later used for consistency checks ("coherency") between the identifications in the different
410  // stages.
411  //
412  // The first successful identification obtained in this way, if one exists, for a KVIDTelescope which includes
413  // the detector where the particle stopped is then attributed to the particle (see KVReconstructedNucleus::SetIdentification()).
414 
415  const KVSeqCollection* idt_list = PART.GetReconstructionTrajectory()->GetIDTelescopes();
416  auto N_independent_ids = PART.GetReconstructionTrajectory()->GetNumberOfIndependentIdentifications();
417  identifying_telescope = nullptr;
418  id_by_type.clear();
419 
420  if (idt_list->GetEntries() > 0) {
421 
422  KVIDTelescope* idt;
423  TIter next(idt_list);
424  Int_t idnumber = 1;
425  Int_t n_success_id = 0;//number of successful identifications
426  while ((idt = (KVIDTelescope*) next())) {
427  KVIdentificationResult* IDR = PART.GetIdentificationResult(idnumber++);
428 
429  if (idt->IsReadyForID()) { // is telescope able to identify for this run ?
430  id_by_type[idt->GetType()] = IDR;// map contains only attempted identifications
431  if (!IDR->IDattempted) { // the identification may already have been attempted, e.g. in gamma particle
432  // rejection in CSI: see KVINDRAGroupReconstructor::ReconstructTrajectory
433  identify_particle(idt, IDR, PART);
434  }
435  if (IDR->IDOK) n_success_id++;
436  }
437  else
438  IDR->IDattempted = kFALSE;
439 
440  N_independent_ids -= (int)idt->IsIndependent();
441 
442  if (n_success_id < 1 && ((!IDR->IDattempted) || (IDR->IDattempted && !IDR->IDOK))) {
443  // the particle is less identifiable than initially thought
444  // we may have to wait for secondary identification
445 
446  if (N_independent_ids < 1 && GetNUnidentifiedInGroup() > 1) {
447  //if there are other unidentified particles in the group and NSegDet is < 1
448  //then exact status depends on segmentation of the other particles : reanalyse
450  if (PART.GetStatus() != KVReconstructedNucleus::kStatusOK) return;
451  }
452  }
453 
454  }
455  // set first successful identification as particle identification
456  // as long as the id telescope concerned contains the stopping detector!
457  Int_t id_no = 1;
458  Bool_t ok = kFALSE;
460  next.Reset();
461  idt = (KVIDTelescope*)next();
462  while (idt && idt->HasDetector(PART.GetStoppingDetector())) {
463  if (pid->IDattempted && pid->IDOK) {
464  ok = kTRUE;
465  partID = *pid;
466  identifying_telescope = idt;
467  break;
468  }
469  ++id_no;
470  pid = PART.GetIdentificationResult(id_no);
471  idt = (KVIDTelescope*)next();
472  }
473  if (ok) {
474  PART.SetIsIdentified();
476  }
477 
478  }
479 
480 }
481 
482 
483 
484 
485 
486 
490 
492 {
493  // particles stopped in first member of a telescope
494  // estimation of Z (minimum) from energy loss (if detector is calibrated)
495  Int_t zmin = d.GetStoppingDetector()->FindZmin(-1., d.GetMassFormula());
496  if (zmin) {
498  idr.Z = zmin;
499  idr.IDcode = GetGroup()->GetParentStructure<KVMultiDetArray>()->GetIDCodeForParticlesStoppingInFirstStageOfTelescopes();
500  idr.Zident = false;
501  idr.Aident = false;
502  idr.PID = zmin;
503  d.SetIsIdentified();
504  KVGeoDNTrajectory* t = (KVGeoDNTrajectory*)d.GetStoppingDetector()->GetNode()->GetTrajectories()->First();
505  d.SetIdentification(&idr, (KVIDTelescope*) t->GetIDTelescopes()->Last());
506  }
507 }
508 
509 
510 
520 
522 {
523  // Identify all particles reconstructed so far in this group which
524  // may be identified independently of all other particles in the group according to the 1st
525  // order coherency analysis (see AnalyseParticles() ). This is done by calling the method
526  // IdentifyParticle() for each particle in turn.
527  //
528  // Particles stopping in the first member of a telescope will
529  // have their Z estimated from the energy loss in the detector (if calibrated):
530  // in this case the Z is a minimum value.
531 
532  for (auto& d : ReconEventIterator(GetEventFragment())) {
533  if (!d.IsIdentified()) {
534  if (d.GetStatus() == KVReconstructedNucleus::kStatusOK) {
535  // identifiable particles
537  }
538  else if (d.GetStatus() == KVReconstructedNucleus::kStatusStopFirstStage) {
539  // particles stopped in first member of a telescope
540  // estimation of Z (minimum) from energy loss (if detector is calibrated)
542  }
543  }
544  }
545 }
546 
547 
548 
549 
552 
554 {
555  // Calculate and set energies of all Z-identified but uncalibrated charged particles in event.
556 
557  for (auto& d : ReconEventIterator(GetEventFragment())) {
558 
559  if (!d.IsCalibrated()) {
560  if (d.IsZMeasured() && d.GetZ()) {
562  }
563  else
564  d.SetECode(GetGroup()->GetParentStructure<KVMultiDetArray>()->GetNoCalibrationCode());
565  }
566 
567  }
568 
569 }
570 
571 
572 
587 
589 {
590  // Calculate the energy loss in the current target of the multidetector
591  // for the reconstructed charged particle 'ion', assuming that the current
592  // energy and momentum of this particle correspond to its state on
593  // leaving the target.
594  //
595  // WARNING: for this correction to work, the target must be in the right 'state':
596  //
597  // gMultiDetArray->GetTarget()->SetOutgoing(kTRUE);
598  //
599  // (see KVTarget::GetParticleEIncFromERes).
600  //
601  // The returned value is the energy lost in the target in MeV.
602  // The energy/momentum of 'ion' are not affected.
603 
604  auto array = GetGroup()->GetParentStructure<KVMultiDetArray>();
605  if (!array->GetTarget() || !ion) return 0.0;
606  return (array->GetTarget()->GetParticleEIncFromERes(ion) - ion->GetEnergy());
607 }
608 
609 
610 
int Int_t
#define SafeDelete(p)
#define d(i)
#define c(i)
bool Bool_t
constexpr Bool_t kFALSE
double Double_t
constexpr Bool_t kTRUE
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t g
char * Form(const char *fmt,...)
Base class for KaliVeda framework.
Definition: KVBase.h:139
virtual const Char_t * GetType() const
Definition: KVBase.h:176
static TPluginHandler * LoadPlugin(const Char_t *base, const Char_t *uri="0")
Definition: KVBase.cpp:772
Path taken by particles through multidetector geometry.
KVGeoDetectorNode * GetNextNode() const
KVString GetPathString() const
void IterateFrom(const KVGeoDetectorNode *node0=nullptr) const
Int_t GetNumberOfIdentifications() const
const KVSeqCollection * GetIDTelescopes() const
Information on relative positions of detectors & particle trajectories.
KVDetector * GetDetector() const
Int_t GetNTrajBackwards() const
const Char_t * GetName() const override
Name of node is same as name of associated detector.
Int_t GetNTrajForwards() const
KVGeoStrucElement * GetParentStructure(const Char_t *type, const Char_t *name="") const
Base class for particle reconstruction in one group of a detector array.
virtual KVReconstructedNucleus * ReconstructTrajectory(const KVGeoDNTrajectory *traj, const KVGeoDetectorNode *node)
KVReconstructedEvent * fGrpEvent
event containing particles reconstructed in this group
KVIDTelescope * identifying_telescope
telescope which identified current particle
virtual void identify_particle(KVIDTelescope *idt, KVIdentificationResult *IDR, KVReconstructedNucleus &)
virtual void ReconstructParticle(KVReconstructedNucleus *part, const KVGeoDNTrajectory *traj, const KVGeoDetectorNode *node)
KVGroup * GetGroup() const
std::unordered_map< std::string, KVIdentificationResult * > id_by_type
identification results by type for current particle
KVReconstructedEvent * GetEventFragment() const
virtual void CalibrateParticle(KVReconstructedNucleus *)
static KVGroupReconstructor * Factory(const TString &plugin="", const KVGroup *g=nullptr)
virtual void AddCoherencyParticles()
int nfireddets
set to true during secondary analysis
KVGroup * fGroup
the group where we are reconstructing
void Calibrate()
Calculate and set energies of all Z-identified but uncalibrated charged particles in event.
virtual void SetGroup(const KVGroup *g)
virtual ~KVGroupReconstructor()
Destructor.
virtual KVReconNucTrajectory * get_recon_traj_for_particle(const KVGeoDNTrajectory *traj, const KVGeoDetectorNode *node)
TString fPartSeedCond
condition for seeding reconstructed particles
Double_t GetTargetEnergyLossCorrection(KVReconstructedNucleus *ion)
virtual void IdentifyParticle(KVReconstructedNucleus &)
KVGroupReconstructor(const KVGroup *g=nullptr)
Default constructor.
void SetReconEventClass(TClass *c)
Instantiate event fragment object.
TString GetPartSeedCond() const
KVIdentificationResult partID
identification to be applied to current particle
void TreatStatusStopFirstStage(KVReconstructedNucleus &)
virtual void PostReconstructionProcessing()
std::vector< particle_to_add_from_coherency_analysis > coherency_particles
Group of detectors which can be treated independently of all others in array.
Definition: KVGroup.h:19
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 IsReadyForID()
Bool_t HasDetector(const KVDetector *d) const
Bool_t IsIndependent() const
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
Bool_t Aident
= kTRUE if A of particle established
Double_t PID
= "real" Z if Zident==kTRUE and Aident==kFALSE, "real" A if Zident==Aident==kTRUE
Int_t Z
Z of particle found (if Zident==kTRUE)
Int_t IDcode
a general identification code for this type of identification
Bool_t Zident
=kTRUE if Z of particle established
Base class for describing the geometry of a detector array.
Double_t GetEnergy() const
Definition: KVParticle.h:624
void SetParameter(const Char_t *name, ValType value) const
Definition: KVParticle.h:822
Path through detector array used to reconstruct detected particle.
Int_t GetNumberOfIndependentIdentifications() const
Event containing KVReconstructedNucleus nuclei reconstructed from hits in detectors.
Nuclei reconstructed from data measured by a detector array .
void SetReconstructionTrajectory(const KVReconNucTrajectory *t)
Method called in initial reconstruction of particle.
@ kStatusOKafterShare
of energy losses of other particles in the same group which have Status=0
@ kStatusStopFirstStage
(arbitrarily) between this and the other particle(s) with Status=2
KVIdentificationResult * GetIdentificationResult(Int_t i)
const KVReconNucTrajectory * GetReconstructionTrajectory() const
void SetIdentification(KVIdentificationResult *, KVIDTelescope *)
KVDetector * GetStoppingDetector() const
void SetDetector(int i, KVDetector *);
KaliVeda extensions to ROOT collection classes.
TObject * First() const override
TObject * Last() const override
Iterator begin() const
Iterator end() const
virtual Int_t GetMult(Option_t *opt="") const
Particle * AddParticle()
Wrapper class for iterating over nuclei in KVReconstructedEvent accessed through base pointer or refe...
virtual Int_t GetEntries() const
void Reset()
const char * GetName() const override
virtual void Info(const char *method, const char *msgfmt,...) const
Longptr_t ExecPlugin(int nargs)
const char * Data() const
const Int_t n
ClassImp(TPyArg)