KaliVeda
Toolkit for HIC analysis
KVINDRAForwardGroupReconstructor.cpp
1 //Created by KVClassFactory on Tue Feb 27 11:35:10 2018
2 //Author: John Frankland,,,
3 
4 #include "KVINDRAForwardGroupReconstructor.h"
5 #include "KVINDRACodeMask.h"
6 #include "KVIDGChIoSi.h"
7 #include "KVIDGCsI.h"
8 
9 #include <KVCsI.h>
10 #include <KVSilicon.h>
11 
13 
14 
15 
19 {
20  // Coherency analysis for forward rings 1-9 of INDRA
21 
22  bool ok = false;
23  if (PART.GetStoppingDetector()->IsType("CSI")) {
24  // particles stopping in CsI detectors
25  // check coherency of CsI and Si-CsI identifications
26  ok = CoherencySiCsI(PART);
27  if(theChio)
28  {
29  // we check that the ChIo contribution is sane:
30  // if no other particles hit this group, the Z given by the ChIoSi
31  // must be <= the Z found from Si-CsI or CsI identification
32  PART.SetParameter("UseFullChIoEnergyForCalib", CoherencyChIoSiCsI(PART));
33  }
34  }
35  else {
36  // particle stopped in Si (=> ChIo-Si, Si-PSA) or ChIo (=> Zmin)
37  ok = PART.IsIdentified() && identifying_telescope;
38  if(theChio)
39  PART.SetParameter("UseFullChIoEnergyForCalib", !(theChio->GetNHits() > 1));
40  }
41 
42  return ok;
43 }
44 
45 
46 
84 
86 {
87  // Special calibration for particles in rings 1 to 9
88  // We set the energy calibration code for the particle here:
89  //
90  //~~~{.cpp}
91  // KVINDRA::ECodes::NO_CALIBRATION_ATTEMPTED = 0, ///< particle stopped in detectors with no available calibration
92  // KVINDRA::ECodes::NORMAL_CALIBRATION = 1, ///< normal well-calibrated particle with no problems
93  // KVINDRA::ECodes::SOME_ENERGY_LOSSES_CALCULATED = 2, ///< particle calibration OK, with some detector energies calculated
94  // KVINDRA::ECodes::WARNING_CSI_MAX_ENERGY = 3, ///< particle calibration OK, although apparent energy would mean punching through the CsI
95  // KVINDRA::ECodes::BAD_CALIBRATION = 15 ///< calibration attempted but bad result (negative energies etc.)
96  //~~~
97  //
98  // The contributions from ChIo, Si, and CsI are stored in particle parameters
99  // INDRA.ECHIO, INDRA.ESI and INDRA.ECSI
100  // If the contribution is calculated rather than measured (see below), it is stored as a negative value.
101  // NOTE: in no case do we ever calculate an energy for uncalibrated detector using measured energy
102  // loss in the detector placed in front (i.e. calculate ECsI from deSi, or calculate ESi
103  // from deChIo) as this gives wildly varying (mostly false) results.
104  //
105  // For neutrons (IDCODE=1): if CsI is calibrated, we use the CsI light response to calculate
106  // the equivalent energy for a proton.
107  // For particles stopping in the CsI detector (IDCODE=2 or 3):
108  // - for "8Be" we use half the CsI light output to calculate 4He kinetic energy which is then doubled
109  // (we assume two 4He of identical energy), and ECODE=kECode2 (calculated)
110  // - if calibrated CsI energy is bizarre (<=0), we cannot calibrate the particle (ECODE=kECode15)
111  // - if the Silicon detector is not calibrated, or if coherency analysis indicates a pile-up
112  // in the silicon or other inconsistency, the Silicon energy is calculated from the calibrated
113  // CsI energy (ECODE=kECode2)
114  // - if the Ionisation Chamber is not calibrated, or if coherency analysis indicates a pile-up
115  // in the ChIo or other inconsistency, this contribution is calculated using the total
116  // cumulated energy measured in the CsI and/or Silicon detectors (ECODE=kECode2)
117  //
118  // For particles stopping in the Silicon detector (IDCODE=3, 4 or 5):
119  // - if no calibration exists for the Silicon, we cannot calibrate the particle (ECODE=kECode0)
120  // - if the Ionisation Chamber is not calibrated, or if coherency analysis indicates a pile-up
121  // in the ChIo or other inconsistency, this contribution is calculated using the total
122  // cumulated energy measured in the CsI and/or Silicon detectors (ECODE=kECode2)
123 
124  bool fUseFullChIoEnergyForCalib = PART->GetParameters()->GetBoolValue("UseFullChIoEnergyForCalib");
125  bool fPileup = PART->GetParameters()->GetBoolValue("Pileup");
126  bool fCoherent = PART->GetParameters()->GetBoolValue("Coherent");
127 
128  if (PART->GetIDCode() == KVINDRA::IDCodes::ID_NEUTRON) { // neutrons
129  DoNeutronCalibration(PART);
130  return;
131  }
132 
133  Bool_t stopped_in_silicon = kTRUE;
134 
135  auto si = GetSi(PART);
136  auto csi = GetCsI(PART);
137  if (csi) {
138  stopped_in_silicon = kFALSE;
139  if (csi->IsCalibrated() && csi->GetDetectorSignalValue("TotLight") > 0) {
140  /* CSI ENERGY CALIBRATION */
141  if (PART->GetIDCode() == KVINDRA::IDCodes::ID_CSI_PSA && PART->IsIsotope(4, 8)) {
143  }
144  else
145  fECsI = csi->GetCorrectedEnergy(PART, -1., kFALSE);
146  }
147  else if ((PART->GetIDCode()!=KVINDRA::IDCodes::ID_GAMMA) && si && !fPileup && fCoherent && si->IsCalibrated()) {
148  // use silicon energy to calculate CsI energy
149  fESi = si->GetCorrectedEnergy(PART);
150  if (fESi <= 0) {
151  // problem with silicon calibration
153  return;
154  }
155  fECsI = si->GetEResFromDeltaE(PART->GetZ(), PART->GetA());
156  // sanity check: very small DE can give very large Eres
157  auto de_max = csi->GetMaxDeltaE(PART->GetZ(), PART->GetA());
158  if (fECsI > de_max)
160  else
162  fECsI = -fECsI;
163  }
164  else {
165  SetNoCalibrationStatus(PART);// no CsI calibration - no calibration performed
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 (si && (PART->GetIDCode()!=KVINDRA::IDCodes::ID_GAMMA)) {
174  /* SILICIUM ENERGY CONTRIBUTION */
175  // if fPileup = kTRUE, the Silicon energy appears to include a contribution from another particle
176  // therefore we have to estimate the silicon energy for this particle using the CsI energy
177  // if fCoherent = kFALSE, the Silicon energy is too small to be consistent with the CsI identification,
178  // therefore we have to estimate the silicon energy for this particle using the CsI energy
179 
180  if (PART->GetIDCode() == KVINDRA::IDCodes::ID_STOPPED_IN_FIRST_STAGE && stopped_in_silicon) {
181  // particles stopped in Silicon detectors with no identification except estimation of Zmin (case of INDRA without Ionization Chambers):
182  // if silicon is calibrated, give measured energy in silicon as particle energy
183  if (si->IsCalibrated())
184  PART->SetEnergy(si->GetEnergy());
185  else
187  return;
188  }
189 
190  if (!fPileup && fCoherent && si->IsCalibrated()) {
191  // all is apparently well. use full energy deposited in silicon.
192  Bool_t si_transmission = kTRUE;
193  if (stopped_in_silicon) {
194  si_transmission = kFALSE;
195  }
196  else {
197  si->SetEResAfterDetector(TMath::Abs(fECsI));
198  }
199  fESi = si->GetCorrectedEnergy(PART, -1., si_transmission);
200  if (fESi <= 0) {
201  // problem with silicon calibration
202  print_part = true;
203  if (!stopped_in_silicon && (TMath::Abs(fECsI) > 0.0)) {
204  if (!CalculateSiliconDEFromResidualEnergy(PART, si)) return;
205  }
206  else {
207  // stopped in Si with bad Si calibration - no good
209  return;
210  }
211  }
212  }
213  else {
214  if (!stopped_in_silicon && (TMath::Abs(fECsI) > 0.0)) {
215  if (!CalculateSiliconDEFromResidualEnergy(PART, si)) return;
216  }
217  else {
218  // cannot calibrate particle stopping in silicon in this case
220  return;
221  }
222  }
223 
224  }
225  if (theChio && (PART->GetIDCode()!=KVINDRA::IDCodes::ID_GAMMA)) {
226  /* CHIO ENERGY CONTRIBUTION */
227  // if fUseFullChIoEnergyForCalib = kFALSE, we have to estimate the ChIo energy for this particle
229  if (fUseFullChIoEnergyForCalib && theChio->IsCalibrated()) {
230  // all is apparently well
231  if (!PART->GetStoppingDetector()->IsType("CI")) {
234  }
235  else {
236  // particle stopped in chio, not in transmission
237  fEChIo = theChio->GetCorrectedEnergy(PART, -1., kFALSE);
238  }
239  if (fEChIo < 0.) {
240  // bad chio calibration
241  if (!PART->GetStoppingDetector()->IsType("CI") && (ERES > 0.0)) {
242  if (!CalculateChIoDEFromResidualEnergy(PART, ERES)) return;
243  }
244  }
245  }
246  else {
247  if (!PART->GetStoppingDetector()->IsType("CI") && (ERES > 0.0)) {
248  if (!CalculateChIoDEFromResidualEnergy(PART, ERES)) return;
249  }
250  else {
251  // particle stopped in ChIo, no calibration available
253  return;
254  }
255  }
256  }
258 }
259 
260 
261 
262 
266 
268 {
269  // use energy of CsI calculated using the Z & A of the CsI identification
270  // to calculate the energy deposited by the neutron
272  KVNucleus tmp(IDcsi->Z, IDcsi->A);
273  auto csi = GetCsI(PART);
274  if (csi && csi->IsCalibrated()) {
275  fECsI = csi->GetCorrectedEnergy(&tmp, -1., kFALSE);
276  PART->SetEnergy(fECsI);
277  SetCalibrationStatus(*PART, KVINDRA::ECodes::SOME_ENERGY_LOSSES_CALCULATED); // not a real energy measure
278  }
279  else
281 }
282 
283 
284 
285 
297 
299 {
300  // Called by DoCoherency() for particles stopping in CsI detectors on rings 2-9,
301  // which have a ChIo in front of them.
302  //
303  // we check that the ChIo contribution is sane:
304  // if no other particles hit this group, the Z given by the ChIoSi
305  // must be <= the Z found from Si-CsI or CsI-RL identification
306  //
307  // in this case the measured energy loss of the ChIo can be solely attributed to this particle
308  // and we return kTRUE;
309 
310  // ChIo was hit by more than one particle in group
311  if (theChio && theChio->GetNHits() > 1) {
312  return kFALSE;
313  }
314 
316  if (!IDchiosi->IDattempted) {
317  // no ChIo-Si identification ? assume coherency ?
318  return kTRUE;
319  }
320 
321  // if we have a successful ChIo-Si id with a Z > Z given by CsI or Si-CsI id,
322  // then we consider that there is a pile-up in the ChIo
323  // note that we consider Z_ChIoSi = 1 to mean the ChIo is in the pedestal i.e. nothing seen
324  // we also require the chio-si identification to be above the punch-through line
325  if (IDchiosi->IDOK && IDchiosi->Z > 1 && IDchiosi->IDquality != KVIDGChIoSi::k_BelowPunchThrough && IDchiosi->Z > partID.Z) {
326  return kFALSE;
327  }
328 
329  return kTRUE;
330 }
331 
332 
333 
346 
348 {
349  // Called by DoCoherency() for particles stopping in CsI detectors on rings 1-9,
350  // which have a Silicon detector just in front of them.
351  //
352  // coherent = kFALSE if CsI and Si-CsI identifications are not coherent.
353  // the CsI identification is kept, either the Si signal
354  // was not good (particle hitting dead zone), or it actually corresponds
355  // to two particles reaching the CsI at the same time
356  // pileup = kTRUE means that the (charged) particle identified in CsI-R/L is correct,
357  // and there is probably a second particle which stopped in the silicon
358  // detector at the same time, to be identified in ChIo-Si/Si-PSA after
359  // subtraction of the Silicon contribution
360 
365  // in case we have PSA identification in Si detector
368  auto the_CsI = idt_csi->GetDetector(1);
369  bool fCoherent = kTRUE;
370  bool fPileup = kFALSE;
371  auto nid = PART.GetNumberOfIdentificationResults();
372 
373  // Unsuccessful/no CsI id attempt with successful id further up trajectory ?
374  // Then use first successful identification result
375  if (!IDcsi->IDOK) {
376  if(nid>1)
377  {
378  for(int i_id=2; i_id<=nid; ++i_id)
379  {
380  auto next_idr = PART.GetIdentificationResult(i_id);
381  if(next_idr && next_idr->IDattempted && next_idr->IDOK)
382  {
383  auto next_idt = (KVIDTelescope*)PART.GetReconstructionTrajectory()->GetIDTelescopes()->FindObjectByType(next_idr->GetIDType());
384  if(next_idt)
385  {
386  if(next_idt->HasDetector(the_CsI))
387  {
388  // CsI is still the stopping detector, we just change the ID
389  partID = *next_idr;
390  identifying_telescope = next_idt;
391  PART.SetParameter("Coherent", fCoherent);
392  PART.SetParameter("Pileup", fPileup);
393  PART.SetParameter("No CsI id", Form("Replaced with %s id", partID.GetIDType()));
394  return kTRUE;
395  }
396  else
397  {
398  // ID achieved without CSI, change stopping detector & recon trajectory
399  auto new_stop_det = next_idt->GetDetector(next_idt->GetSize());
400  auto traj = (KVGeoDNTrajectory*)new_stop_det->GetNode()->GetTrajectories()->First();
401  auto new_recon_traj = (const KVReconNucTrajectory*)GetGroup()->GetTrajectoryForReconstruction(traj, new_stop_det->GetNode());
402  PART.ModifyReconstructionTrajectory(new_recon_traj);
403  partID = *next_idr;
404  identifying_telescope = next_idt;
405  PART.SetParameter("Coherent", fCoherent);
406  PART.SetParameter("Pileup", fPileup);
407  PART.SetParameter("No CsI id", Form("Replaced with %s id, stopping detector changed to %s", partID.GetIDType(), new_stop_det->GetName()));
408  return kTRUE;
409  }
410  }
411  }
412  }
413  // no identification possible
414  if(PART.IsIdentified())
415  PART.SetIsUnidentified();
416  return kFALSE;
417  }
418  partID = *IDsicsi;
419  identifying_telescope = idt_sicsi;
420  PART.SetParameter("Coherent", fCoherent);
421  PART.SetParameter("Pileup", fPileup);
422  return kTRUE;
423  }
424 
425  // check coherency of CsI-R/L and Si-CsI identifications
426  if (IDcsi->IDOK) {
427  partID = *IDcsi;
428  identifying_telescope = idt_csi;
429 
430  /************ CHECKS FOR 'GAMMA' IDENTIFICATION IN CSI ID TELESCOPE ************/
431  if(IDcsi->IDquality==KVIDGCsI::kICODE10)
432  {
433  if(nid>1)
434  {
435  for(int i_id=2; i_id<=nid; ++i_id)
436  {
437  auto next_idr = PART.GetIdentificationResult(i_id);
438  if(next_idr && next_idr->IDattempted && next_idr->IDOK)
439  {
440  auto next_idt = (KVIDTelescope*)PART.GetReconstructionTrajectory()->GetIDTelescopes()->FindObjectByType(next_idr->GetIDType());
441  if(next_idt)
442  {
443  if(next_idt->HasDetector(the_CsI))
444  {
445  // We check the next id telescope along the trajectory which includes the CsI detector as its second member
446  // If this telescope has a successful (charged) particle identification, we keep that one instead.
447  // -- check for incorrect gamma identification in CsI, with good charged particle id in DE-CsI
448  // this may occur for low energy Z=1,2, etc. which are difficult to distinguish from gamma line
449  partID = *next_idr;
450  identifying_telescope = next_idt;
451  PART.SetParameter("Coherent", fCoherent);
452  PART.SetParameter("Pileup", fPileup);
453  PART.SetParameter("Bad gamma id", Form("switched to %s id: Z=%d A=%d",next_idr->GetIDType(),next_idr->Z,next_idr->A));
454  return kTRUE;
455  }
456  else
457  {
458  // a gamma identified in the CsI will hide any charged particles which stop in a detector further
459  // up the reconstruction trajectory. if an identification which does NOT include the CsI was successful,
460  // we add a coherency particle stopping in the 'last' detector of the corresponding idtelescope.
461  auto new_stop_det = next_idt->GetDetector(next_idt->GetSize());
462  coherency_particles.push_back(
463  {
464  &PART, new_stop_det->GetNode(), (KVGeoDNTrajectory*)the_CsI->GetNode()->GetTrajectories()->First(), next_idt, i_id, nid
465  }
466  );
467  fPileup=true;
468  PART.SetParameter("Coherent", fCoherent);
469  PART.SetParameter("Pileup", fPileup);
470  PART.SetParameter("Gamma pileup", Form("added new particle identified in %s", next_idt->GetName()));
471  return kTRUE;
472  }
473  }
474  }
475  }
476  }
477  }
478  // Neutrons have no energy loss in Si detector (pedestal), have a reaction in the CsI and create a Z=1
479  // or Z=2 which is identified in CsI R-L, while they show up in Si-CsI maps as a horizontal
480  // band around the Si pedestal for low energies (energies where proton dE is significantly larger than
481  // the pedestal).
482  if ((IDcsi->Z == 1 || IDcsi->Z == 2) && IDsicsi->IDattempted) {
484  // explicit treatment of 'neutron-like' particles with a cut in Si-CsI id grid
485  partID = *IDsicsi;
486  identifying_telescope = idt_sicsi;
487  partID.IDOK = kTRUE;
488  partID.Zident = kTRUE;
489  partID.Aident = kTRUE;
490  partID.Z = 0;
491  partID.A = 1;
492  partID.IDcode = KVINDRA::IDCodes::ID_NEUTRON; // general code for neutrons
493  PART.SetParameter("Coherent", fCoherent);
494  PART.SetParameter("Pileup", fPileup);
495  return kTRUE;
496  }
497  }
498 
499  // We check the coherency of the mass and charge identifications
500  // If a successful Si-CsI identification is available we check:
501  // if Si-CsI gives A & Z - must have same Z, A within +/-1 unit
502  // if Z or A smaller => incoherency : pile-up of two particles in CsI ?
503  // or bad signal from Si detector (dead zones) ?
504  // if Z or A larger, CsI identification is good,
505  // assume another particle stopped in Si (identify in ChIo-Si)
506  // if Si-CsI gives just Z - must have same Z
507  // if Z smaller => incoherency : pile-up of two particles in CsI ?
508  // or bad signal from Si detector (dead zones) ?
509  // if Z larger => CsI identification is good,
510  // assume another particle stopped in Si (identify in ChIo-Si)
511  //
512  // If CsI identification gives code KVIDGCsI::kICode1 ou KVIDGCsI::kICode3 and the
513  // Si-CsI gives the same Z but A = Acsi + 1, we use the Si-CsI identification.
514  //
515  // If CsI identification gives code KVIDGCsI::kICode2 ou KVIDGCsI::kICode3 and the
516  // Si-CsI gives the same Z but A = Acsi - 1, we use the Si-CsI identification.
517  //
518  // N.B. if CsI-R/L identification gives "8Be" (2 alpha particles) then there are two correct possibilities:
519  // 1) Si-CsI identification gives 7Li => CsI identification is correct ("8Be")
520  // 2) Si-CsI identification gives 8He => the particle is 8He (falls on same R/L line as 2*alpha)
521  // Seeing the very low statistics for 8He compared to 8Be/2alpha, we assume that if Si-CsI id
522  // gives something above 8He it is either incoherent (below 7Li) or 8Be + something else in ChIo-Si
523  // (above 7Li).
524  Int_t Zref = IDcsi->Z;
525  Int_t Aref = IDcsi->A;
526  if (IDsicsi->IDOK) {
527 
528  if (IDsicsi->Aident) { // Si-CsI provides mass identification
529 
530  if (IDcsi->Z == 4 && IDcsi->A == 8) {
531  // traitement special 8Be
532  // if sicsi => 7Li, it is 8Be (2alpha)
533  // if sicsi => 8He, it is 8He
534  if (IDsicsi->Z < 2 || (IDsicsi->Z == 2 && IDsicsi->A < 7)) {
535  fCoherent = kFALSE;
536  IDsicsi->SetComment("CsI-R/L & Si-CsI identifications not coherent");
537  PART.SetParameter("Coherent", fCoherent);
538  PART.SetParameter("Pileup", fPileup);
539  return kTRUE;
540  }
541  else if (IDsicsi->Z == 2 && IDsicsi->A > 6 && IDsicsi->A < 10) {
542  // accept helium-7,8,9 as 8He
543  partID = *IDsicsi;
544  identifying_telescope = idt_sicsi;
545  PART.SetParameter("Coherent", fCoherent);
546  PART.SetParameter("Pileup", fPileup);
547  return kTRUE;
548  }
549  else if ((IDsicsi->Z == 2 && IDsicsi->A > 9) || (IDsicsi->Z == 3 && IDsicsi->A < 6)) {
550  fCoherent = kFALSE;
551  IDsicsi->SetComment("CsI-R/L & Si-CsI identifications not coherent");
552  PART.SetParameter("Coherent", fCoherent);
553  PART.SetParameter("Pileup", fPileup);
554  return kTRUE;
555  }
556  else if (IDsicsi->Z == 3 && IDsicsi->A > 5 && IDsicsi->A < 9) {
557  // accept lithium-6,7,8 as 7Li
558  PART.SetParameter("Coherent", fCoherent);
559  PART.SetParameter("Pileup", fPileup);
560  return kTRUE;
561  }
562  else if ((IDsicsi->Z == 3 && IDsicsi->A > 8) || IDsicsi->Z > 3) {
563  fPileup = kTRUE;
564  IDsicsi->SetComment("Second particle stopping in Si, identification ChIo-Si required");
565  PART.SetParameter("Coherent", fCoherent);
566  PART.SetParameter("Pileup", fPileup);
567  return kTRUE;
568  }
569  }
570  // if CsI says A could be bigger and Si-CsI gives same Z and A+1, use Si-CsI
571  if ((IDsicsi->Z == Zref) && (IDsicsi->A == (Aref + 1))
572  && (IDcsi->IDquality == KVIDGCsI::kICODE1 || IDcsi->IDquality == KVIDGCsI::kICODE3)) {
573  partID = *IDsicsi;
574  identifying_telescope = idt_sicsi;
575  PART.SetParameter("Coherent", fCoherent);
576  PART.SetParameter("Pileup", fPileup);
577  return kTRUE;
578  }
579  // if CsI says A could be smaller and Si-CsI gives same Z and A-1, use Si-CsI
580  if ((IDsicsi->Z == Zref) && (IDsicsi->A == (Aref - 1))
581  && (IDcsi->IDquality == KVIDGCsI::kICODE2 || IDcsi->IDquality == KVIDGCsI::kICODE3)) {
582  partID = *IDsicsi;
583  identifying_telescope = idt_sicsi;
584  PART.SetParameter("Coherent", fCoherent);
585  PART.SetParameter("Pileup", fPileup);
586  return kTRUE;
587  }
588  // Si-CsI gives unambiguous mass identification, CsI is less sure, and Si-CsI gives same Z, smaller A (=>no pileup): use Si-CsI
589  if((IDsicsi->Z == Zref) && (IDsicsi->A < Aref)
590  && (IDsicsi->IDquality == KVIDZAGrid::kICODE0 && IDcsi->IDquality > KVIDZAGrid::kICODE0))
591  {
592  partID = *IDsicsi;
593  identifying_telescope = idt_sicsi;
594  PART.SetParameter("Coherent", fCoherent);
595  PART.SetParameter("Pileup", fPileup);
596  return kTRUE;
597  }
598  // everything else - Z must be same, A +/- 1 unit
599  if (IDsicsi->Z == Zref && TMath::Abs(IDsicsi->A - Aref) < 2) {
600  PART.SetParameter("Coherent", fCoherent);
601  PART.SetParameter("Pileup", fPileup);
602  return kTRUE;
603  }
604  else if (IDsicsi->Z < Zref || (IDsicsi->Z == Zref && IDsicsi->A < (Aref - 1))) {
605  fCoherent = kFALSE;
606  IDsicsi->SetComment("CsI-R/L & Si-CsI identifications not coherent");
607  PART.SetParameter("Coherent", fCoherent);
608  PART.SetParameter("Pileup", fPileup);
609  return kTRUE;
610  }
611  else if (IDsicsi->Z > Zref || (IDsicsi->Z == Zref && IDsicsi->A > (Aref + 1))) {
612  fPileup = kTRUE;
613  IDsicsi->SetComment("Second particle stopping in Si");
614  PART.SetParameter("Coherent", fCoherent);
615  PART.SetParameter("Pileup", fPileup);
616  return kTRUE;
617  }
618  }
619  else { // only Z identification from Si-CsI
620  if (IDcsi->Z == 4 && IDcsi->A == 8) {
621  // traitement special 8Be
622  // we ask for Z to be equal 3 in SiCsI, but with no mass identification
623  // we do not try for 8He identification
624  if (IDsicsi->Z < 3) {
625  fCoherent = kFALSE;
626  IDsicsi->SetComment("CsI-R/L & Si-CsI identifications not coherent");
627  PART.SetParameter("Coherent", fCoherent);
628  PART.SetParameter("Pileup", fPileup);
629  return kTRUE;
630  }
631  else if (IDsicsi->Z == 3) {
632  PART.SetParameter("Coherent", fCoherent);
633  PART.SetParameter("Pileup", fPileup);
634  return kTRUE;
635  }
636  else {
637  fPileup = kTRUE;
638  IDsicsi->SetComment("Second particle stopping in Si, identification ChIo-Si required");
639  PART.SetParameter("Coherent", fCoherent);
640  PART.SetParameter("Pileup", fPileup);
641  return kTRUE;
642  }
643  }
644  // everything else
645  if (IDsicsi->Z == Zref) {
646  PART.SetParameter("Coherent", fCoherent);
647  PART.SetParameter("Pileup", fPileup);
648  return kTRUE;
649  }
650  else if (IDsicsi->Z < Zref) {
651  fCoherent = kFALSE;
652  IDsicsi->SetComment("CsI-R/L & Si-CsI identifications not coherent");
653  PART.SetParameter("Coherent", fCoherent);
654  PART.SetParameter("Pileup", fPileup);
655  return kTRUE;
656  }
657  else {
658  fPileup = kTRUE;
659 
660  IDsicsi->SetComment("Second particle stopping in Si, identification ChIo-Si required");
661  PART.SetParameter("Coherent", fCoherent);
662  PART.SetParameter("Pileup", fPileup);
663  return kTRUE;
664  }
665  }
666  }
667  else if (IDsi && IDsi->IDOK)
668  {
669  // check for particle stopping in Si detector
670  if(IDsi->Z > Zref)
671  {
672  // pile-up: a second charged particle stopped in Si
673  auto new_stop_det = idt_si->GetDetector(1);
674  coherency_particles.push_back(
675  {
676  &PART, new_stop_det->GetNode(), (KVGeoDNTrajectory*)the_CsI->GetNode()->GetTrajectories()->First(),
677  idt_si, 3, nid
678  }
679  );
680  fPileup=true;
681  PART.SetParameter("Coherent", fCoherent);
682  PART.SetParameter("Pileup", fPileup);
683  PART.SetParameter("Ion pileup", Form("added new particle identified in %s", idt_si->GetName()));
684  return kTRUE;
685  }
686  }
687  else if (IDsicsi->IDattempted)
688  {
689  if(IDsicsi->IDquality == 4 || IDsicsi->IDquality == 5)
690  {
691  // "noise" in between Si-CsI identification lines => pile-up with good particle
692  // in CsI plus another particle stopped in the Silicon
693  if (IDsicsi->Z < Zref) fCoherent = kFALSE;
694  else fPileup = kTRUE;
695  }
696  else if (IDsicsi->IDquality == 7)
697  {
698  // Point to identify in Si-CsI matrix is above the last line in the grid
699  // Z given to identification result is Zmin = lastZ + 1
700  // if this is > Z from CsI identification, pileup in Si
701  if (IDsicsi->Z > Zref) fPileup = kTRUE;
702  }
703  }
704  PART.SetParameter("Coherent", fCoherent);
705  PART.SetParameter("Pileup", fPileup);
706  return kTRUE;
707  }
708  PART.SetParameter("Coherent", fCoherent);
709  PART.SetParameter("Pileup", fPileup);
710  return kFALSE;
711 }
712 
713 
714 
724 
726 {
727  // calculate fESi from fECsI
728  // returns kTRUE if OK
729  //
730  // this sets directly the value of fESi
731  //
732  // if result is not good, bad calibration status is set for particle and we return false: in this case fESi=0
733  //
734  // if result is good, particle calibration status set to SOME_ENERGY_LOSSES_CALCULATED and fESi<0
735 
736  Double_t e0 = si->GetDeltaEFromERes(n->GetZ(), n->GetA(), TMath::Abs(fECsI));
738  fESi = si->GetCorrectedEnergy(n, e0);
739  if (fESi <= 0) {
740  // can't calculate fESi from CsI energy - bad
742  fESi = 0;
743  return kFALSE;
744  }
745  else {
746  // calculated energy: negative
747  fESi = -TMath::Abs(fESi);
748  SetCalibrationStatus(*n, KVINDRA::ECodes::SOME_ENERGY_LOSSES_CALCULATED);
749  }
750  return kTRUE;
751 }
752 
753 
754 
int Int_t
bool Bool_t
constexpr Bool_t kFALSE
double Double_t
constexpr Bool_t kTRUE
char * Form(const char *fmt,...)
virtual const Char_t * GetType() const
Definition: KVBase.h:176
virtual Bool_t IsType(const Char_t *typ) const
Definition: KVBase.h:184
Base class for detector geometry description, interface to energy-loss calculations.
Definition: KVDetector.h:160
Int_t GetNHits() const
Return the number of particles hitting this detector in an event.
Definition: KVDetector.h:444
Bool_t IsCalibrated() const
Definition: KVDetector.h:406
virtual void SetEResAfterDetector(Double_t e)
Definition: KVDetector.h:623
Double_t GetDeltaEFromERes(Int_t Z, Int_t A, Double_t Eres) override
virtual Double_t GetCorrectedEnergy(KVNucleus *, Double_t e=-1., Bool_t transmission=kTRUE)
Definition: KVDetector.cpp:749
Path taken by particles through multidetector geometry.
const KVSeqCollection * GetIDTelescopes() const
KVIDTelescope * identifying_telescope
telescope which identified current particle
KVGroup * GetGroup() const
void SetCalibrationStatus(KVReconstructedNucleus &PART, UShort_t code)
KVIdentificationResult partID
identification to be applied to current particle
std::vector< particle_to_add_from_coherency_analysis > coherency_particles
const KVGeoDNTrajectory * GetTrajectoryForReconstruction(const KVGeoDNTrajectory *t, const KVGeoDetectorNode *n) const
Definition: KVGroup.h:117
@ k_BelowPunchThrough
Definition: KVIDGChIoSi.h:77
Base class for all detectors or associations of detectors in array which can identify charged particl...
Definition: KVIDTelescope.h:85
KVDetector * GetDetector(UInt_t n) const
Reconstruct data in rings 1-9 of INDRA.
Bool_t CalculateSiliconDEFromResidualEnergy(KVReconstructedNucleus *n, KVDetector *si)
void DoNeutronCalibration(KVReconstructedNucleus *PART)
Bool_t CoherencyChIoSiCsI(KVReconstructedNucleus &PART)
void DoCalibration(KVReconstructedNucleus *PART) override
KVDetector * GetSi(KVReconstructedNucleus *n)
Bool_t CoherencySiCsI(KVReconstructedNucleus &PART)
void SetNoCalibrationStatus(KVReconstructedNucleus *n)
Bool_t CalculateChIoDEFromResidualEnergy(KVReconstructedNucleus *n, Double_t ERES)
double DoBeryllium8Calibration(KVReconstructedNucleus *n)
KVDetector * GetCsI(KVReconstructedNucleus *n)
void SetBadCalibrationStatus(KVReconstructedNucleus *n)
KVDetector * theChio
the ChIo of the group
@ WARNING_CSI_MAX_ENERGY
particle calibration OK, although apparent energy would mean punching through the CsI
Definition: KVINDRA.h:177
@ SOME_ENERGY_LOSSES_CALCULATED
particle calibration OK, with some detector energies calculated
Definition: KVINDRA.h:176
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
const Char_t * GetIDType() const
Int_t deltaEpedestal
special code for handling particles which give no signal in deltaE
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
Bool_t Zident
=kTRUE if Z of particle established
Bool_t GetBoolValue(const Char_t *name) const
Description of properties and kinematics of atomic nuclei.
Definition: KVNucleus.h:123
Int_t GetA() const
Definition: KVNucleus.cpp:796
Bool_t IsIsotope(Int_t Z, Int_t A) const
Definition: KVNucleus.h:330
Int_t GetZ() const
Return the number of proton / atomic number.
Definition: KVNucleus.cpp:767
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
Path through detector array used to reconstruct detected particle.
Nuclei reconstructed from data measured by a detector array .
virtual Int_t GetECode() const
Int_t GetNumberOfIdentificationResults() const
KVIdentificationResult * GetIdentificationResult(Int_t i)
const KVReconNucTrajectory * GetReconstructionTrajectory() const
virtual Int_t GetIDCode() const
KVDetector * GetStoppingDetector() const
void SetDetector(int i, KVDetector *);
void ModifyReconstructionTrajectory(const KVReconNucTrajectory *t)
virtual TObject * FindObjectByType(const Char_t *) const
const char * GetName() const override
const Int_t n
Double_t Abs(Double_t d)
ClassImp(TPyArg)