KaliVeda  1.13/01
Heavy-Ion Analysis Toolkit
KVGroupReconstructor.cpp
Go to the documentation of this file.
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  fGroup(nullptr), fGrpEvent(nullptr)
21 {
22  // Default constructor
23 
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 = 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;
80  TPluginHandler* ph = LoadPlugin("KVGroupReconstructor", plugin);
81  if (ph) {
82  return (KVGroupReconstructor*)ph->ExecPlugin(0);
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  // loop over trajectories
144  while ((traj = (KVGeoDNTrajectory*)nxt_traj())) {
145 
146  // Work our way along the trajectory, starting from furthest detector from target,
147  // start reconstruction of new detected particle from first fired detector.
148  traj->IterateFrom();
149  KVGeoDetectorNode* node;
150  while ((node = traj->GetNextNode())) {
151 
153  if ((kvdp = ReconstructTrajectory(traj, node))) {
154  ReconstructParticle(kvdp, traj, node);
155  break; //start next trajectory
156  }
157 
158  }
159 
160  }
161 
162  if (GetEventFragment()->GetMult()) {
165  }
166 }
167 
168 
169 
174 
176 {
177  // This method will be called after reconstruction and first-order coherency analysis
178  // of all particles in the group (if there are any reconstructed particles).
179  // By default it does nothing.
180 }
181 
182 
183 
193 
195 {
196  // \param traj trajectory currently being scanned
197  // \param node current detector on trajectory to test
198  // \returns pointer to a new reconstructed particle added to this group's event; nullptr if nothing is to be done
199  //
200  // The condition which must be fulfilled for us to begin the reconstruction of a new particle starting from
201  // a fired detector on the trajectory is either:
202  // - the trajectory is the only one which passes through this detector; or
203  // - the detector directly in front of this one on this trajectory also fired.
204 
205  KVDetector* d = node->GetDetector();
206  nfireddets += d->Fired();
207  // if d has fired and is either independent (only one trajectory passes through it)
208  // or, if several trajectories pass through it,
209  // only if the detector directly in front of it on this trajectory fired also
210  if (!d->IsAnalysed() && d->Fired(fPartSeedCond)
211  && (node->GetNTraj() == 1 ||
212  (traj->GetNodeInFront(node) &&
213  traj->GetNodeInFront(node)->GetDetector()->Fired()))) {
214 
215  return GetEventFragment()->AddParticle();
216  }
217 
218  return nullptr;
219 }
220 
221 
222 
234 
236 {
237  // Reconstruction of a detected nucleus from the successive energy losses
238  // measured in a series of detectors/telescopes along a given trajectory.
239  //
240  // The particle is associated with a reconstruction trajectory which starts from the detector in
241  // which the particle stopped and leads up through the detection layers towards the target.
242  // These can be accessed in later analysis using the two methods
243  // - KVReconstructedNucleus::GetStoppingDetector()
244  // - KVReconstructedNucleus::GetReconstructionTrajectory()
245  //
246  // \sa KVReconNucTrajectory
247 
249  part->SetReconstructionTrajectory(Rtraj);
250  part->SetParameter("ARRAY", GetGroup()->GetArray()->GetName());
251 
252  Rtraj->IterateFrom();// iterate over trajectory
254  while ((n = Rtraj->GetNextNode())) {
255 
256  KVDetector* d = n->GetDetector();
257  d->AddHit(part); // add particle to list of particles hitting detector
258 
259  }
260 
261 }
262 
263 
264 
273 
275 {
276  // Analyse and set status of reconstructed particles in group, to decide whether they can be identified
277  // and further treated straight away.
278  //
279  // If there is more than one reconstructed particle in the group on different trajectories which
280  // have a detector in common, then it may be necessary to identify one of the particles before the
281  // others in order to try to subtract its contribution from the common detector and allow the
282  // identification of the other particles.
283 
284  if (GetNUnidentifiedInGroup() > 1) { //if there is more than one unidentified particle in the group
285 
286  Int_t n_nseg_1 = 0;
287  //loop over particles counting up different cases
288  for (KVReconstructedEvent::Iterator it = GetEventFragment()->begin(); it != GetEventFragment()->end(); ++it) {
289  KVReconstructedNucleus* nuc = it.get_pointer();
290  //ignore identified particles
291  if (nuc->IsIdentified())
292  continue;
293  // The condition for a particle to be identifiable straight away is that the first
294  // identification method that will be used must be independent
295  //if (nuc->GetNSegDet() >= 1) {
297  && ((KVIDTelescope*)nuc->GetReconstructionTrajectory()->GetIDTelescopes()->First())->IsIndependent()) {
298  //all particles whose first identification telescope is independent are fine
300  }
302  //no independent identification telescope => depends on what's in the rest of the group
303  ++n_nseg_1;
304  }
305  else {
306  //no identification available
308  }
309  }
310  //loop again, setting status
311  for (KVReconstructedEvent::Iterator it = GetEventFragment()->begin(); it != GetEventFragment()->end(); ++it) {
312  KVReconstructedNucleus* nuc = it.get_pointer();
313  if (nuc->IsIdentified())
314  continue; //ignore identified particles
315 
317  && ((KVIDTelescope*)nuc->GetReconstructionTrajectory()->GetIDTelescopes()->First())->IsIndependent())
319  //particles with no independent identification possibility
320  if (n_nseg_1 == 1) {
321  //just the one ? then we can get it no problem
322  //after identifying the others and subtracting their calculated
323  //energy losses from the other detectors
325  }
326  else {
327  //more than one ? then we can make some wild guess by sharing the
328  //contribution between them, but I wouldn't trust it as far as I can spit
330  }
331  //one possibility remains: the particle may actually have stopped e.g.
332  //in the DE detector of a DE-E telescope
334  //no ID telescopes with which to identify particle
336  }
337  }
338  }
339  }
340  else if (GetNUnidentifiedInGroup() == 1) {
341  //only one unidentified particle in group: just need an idtelescope which works
342 
343  //loop over particles looking for the unidentified one
344  KVReconstructedNucleus* nuc(nullptr);
345  for (KVReconstructedEvent::Iterator it = GetEventFragment()->begin(); it != GetEventFragment()->end(); ++it) {
346  nuc = it.get_pointer();
347  if (!nuc->IsIdentified()) break;
348  }
349  //cout << "nuc->GetNSegDet()=" << nuc->GetNSegDet() << endl;
351  //OK no problem
353  }
354  else {
355  //dead in the water
357  }
358  }
359 }
360 
361 
362 
379 
381 {
382  // Try to identify this nucleus by calling the KVIDTelescope::Identify() method of each
383  // identification telescope on its reconstruction trajectory, starting with the telescope
384  // where the particle stopped (i.e. containing its stopping detector), in order.
385  //
386  // Only identifications which have been correctly initialised for the current run are used,
387  // i.e. those for which KVIDTelescope::IsReadyForID() returns kTRUE.
388  //
389  // Note that *all* identifications along the trajectory are tried, even those far in front
390  // of the detector where the particle stopped. The results of all identifications (KVIdentificationResult)
391  // are stored with the particle (they can be retrieved later using KVReconstructedNucleus::GetIdentificationResult() ).
392  // They are later used for consistency checks ("coherency") between the identifications in the different
393  // stages.
394  //
395  // The first successful identification obtained in this way, if one exists, for a KVIDTelescope which includes
396  // the detector where the particle stopped is then attributed to the particle (see KVReconstructedNucleus::SetIdentification()).
397 
398  const KVSeqCollection* idt_list = PART.GetReconstructionTrajectory()->GetIDTelescopes();
399  identifying_telescope = nullptr;
400  id_by_type.clear();
401 
402  if (idt_list->GetEntries() > 0) {
403 
404  KVIDTelescope* idt;
405  TIter next(idt_list);
406  Int_t idnumber = 1;
407  Int_t n_success_id = 0;//number of successful identifications
408  while ((idt = (KVIDTelescope*) next())) {
409  KVIdentificationResult* IDR = PART.GetIdentificationResult(idnumber++);
410 
411  if (idt->IsReadyForID()) { // is telescope able to identify for this run ?
412  id_by_type[idt->GetType()] = IDR;// map contains only attempted identifications
413  if (!IDR->IDattempted) { // the identification may already have been attempted, e.g. in gamma particle
414  // rejection in CSI: see KVINDRAGroupReconstructor::ReconstructTrajectory
415  idt->Identify(IDR);
416  }
417  if (IDR->IDOK) n_success_id++;
418  }
419  else
420  IDR->IDattempted = kFALSE;
421 
422  if (n_success_id < 1 &&
423  ((!IDR->IDattempted) || (IDR->IDattempted && !IDR->IDOK))) {
424  // the particle is less identifiable than initially thought
425  // we may have to wait for secondary identification
426  Int_t nseg = PART.GetNSegDet();
427  PART.SetNSegDet(TMath::Max(nseg - 1, 0));
428  //if there are other unidentified particles in the group and NSegDet is < 1
429  //then exact status depends on segmentation of the other particles : reanalyse
430  if (PART.GetNSegDet() < 1 && GetNUnidentifiedInGroup() > 1) {
432  return;
433  }
434  //if NSegDet = 0 it's hopeless
435  if (!PART.GetNSegDet()) {
437  return;
438  }
439  }
440 
441  }
442  // set first successful identification as particle identification
443  // as long as the id telescope concerned contains the stopping detector!
444  Int_t id_no = 1;
445  Bool_t ok = kFALSE;
447  next.Reset();
448  idt = (KVIDTelescope*)next();
449  while (idt->HasDetector(PART.GetStoppingDetector())) {
450  if (pid->IDattempted && pid->IDOK) {
451  ok = kTRUE;
452  partID = *pid;
453  identifying_telescope = idt;
454  break;
455  }
456  ++id_no;
457  pid = PART.GetIdentificationResult(id_no);
458  idt = (KVIDTelescope*)next();
459  }
460  if (ok) {
461  PART.SetIsIdentified();
463  }
464 
465  }
466 
467 }
468 
469 
470 
471 
475 
477 {
478  // particles stopped in first member of a telescope
479  // estimation of Z (minimum) from energy loss (if detector is calibrated)
480  Int_t zmin = d.GetStoppingDetector()->FindZmin(-1., d.GetMassFormula());
481  if (zmin) {
483  idr.Z = zmin;
484  idr.IDcode = ((KVMultiDetArray*)GetGroup()->GetArray())->GetIDCodeForParticlesStoppingInFirstStageOfTelescopes();
485  idr.Zident = false;
486  idr.Aident = false;
487  idr.PID = zmin;
488  d.SetIsIdentified();
489  KVGeoDNTrajectory* t = (KVGeoDNTrajectory*)d.GetStoppingDetector()->GetNode()->GetTrajectories()->First();
490  d.SetIdentification(&idr, (KVIDTelescope*) t->GetIDTelescopes()->Last());
491  }
492 }
493 
494 
495 
505 
507 {
508  // Identify all particles reconstructed so far in this group which
509  // may be identified independently of all other particles in the group according to the 1st
510  // order coherency analysis (see AnalyseParticles() ). This is done by calling the method
511  // IdentifyParticle() for each particle in turn.
512  //
513  // Particles stopping in the first member of a telescope will
514  // have their Z estimated from the energy loss in the detector (if calibrated):
515  // in this case the Z is a minimum value.
516 
517  for (KVReconstructedEvent::Iterator it = GetEventFragment()->begin(); it != GetEventFragment()->end(); ++it) {
518  KVReconstructedNucleus& d = it.get_reference();
519  if (!d.IsIdentified()) {
520  if (d.GetStatus() == KVReconstructedNucleus::kStatusOK) {
521  // identifiable particles
523  }
524  else if (d.GetStatus() == KVReconstructedNucleus::kStatusStopFirstStage) {
525  // particles stopped in first member of a telescope
526  // estimation of Z (minimum) from energy loss (if detector is calibrated)
528  }
529  }
530  }
531 }
532 
533 
534 
535 
538 
540 {
541  // Calculate and set energies of all identified but uncalibrated particles in event.
542 
543  for (auto& d : ReconEventIterator(GetEventFragment())) {
544 
545  if (d.IsIdentified() && !d.IsCalibrated()) {
547  }
548 
549  }
550 
551 }
552 
553 
554 
570 
572 {
573  // Calculate the energy loss in the current target of the multidetector
574  // for the reconstructed charged particle 'ion', assuming that the current
575  // energy and momentum of this particle correspond to its state on
576  // leaving the target.
577  //
578  // WARNING: for this correction to work, the target must be in the right 'state':
579  //
580  // gMultiDetArray->GetTarget()->SetIncoming(kFALSE);
581  // gMultiDetArray->GetTarget()->SetOutgoing(kTRUE);
582  //
583  // (see KVTarget::GetParticleEIncFromERes).
584  //
585  // The returned value is the energy lost in the target in MeV.
586  // The energy/momentum of 'ion' are not affected.
587 
589  if (!array->GetTarget() || !ion) return 0.0;
590  return (array->GetTarget()->GetParticleEIncFromERes(ion) - ion->GetEnergy());
591 }
592 
593 
594 
int Int_t
ClassImp(KVPartitionList) void KVPartitionList
Initialisation.
KVReconstructedEvent::EventIterator ReconEventIterator
#define SafeDelete(p)
#define d(i)
#define c(i)
const Bool_t kFALSE
bool Bool_t
double Double_t
const Bool_t kTRUE
Base class for KaliVeda framework.
Definition: KVBase.h:141
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:793
Base class for detector geometry description.
Definition: KVDetector.h:159
virtual Bool_t Fired(Option_t *opt="any") const
Definition: KVDetector.h:450
Path taken by particles through multidetector geometry.
KVGeoDetectorNode * GetNextNode() const
void IterateFrom(const KVGeoDetectorNode *node0=nullptr) const
Int_t GetNumberOfIdentifications() const
const KVSeqCollection * GetIDTelescopes() const
KVGeoDetectorNode * GetNodeInFront(const KVGeoDetectorNode *n) const
Information on relative positions of detectors & particle trajectories.
KVDetector * GetDetector() const
Int_t GetNTraj() const
Returns number of trajectories passing through this node.
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
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 *)
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 identified but uncalibrated particles in event.
virtual void IdentifyParticle(KVReconstructedNucleus &PART)
virtual ~KVGroupReconstructor()
Destructor.
TString fPartSeedCond
condition for seeding reconstructed particles
Double_t GetTargetEnergyLossCorrection(KVReconstructedNucleus *ion)
void SetReconEventClass(TClass *c)
Instantiate event fragment object.
TString GetPartSeedCond() const
KVIdentificationResult partID
identification to be applied to current particle
KVGroupReconstructor()
Default constructor.
void TreatStatusStopFirstStage(KVReconstructedNucleus &)
virtual void PostReconstructionProcessing()
static KVGroupReconstructor * Factory(const TString &plugin="")
virtual void SetGroup(KVGroup *g)
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
KVGeoStrucElement * GetArray() const
Definition: KVGroup.h:44
const KVGeoDNTrajectory * GetTrajectoryForReconstruction(const KVGeoDNTrajectory *t, const KVGeoDetectorNode *n) const
Definition: KVGroup.h:103
Base class for all detectors or associations of detectors in array which can identify charged particl...
Definition: KVIDTelescope.h:83
virtual Bool_t IsReadyForID()
virtual Bool_t Identify(KVIdentificationResult *, Double_t x=-1., Double_t y=-1.)
Bool_t HasDetector(const KVDetector *d) 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.
KVTarget * GetTarget()
Double_t GetEnergy() const
Definition: KVParticle.h:623
void SetParameter(const Char_t *name, ValType value) const
Definition: KVParticle.h:820
Path through detector array used to reconstruct detected particle.
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.
KVIdentificationResult * GetIdentificationResult(Int_t i)
const KVReconNucTrajectory * GetReconstructionTrajectory() const
void SetIdentification(KVIdentificationResult *, KVIDTelescope *)
KVDetector * GetStoppingDetector() const
void SetDetector(int i, KVDetector *);
@ 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
KaliVeda extensions to ROOT collection classes.
virtual TObject * Last() const
virtual TObject * First() const
virtual Double_t GetParticleEIncFromERes(KVNucleus *, TVector3 *norm=0)
Definition: KVTarget.cpp:957
Iterator begin() const
Iterator end() const
Particle * AddParticle()
virtual Int_t GetEntries() const
void Reset()
virtual const char * GetName() const
Longptr_t ExecPlugin(int nargs, const T &... params)
const Int_t n
const long double g
masses
Definition: KVUnits.h:72
Double_t Max(Double_t a, Double_t b)