Bool_t KVINDRABackwardGroupReconstructor::CoherencyChIoCsI(KVReconstructedNucleus& PART)
{
   // Called by Identify() for particles stopping in CsI detectors on rings 10-17,
   // which have a ChIo detector just in front of them.
   //
   // fPileupChIo = kTRUE if ChIo-CsI identification gives Z >> CsI-R/L identification
   //              this means that the particle identified in CsI-R/L is correct,
   //              and there is probably a second particle which stopped in the ChIo
   //              detector at the same time (will be added as a Zmin/code5)

   KVIdentificationResult* IDcsi = PART.GetIdentificationResult(1);
   KVIdentificationResult* IDcicsi = PART.GetIdentificationResult(2);
   KVIDTelescope* idt_cicsi = (KVIDTelescope*)PART.GetReconstructionTrajectory()->GetIDTelescopes()->FindObjectByType(IDcicsi->GetType());
   KVIDTelescope* idt_csi = (KVIDTelescope*)PART.GetReconstructionTrajectory()->GetIDTelescopes()->FindObjectByType(IDcsi->GetType());

   PART.SetParameter("PileupChIo", kFALSE);

   // Unsuccessful/no CsI id attempt with successful ChIo-CsI id ?
   // Then use ChIo-CsI identification result
   if (IDcsi && !IDcsi->IDOK) {
      if (IDcicsi && IDcicsi->IDOK) {
         partID = *IDcicsi;
         identifying_telescope = idt_cicsi;
         return kTRUE;
      }
   }

   // check coherency of CsI-R/L and ChIo-CsI identifications
   if (IDcsi && IDcsi->IDOK) {

      // We check the coherency of the identifications
      // Because ChIo-Csi identification is not of very high quality (compared to CsI R-L),
      // we only check that the Z given by ChIo-CsI is < Zref+1
      // If not, we can suspect the presence of another particle in the ChIo

      if (IDcicsi && IDcicsi->IDOK) {
         Int_t Zref = IDcsi->Z;
         if (IDcicsi->Z > (Zref + 1) && PART.GetParameters()->GetBoolValue("UseFullChIoEnergyForCalib")) {
            PART.SetParameter("PileupChIo", kTRUE);
            IDcicsi->SetComment("Possible pile-up in ChIo");
         }
      }

      // in all other cases accept CsI identification
      partID = *IDcsi;
      identifying_telescope = idt_csi;
      return kTRUE;
   }
   return kFALSE;
}
bool KVINDRAEtalonGroupReconstructor::DoCoherencyAnalysis(KVReconstructedNucleus& PART)
{
   // Coherency analysis for etalon groups on rings 10-17 of INDRA
   // Note that the treatment of all modules in the group except the one with the etalons
   // is standard (KVINDRABackwardGroupReconstructor), but all modules will call here first

   if (!GetSi75(&PART) && !GetSiLi(&PART)) // => no etalons in particle trajectory
      return KVINDRABackwardGroupReconstructor::DoCoherencyAnalysis(PART);

   PART.SetParameter("UseFullChIoEnergyForCalib", !(theChio && theChio->GetNHits() > 1));
   bool ok = CoherencyEtalons(PART);

   return ok;
}
bool KVINDRABackwardGroupReconstructor::DoCoherencyAnalysis(KVReconstructedNucleus& PART)
{
   // Coherency analysis for backward rings 10-17 of INDRA

   PART.SetParameter("UseFullChIoEnergyForCalib", !(theChio && theChio->GetNHits() > 1));
   bool ok = false;
   if (PART.GetStoppingDetector()->IsType("CSI")) {
      // particles stopping in CsI detectors
      // check coherency of CsI-R/L and Si-CsI identifications
      ok = CoherencyChIoCsI(PART);
   }
   else {
      // particle stopped in ChIo (=> Zmin)
      ok = PART.IsIdentified() && identifying_telescope;
   }

   return ok;
}
Bool_t KVINDRAEtalonGroupReconstructor::CoherencyEtalons(KVReconstructedNucleus& PART)
{
   // Called by Identify() for particles stopping in etalon modules of Rings 10-17.

   KVIdentificationResult* IDcsi, *IDsilicsi, *IDsi75sili, *IDcisi75, *IDcicsi;
   IDcsi = IDsilicsi = IDsi75sili = IDcisi75 = IDcicsi = nullptr;
   if (PART.GetStoppingDetector()->IsType("CSI")) {
      IDcsi = PART.GetIdentificationResult("CSI_R_L");
      IDcicsi = PART.GetIdentificationResult("CI_CSI");
      IDsilicsi = PART.GetIdentificationResult("SILI_CSI");
   }
   IDsi75sili = PART.GetIdentificationResult("SI75_SILI");
   IDcisi75 = PART.GetIdentificationResult("CI_SI75");

   PART.SetParameter("PileupChIo", kFALSE);
   PART.SetParameter("IncludeEtalonsInCalibration", kTRUE);

   Bool_t haveCsI = IDcsi && IDcsi->IDOK;
   Bool_t haveSiLiCsI = IDsilicsi && IDsilicsi->IDOK;
   Bool_t haveSi75SiLi = IDsi75sili && IDsi75sili->IDOK;
   Bool_t haveChIoSi75 = IDcisi75 && IDcisi75->IDOK;

   KVIDTelescope* idt_csi, *idt_silicsi, *idt_si75sili, *idt_cisi75, *idt_cicsi;
   idt_csi = idt_silicsi = idt_si75sili = idt_cisi75 = idt_cicsi = nullptr;
   if (PART.GetStoppingDetector()->IsType("CSI")) {
      idt_csi =
         (KVIDTelescope*)PART.GetReconstructionTrajectory()->GetIDTelescopes()->FindObjectByType(IDcsi->GetType());
      idt_silicsi =
         (KVIDTelescope*)PART.GetReconstructionTrajectory()->GetIDTelescopes()->FindObjectByType(IDsilicsi->GetType());
      idt_cicsi =
         (KVIDTelescope*)PART.GetReconstructionTrajectory()->GetIDTelescopes()->FindObjectByType(IDcicsi->GetType());
   }
   idt_si75sili = (KVIDTelescope*)PART.GetReconstructionTrajectory()->GetIDTelescopes()->FindObjectByType(IDsi75sili->GetType());
   idt_cisi75 = (KVIDTelescope*)PART.GetReconstructionTrajectory()->GetIDTelescopes()->FindObjectByType(IDcisi75->GetType());

   // Treat cases where particle hit etalon telescope
   if (idt_csi) {
      if (haveCsI) {

         partID = *IDcsi;
         identifying_telescope = idt_csi;

         if (haveSi75SiLi) {
            // check for heavy fragment in Si75-SiLi
            if (IDsi75sili->Z > partID.Z) {
               if (haveChIoSi75) {
                  // check we don't have a better identification in ChIo-Si75
                  if (IDcisi75->IDquality < IDsi75sili->IDquality && IDcisi75->Z > partID.Z) {
                     PART.SetParameter("PileupSi75", kTRUE);
                     IDcisi75->SetComment("CsI identification with another particle stopped in Si75");
                     PART.SetParameter("UseFullChIoEnergyForCalib", kFALSE); // calculate ChIo energy for this particle
                  }
                  else {
                     PART.SetParameter("PileupSiLi", kTRUE);
                     IDsi75sili->SetComment("CsI identification with another particle stopped in SiLi");
                     PART.SetParameter("UseFullChIoEnergyForCalib", kFALSE); // calculate ChIo energy for this particle
                  }
               }
            }
         }
         else if (haveChIoSi75) {
            // check for heavy fragment in ChIo-Si75
            if (IDcisi75->Z > partID.Z) {
               PART.SetParameter("PileupSi75", kTRUE);
               IDcisi75->SetComment("CsI identification with another particle stopped in Si75");
               PART.SetParameter("UseFullChIoEnergyForCalib", kFALSE); // calculate ChIo energy for this particle
            }
         }
         return kTRUE;
      }
      else if (haveSiLiCsI) {
         partID = *IDsilicsi;
         identifying_telescope = idt_silicsi;
         if (haveChIoSi75) {
            // check for heavy fragment in ChIo-Si75
            if (IDcisi75->Z > partID.Z) {
               PART.SetParameter("PileupSi75", kTRUE);
               IDcisi75->SetComment("CsI identification with another particle stopped in Si75");
               PART.SetParameter("UseFullChIoEnergyForCalib", kFALSE); // calculate ChIo energy for this particle
            }
         }
         return kTRUE;
      }
   }
   else if (PART.GetStoppingDetector()->IsType("SILI")) {
      if (haveSi75SiLi) {
         partID = *IDsi75sili;
         identifying_telescope = idt_si75sili;
         // check ChIo-Si75 id is coherent (either no id or Z<=this one)
         if (haveChIoSi75) {
            if (IDcisi75->Z > partID.Z) PART.SetParameter("PileupChIo", kTRUE);
         }
         return kTRUE;
      }
      else if (haveChIoSi75) {
         partID = *IDcisi75;
         identifying_telescope = idt_cisi75;
         return kTRUE;
      }
   }
   else if (PART.GetStoppingDetector()->IsType("SI75")) {   // MFR march 2014 SiLi is not the real stopping detector
      if (haveChIoSi75) {
         partID = *IDcisi75;
         identifying_telescope = idt_cisi75;
         return kTRUE;
      }                       // end MFR march 2014
   }

   return kFALSE;
}