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  try {
157  ReconstructParticle(kvdp, traj, node);
158  break;
159  }
160  catch (const std::exception& e) {
161  Warning("Reconstruct", "Caught exception: %s", e.what());
162  throw;
163  }
164  }
165 
166  }
167 
168  }
169 
170  if (GetEventFragment()->GetMult() > old_mult) {
173  }
174 }
175 
176 
177 
182 
184 {
185  // This method will be called after reconstruction and first-order coherency analysis
186  // of all particles in the group (if there are any reconstructed particles).
187  // By default it does nothing.
188 }
189 
190 
191 
201 
203 {
204  // \param traj trajectory currently being scanned
205  // \param node current detector on trajectory to test
206  // \returns pointer to a new reconstructed particle added to this group's event; nullptr if nothing is to be done
207  //
208  // The condition which must be fulfilled for us to begin the reconstruction of a new particle starting from
209  // a fired detector on the trajectory is either:
210  // - the trajectory is the only one which passes through this detector; or
211  // - the detector directly in front of this one on this trajectory also fired.
212 
213  KVDetector* d = node->GetDetector();
214  nfireddets += d->Fired();
215  // if d has fired, has not been used to seed a reconstructed particle (IsAnalysed),
216  // is not on the trajectory of a reconstructed particle (GetHits()->GetEntries()),
217  // and only if the detector belongs to a unique trajectory (i.e. neither multiple trajectories
218  // arrive from behind nor continue in front)
219  if (
220  !d->IsAnalysed() && d->Fired(GetPartSeedCond())
221  && (!d->GetHits() || !d->GetHits()->GetEntries())
222  && (node->GetNTrajForwards() <= 1 && node->GetNTrajBackwards() <= 1)
223  )
224  return GetEventFragment()->AddParticle();
225 
226  return nullptr;
227 }
228 
229 
230 
232 
234 {
236 }
237 
238 
239 
251 
253 {
254  // Reconstruction of a detected nucleus from the successive energy losses
255  // measured in a series of detectors/telescopes along a given trajectory.
256  //
257  // The particle is associated with a reconstruction trajectory which starts from the detector in
258  // which the particle stopped and leads up through the detection layers towards the target.
259  // These can be accessed in later analysis using the two methods
260  // - KVReconstructedNucleus::GetStoppingDetector()
261  // - KVReconstructedNucleus::GetReconstructionTrajectory()
262  //
263  // \sa KVReconNucTrajectory
264 
265  auto Rtraj = get_recon_traj_for_particle(traj, node);
266  if (!Rtraj) {
267  Info("ReconstructParticle", "%s fired=%d energy=%f", node->GetName(), node->GetDetector()->Fired(GetPartSeedCond()), node->GetDetector()->GetEnergyLoss());
268  throw std::runtime_error(Form("<KVGroupReconstructor::ReconstructParticle>: Failed to obtain reconstruction trajectory for node %s on trajectory %s",
269  node->GetName(), traj->GetPathString().Data()));
270  }
271  part->SetReconstructionTrajectory(Rtraj);
272  part->SetParameter("ARRAY", GetGroup()->GetParentStructure<KVMultiDetArray>()->GetName());
273  // only the stopping detector is set 'analysed' (to stop any new particles
274  // being reconstructed starting from it) in case other particles stopped
275  // in other detectors further up the reconstruction trajectory
276  part->GetStoppingDetector()->SetAnalysed();
277  Rtraj->IterateFrom();// iterate over trajectory
279  while ((n = Rtraj->GetNextNode())) {
280 
281  KVDetector* d = n->GetDetector();
282  d->AddHit(part); // add particle to list of particles hitting detector
283  }
284 
285 }
286 
287 
288 
297 
299 {
300  // Analyse and set status of reconstructed particles in group, to decide whether they can be identified
301  // and further treated straight away.
302  //
303  // If there is more than one reconstructed particle in the group on different trajectories which
304  // have a detector in common, then it may be necessary to identify one of the particles before the
305  // others in order to try to subtract its contribution from the common detector and allow the
306  // identification of the other particles.
307 
308  if (GetNUnidentifiedInGroup() > 1) { //if there is more than one unidentified particle in the group
309 
310  Int_t n_nseg_1 = 0;
311  //loop over particles counting up different cases
312  for (KVReconstructedEvent::Iterator it = GetEventFragment()->begin(); it != GetEventFragment()->end(); ++it) {
313  KVReconstructedNucleus* nuc = it.get_pointer();
314  //ignore identified particles
315  if (nuc->IsIdentified())
316  continue;
317  // The condition for a particle to be identifiable straight away is that the first
318  // identification method that will be used must be independent
320  && ((KVIDTelescope*)nuc->GetReconstructionTrajectory()->GetIDTelescopes()->First())->IsIndependent()) {
321  //all particles whose first identification telescope is independent are fine
323  }
325  //no independent identification telescope => depends on what's in the rest of the group
326  ++n_nseg_1;
327  }
328  else {
329  //no identification available
331  }
332  }
333  //loop again, setting status
334  for (KVReconstructedEvent::Iterator it = GetEventFragment()->begin(); it != GetEventFragment()->end(); ++it) {
335  KVReconstructedNucleus* nuc = it.get_pointer();
336  if (nuc->IsIdentified())
337  continue; //ignore identified particles
338 
340  && ((KVIDTelescope*)nuc->GetReconstructionTrajectory()->GetIDTelescopes()->First())->IsIndependent())
342  //particles with no independent identification possibility
343  if (n_nseg_1 == 1) {
344  //just the one ? then we can get it no problem
345  //after identifying the others and subtracting their calculated
346  //energy losses from the other detectors
348  }
349  else {
350  //more than one ? then we can make some wild guess by sharing the
351  //contribution between them, but I wouldn't trust it as far as I can spit
353  }
354  //one possibility remains: the particle may actually have stopped e.g.
355  //in the DE detector of a DE-E telescope
357  //no ID telescopes with which to identify particle
359  }
360  }
361  }
362  }
363  else if (GetNUnidentifiedInGroup() == 1) {
364  //only one unidentified particle in group: just need an idtelescope which works
365 
366  //loop over particles looking for the unidentified one
367  KVReconstructedNucleus* nuc(nullptr);
368  for (KVReconstructedEvent::Iterator it = GetEventFragment()->begin(); it != GetEventFragment()->end(); ++it) {
369  nuc = it.get_pointer();
370  if (!nuc->IsIdentified()) break;
371  }
372  //cout << "nuc->GetNSegDet()=" << nuc->GetNSegDet() << endl;
374  //OK no problem
376  }
377  else {
378  //dead in the water
380  }
381  }
382 }
383 
384 
385 
402 
404 {
405  // Try to identify this nucleus by calling the KVIDTelescope::Identify() method of each
406  // identification telescope on its reconstruction trajectory, starting with the telescope
407  // where the particle stopped (i.e. containing its stopping detector), in order.
408  //
409  // Only identifications which have been correctly initialised for the current run are used,
410  // i.e. those for which KVIDTelescope::IsReadyForID() returns kTRUE.
411  //
412  // Note that *all* identifications along the trajectory are tried, even those far in front
413  // of the detector where the particle stopped. The results of all identifications (KVIdentificationResult)
414  // are stored with the particle (they can be retrieved later using KVReconstructedNucleus::GetIdentificationResult() ).
415  // They are later used for consistency checks ("coherency") between the identifications in the different
416  // stages.
417  //
418  // The first successful identification obtained in this way, if one exists, for a KVIDTelescope which includes
419  // the detector where the particle stopped is then attributed to the particle (see KVReconstructedNucleus::SetIdentification()).
420 
421  const KVSeqCollection* idt_list = PART.GetReconstructionTrajectory()->GetIDTelescopes();
422  auto N_independent_ids = PART.GetReconstructionTrajectory()->GetNumberOfIndependentIdentifications();
423  identifying_telescope = nullptr;
424  id_by_type.clear();
425 
426  if (idt_list->GetEntries() > 0) {
427 
428  KVIDTelescope* idt;
429  TIter next(idt_list);
430  Int_t idnumber = 1;
431  Int_t n_success_id = 0;//number of successful identifications
432  while ((idt = (KVIDTelescope*) next())) {
433  KVIdentificationResult* IDR = PART.GetIdentificationResult(idnumber++);
434 
435  if (idt->IsReadyForID()) { // is telescope able to identify for this run ?
436  id_by_type[idt->GetType()] = IDR;// map contains only attempted identifications
437  if (!IDR->IDattempted) { // the identification may already have been attempted, e.g. in gamma particle
438  // rejection in CSI: see KVINDRAGroupReconstructor::ReconstructTrajectory
439  identify_particle(idt, IDR, PART);
440  }
441  if (IDR->IDOK) n_success_id++;
442  }
443  else
444  IDR->IDattempted = kFALSE;
445 
446  N_independent_ids -= (int)idt->IsIndependent();
447 
448  if (n_success_id < 1 && ((!IDR->IDattempted) || (IDR->IDattempted && !IDR->IDOK))) {
449  // the particle is less identifiable than initially thought
450  // we may have to wait for secondary identification
451 
452  if (N_independent_ids < 1 && GetNUnidentifiedInGroup() > 1) {
453  //if there are other unidentified particles in the group and NSegDet is < 1
454  //then exact status depends on segmentation of the other particles : reanalyse
456  if (PART.GetStatus() != KVReconstructedNucleus::kStatusOK) return;
457  }
458  }
459 
460  }
461  // set first successful identification as particle identification
462  // as long as the id telescope concerned contains the stopping detector!
463  Int_t id_no = 1;
464  Bool_t ok = kFALSE;
466  next.Reset();
467  idt = (KVIDTelescope*)next();
468  while (idt && idt->HasDetector(PART.GetStoppingDetector())) {
469  if (pid->IDattempted && pid->IDOK) {
470  ok = kTRUE;
471  partID = *pid;
472  identifying_telescope = idt;
473  break;
474  }
475  ++id_no;
476  pid = PART.GetIdentificationResult(id_no);
477  idt = (KVIDTelescope*)next();
478  }
479  if (ok) {
480  PART.SetIsIdentified();
482  }
483 
484  }
485 
486 }
487 
488 
489 
490 
491 
492 
496 
498 {
499  // particles stopped in first member of a telescope
500  // estimation of Z (minimum) from energy loss (if detector is calibrated)
501 
502  Int_t zmin = d.GetStoppingDetector()->FindZmin(-1., d.GetMassFormula());
503 
504  if (zmin > 0) {
506  idr.Z = zmin;
507  idr.IDcode = GetGroup()->GetParentStructure<KVMultiDetArray>()->GetIDCodeForParticlesStoppingInFirstStageOfTelescopes();
508  idr.Zident = true;
509  idr.Aident = false;
510  idr.PID = zmin;
511  d.SetIsIdentified();
512  KVGeoDNTrajectory* t = (KVGeoDNTrajectory*)d.GetStoppingDetector()->GetNode()->GetTrajectories()->First();
513  d.SetIdentification(&idr, (KVIDTelescope*) t->GetIDTelescopes()->Last());
514  }
515 }
516 
517 
518 
528 
530 {
531  // Identify all particles reconstructed so far in this group which
532  // may be identified independently of all other particles in the group according to the 1st
533  // order coherency analysis (see AnalyseParticles() ). This is done by calling the method
534  // IdentifyParticle() for each particle in turn.
535  //
536  // Particles stopping in the first member of a telescope will
537  // have their Z estimated from the energy loss in the detector (if calibrated):
538  // in this case the Z is a minimum value.
539 
540  for (auto& d : ReconEventIterator(GetEventFragment())) {
541  if (!d.IsIdentified()) {
542  if (d.GetStatus() == KVReconstructedNucleus::kStatusOK) {
543  // identifiable particles
545  }
546  else if (d.GetStatus() == KVReconstructedNucleus::kStatusStopFirstStage) {
547  // particles stopped in first member of a telescope
548  // estimation of Z (minimum) from energy loss (if detector is calibrated)
550  }
551  }
552  }
553 }
554 
555 
556 
557 
560 
562 {
563  // Calculate and set energies of all Z-identified but uncalibrated charged particles in event.
564 
565  for (auto& d : ReconEventIterator(GetEventFragment())) {
566 
567  if (!d.IsCalibrated()) {
568  if (d.IsZMeasured() && d.GetZ()) {
570  }
571  else
572  d.SetECode(GetGroup()->GetParentStructure<KVMultiDetArray>()->GetNoCalibrationCode());
573  }
574 
575  }
576 
577 }
578 
579 
580 
595 
597 {
598  // Calculate the energy loss in the current target of the multidetector
599  // for the reconstructed charged particle 'ion', assuming that the current
600  // energy and momentum of this particle correspond to its state on
601  // leaving the target.
602  //
603  // WARNING: for this correction to work, the target must be in the right 'state':
604  //
605  // gMultiDetArray->GetTarget()->SetOutgoing(kTRUE);
606  //
607  // (see KVTarget::GetParticleEIncFromERes).
608  //
609  // The returned value is the energy lost in the target in MeV.
610  // The energy/momentum of 'ion' are not affected.
611 
612  auto array = GetGroup()->GetParentStructure<KVMultiDetArray>();
613  if (!array->GetTarget() || !ion) return 0.0;
614  return (array->GetTarget()->GetParticleEIncFromERes(ion) - ion->GetEnergy());
615 }
616 
617 
618 
int Int_t
#define SafeDelete(p)
#define d(i)
#define c(i)
#define e(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:788
void Warning(const char *method, const char *msgfmt,...) const override
Definition: KVBase.cpp:1653
Base class for detector geometry description, interface to energy-loss calculations.
Definition: KVDetector.h:159
virtual Bool_t Fired(Option_t *opt="any") const
Definition: KVDetector.h:463
Double_t GetEnergyLoss() const override
Definition: KVDetector.h:385
void SetAnalysed(Bool_t b=kTRUE)
Definition: KVDetector.h:459
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
number of fired detectors in group for current event
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:20
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:85
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)