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(Form("Z=%d,A=%d",PART->GetZ(),PART->GetA())) && 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(Form("Z=%d,A=%d",IDcsi->Z,IDcsi->A))) {
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  }
414  // no identification possible
415  if(PART.IsIdentified())
416  PART.SetIsUnidentified();
417  return kFALSE;
418  }
419 
420  // check coherency of CsI-R/L and Si-CsI identifications
421  if (IDcsi->IDOK) {
422  partID = *IDcsi;
423  identifying_telescope = idt_csi;
424 
425  /************ CHECKS FOR 'GAMMA' IDENTIFICATION IN CSI ID TELESCOPE ************/
426  if(IDcsi->IDquality==KVIDGCsI::kICODE10)
427  {
428  if(nid>1)
429  {
430  for(int i_id=2; i_id<=nid; ++i_id)
431  {
432  auto next_idr = PART.GetIdentificationResult(i_id);
433  if(next_idr && next_idr->IDattempted && next_idr->IDOK)
434  {
435  auto next_idt = (KVIDTelescope*)PART.GetReconstructionTrajectory()->GetIDTelescopes()->FindObjectByType(next_idr->GetIDType());
436  if(next_idt)
437  {
438  if(next_idt->HasDetector(the_CsI))
439  {
440  // We check the next id telescope along the trajectory which includes the CsI detector as its second member
441  // If this telescope has a successful (charged) particle identification, we keep that one instead.
442  // -- check for incorrect gamma identification in CsI, with good charged particle id in DE-CsI
443  // this may occur for low energy Z=1,2, etc. which are difficult to distinguish from gamma line
444  partID = *next_idr;
445  identifying_telescope = next_idt;
446  PART.SetParameter("Coherent", fCoherent);
447  PART.SetParameter("Pileup", fPileup);
448  PART.SetParameter("Bad gamma id", Form("switched to %s id: Z=%d A=%d",next_idr->GetIDType(),next_idr->Z,next_idr->A));
449  return kTRUE;
450  }
451  else
452  {
453  // a gamma identified in the CsI will hide any charged particles which stop in a detector further
454  // up the reconstruction trajectory. if an identification which does NOT include the CsI was successful,
455  // we add a coherency particle stopping in the 'last' detector of the corresponding idtelescope.
456  auto new_stop_det = next_idt->GetDetector(next_idt->GetSize());
457  coherency_particles.push_back(
458  {
459  &PART, new_stop_det->GetNode(), (KVGeoDNTrajectory*)the_CsI->GetNode()->GetTrajectories()->First(), next_idt, i_id, nid
460  }
461  );
462  fPileup=true;
463  PART.SetParameter("Coherent", fCoherent);
464  PART.SetParameter("Pileup", fPileup);
465  PART.SetParameter("Gamma pileup", Form("added new particle identified in %s", next_idt->GetName()));
466  return kTRUE;
467  }
468  }
469  }
470  }
471  }
472  }
473  // Neutrons have no energy loss in Si detector (pedestal), have a reaction in the CsI and create a Z=1
474  // or Z=2 which is identified in CsI R-L, while they show up in Si-CsI maps as a horizontal
475  // band around the Si pedestal for low energies (energies where proton dE is significantly larger than
476  // the pedestal).
477  if ((IDcsi->Z == 1 || IDcsi->Z == 2) && IDsicsi->IDattempted) {
479  // explicit treatment of 'neutron-like' particles with a cut in Si-CsI id grid
480  partID = *IDsicsi;
481  identifying_telescope = idt_sicsi;
482  partID.IDOK = kTRUE;
483  partID.Zident = kTRUE;
484  partID.Aident = kTRUE;
485  partID.Z = 0;
486  partID.A = 1;
487  partID.IDcode = KVINDRA::IDCodes::ID_NEUTRON; // general code for neutrons
488  PART.SetParameter("Coherent", fCoherent);
489  PART.SetParameter("Pileup", fPileup);
490  return kTRUE;
491  }
492  }
493 
494  // We check the coherency of the mass and charge identifications
495  //
496  // If the CsI identification is not isotopic i.e. IDcsi->Aident=false and Si-CsI identification *is* isotopic,
497  // we prefer the Si-CsI identification always.
498  //
499  // Otherwise, if CsI identification *is* isotopic:
500  // If a successful Si-CsI identification is available we check:
501  // if Si-CsI has isotopic identification:
502  // - for Z=1, at low energies Si-CsI identification is more sure than PSA in CsI, as all isotopes merge
503  // together and can even be confused with gammas at low energy in the CsI.
504  // Therefore as long as Si-CsI ID is good for Z=1, we prefer Si-CsI
505  // - for Z>1, must have same Z, A within +/-1 unit
506  // if Z or A smaller => incoherency : pile-up of two particles in CsI ?
507  // or bad signal from Si detector (dead zones) ?
508  // if Z or A larger, CsI identification is good,
509  // assume another particle stopped in Si (identify in ChIo-Si)
510  // if Si-CsI gives just Z - must have same Z
511  // if Z smaller => incoherency : pile-up of two particles in CsI ?
512  // or bad signal from Si detector (dead zones) ?
513  // if Z larger => CsI identification is good,
514  // assume another particle stopped in Si (identify in ChIo-Si)
515  //
516  // If CsI identification gives code KVIDGCsI::kICode1 ou KVIDGCsI::kICode3 and the
517  // Si-CsI gives the same Z but A = Acsi + 1, we use the Si-CsI identification.
518  //
519  // If CsI identification gives code KVIDGCsI::kICode2 ou KVIDGCsI::kICode3 and the
520  // Si-CsI gives the same Z but A = Acsi - 1, we use the Si-CsI identification.
521  //
522  // N.B. if CsI-R/L identification gives "8Be" (2 alpha particles) then there are two correct possibilities:
523  // 1) Si-CsI identification gives 7Li => CsI identification is correct ("8Be")
524  // 2) Si-CsI identification gives 8He => the particle is 8He (falls on same R/L line as 2*alpha)
525  // Seeing the very low statistics for 8He compared to 8Be/2alpha, we assume that if Si-CsI id
526  // gives something above 8He it is either incoherent (below 7Li) or 8Be + something else in ChIo-Si
527  // (above 7Li).
528  Int_t Zref = IDcsi->Z;
529  Int_t Aref = IDcsi->A;
530  if (IDsicsi->IDOK) {
531 
532  if (IDsicsi->Aident) { // Si-CsI provides mass identification
533 
534  if(!IDcsi->Aident)
535  {
536  // CsI identification is approximative (Z only), Si-CsI has full Z & A identification
537  // => use Si-CsI identification, don't ask questions about 'coherency'
538  partID = *IDsicsi;
539  identifying_telescope = idt_sicsi;
540  PART.SetParameter("Coherent", fCoherent);
541  PART.SetParameter("Pileup", fPileup);
542  return kTRUE;
543  }
544 
545  // for Z=1: at low energies Si-CsI identification is more sure than PSA in CsI, as all isotopes merge
546  // together and can even be confused with gammas at low energy in the CsI.
547  // Therefore as long as Si-CsI ID is good for Z=1, we prefer Si-CsI
548  if(IDcsi->Z==1 && IDsicsi->Z==1)
549  {
550  partID = *IDsicsi;
551  identifying_telescope = idt_sicsi;
552  PART.SetParameter("Coherent", fCoherent);
553  PART.SetParameter("Pileup", fPileup);
554  return kTRUE;
555  }
556  if (IDcsi->Z == 4 && IDcsi->A == 8) {
557  // traitement special 8Be
558  // if sicsi => 7Li, it is 8Be (2alpha)
559  // if sicsi => 8He, it is 8He
560  if (IDsicsi->Z < 2 || (IDsicsi->Z == 2 && IDsicsi->A < 7)) {
561  fCoherent = kFALSE;
562  IDsicsi->SetComment("CsI-R/L & Si-CsI identifications not coherent");
563  PART.SetParameter("Coherent", fCoherent);
564  PART.SetParameter("Pileup", fPileup);
565  return kTRUE;
566  }
567  else if (IDsicsi->Z == 2 && IDsicsi->A > 6 && IDsicsi->A < 10) {
568  // accept helium-7,8,9 as 8He
569  partID = *IDsicsi;
570  identifying_telescope = idt_sicsi;
571  PART.SetParameter("Coherent", fCoherent);
572  PART.SetParameter("Pileup", fPileup);
573  return kTRUE;
574  }
575  else if ((IDsicsi->Z == 2 && IDsicsi->A > 9) || (IDsicsi->Z == 3 && IDsicsi->A < 6)) {
576  fCoherent = kFALSE;
577  IDsicsi->SetComment("CsI-R/L & Si-CsI identifications not coherent");
578  PART.SetParameter("Coherent", fCoherent);
579  PART.SetParameter("Pileup", fPileup);
580  return kTRUE;
581  }
582  else if (IDsicsi->Z == 3 && IDsicsi->A > 5 && IDsicsi->A < 9) {
583  // accept lithium-6,7,8 as 7Li
584  PART.SetParameter("Coherent", fCoherent);
585  PART.SetParameter("Pileup", fPileup);
586  return kTRUE;
587  }
588  else if ((IDsicsi->Z == 3 && IDsicsi->A > 8) || IDsicsi->Z > 3) {
589  fPileup = kTRUE;
590  IDsicsi->SetComment("Second particle stopping in Si, identification ChIo-Si required");
591  PART.SetParameter("Coherent", fCoherent);
592  PART.SetParameter("Pileup", fPileup);
593  return kTRUE;
594  }
595  }
596  // if CsI says A could be bigger and Si-CsI gives same Z and A+1, use Si-CsI
597  if ((IDsicsi->Z == Zref) && (IDsicsi->A == (Aref + 1))
598  && (IDcsi->IDquality == KVIDGCsI::kICODE1 || IDcsi->IDquality == KVIDGCsI::kICODE3)) {
599  partID = *IDsicsi;
600  identifying_telescope = idt_sicsi;
601  PART.SetParameter("Coherent", fCoherent);
602  PART.SetParameter("Pileup", fPileup);
603  return kTRUE;
604  }
605  // if CsI says A could be smaller and Si-CsI gives same Z and A-1, use Si-CsI
606  if ((IDsicsi->Z == Zref) && (IDsicsi->A == (Aref - 1))
607  && (IDcsi->IDquality == KVIDGCsI::kICODE2 || IDcsi->IDquality == KVIDGCsI::kICODE3)) {
608  partID = *IDsicsi;
609  identifying_telescope = idt_sicsi;
610  PART.SetParameter("Coherent", fCoherent);
611  PART.SetParameter("Pileup", fPileup);
612  return kTRUE;
613  }
614  // Si-CsI gives unambiguous mass identification, CsI is less sure, and Si-CsI gives same Z, smaller A (=>no pileup): use Si-CsI
615  if((IDsicsi->Z == Zref) && (IDsicsi->A < Aref)
616  && (IDsicsi->IDquality == KVIDZAGrid::kICODE0 && IDcsi->IDquality > KVIDZAGrid::kICODE0))
617  {
618  partID = *IDsicsi;
619  identifying_telescope = idt_sicsi;
620  PART.SetParameter("Coherent", fCoherent);
621  PART.SetParameter("Pileup", fPileup);
622  return kTRUE;
623  }
624  // everything else - Z must be same, A +/- 1 unit
625  if (IDsicsi->Z == Zref && TMath::Abs(IDsicsi->A - Aref) < 2) {
626  PART.SetParameter("Coherent", fCoherent);
627  PART.SetParameter("Pileup", fPileup);
628  return kTRUE;
629  }
630  else if (IDsicsi->Z < Zref || (IDsicsi->Z == Zref && IDsicsi->A < (Aref - 1))) {
631  fCoherent = kFALSE;
632  IDsicsi->SetComment("CsI-R/L & Si-CsI identifications not coherent");
633  PART.SetParameter("Coherent", fCoherent);
634  PART.SetParameter("Pileup", fPileup);
635  return kTRUE;
636  }
637  else if (IDsicsi->Z > Zref || (IDsicsi->Z == Zref && IDsicsi->A > (Aref + 1))) {
638  fPileup = kTRUE;
639  IDsicsi->SetComment("Second particle stopping in Si");
640  PART.SetParameter("Coherent", fCoherent);
641  PART.SetParameter("Pileup", fPileup);
642  return kTRUE;
643  }
644  }
645  else { // only Z identification from Si-CsI
646  if (IDcsi->Z == 4 && IDcsi->A == 8) {
647  // traitement special 8Be
648  // we ask for Z to be equal 3 in SiCsI, but with no mass identification
649  // we do not try for 8He identification
650  if (IDsicsi->Z < 3) {
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 if (IDsicsi->Z == 3) {
658  PART.SetParameter("Coherent", fCoherent);
659  PART.SetParameter("Pileup", fPileup);
660  return kTRUE;
661  }
662  else {
663  fPileup = kTRUE;
664  IDsicsi->SetComment("Second particle stopping in Si, identification ChIo-Si required");
665  PART.SetParameter("Coherent", fCoherent);
666  PART.SetParameter("Pileup", fPileup);
667  return kTRUE;
668  }
669  }
670  // everything else
671  if (IDsicsi->Z == Zref) {
672  PART.SetParameter("Coherent", fCoherent);
673  PART.SetParameter("Pileup", fPileup);
674  return kTRUE;
675  }
676  else if (IDsicsi->Z < Zref) {
677  fCoherent = kFALSE;
678  IDsicsi->SetComment("CsI-R/L & Si-CsI identifications not coherent");
679  PART.SetParameter("Coherent", fCoherent);
680  PART.SetParameter("Pileup", fPileup);
681  return kTRUE;
682  }
683  else {
684  fPileup = kTRUE;
685 
686  IDsicsi->SetComment("Second particle stopping in Si, identification ChIo-Si required");
687  PART.SetParameter("Coherent", fCoherent);
688  PART.SetParameter("Pileup", fPileup);
689  return kTRUE;
690  }
691  }
692  }
693  else if (IDsicsi->IDattempted && IDsicsi->IDquality == KVIDZAGrid::kICODE8)
694  {
695  // Si-CsI id failed because totally out of grid i.e. no Si signal fired, but we have a good CsI id:
696  // use the CsI id in this case
697  partID = *IDcsi;
698  identifying_telescope = idt_csi;
699  PART.SetParameter("Coherent", fCoherent);
700  PART.SetParameter("Pileup", fPileup);
701  return kTRUE;
702  }
703  else if (IDsi && IDsi->IDOK)
704  {
705  // check for particle stopping in Si detector
706  if(IDsi->Z > Zref)
707  {
708  // pile-up: a second charged particle stopped in Si
709  auto new_stop_det = idt_si->GetDetector(1);
710  coherency_particles.push_back(
711  {
712  &PART, new_stop_det->GetNode(), (KVGeoDNTrajectory*)the_CsI->GetNode()->GetTrajectories()->First(),
713  idt_si, 3, nid
714  }
715  );
716  fPileup=true;
717  PART.SetParameter("Coherent", fCoherent);
718  PART.SetParameter("Pileup", fPileup);
719  PART.SetParameter("Ion pileup", Form("added new particle identified in %s", idt_si->GetName()));
720  return kTRUE;
721  }
722  }
723  else if (IDsicsi->IDattempted)
724  {
725  if(IDsicsi->IDquality == KVIDZAGrid::kICODE4 || IDsicsi->IDquality == KVIDZAGrid::kICODE5)
726  {
727  // "noise" in between Si-CsI identification lines => pile-up with good particle
728  // in CsI plus another particle stopped in the Silicon
729  if (IDsicsi->Z < Zref) fCoherent = kFALSE;
730  else fPileup = kTRUE;
731  }
732  else if (IDsicsi->IDquality == KVIDZAGrid::kICODE7)
733  {
734  // Point to identify in Si-CsI matrix is above the last line in the grid
735  // Z given to identification result is Zmin = lastZ + 1
736  // if this is > Z from CsI identification, pileup in Si
737  if (IDsicsi->Z > Zref) fPileup = kTRUE;
738  }
739  }
740  PART.SetParameter("Coherent", fCoherent);
741  PART.SetParameter("Pileup", fPileup);
742  return kTRUE;
743  }
744  PART.SetParameter("Coherent", fCoherent);
745  PART.SetParameter("Pileup", fPileup);
746  return kFALSE;
747 }
748 
749 
750 
760 
762 {
763  // calculate fESi from fECsI
764  // returns kTRUE if OK
765  //
766  // this sets directly the value of fESi
767  //
768  // if result is not good, bad calibration status is set for particle and we return false: in this case fESi=0
769  //
770  // if result is good, particle calibration status set to SOME_ENERGY_LOSSES_CALCULATED and fESi<0
771 
772  Double_t e0 = si->GetDeltaEFromERes(n->GetZ(), n->GetA(), TMath::Abs(fECsI));
774  fESi = si->GetCorrectedEnergy(n, e0);
775  if (fESi <= 0) {
776  // can't calculate fESi from CsI energy - bad
778  fESi = 0;
779  return kFALSE;
780  }
781  else {
782  // calculated energy: negative
783  fESi = -TMath::Abs(fESi);
784  SetCalibrationStatus(*n, KVINDRA::ECodes::SOME_ENERGY_LOSSES_CALCULATED);
785  }
786  return kTRUE;
787 }
788 
789 
790 
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
Bool_t IsCalibrated(const KVNameValueList &params={}) const
Definition: KVDetector.cpp:545
Int_t GetNHits() const
Return the number of particles hitting this detector in an event.
Definition: KVDetector.h:439
virtual void SetEResAfterDetector(Double_t e)
Definition: KVDetector.h:618
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:752
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)