KaliVeda
Toolkit for HIC analysis
KVINDRAEtalonGroupReconstructor.cpp
1 //Created by KVClassFactory on Wed Feb 21 13:43:10 2018
2 //Author: John Frankland,,,
3 
4 #include "KVINDRAEtalonGroupReconstructor.h"
5 #include <string>
6 #include <unordered_map>
7 #include <iostream>
8 #include <KVSilicon.h>
9 #include "KVIDGCsI.h"
10 using namespace std;
11 
13 
14 
15 
16 
34 {
35  // \param traj trajectory currently being scanned
36  // \param node current detector on trajectory to test
37  // \returns pointer to a new reconstructed particle added to this group's event; nullptr if nothing is to be done
38  //
39  // Specialised particle reconstruction for INDRA groups with etalon telescopes (Rings 10-17).
40  //
41  // If node is a CsI detector with more than one trajectory passing through it (in front of it),
42  // we are behind the etalons Si(75)-Si(Li).
43  //
44  // As the Si(75)-Si(Li) coders are opened by every firing of the CsI directly behind them,
45  // their acquisition parameters are present in the event whether the particle went through them
46  // or passed directly from ChIo to CsI.
47  //
48  // The best way to choose the right reconstruction trajectory is to see if Si(Li)-CsI
49  // provides an identification, and if so is it coherent with that of the CsI.
50 
51  if (!node->GetDetector()->IsAnalysed() &&
52  node->GetDetector()->Fired(GetPartSeedCond()) &&
53  node->GetDetector()->IsType("CSI") &&
54  node->GetNTrajForwards() > 1) {
55 
56  ++nfireddets;
57  const KVSeqCollection* idt_list = traj->GetIDTelescopes();
58  TIter next_idt(idt_list);
59  KVIDTelescope* idt;
60  bool with_etalon = (traj->GetN() == 4);
61 
62  std::unordered_map<std::string, KVIdentificationResult> IDR;
63  while ((idt = (KVIDTelescope*)next_idt())) {
64  if (idt->IsReadyForID()) { // is telescope able to identify for this run ?
65  idt->Identify(&IDR[idt->GetType()]);
66  }
67  }
68  // cases:
69  // gamma in CsI: * same as general INDRA reconstruction: count the gammmas, do not
70  // reconstruct a particle (but set CsI analysed state)
71  // particle identified in CsI:
72  // * if this is the long trajectory, check the SILI-CSI identification
73  // if SILI-CSI identification no good, then short trajectory should be used
74  // so we return nullptr
75  // * if this is the short trajectory, we accept it
76  KVIdentificationResult& idcsi = IDR[CSI_ID_TYPE.Data()];
77  if (idcsi.IDattempted) {
78  if (idcsi.IDOK) {
79  if (idcsi.IDcode == KVINDRA::IDCodes::ID_GAMMA || idcsi.IDquality == KVIDGCsI::kICODE10) {
80  // gamma
81  //Info("ReconstructTrajectory","Gamma in CsI: with_etalon=%d",with_etalon);
82  GetEventFragment()->GetParameters()->IncrementValue("INDRA_GAMMA_MULT", 1);
83  GetEventFragment()->GetParameters()->IncrementValue("INDRA_GAMMA_DETS", node->GetName());
84  node->GetDetector()->SetAnalysed();
85  return nullptr;
86  }
87  else { // charged particle identified
88  //Info("ReconstructTrajectory","Charged particle in CsI: with_etalon=%d",with_etalon);
89  if (with_etalon) {
90  if (IDR["SILI_CSI"].IDattempted && IDR["SILI_CSI"].IDOK) {
91  //Info("ReconstructTrajectory","Charged particle in SILI too Zcsi=%d Zsili=%d",idcsi.Z,IDR["SILI_CSI"].Z);
92  return GetEventFragment()->AddParticle();
93  }
94  else return nullptr;
95  }
96  else
97  return GetEventFragment()->AddParticle();
98  }
99  }
100  }
101  return nullptr;
102  }
103  // standard non-etalon treatment
105 }
106 
107 
108 
113 
115 {
116  // Coherency analysis for etalon groups on rings 10-17 of INDRA
117  // Note that the treatment of all modules in the group except the one with the etalons
118  // is standard (KVINDRABackwardGroupReconstructor), but all modules will call here first
119 
120  if (!GetSi75(&PART) && !GetSiLi(&PART)) // => no etalons in particle trajectory
122 
123  PART.SetParameter("UseFullChIoEnergyForCalib", !(theChio && theChio->GetNHits() > 1));
124  bool ok = CoherencyEtalons(PART);
125 
126  return ok;
127 }
128 
129 
130 
133 
135 {
136  // Calibration of particle stopping in etalon modules
137 
138  fESiLi = fESi75 = 0;
139 
140  if (!GetSi75(PART) && !GetSiLi(PART)) // => no etalons in particle trajectory
142 
143  // change fUseFullChioenergyforcalib for "coherency" particles
144  // we assume they are calibrated after all other particles in group have
145  // been identified, calibrated, and their energy contributions removed
146  // from the ChIo
147  if (PART->GetIDCode() == KVINDRA::IDCodes::ID_CI_SI_COHERENCY
148  || PART->GetIDCode() == KVINDRA::IDCodes::ID_CI_COHERENCY
149  || PART->GetIDCode() == KVINDRA::IDCodes::ID_CI_MULTIHIT)
150  PART->SetParameter("UseFullChIoEnergyForCalib", kTRUE);
151 
152  Bool_t stopped_in_chio = kTRUE;
153  auto csi = GetCsI(PART);
154  if (csi) {
155  stopped_in_chio = kFALSE;
156  if (csi->IsCalibrated()) {
157  /* CSI ENERGY CALIBRATION */
158  if (PART->GetIDCode() == KVINDRA::IDCodes::ID_CSI_PSA && PART->IsIsotope(4, 8)) {
159  fECsI = DoBeryllium8Calibration(PART);
160  }
161  else
162  fECsI = csi->GetCorrectedEnergy(PART, -1., kFALSE);
163  }
164  else {
165  SetNoCalibrationStatus(PART);
166  return;
167  }
168  if (fECsI <= 0 && (PART->GetECode() != KVINDRA::ECodes::SOME_ENERGY_LOSSES_CALCULATED)) { // DoBeryllium8Calibration returns fECsI<0 with ECode=SOME_ENERGY_LOSSES_CALCULATED if OK
169  SetBadCalibrationStatus(PART);// problem with CsI energy - no calibration
170  return;
171  }
172  }
173  if (PART->GetParameters()->GetBoolValue("IncludeEtalonsInCalibration")) {
174  auto sili = GetSiLi(PART);
175  if (sili) {
176  bool stopped_in_sili = PART->GetStoppingDetector()->IsType("SILI");
177  Double_t ERES = TMath::Abs(fECsI);
178  if (!PART->GetParameters()->GetBoolValue("PileupSiLi") && sili->IsCalibrated()) {
179  Bool_t si_transmission = kTRUE;
180  if (stopped_in_sili) {
181  si_transmission = kFALSE;
182  }
183  else {
184  sili->SetEResAfterDetector(ERES);
185  }
186  fESiLi = sili->GetCorrectedEnergy(PART, -1., si_transmission);
187  if (fESiLi <= 0) {
188  if (!stopped_in_sili && ERES > 0.0) {
189  if (!CalculateSiLiDEFromResidualEnergy(ERES, sili, PART)) return;
190  }
191  else {
192  SetBadCalibrationStatus(PART);
193  return;
194  }
195  }
196  }
197  else {
198  if (!CalculateSiLiDEFromResidualEnergy(ERES, sili, PART)) return;
199  }
200  }
201  auto si75 = GetSi75(PART);
202  if (si75) {
203  bool stopped_in_si75 = PART->GetStoppingDetector()->IsType("SI75");
204  Double_t ERES = TMath::Abs(fECsI) + TMath::Abs(fESiLi);
205  if (!PART->GetParameters()->GetBoolValue("PileupSi75")
206  && !PART->GetParameters()->GetBoolValue("PileupSiLi")
207  && si75->IsCalibrated()) {
208  Bool_t si_transmission = kTRUE;
209  if (stopped_in_si75) {
210  si_transmission = kFALSE;
211  }
212  else {
213  si75->SetEResAfterDetector(ERES);
214  }
215  fESi75 = si75->GetCorrectedEnergy(PART, -1., si_transmission);
216  if (fESi75 <= 0) {
217  if (!stopped_in_si75 && ERES > 0.0) {
218  if (!CalculateSi75DEFromResidualEnergy(ERES, si75, PART)) return;
219  }
220  else {
221  SetBadCalibrationStatus(PART);
222  return;
223  }
224  }
225  }
226  else {
227  if (!CalculateSi75DEFromResidualEnergy(ERES, si75, PART)) return;
228  }
229  }
230  }
231  if (theChio) {
232  /* IONISATION CHAMBER ENERGY CONTRIBUTION */
233  // if fUseFullChIoEnergyForCalib = kFALSE, ChIo was hit by other particles in group
234  // therefore we have to estimate the ChIo energy for this particle using the CsI energy
235  // if fPileupChIo = kTRUE, there appears to be another particle stopped in the ChIo
236  // therefore we have to estimate the ChIo energy for this particle using the CsI energy
237  Double_t ERES = TMath::Abs(fECsI) + TMath::Abs(fESiLi) + TMath::Abs(fESi75);
238  if (!PART->GetParameters()->GetBoolValue("PileupChIo")
239  && PART->GetParameters()->GetBoolValue("UseFullChIoEnergyForCalib")
240  && theChio->IsCalibrated()) {
241  // all is apparently well
242  Bool_t ci_transmission = kTRUE;
243  if (stopped_in_chio) {
244  ci_transmission = kFALSE;
245  }
246  else {
247  theChio->SetEResAfterDetector(ERES);
248  }
249  fEChIo = theChio->GetCorrectedEnergy(PART, -1., ci_transmission);
250  if (fEChIo <= 0) {
251  if (!stopped_in_chio && ERES > 0) {
252  if (!CalculateChIoDEFromResidualEnergy(PART, ERES)) return;
253  }
254  }
255  }
256  else {
257  if (!stopped_in_chio && ERES > 0) {
258  if (!CalculateChIoDEFromResidualEnergy(PART, ERES)) return;
259  }
260  }
261  }
262 
263  PART->SetEnergy(TMath::Abs(fECsI) + TMath::Abs(fESiLi) + TMath::Abs(fESi75) + TMath::Abs(fEChIo));
264 }
265 
266 
267 
270 
272 {
273  // Called by Identify() for particles stopping in etalon modules of Rings 10-17.
274 
275  KVIdentificationResult* IDcsi, *IDsilicsi, *IDsi75sili, *IDcisi75, *IDcicsi;
276  IDcsi = IDsilicsi = IDsi75sili = IDcisi75 = IDcicsi = nullptr;
277  if (PART.GetStoppingDetector()->IsType("CSI")) {
278  IDcsi = PART.GetIdentificationResult("CSI_R_L");
279  IDcicsi = PART.GetIdentificationResult("CI_CSI");
280  IDsilicsi = PART.GetIdentificationResult("SILI_CSI");
281  }
282  IDsi75sili = PART.GetIdentificationResult("SI75_SILI");
283  IDcisi75 = PART.GetIdentificationResult("CI_SI75");
284 
285  PART.SetParameter("PileupChIo", kFALSE);
286  PART.SetParameter("IncludeEtalonsInCalibration", kTRUE);
287 
288  Bool_t haveCsI = IDcsi && IDcsi->IDOK;
289  Bool_t haveSiLiCsI = IDsilicsi && IDsilicsi->IDOK;
290  Bool_t haveSi75SiLi = IDsi75sili && IDsi75sili->IDOK;
291  Bool_t haveChIoSi75 = IDcisi75 && IDcisi75->IDOK;
292 
293  KVIDTelescope* idt_csi, *idt_silicsi, *idt_si75sili, *idt_cisi75, *idt_cicsi;
294  idt_csi = idt_silicsi = idt_si75sili = idt_cisi75 = idt_cicsi = nullptr;
295  if (PART.GetStoppingDetector()->IsType("CSI")) {
296  idt_csi =
298  idt_silicsi =
300  idt_cicsi =
302  }
303  idt_si75sili = (KVIDTelescope*)PART.GetReconstructionTrajectory()->GetIDTelescopes()->FindObjectByType(IDsi75sili->GetType());
305 
306  // Treat cases where particle hit etalon telescope
307  if (idt_csi) {
308  if (haveCsI) {
309 
310  partID = *IDcsi;
311  identifying_telescope = idt_csi;
312 
313  if (haveSi75SiLi) {
314  // check for heavy fragment in Si75-SiLi
315  if (IDsi75sili->Z > partID.Z) {
316  if (haveChIoSi75) {
317  // check we don't have a better identification in ChIo-Si75
318  if (IDcisi75->IDquality < IDsi75sili->IDquality && IDcisi75->Z > partID.Z) {
319  PART.SetParameter("PileupSi75", kTRUE);
320  IDcisi75->SetComment("CsI identification with another particle stopped in Si75");
321  PART.SetParameter("UseFullChIoEnergyForCalib", kFALSE); // calculate ChIo energy for this particle
322  }
323  else {
324  PART.SetParameter("PileupSiLi", kTRUE);
325  IDsi75sili->SetComment("CsI identification with another particle stopped in SiLi");
326  PART.SetParameter("UseFullChIoEnergyForCalib", kFALSE); // calculate ChIo energy for this particle
327  }
328  }
329  }
330  }
331  else if (haveChIoSi75) {
332  // check for heavy fragment in ChIo-Si75
333  if (IDcisi75->Z > partID.Z) {
334  PART.SetParameter("PileupSi75", kTRUE);
335  IDcisi75->SetComment("CsI identification with another particle stopped in Si75");
336  PART.SetParameter("UseFullChIoEnergyForCalib", kFALSE); // calculate ChIo energy for this particle
337  }
338  }
339  return kTRUE;
340  }
341  else if (haveSiLiCsI) {
342  partID = *IDsilicsi;
343  identifying_telescope = idt_silicsi;
344  if (haveChIoSi75) {
345  // check for heavy fragment in ChIo-Si75
346  if (IDcisi75->Z > partID.Z) {
347  PART.SetParameter("PileupSi75", kTRUE);
348  IDcisi75->SetComment("CsI identification with another particle stopped in Si75");
349  PART.SetParameter("UseFullChIoEnergyForCalib", kFALSE); // calculate ChIo energy for this particle
350  }
351  }
352  return kTRUE;
353  }
354  }
355  else if (PART.GetStoppingDetector()->IsType("SILI")) {
356  if (haveSi75SiLi) {
357  partID = *IDsi75sili;
358  identifying_telescope = idt_si75sili;
359  // check ChIo-Si75 id is coherent (either no id or Z<=this one)
360  if (haveChIoSi75) {
361  if (IDcisi75->Z > partID.Z) PART.SetParameter("PileupChIo", kTRUE);
362  }
363  return kTRUE;
364  }
365  else if (haveChIoSi75) {
366  partID = *IDcisi75;
367  identifying_telescope = idt_cisi75;
368  return kTRUE;
369  }
370  }
371  else if (PART.GetStoppingDetector()->IsType("SI75")) { // MFR march 2014 SiLi is not the real stopping detector
372  if (haveChIoSi75) {
373  partID = *IDcisi75;
374  identifying_telescope = idt_cisi75;
375  return kTRUE;
376  } // end MFR march 2014
377  }
378 
379  return kFALSE;
380 }
381 
382 
383 
387 
389 {
390  // Etalon modules
391  // calculate fESiLi from residual CsI energy
392  Double_t e0 = sili->GetDeltaEFromERes(n->GetZ(), n->GetA(), ERES);
393  sili->SetEResAfterDetector(ERES);
394  fESiLi = sili->GetCorrectedEnergy(n, e0);
395  if (fESiLi <= 0) {
396  fESiLi = 0;
397  SetBadCalibrationStatus(n);
398  return kFALSE;
399  }
400  fESiLi = -TMath::Abs(fESiLi);
401  SetCalibrationStatus(*n, KVINDRA::ECodes::SOME_ENERGY_LOSSES_CALCULATED);
402  return kTRUE;
403 }
404 
405 
406 
410 
412 {
413  // Etalon modules
414  // calculate fESi75 from residual CsI+SiLi energy
415  Double_t e0 = si75->GetDeltaEFromERes(n->GetZ(), n->GetA(), ERES);
416  si75->SetEResAfterDetector(ERES);
417  fESi75 = si75->GetCorrectedEnergy(n, e0);
418  if (fESi75 <= 0) {
419  fESi75 = 0;
420  SetBadCalibrationStatus(n);
421  return kFALSE;
422  }
423  fESi75 = -TMath::Abs(fESi75);
424  SetCalibrationStatus(*n, KVINDRA::ECodes::SOME_ENERGY_LOSSES_CALCULATED);
425  return kTRUE;
426 }
427 
428 
bool Bool_t
constexpr Bool_t kFALSE
double Double_t
constexpr Bool_t kTRUE
virtual const Char_t * GetType() const
Definition: KVBase.h:176
Path taken by particles through multidetector geometry.
const KVSeqCollection * GetIDTelescopes() const
Information on relative positions of detectors & particle trajectories.
Base class for all detectors or associations of detectors in array which can identify charged particl...
Definition: KVIDTelescope.h:84
virtual Bool_t IsReadyForID()
virtual Bool_t Identify(KVIdentificationResult *, Double_t x=-1., Double_t y=-1.)
bool DoCoherencyAnalysis(KVReconstructedNucleus &PART) override
Coherency analysis for backward rings 10-17 of INDRA.
void DoCalibration(KVReconstructedNucleus *PART) override
Reconstruct particles in INDRA groups with etalon telescopes.
bool DoCoherencyAnalysis(KVReconstructedNucleus &PART) override
Bool_t CoherencyEtalons(KVReconstructedNucleus &PART)
Called by Identify() for particles stopping in etalon modules of Rings 10-17.
Bool_t CalculateSi75DEFromResidualEnergy(Double_t ERES, KVDetector *si75, KVReconstructedNucleus *n)
Bool_t CalculateSiLiDEFromResidualEnergy(Double_t ERES, KVDetector *sili, KVReconstructedNucleus *n)
void DoCalibration(KVReconstructedNucleus *PART) override
Calibration of particle stopping in etalon modules.
KVReconstructedNucleus * ReconstructTrajectory(const KVGeoDNTrajectory *traj, const KVGeoDetectorNode *node) override
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)
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
Bool_t GetBoolValue(const Char_t *name) const
Bool_t IsIsotope(Int_t Z, Int_t A) const
Definition: KVNucleus.h:330
KVNameValueList * GetParameters() const
Definition: KVParticle.h:818
void SetParameter(const Char_t *name, ValType value) const
Definition: KVParticle.h:822
void SetEnergy(Double_t e)
Definition: KVParticle.h:602
Nuclei reconstructed from data measured by a detector array .
virtual Int_t GetECode() const
KVIdentificationResult * GetIdentificationResult(Int_t i)
const KVReconNucTrajectory * GetReconstructionTrajectory() const
virtual Int_t GetIDCode() const
KVDetector * GetStoppingDetector() const
void SetDetector(int i, KVDetector *);
KaliVeda extensions to ROOT collection classes.
virtual TObject * FindObjectByType(const Char_t *) const
const Int_t n
Double_t Abs(Double_t d)
ClassImp(TPyArg)