/** @file CbmTofSimpClusterizer.cxx
 ** @author Pierre-Alain Loizeau <loizeau@physi.uni-heidelberg.de>
 ** @date 23.08.2013
 **/

#include "CbmTofSimpClusterizer.h"

// TOF Classes and includes
#include "CbmTofAddress.h"          // in cbmdata/tof
#include "CbmTofCell.h"             // in tof/TofData
#include "CbmTofDetectorId_v12b.h"  // in cbmdata/tof
#include "CbmTofDetectorId_v14a.h"  // in cbmdata/tof
#include "CbmTofDigi.h"             // in cbmdata/tof
#include "CbmTofDigiBdfPar.h"       // in tof/TofParam
#include "CbmTofDigiPar.h"          // in tof/TofParam
#include "CbmTofGeoHandler.h"       // in tof/TofTools
#include "CbmTofHit.h"              // in cbmdata/tof
#include "CbmTofPoint.h"            // in cbmdata/tof

// CBMroot classes and includes
#include "CbmDigiManager.h"
#include "CbmMCTrack.h"
#include "CbmMatch.h"

// FAIR classes and includes
#include "FairEventHeader.h"  // from CbmStsDigitize, for GetEventInfo
#include "FairLogger.h"
#include "FairMCEventHeader.h"  // from CbmStsDigitize, for GetEventInfo
#include "FairRootManager.h"
#include "FairRunAna.h"
#include "FairRunSim.h"  // from CbmStsDigitize, for GetEventInfo
#include "FairRuntimeDb.h"

// ROOT Classes and includes
#include "TClonesArray.h"
#include "TDirectory.h"
#include "TF2.h"
#include "TGeoManager.h"
#include "TH1.h"
#include "TH2.h"
#include "TLine.h"
#include "TMath.h"
#include "TProfile.h"
#include "TROOT.h"
#include "TRandom3.h"
#include "TVector3.h"
#include <TFile.h>

// C++ Classes and includes

// const Int_t DetMask = 4194303;  (VF) not used
const Int_t nbClWalkBinX = 20;
//const Int_t nbClWalkBinY=41;   (VF) not used // choose odd number to have central bin symmetric around 0
//const Double_t WalkNHmin=100;  (VF) not used // minimal number of hits in bin for walk correction
Double_t TOTMax         = 5.E4;
Double_t TOTMin         = 2.E4;
const Double_t TTotMean = 2.E4;

const Int_t nbClDelTofBinX = 50;
//const Int_t nbClDelTofBinY=49;  (VF) not used
//const Double_t DelTofMax=5000.;  (VF) not used

//const Int_t nbCldXdYBinX=49;  (VF) not used
//const Int_t nbCldXdYBinY=49;  (VF) not used
//const Double_t dXdYMax=10.;  (VF) not used

const Int_t iNTrg = 1;

//const Double_t Zref = 200.;  (VF) not used   // distance of projection plane to target
// C++ Classes and includes

/************************************************************************************/
CbmTofSimpClusterizer::CbmTofSimpClusterizer()
  : FairTask("CbmTofSimpClusterizer")
  , fGeoHandler(new CbmTofGeoHandler())
  , fTofId(NULL)
  , fDigiPar(NULL)
  , fChannelInfo(NULL)
  , fDigiBdfPar(NULL)
  , fdParFeeTimeRes(0.0)
  , fdParSystTimeRes(0.0)
  , fTofPointsColl(NULL)
  , fMcTracksColl(NULL)
  , fDigiMan(nullptr)
  , fTofHitsColl(NULL)
  , fTofDigiMatchColl(NULL)
  , fiNbHits(0)
  , fVerbose(1)
  , fStorDigiExp()
  , fStorDigiInd()
  , fviClusterMul()
  , fviClusterSize()
  , fviTrkMul()
  , fvdX()
  , fvdY()
  , fvdDifX()
  , fvdDifY()
  , fvdDifCh()
  , fsHistoOutFilename("")
  , fhClustBuildTime(NULL)
  , fhHitsPerTracks(NULL)
  , fhPtsPerHit(NULL)
  , fhTimeResSingHits(NULL)
  , fhTimeResSingHitsB(NULL)
  , fhTimePtVsHits(NULL)
  , fhClusterSize(NULL)
  , fhClusterSizeType(NULL)
  , fhTrackMul(NULL)
  , fhClusterSizeMulti(NULL)
  , fhTrk1MulPos(NULL)
  , fhHiTrkMulPos(NULL)
  , fhAllTrkMulPos(NULL)
  , fhMultiTrkProbPos(NULL)
  , fhDigSpacDifClust(NULL)
  , fhDigTimeDifClust(NULL)
  , fhDigDistClust(NULL)
  , fhClustSizeDifX(NULL)
  , fhClustSizeDifY(NULL)
  , fhChDifDifX(NULL)
  , fhChDifDifY(NULL)
  , fhRpcDigiCor()
  , fhRpcCluMul()
  , fhRpcSigPropSpeed()
  , fhRpcCluPosition()
  , fhRpcCluTOff()
  , fhRpcCluTrms()
  , fhRpcCluTot()
  , fhRpcCluSize()
  , fhRpcCluAvWalk()
  , fhRpcCluWalk()
  , fhTRpcCluMul()
  , fhTRpcCluPosition()
  , fhTRpcCluTOff()
  , fhTRpcCluTot()
  , fhTRpcCluSize()
  , fhTRpcCluAvWalk()
  , fhTRpcCluDelTof()
  , fhTRpcCludXdY()
  , fhTRpcCluWalk()
  , fhTrgdT()
  , fvCPSigPropSpeed()
  , fvCPDelTof()
  , fvCPTOff()
  , fvCPTotGain()
  , fvCPWalk()
  , fiNbSameSide(0)
  , fhNbSameSide(NULL)
  , fhNbDigiPerChan(NULL)
  , fStart()
  , fStop()
  , fTimer()
  , fiNofEvents(0.)
  , fdNofDigisTot(0.)
  , fdNofHitsTot(0.)
  , fdTimeTot(0.)
  , dTRef(0.)
  , fdTRefMax(0.)
  , fCalMode(0)
  , fCalTrg(0)
  , fCalSmType(0)
  , fdCaldXdYMax(0.)
  , fTRefMode(0)
  , fTRefHits(0)
  , fPosYMaxScal(0.)
  , fTRefDifMax(0.)
  , fTotMax(0.)
  , fTotMin(0.)
  , fOutTimeFactor(1.)
  , fCalParFileName("")
  , fCalParFile(NULL)
  , fbMcTrkMonitor(kFALSE) {}

CbmTofSimpClusterizer::CbmTofSimpClusterizer(const char* name, Int_t verbose)
  : FairTask(TString(name), verbose)
  , fGeoHandler(new CbmTofGeoHandler())
  , fTofId(NULL)
  , fDigiPar(NULL)
  , fChannelInfo(NULL)
  , fDigiBdfPar(NULL)
  , fdParFeeTimeRes(0.0)
  , fdParSystTimeRes(0.0)
  , fTofPointsColl(NULL)
  , fMcTracksColl(NULL)
  , fDigiMan(nullptr)
  , fTofHitsColl(NULL)
  , fTofDigiMatchColl(NULL)
  , fiNbHits(0)
  , fVerbose(verbose)
  , fStorDigiExp()
  , fStorDigiInd()
  , fviClusterMul()
  , fviClusterSize()
  , fviTrkMul()
  , fvdX()
  , fvdY()
  , fvdDifX()
  , fvdDifY()
  , fvdDifCh()
  , fsHistoOutFilename("")
  , fhClustBuildTime(NULL)
  , fhHitsPerTracks(NULL)
  , fhPtsPerHit(NULL)
  , fhTimeResSingHits(NULL)
  , fhTimeResSingHitsB(NULL)
  , fhTimePtVsHits(NULL)
  , fhClusterSize(NULL)
  , fhClusterSizeType(NULL)
  , fhTrackMul(NULL)
  , fhClusterSizeMulti(NULL)
  , fhTrk1MulPos(NULL)
  , fhHiTrkMulPos(NULL)
  , fhAllTrkMulPos(NULL)
  , fhMultiTrkProbPos(NULL)
  , fhDigSpacDifClust(NULL)
  , fhDigTimeDifClust(NULL)
  , fhDigDistClust(NULL)
  , fhClustSizeDifX(NULL)
  , fhClustSizeDifY(NULL)
  , fhChDifDifX(NULL)
  , fhChDifDifY(NULL)
  , fhRpcDigiCor()
  , fhRpcCluMul()
  , fhRpcSigPropSpeed()
  , fhRpcCluPosition()
  , fhRpcCluTOff()
  , fhRpcCluTrms()
  , fhRpcCluTot()
  , fhRpcCluSize()
  , fhRpcCluAvWalk()
  , fhRpcCluWalk()
  , fhTRpcCluMul()
  , fhTRpcCluPosition()
  , fhTRpcCluTOff()
  , fhTRpcCluTot()
  , fhTRpcCluSize()
  , fhTRpcCluAvWalk()
  , fhTRpcCluDelTof()
  , fhTRpcCludXdY()
  , fhTRpcCluWalk()
  , fhTrgdT()
  , fvCPSigPropSpeed()
  , fvCPDelTof()
  , fvCPTOff()
  , fvCPTotGain()
  , fvCPWalk()
  , fiNbSameSide(0)
  , fhNbSameSide(NULL)
  , fhNbDigiPerChan(NULL)
  , fStart()
  , fStop()
  , fTimer()
  , fiNofEvents(0.)
  , fdNofDigisTot(0.)
  , fdNofHitsTot(0.)
  , fdTimeTot(0.)
  , dTRef(0.)
  , fdTRefMax(0.)
  , fCalMode(0)
  , fCalTrg(0)
  , fCalSmType(0)
  , fdCaldXdYMax(0.)
  , fTRefMode(0)
  , fTRefHits(0)
  , fPosYMaxScal(0.)
  , fTRefDifMax(0.)
  , fTotMax(0.)
  , fTotMin(0.)
  , fOutTimeFactor(1.)
  , fCalParFileName("")
  , fCalParFile(NULL)
  , fbMcTrkMonitor(kFALSE)

{}

CbmTofSimpClusterizer::~CbmTofSimpClusterizer() {
  if (fGeoHandler) delete fGeoHandler;
  //   DeleteHistos(); // <-- if needed  ?
}

/************************************************************************************/
// FairTasks inherited functions
InitStatus CbmTofSimpClusterizer::Init() {

  fDigiMan = CbmDigiManager::Instance(), fDigiMan->Init();

  if (kFALSE == RegisterInputs()) return kFATAL;

  if (kFALSE == RegisterOutputs()) return kFATAL;

  if (kFALSE == InitParameters()) return kFATAL;

  if (kFALSE == LoadGeometry()) return kFATAL;

  if (kFALSE == InitCalibParameter()) return kFATAL;

  if (kFALSE == CreateHistos()) return kFATAL;

  return kSUCCESS;
}

void CbmTofSimpClusterizer::SetParContainers() {
  LOG(info) << " CbmTofSimpClusterizer => Get the digi parameters for tof";

  // Get Base Container
  FairRunAna* ana     = FairRunAna::Instance();
  FairRuntimeDb* rtdb = ana->GetRuntimeDb();

  fDigiPar = (CbmTofDigiPar*) (rtdb->getContainer("CbmTofDigiPar"));

  LOG(info) << "  CbmTofSimpClusterizer::SetParContainers found "
            << fDigiPar->GetNrOfModules() << " cells ";

  fDigiBdfPar = (CbmTofDigiBdfPar*) (rtdb->getContainer("CbmTofDigiBdfPar"));
}

void CbmTofSimpClusterizer::Exec(Option_t* /*option*/) {
  // Start timer counter
  fTimer.Start();

  fTofHitsColl->Clear("C");
  //   fTofDigiMatchColl->Clear("C"); // Not enough => CbmMatch has no Clear functions!!
  fTofDigiMatchColl->Delete();

  fiNbHits = 0;

  Int_t iNbTofDigi = CbmDigiManager::GetNofDigis(ECbmModuleId::kTof);
  LOG(debug) << " CbmTofSimpClusterizer => New event with " << iNbTofDigi
             << " digis ";
  fStart.Set();

  BuildClusters();

  fStop.Set();

  FillHistos();

  // --- Update Counters
  fTimer.Stop();
  fiNofEvents++;
  fdNofDigisTot += iNbTofDigi;
  fdNofHitsTot += fiNbHits;
  fdTimeTot += fTimer.RealTime();
}

void CbmTofSimpClusterizer::Finish() {
  WriteHistos();
  // Prevent them from being sucked in by the CbmHadronAnalysis WriteHistograms method
  DeleteHistos();

  // Final printout for reference
  LOG(info) << "=====================================";
  LOG(info) << GetName() << ": Run summary (Time includes Hist filling)";
  LOG(info) << "Events processed   : " << fiNofEvents;
  LOG(info) << "Digis / event      : "
            << fdNofDigisTot / static_cast<Double_t>(fiNofEvents);
  LOG(info) << "Hits / event       : "
            << fdNofHitsTot / static_cast<Double_t>(fiNofEvents);
  LOG(info) << "Digis per Hits     : " << fdNofDigisTot / fdNofHitsTot;
  LOG(info) << "Time per event     : "
            << fdTimeTot / static_cast<Double_t>(fiNofEvents) << " ";
  LOG(info) << "=====================================";
}

/************************************************************************************/
// Functions common for all clusters approximations
Bool_t CbmTofSimpClusterizer::RegisterInputs() {
  FairRootManager* fManager = FairRootManager::Instance();

  /** VF: The task should run without MC input
   fTofPointsColl  = (TClonesArray *) fManager->GetObject("TofPoint");
   if( NULL == fTofPointsColl)
   {
      LOG(error)<<"CbmTofSimpClusterizer::RegisterInputs => Could not get the TofPoint TClonesArray!!!";
      return kFALSE;
   } // if( NULL == fTofPointsColl)
   **/
  fTofPointsColl = nullptr;


  // --- Check input branch (TofDigiExp). If not present, set task inactive.
  if (!fDigiMan->IsPresent(ECbmModuleId::kTof)) {
    LOG(error) << GetName() << ": No TofDigi input array present; "
               << "task will be inactive.";
    return kERROR;
  }


  fMcTracksColl = (TClonesArray*) fManager->GetObject("MCTrack");
  if (NULL == fMcTracksColl) {
    LOG(info) << "CbmTofSimpClusterizer: No MCTrack array.";
  }  // if( NULL == fMcTracksColl)


  return kTRUE;
}
Bool_t CbmTofSimpClusterizer::RegisterOutputs() {
  FairRootManager* rootMgr = FairRootManager::Instance();

  fTofHitsColl = new TClonesArray("CbmTofHit");

  // Flag check to control whether digis are written in output root file
  rootMgr->Register(
    "TofHit", "Tof", fTofHitsColl, IsOutputBranchPersistent("TofHit"));

  fTofDigiMatchColl = new TClonesArray("CbmMatch", 100);
  rootMgr->Register("TofHitDigiMatch",
                    "Tof",
                    fTofDigiMatchColl,
                    IsOutputBranchPersistent("TofHitDigiMatch"));

  return kTRUE;
}
Bool_t CbmTofSimpClusterizer::InitParameters() {

  // Initialize the TOF GeoHandler
  Bool_t isSimulation = kFALSE;
  Int_t iGeoVersion   = fGeoHandler->Init(isSimulation);
  LOG(info) << "CbmTofSimpClusterizer::InitParameters with GeoVersion "
            << iGeoVersion;

  if (k12b > iGeoVersion) {
    LOG(error) << "CbmTofSimpClusterizer::InitParameters => Only compatible "
                  "with geometries after v12b !!!";
    return kFALSE;
  }

  if (NULL != fTofId)
    LOG(info) << "CbmTofSimpClusterizer::InitParameters with GeoVersion "
              << fGeoHandler->GetGeoVersion();
  else {
    switch (iGeoVersion) {
      case k12b: fTofId = new CbmTofDetectorId_v12b(); break;
      case k14a: fTofId = new CbmTofDetectorId_v14a(); break;
      default:
        LOG(error)
          << "CbmTofSimpClusterizer::InitParameters => Invalid geometry!!!"
          << iGeoVersion;
        return kFALSE;
    }
  }

  fdParFeeTimeRes  = fDigiBdfPar->GetFeeTimeRes();
  fdParSystTimeRes = 0.080;

  LOG(info) << "  CbmTofSimpClusterizer::InitParameters found Tres FEE  = "
            << fdParFeeTimeRes << " ns ";
  LOG(info) << "  CbmTofSimpClusterizer::InitParameters found Tres Syst = "
            << fdParSystTimeRes << " ns ";

  return kTRUE;
}
/************************************************************************************/
Bool_t CbmTofSimpClusterizer::InitCalibParameter() {
  // dimension and initialize calib parameter
  //
  Int_t iNbSmTypes = fDigiBdfPar->GetNbSmTypes();

  fvCPSigPropSpeed.resize(iNbSmTypes);
  for (Int_t iT = 0; iT < iNbSmTypes; iT++) {
    Int_t iNbRpc = fDigiBdfPar->GetNbRpc(iT);
    fvCPSigPropSpeed[iT].resize(iNbRpc);
    for (Int_t iRpc = 0; iRpc < iNbRpc; iRpc++)
      if (0.0 < fDigiBdfPar->GetSigVel(iT, 0, iRpc))
        fvCPSigPropSpeed[iT][iRpc] = fDigiBdfPar->GetSigVel(iT, 0, iRpc);
      else
        fvCPSigPropSpeed[iT][iRpc] = fDigiBdfPar->GetSignalSpeed();
  }  // for (Int_t iT=0; iT<iNbSmTypes; iT++)

  fvCPTOff.resize(iNbSmTypes);
  fvCPTotGain.resize(iNbSmTypes);
  fvCPWalk.resize(iNbSmTypes);
  fvCPDelTof.resize(iNbSmTypes);
  for (Int_t iSmType = 0; iSmType < iNbSmTypes; iSmType++) {
    Int_t iNbSm  = fDigiBdfPar->GetNbSm(iSmType);
    Int_t iNbRpc = fDigiBdfPar->GetNbRpc(iSmType);
    fvCPTOff[iSmType].resize(iNbSm * iNbRpc);
    fvCPTotGain[iSmType].resize(iNbSm * iNbRpc);
    fvCPWalk[iSmType].resize(iNbSm * iNbRpc);
    fvCPDelTof[iSmType].resize(iNbSm * iNbRpc);
    for (Int_t iSm = 0; iSm < iNbSm; iSm++) {
      for (Int_t iRpc = 0; iRpc < iNbRpc; iRpc++) {
        //          LOG(info)<<Form(" fvCPDelTof resize for SmT %d, R %d, B %d ",iSmType,iNbSm*iNbRpc,nbClDelTofBinX)
        //           ;
        fvCPDelTof[iSmType][iSm * iNbRpc + iRpc].resize(nbClDelTofBinX);
        for (Int_t iBx = 0; iBx < nbClDelTofBinX; iBx++) {
          // LOG(info)<<Form(" fvCPDelTof for SmT %d, R %d, B %d",iSmType,iSm*iNbRpc+iRpc,iBx);
          fvCPDelTof[iSmType][iSm * iNbRpc + iRpc][iBx].resize(iNTrg);
          for (Int_t iTrg = 0; iTrg < iNTrg; iTrg++)
            fvCPDelTof[iSmType][iSm * iNbRpc + iRpc][iBx][iTrg] =
              0.;  // initialize
        }

        Int_t iNbChan = fDigiBdfPar->GetNbChan(iSmType, iRpc);
        fvCPTOff[iSmType][iSm * iNbRpc + iRpc].resize(iNbChan);
        fvCPTotGain[iSmType][iSm * iNbRpc + iRpc].resize(iNbChan);
        fvCPWalk[iSmType][iSm * iNbRpc + iRpc].resize(iNbChan);
        Int_t nbSide = 2 - fDigiBdfPar->GetChanType(iSmType, iRpc);
        for (Int_t iCh = 0; iCh < iNbChan; iCh++) {
          fvCPTOff[iSmType][iSm * iNbRpc + iRpc][iCh].resize(nbSide);
          fvCPTotGain[iSmType][iSm * iNbRpc + iRpc][iCh].resize(nbSide);
          fvCPWalk[iSmType][iSm * iNbRpc + iRpc][iCh].resize(nbSide);
          for (Int_t iSide = 0; iSide < nbSide; iSide++) {
            fvCPTOff[iSmType][iSm * iNbRpc + iRpc][iCh][iSide] =
              0.;  //initialize
            fvCPTotGain[iSmType][iSm * iNbRpc + iRpc][iCh][iSide] =
              1.;  //initialize
            fvCPWalk[iSmType][iSm * iNbRpc + iRpc][iCh][iSide].resize(
              nbClWalkBinX);
            for (Int_t iWx = 0; iWx < nbClWalkBinX; iWx++) {
              fvCPWalk[iSmType][iSm * iNbRpc + iRpc][iCh][iSide][iWx] = 0.;
            }
          }
        }
      }
    }
  }

  LOG(info) << "CbmTofSimpClusterizer::InitCalibParameter: defaults set";

  TDirectory* oldir =
    gDirectory;  // <= To prevent histos from being sucked in by the param file of the TRootManager!
  /*
  gROOT->cd(); // <= To prevent histos from being sucked in by the param file of the TRootManager !
  */

  if (0 < fCalMode) {
    LOG(info) << "CbmTofSimpClusterizer::InitCalibParameter: read histos from "
              << "file " << fCalParFileName;

    // read parameter from histos
    if (fCalParFileName.IsNull()) return kTRUE;

    fCalParFile = new TFile(fCalParFileName, "");
    if (NULL == fCalParFile) {
      LOG(error) << "CbmTofSimpClusterizer::InitCalibParameter: "
                 << "file " << fCalParFileName << " does not exist!";
      return kTRUE;
    }
    /*
    gDirectory->Print();
    fCalParFile->cd();
    fCalParFile->ls();
    */

    for (Int_t iSmType = 0; iSmType < iNbSmTypes; iSmType++) {
      Int_t iNbSm  = fDigiBdfPar->GetNbSm(iSmType);
      Int_t iNbRpc = fDigiBdfPar->GetNbRpc(iSmType);
      for (Int_t iSm = 0; iSm < iNbSm; iSm++)
        for (Int_t iRpc = 0; iRpc < iNbRpc; iRpc++) {
          TH2F* htempPos_pfx = (TH2F*) gDirectory->FindObjectAny(
            Form("cl_CorSmT%01d_sm%03d_rpc%03d_Pos_pfx", iSmType, iSm, iRpc));
          TH2F* htempTOff_pfx = (TH2F*) gDirectory->FindObjectAny(
            Form("cl_CorSmT%01d_sm%03d_rpc%03d_TOff_pfx", iSmType, iSm, iRpc));
          TH2F* htempTot_pfx = (TH2F*) gDirectory->FindObjectAny(
            Form("cl_CorSmT%01d_sm%03d_rpc%03d_Tot_pfx", iSmType, iSm, iRpc));
          if (NULL != htempPos_pfx && NULL != htempTOff_pfx
              && NULL != htempTot_pfx) {
            Int_t iNbCh    = fDigiBdfPar->GetNbChan(iSmType, iRpc);
            Int_t iNbinTot = htempTot_pfx->GetNbinsX();
            for (Int_t iCh = 0; iCh < iNbCh; iCh++) {
              Double_t YMean = ((TProfile*) htempPos_pfx)
                                 ->GetBinContent(iCh + 1);  //nh +1 empirical(?)
              Double_t TMean =
                ((TProfile*) htempTOff_pfx)->GetBinContent(iCh + 1);
              Double_t dTYOff = YMean / fvCPSigPropSpeed[iSmType][iRpc];
              fvCPTOff[iSmType][iSm * iNbRpc + iRpc][iCh][0] += -dTYOff + TMean;
              fvCPTOff[iSmType][iSm * iNbRpc + iRpc][iCh][1] += +dTYOff + TMean;

              Double_t TotMean =
                ((TProfile*) htempTot_pfx)
                  ->GetBinContent(iCh + 1);  //nh +1 empirical(?)
              if (1 < TotMean) {
                fvCPTotGain[iSmType][iSm * iNbRpc + iRpc][iCh][0] *=
                  TTotMean / TotMean;
                fvCPTotGain[iSmType][iSm * iNbRpc + iRpc][iCh][1] *=
                  TTotMean / TotMean;
              }
              LOG(debug1) << "CbmTofSimpClusterizer::InitCalibParameter:"
                          << " SmT " << iSmType << " Sm " << iSm << " Rpc "
                          << iRpc << " Ch " << iCh << ": YMean " << YMean
                          << ", TMean " << TMean << " -> "
                          << fvCPTOff[iSmType][iSm * iNbRpc + iRpc][iCh][0]
                          << ", "
                          << fvCPTOff[iSmType][iSm * iNbRpc + iRpc][iCh][1]
                          << ", "
                          << fvCPTotGain[iSmType][iSm * iNbRpc + iRpc][iCh][0]
                          << ", NbinTot " << iNbinTot;

              TH1D* htempWalk0 = (TH1D*) gDirectory->FindObjectAny(
                Form("Cor_SmT%01d_sm%03d_rpc%03d_Ch%03d_S0_Walk_px",
                     iSmType,
                     iSm,
                     iRpc,
                     iCh));
              TH1D* htempWalk1 = (TH1D*) gDirectory->FindObjectAny(
                Form("Cor_SmT%01d_sm%03d_rpc%03d_Ch%03d_S1_Walk_px",
                     iSmType,
                     iSm,
                     iRpc,
                     iCh));
              if (NULL != htempWalk0
                  && NULL != htempWalk1) {  // reinitialize Walk array
                LOG(info) << "Initialize Walk correction for "
                          << Form(" SmT%01d_sm%03d_rpc%03d_Ch%03d",
                                  iSmType,
                                  iSm,
                                  iRpc,
                                  iCh);
                if (htempWalk0->GetNbinsX() != nbClWalkBinX)
                  LOG(error) << "CbmTofSimpClusterizer::InitCalibParameter: "
                                "Inconsistent Walk histograms";
                for (Int_t iBin = 0; iBin < nbClWalkBinX; iBin++) {
                  fvCPWalk[iSmType][iSm * iNbRpc + iRpc][iCh][0][iBin] =
                    htempWalk0->GetBinContent(iBin + 1);
                  fvCPWalk[iSmType][iSm * iNbRpc + iRpc][iCh][1][iBin] =
                    htempWalk1->GetBinContent(iBin + 1);
                  LOG(debug1) << Form(
                    " SmT%01d_sm%03d_rpc%03d_Ch%03d bin %d walk %f ",
                    iSmType,
                    iSm,
                    iRpc,
                    iCh,
                    iBin,
                    fvCPWalk[iSmType][iSm * iNbRpc + iRpc][iCh][0][iBin]);
                }
              }
            }
          } else {
            LOG(error) << " Histos "
                       << Form(
                            "cl_SmT%01d_sm%03d_rpc%03d_XXX", iSmType, iSm, iRpc)
                       << " not found. ";
          }
          for (Int_t iTrg = 0; iTrg < iNTrg; iTrg++) {
            TH1D* htmpDelTof = (TH1D*) gDirectory->FindObjectAny(
              Form("cl_CorSmT%01d_sm%03d_rpc%03d_Trg%02d_DelTof",
                   iSmType,
                   iSm,
                   iRpc,
                   iTrg));
            if (NULL == htmpDelTof) {
              LOG(info) << " Histos "
                        << Form("cl_CorSmT%01d_sm%03d_rpc%03d_Trg%02d_DelTof",
                                iSmType,
                                iSm,
                                iRpc,
                                iTrg)
                        << " not found. ";
              continue;
            }
            LOG(info) << " Load DelTof from histos "
                      << Form("cl_CorSmT%01d_sm%03d_rpc%03d_Trg%02d_DelTof",
                              iSmType,
                              iSm,
                              iRpc,
                              iTrg)
                      << ".";
            for (Int_t iBx = 0; iBx < nbClDelTofBinX; iBx++) {
              fvCPDelTof[iSmType][iSm * iNbRpc + iRpc][iBx][iTrg] +=
                htmpDelTof->GetBinContent(iBx + 1);
            }

            // copy Histo to memory
            TDirectory* curdir = gDirectory;
            gDirectory->cd(oldir->GetPath());
            TH1D* h1DelTof = (TH1D*) htmpDelTof->Clone(
              Form("cl_CorSmT%01d_sm%03d_rpc%03d_Trg%02d_DelTof",
                   iSmType,
                   iSm,
                   iRpc,
                   iTrg));

            LOG(info) << " copy histo " << h1DelTof->GetName()
                      << " to directory " << oldir->GetName();

            gDirectory->cd(curdir->GetPath());
          }
        }
    }
  }
  //   fCalParFile->Delete();
  gDirectory->cd(
    oldir
      ->GetPath());  // <= To prevent histos from being sucked in by the param file of the TRootManager!
  LOG(info) << "CbmTofSimpClusterizer::InitCalibParameter: initialization done";
  return kTRUE;
}
/************************************************************************************/
Bool_t CbmTofSimpClusterizer::LoadGeometry() {
  LOG(debug) << "CbmTofSimpClusterizer::LoadGeometry starting for  "
             << fDigiPar->GetNrOfModules() << " geometrically known modules ";

  Int_t iNrOfCells = fDigiPar->GetNrOfModules();
  LOG(debug) << "Digi Parameter container contains " << iNrOfCells << " cells"
             << ", interpret with GeoVersion " << fGeoHandler->GetGeoVersion();

  fGeoHandler->CheckGeometryVersion();

  for (Int_t icell = 0; icell < iNrOfCells; ++icell) {

    Int_t cellId =
      fDigiPar->GetCellId(icell);  // cellId is assigned in CbmTofCreateDigiPar
    fChannelInfo = fDigiPar->GetCell(cellId);

    Int_t smtype  = fGeoHandler->GetSMType(cellId);
    Int_t smodule = fGeoHandler->GetSModule(cellId);
    Int_t module  = fGeoHandler->GetCounter(cellId);
    Int_t cell    = fGeoHandler->GetCell(cellId);

    Double_t x  = fChannelInfo->GetX();
    Double_t y  = fChannelInfo->GetY();
    Double_t z  = fChannelInfo->GetZ();
    Double_t dx = fChannelInfo->GetSizex();
    Double_t dy = fChannelInfo->GetSizey();
    LOG(debug1) << "-I- InitPar " << icell << " Id: " << Form("0x%08x", cellId)
                << " " << cell << " tmcs: " << smtype << " " << smodule << " "
                << module << " " << cell << " x=" << Form("%6.2f", x)
                << " y=" << Form("%6.2f", y) << " z=" << Form("%6.2f", z)
                << " dx=" << dx << " dy=" << dy;
  }

  Int_t iNbSmTypes = fDigiBdfPar->GetNbSmTypes();

  if (kTRUE == fDigiBdfPar->UseExpandedDigi()) {
    fStorDigiExp.resize(iNbSmTypes);
    fStorDigiInd.resize(iNbSmTypes);
    fviClusterSize.resize(iNbSmTypes);
    fviTrkMul.resize(iNbSmTypes);
    fvdX.resize(iNbSmTypes);
    fvdY.resize(iNbSmTypes);
    fvdDifX.resize(iNbSmTypes);
    fvdDifY.resize(iNbSmTypes);
    fvdDifCh.resize(iNbSmTypes);
    fviClusterMul.resize(iNbSmTypes);
    for (Int_t iSmType = 0; iSmType < iNbSmTypes; iSmType++) {
      Int_t iNbSm  = fDigiBdfPar->GetNbSm(iSmType);
      Int_t iNbRpc = fDigiBdfPar->GetNbRpc(iSmType);
      fStorDigiExp[iSmType].resize(iNbSm * iNbRpc);
      fStorDigiInd[iSmType].resize(iNbSm * iNbRpc);
      fviClusterSize[iSmType].resize(iNbRpc);
      fviTrkMul[iSmType].resize(iNbRpc);
      fvdX[iSmType].resize(iNbRpc);
      fvdY[iSmType].resize(iNbRpc);
      fvdDifX[iSmType].resize(iNbRpc);
      fvdDifY[iSmType].resize(iNbRpc);
      fvdDifCh[iSmType].resize(iNbRpc);
      for (Int_t iSm = 0; iSm < iNbSm; iSm++) {
        fviClusterMul[iSmType].resize(iNbSm);
        for (Int_t iRpc = 0; iRpc < iNbRpc; iRpc++) {
          fviClusterMul[iSmType][iSm].resize(iNbRpc);
          Int_t iNbChan = fDigiBdfPar->GetNbChan(iSmType, iRpc);
          LOG(debug)
            << "CbmTofSimpClusterizer::LoadGeometry: StoreDigi with "
            << Form(
                 " %3d %3d %3d %3d %5d ", iSmType, iSm, iNbRpc, iRpc, iNbChan);
          fStorDigiExp[iSmType][iSm * iNbRpc + iRpc].resize(iNbChan);
          fStorDigiInd[iSmType][iSm * iNbRpc + iRpc].resize(iNbChan);
        }  // for( Int_t iRpc = 0; iRpc < iNbRpc; iRpc++ )
      }    // for( Int_t iSm = 0; iSm < iNbSm; iSm++ )
    }      // for( Int_t iSmType = 0; iSmType < iNbSmTypes; iSmType++ )
  }        // if( kTRUE == fDigiBdfPar->UseExpandedDigi() )
  LOG(debug) << "CbmTofSimpClusterizer::LoadGeometry: Done!";
  return kTRUE;
}
Bool_t CbmTofSimpClusterizer::DeleteGeometry() {
  Int_t iNbSmTypes = fDigiBdfPar->GetNbSmTypes();
  if (kTRUE == fDigiBdfPar->UseExpandedDigi()) {
    for (Int_t iSmType = 0; iSmType < iNbSmTypes; iSmType++) {
      Int_t iNbSm  = fDigiBdfPar->GetNbSm(iSmType);
      Int_t iNbRpc = fDigiBdfPar->GetNbRpc(iSmType);
      for (Int_t iSm = 0; iSm < iNbSm; iSm++) {
        for (Int_t iRpc = 0; iRpc < iNbRpc; iRpc++) {
          fStorDigiExp[iSmType][iSm * iNbRpc + iRpc].clear();
          fStorDigiInd[iSmType][iSm * iNbRpc + iRpc].clear();
        }
      }  // for( Int_t iSm = 0; iSm < iNbSm; iSm++ )
      fStorDigiExp[iSmType].clear();
      fStorDigiInd[iSmType].clear();
    }  // for( Int_t iSmType = 0; iSmType < iNbSmTypes; iSmType++ )
    fStorDigiExp.clear();
    fStorDigiInd.clear();
  }  // if( kTRUE == fDigiBdfPar->UseExpandedDigi() )
  return kTRUE;
}
/************************************************************************************/
// Histogramming functions
Bool_t CbmTofSimpClusterizer::CreateHistos() {
  TDirectory* oldir =
    gDirectory;  // <= To prevent histos from being sucked in by the param file of the TRootManager!
  gROOT
    ->cd();  // <= To prevent histos from being sucked in by the param file of the TRootManager !
  fhClustBuildTime =
    new TH1I("TofSimpClus_ClustBuildTime",
             "Time needed to build clusters in each event; Time [s]",
             4000,
             0.0,
             4.0);
  fhHitsPerTracks =
    new TH1I("TofSimpClus_TofHitPerTrk",
             "Mean Number of TofHit per Mc Track; Nb TofHits/Nb MC Tracks []",
             2000,
             0.0,
             20.0);
  if (kFALSE == fDigiBdfPar->ClustUseTrackId())
    fhPtsPerHit = new TH1I("TofSimpClus_TofPtsPerHit",
                           "Distribution of the Number of MCPoints associated "
                           "to each TofHit; Nb MCPoint []",
                           20,
                           0.0,
                           20.0);
  if (kTRUE == fDigiBdfPar->ClustUseTrackId()) {
    fhTimeResSingHits =
      new TH1I("TofSimpClus_TofTimeResClust",
               "Time resolution for TofHits containing Digis from a single MC "
               "Track; t(1st Mc Point) -tTofHit [ns]",
               10000,
               -25.0,
               25.0);
    fhTimeResSingHitsB =
      new TH2I("TofSimpClus_TofTimeResClustB",
               "Time resolution for TofHits containing Digis from a single MC "
               "Track; (1st Mc Point) -tTofHit [ns]",
               5000,
               -25.0,
               25.0,
               6,
               0,
               6);
    fhTimePtVsHits =
      new TH2I("TofSimpClus_TofTimePtVsHit",
               "Time resolution for TofHits containing Digis from a single MC "
               "Track; t(1st Mc Point) -tTofHit [ps]",
               2000,
               0.0,
               50000.0,
               2000,
               0.0,
               50000.0);
  } else {
    fhTimeResSingHits =
      new TH1I("TofSimpClus_TofTimeResClust",
               "Time resolution for TofHits containing Digis from a single "
               "TofPoint; tMcPoint -tTofHit [ns]",
               10000,
               -25.0,
               25.0);
    fhTimeResSingHitsB =
      new TH2I("TofSimpClus_TofTimeResClustB",
               "Time resolution for TofHits containing Digis from a single "
               "TofPoint; tMcPoint -tTofHit [ns]",
               5000,
               -25.0,
               25.0,
               6,
               0,
               6);
    fhTimePtVsHits = new TH2I("TofSimpClus_TofTimePtVsHit",
                              "Time resolution for TofHits containing Digis "
                              "from a single TofPoint; tMcPoint -tTofHit [ps]",
                              2000,
                              0.0,
                              50000.0,
                              2000,
                              0.0,
                              50000.0);
  }  // else of if( kTRUE == fDigiBdfPar->ClustUseTrackId() )
  fhClusterSize = new TH1I("TofSimpClus_ClusterSize",
                           "Cluster Size distribution; Cluster Size [Strips]",
                           100,
                           0.5,
                           100.5);
  fhClusterSizeType =
    new TH2I("TofSimpClus_ClusterSizeType",
             "Cluster Size distribution in each (SM type, Rpc) pair; Cluster "
             "Size [Strips]; 10*SM Type + Rpc Index []",
             100,
             0.5,
             100.5,
             40 * fDigiBdfPar->GetNbSmTypes(),
             0.0,
             40 * fDigiBdfPar->GetNbSmTypes());
  if (kTRUE == fDigiBdfPar->ClustUseTrackId()) {
    fhTrackMul = new TH1I(
      "TofSimpClus_TrackMul",
      "Number of MC tracks generating the cluster; MC Tracks multiplicity []",
      100,
      0.5,
      100.5);
    fhClusterSizeMulti = new TH2I(
      "TofSimpClus_ClusterSizeMulti",
      "Cluster Size distribution as function of Number of MC tracks generating "
      "the cluster; Cluster Size [Strips]; MC tracks mul. []",
      100,
      0.5,
      100.5,
      100,
      0.5,
      100.5);
    fhTrk1MulPos   = new TH2D("TofSimpClus_Trk1MulPos",
                            "Position of Clusters with only 1 MC tracks "
                            "generating the cluster; X [cm]; Y [cm]",
                            1500,
                            -750,
                            750,
                            1000,
                            -500,
                            500);
    fhHiTrkMulPos  = new TH2D("TofSimpClus_HiTrkMulPos",
                             "Position of Clusters with >1 MC tracks "
                             "generating the cluster; X [cm]; Y [cm]",
                             1500,
                             -750,
                             750,
                             1000,
                             -500,
                             500);
    fhAllTrkMulPos = new TH2D(
      "TofSimpClus_AllTrkMulPos",
      "Position of all clusters generating the cluster; X [cm]; Y [cm]",
      1500,
      -750,
      750,
      1000,
      -500,
      500);
    fhMultiTrkProbPos =
      new TH2D("TofSimpClus_MultiTrkProbPos",
               "Probability of having a cluster with multiple tracks as "
               "function of position; X [cm]; Y [cm]; Prob. [%]",
               1500,
               -750,
               750,
               1000,
               -500,
               500);
  }  // if( kTRUE == fDigiBdfPar->ClustUseTrackId() )

  fhDigSpacDifClust =
    new TH1I("TofSimpClus_DigSpacDifClust",
             "Space difference along channel direction between Digi pairs on "
             "adjacent channels; PosCh i - Pos Ch i+1 [cm]",
             5000,
             -10.0,
             10.0);
  fhDigTimeDifClust =
    new TH1I("TofSimpClus_DigTimeDifClust",
             "Time difference between Digi pairs on adjacent channels; "
             "0.5*(tDigiA + tDigiA)chi - 0.5*(tDigiA + tDigiA)chi+1 [ns]",
             5000,
             -5.0,
             5.0);
  fhDigDistClust = new TH2I(
    "TofSimpClus_DigDistClust",
    "Distance between Digi pairs on adjacent channels; PosCh i - Pos Ch i+1 "
    "[cm along ch]; 0.5*(tDigiA + tDigiA)chi - 0.5*(tDigiA + tDigiA)chi+1 [ns]",
    5000,
    -10.0,
    10.0,
    2000,
    -5.0,
    5.0);

  fhClustSizeDifX =
    new TH2I("TofSimpClus_ClustSizeDifX",
             "Position difference between Point and Hit as function of Cluster "
             "Size; Cluster Size [Strips]; dX [cm]",
             100,
             0.5,
             100.5,
             500,
             -50,
             50);
  fhClustSizeDifY =
    new TH2I("TofSimpClus_ClustSizeDifY",
             "Position difference between Point and Hit as function of Cluster "
             "Size; Cluster Size [Strips]; dY [cm]",
             100,
             0.5,
             100.5,
             500,
             -50,
             50);
  fhChDifDifX = new TH2I("TofSimpClus_ChDifDifX",
                         "Position difference between Point and Hit as "
                         "function of Channel dif; Ch Dif [Strips]; dX [cm]",
                         101,
                         -50.5,
                         50.5,
                         500,
                         -50,
                         50);
  fhChDifDifY = new TH2I("TofSimpClus_ChDifDifY",
                         "Position difference between Point and Hit as "
                         "function of Channel Dif; Ch Dif [Strips]; dY [cm]",
                         101,
                         -50.5,
                         50.5,
                         500,
                         -50,
                         50);

  fhNbSameSide    = new TH1I("TofSimpClus_NbSameSide",
                          "How many time per event the 2 digis on a channel "
                          "were of the same side ; Counts/Event []",
                          500,
                          0.0,
                          500.0);
  fhNbDigiPerChan = new TH1I("TofSimpClus_NbDigiPerChan",
                             "Nb of Digis per channel; Nb Digis []",
                             100,
                             0.0,
                             100.0);

  gDirectory->cd(
    oldir
      ->GetPath());  // <= To prevent histos from being sucked in by the param file of the TRootManager!

  return kTRUE;
}
Bool_t CbmTofSimpClusterizer::FillHistos() {
  fhClustBuildTime->Fill(fStop.GetSec() - fStart.GetSec()
                         + (fStop.GetNanoSec() - fStart.GetNanoSec()) / 1e9);
  Int_t iNbTofHits = fTofHitsColl->GetEntries();

  if (fbMcTrkMonitor && fMcTracksColl) {
    Int_t iNbTracks = fMcTracksColl->GetEntries();

    // Trakcs Info
    Int_t iNbTofTracks     = 0;
    Int_t iNbTofTracksPrim = 0;
    CbmMCTrack* pMcTrk;
    for (Int_t iTrkInd = 0; iTrkInd < iNbTracks; iTrkInd++) {
      pMcTrk = (CbmMCTrack*) fMcTracksColl->At(iTrkInd);

      if (0 < pMcTrk->GetNPoints(ECbmModuleId::kTof)) { iNbTofTracks++; }
      if (0 < pMcTrk->GetNPoints(ECbmModuleId::kTof)
          && -1 == pMcTrk->GetMotherId())
        iNbTofTracksPrim++;

    }  // for(Int_t iTrkInd = 0; iTrkInd < nMcTracks; iTrkInd++)

    if (0 < iNbTofTracks)
      fhHitsPerTracks->Fill((Double_t) iNbTofHits / (Double_t) iNbTofTracks);
  }  // if( fbMcTrkMonitor )

  CbmTofHit* pHit;
  for (Int_t iHitInd = 0; iHitInd < iNbTofHits; iHitInd++) {
    pHit = (CbmTofHit*) fTofHitsColl->At(iHitInd);
    if (kFALSE == fDigiBdfPar->ClustUseTrackId())
      fhPtsPerHit->Fill(pHit->GetFlag());
    if (1 == pHit->GetFlag()) {
      //         CbmTofPoint* pPt = (CbmTofPoint*)pHit->GetRefId();
      // Using the SetLinks/GetLinks of the TofHit class seems to conflict
      // with something in littrack QA
      //         CbmTofPoint* pPt = (CbmTofPoint*)(pHit->GetLinks());
      /*
         // Use instead the index => WRONG and not consistent with hit creation
         // Need to loop on digi match object, check the digi to pnt match object for each, etc....
         // ====> Just comment this code, if anybody needs it, have to implement proper solution
         CbmTofPoint* pPt = (CbmTofPoint*)fTofPointsColl->At( pHit->GetRefId() );
         fhTimePtVsHits->Fill( pPt->GetTime(), pHit->GetTime() );
         fhTimeResSingHits->Fill( pHit->GetTime() - pPt->GetTime() );
         fhTimeResSingHitsB->Fill( pHit->GetTime() - pPt->GetTime(),
               fGeoHandler->GetSMType(pPt->GetDetectorID()) );
*/
    }  // if( 1 == pHit->GetFlag() )
  }    // for( Int_t iHitInd = 0; iHitInd < iNbTofHits; iHitInd++)

  for (Int_t iSmType = 0; iSmType < fDigiBdfPar->GetNbSmTypes(); iSmType++)
    for (Int_t iRpc = 0; iRpc < fDigiBdfPar->GetNbRpc(iSmType); iRpc++) {
      for (UInt_t uCluster = 0; uCluster < fviClusterSize[iSmType][iRpc].size();
           uCluster++) {
        fhClusterSize->Fill(fviClusterSize[iSmType][iRpc][uCluster]);
        fhClusterSizeType->Fill(fviClusterSize[iSmType][iRpc][uCluster],
                                40 * iSmType + iRpc);
        if (kTRUE == fDigiBdfPar->ClustUseTrackId()) {
          fhTrackMul->Fill(fviTrkMul[iSmType][iRpc][uCluster]);
          fhClusterSizeMulti->Fill(fviClusterSize[iSmType][iRpc][uCluster],
                                   fviTrkMul[iSmType][iRpc][uCluster]);
          if (1 == fviTrkMul[iSmType][iRpc][uCluster])
            fhTrk1MulPos->Fill(fvdX[iSmType][iRpc][uCluster],
                               fvdY[iSmType][iRpc][uCluster]);
          if (1 < fviTrkMul[iSmType][iRpc][uCluster])
            fhHiTrkMulPos->Fill(fvdX[iSmType][iRpc][uCluster],
                                fvdY[iSmType][iRpc][uCluster]);
          fhAllTrkMulPos->Fill(fvdX[iSmType][iRpc][uCluster],
                               fvdY[iSmType][iRpc][uCluster]);
        }  // if( kTRUE == fDigiBdfPar->ClustUseTrackId() )
        if (1 == fviTrkMul[iSmType][iRpc][uCluster]) {
          fhClustSizeDifX->Fill(fviClusterSize[iSmType][iRpc][uCluster],
                                fvdDifX[iSmType][iRpc][uCluster]);
          fhClustSizeDifY->Fill(fviClusterSize[iSmType][iRpc][uCluster],
                                fvdDifY[iSmType][iRpc][uCluster]);
          if (1 == fviClusterSize[iSmType][iRpc][uCluster]) {
            fhChDifDifX->Fill(fvdDifCh[iSmType][iRpc][uCluster],
                              fvdDifX[iSmType][iRpc][uCluster]);
            fhChDifDifY->Fill(fvdDifCh[iSmType][iRpc][uCluster],
                              fvdDifY[iSmType][iRpc][uCluster]);
          }
        }
      }  // for( UInt_t uCluster = 0; uCluster < fviClusterSize[iSmType][iRpc].size(); uCluster++ )
      fviClusterSize[iSmType][iRpc].clear();
      fviTrkMul[iSmType][iRpc].clear();
      fvdX[iSmType][iRpc].clear();
      fvdY[iSmType][iRpc].clear();
      fvdDifX[iSmType][iRpc].clear();
      fvdDifY[iSmType][iRpc].clear();
      fvdDifCh[iSmType][iRpc].clear();
    }  // for( Int_t iRpc = 0; iRpc < fDigiBdfPar->GetNbRpc( iSmType); iRpc++ )

  fhNbSameSide->Fill(fiNbSameSide);

  return kTRUE;
}
Bool_t CbmTofSimpClusterizer::WriteHistos() {
  if ("" == fsHistoOutFilename) {
    LOG(info) << "CbmTofSimpClusterizer::WriteHistos => Control histograms "
                 "will not be written to disk!";
    LOG(info) << "CbmTofSimpClusterizer::WriteHistos => To change this "
                 "behavior please provide a full path "
              << "with the SetHistoFileName method";
    return kTRUE;
  }  // if( "" == fsHistoOutFilename )

  TDirectory* oldir = gDirectory;
  TFile* fHist      = new TFile(fsHistoOutFilename, "RECREATE");

  fHist->cd();
  fhClustBuildTime->Write();
  fhHitsPerTracks->Write();
  if (kFALSE == fDigiBdfPar->ClustUseTrackId()) fhPtsPerHit->Write();
  fhTimeResSingHits->Write();
  fhTimeResSingHitsB->Write();
  fhTimePtVsHits->Write();
  fhClusterSize->Write();
  fhClusterSizeType->Write();
  if (kTRUE == fDigiBdfPar->ClustUseTrackId()) {
    fhTrackMul->Write();
    fhClusterSizeMulti->Write();
    fhTrk1MulPos->Write();
    fhHiTrkMulPos->Write();
    fhAllTrkMulPos->Write();
    fhMultiTrkProbPos->Divide(fhHiTrkMulPos, fhAllTrkMulPos);
    fhMultiTrkProbPos->Scale(100.0);
    fhMultiTrkProbPos->Write();
  }  // if( kTRUE == fDigiBdfPar->ClustUseTrackId() )
  fhDigSpacDifClust->Write();
  fhDigTimeDifClust->Write();
  fhDigDistClust->Write();

  fhClustSizeDifX->Write();
  fhClustSizeDifY->Write();

  fhChDifDifX->Write();
  fhChDifDifY->Write();

  fhNbSameSide->Write();
  fhNbDigiPerChan->Write();

  gDirectory->cd(oldir->GetPath());

  fHist->Close();

  return kTRUE;
}
Bool_t CbmTofSimpClusterizer::SetHistoFileName(TString sFilenameIn) {
  fsHistoOutFilename = sFilenameIn;
  return kTRUE;
}
Bool_t CbmTofSimpClusterizer::DeleteHistos() {
  delete fhClustBuildTime;
  delete fhHitsPerTracks;
  delete fhPtsPerHit;
  delete fhTimeResSingHits;
  delete fhTimeResSingHitsB;
  delete fhTimePtVsHits;
  delete fhClusterSize;
  delete fhClusterSizeType;

  if (kTRUE == fDigiBdfPar->ClustUseTrackId()) {
    delete fhTrackMul;
    delete fhClusterSizeMulti;
    delete fhTrk1MulPos;
    delete fhHiTrkMulPos;
    delete fhAllTrkMulPos;
    delete fhMultiTrkProbPos;
  }
  delete fhDigSpacDifClust;
  delete fhDigTimeDifClust;
  delete fhDigDistClust;

  delete fhClustSizeDifX;
  delete fhClustSizeDifY;

  delete fhChDifDifX;
  delete fhChDifDifY;

  delete fhNbSameSide;
  delete fhNbDigiPerChan;

  return kTRUE;
}
/************************************************************************************/
Bool_t CbmTofSimpClusterizer::BuildClusters() {
  // --- MC Event info (input file, entry number, start time)
  Int_t iInputNr      = 0;
  Int_t iEventNr      = 0;
  Double_t dEventTime = 0.;
  GetEventInfo(iInputNr, iEventNr, dEventTime);

  /*
    * FIXME: maybe use the 2D distance (X/Y) as criteria instead of the distance long channel
    * direction
    */
  Double_t dMaxTimeDist  = fDigiBdfPar->GetMaxTimeDist();
  Double_t dMaxSpaceDist = fDigiBdfPar->GetMaxDistAlongCh();

  LOG(debug) << " BuildCluster with MaxTimeDist " << dMaxTimeDist
             << ", MaxSpaceDist " << dMaxSpaceDist;

  // First Time order the Digis array
  //   fTofDigisColl->Sort();

  // Then loop over the digis array and store the Digis in separate vectors for
  // each RPC modules
  Int_t iNbTofDigi = fDigiMan->GetNofDigis(ECbmModuleId::kTof);
  LOG(info) << "Number of TOF digis: " << iNbTofDigi;
  if (kTRUE == fDigiBdfPar->UseExpandedDigi()) {
    CbmTofDigi* pDigi = nullptr;
    for (Int_t iDigInd = 0; iDigInd < iNbTofDigi; iDigInd++) {
      assert(fDigiMan->Get<CbmTofDigi>(iDigInd));
      pDigi = new CbmTofDigi(*(fDigiMan->Get<CbmTofDigi>(iDigInd)));
      LOG(debug1) << "CbmTofSimpClusterizer::BuildClusters: " << iDigInd << " "
                  << pDigi << " " << pDigi->GetType() << " " << pDigi->GetSm()
                  << " " << pDigi->GetRpc() << " " << pDigi->GetChannel() << " "
                  << Form("T %6.2f, Tot %6.1f ",
                          pDigi->GetTime(),
                          pDigi->GetTot());
      if (fDigiBdfPar->GetNbSmTypes()
            > pDigi->GetType()  // prevent crash due to misconfiguration
          && fDigiBdfPar->GetNbSm(pDigi->GetType()) > pDigi->GetSm()
          && fDigiBdfPar->GetNbRpc(pDigi->GetType()) > pDigi->GetRpc()
          && fDigiBdfPar->GetNbChan(pDigi->GetType(), 0)
               > pDigi->GetChannel()) {

        fStorDigiExp[pDigi->GetType()]
                    [pDigi->GetSm() * fDigiBdfPar->GetNbRpc(pDigi->GetType())
                     + pDigi->GetRpc()][pDigi->GetChannel()]
                      .push_back(pDigi);
        fStorDigiInd[pDigi->GetType()]
                    [pDigi->GetSm() * fDigiBdfPar->GetNbRpc(pDigi->GetType())
                     + pDigi->GetRpc()][pDigi->GetChannel()]
                      .push_back(iDigInd);

        // apply calibration vectors
        pDigi->SetTime(
          pDigi->GetTime() -  // calibrate Digi Time
          fvCPTOff[pDigi->GetType()]
                  [pDigi->GetSm() * fDigiBdfPar->GetNbRpc(pDigi->GetType())
                   + pDigi->GetRpc()][pDigi->GetChannel()][pDigi->GetSide()]);

        pDigi->SetTot(
          pDigi->GetTot() *  // calibrate Digi ToT
          fvCPTotGain[pDigi->GetType()]
                     [pDigi->GetSm() * fDigiBdfPar->GetNbRpc(pDigi->GetType())
                      + pDigi->GetRpc()][pDigi->GetChannel()]
                     [pDigi->GetSide()]);

        // walk correction
        Double_t dTotBinSize = (TOTMax - TOTMin) / 2. / nbClWalkBinX;
        Int_t iWx = (Int_t)((pDigi->GetTot() - TOTMin / 2.) / dTotBinSize);
        if (0 > iWx) iWx = 0;
        if (iWx > (nbClWalkBinX - 1)) iWx = nbClWalkBinX - 1;
        Double_t dDTot =
          (pDigi->GetTot() - TOTMin / 2.) / dTotBinSize - (Double_t) iWx - 0.5;
        Double_t dWT =
          fvCPWalk[pDigi->GetType()]
                  [pDigi->GetSm() * fDigiBdfPar->GetNbRpc(pDigi->GetType())
                   + pDigi->GetRpc()][pDigi->GetChannel()][pDigi->GetSide()]
                  [iWx];
        if (dDTot > 0) {
          if (iWx < nbClWalkBinX - 1) {  // linear interpolation to next bin
            dWT += dDTot
                   * (fvCPWalk[pDigi->GetType()]
                              [pDigi->GetSm()
                                 * fDigiBdfPar->GetNbRpc(pDigi->GetType())
                               + pDigi->GetRpc()][pDigi->GetChannel()]
                              [pDigi->GetSide()][iWx + 1]
                      - fvCPWalk[pDigi->GetType()]
                                [pDigi->GetSm()
                                   * fDigiBdfPar->GetNbRpc(pDigi->GetType())
                                 + pDigi->GetRpc()][pDigi->GetChannel()]
                                [pDigi->GetSide()][iWx]);
          }     // if(iWx < nbClWalkBinX -1)
        } else  // dDTot < 0,
        {
          if (0 < iWx) {  // linear interpolation to next bin
            dWT -= dDTot
                   * (fvCPWalk[pDigi->GetType()]
                              [pDigi->GetSm()
                                 * fDigiBdfPar->GetNbRpc(pDigi->GetType())
                               + pDigi->GetRpc()][pDigi->GetChannel()]
                              [pDigi->GetSide()][iWx - 1]
                      - fvCPWalk[pDigi->GetType()]
                                [pDigi->GetSm()
                                   * fDigiBdfPar->GetNbRpc(pDigi->GetType())
                                 + pDigi->GetRpc()][pDigi->GetChannel()]
                                [pDigi->GetSide()][iWx]);
          }  // if(0 < iWx)
        }

        pDigi->SetTime(pDigi->GetTime() - dWT);  // calibrate Digi Time

        if (0) {  //pDigi->GetType()==2 && pDigi->GetSm()==0){
          LOG(info)
            << "CbmTofSimpClusterizer::BuildClusters: CalDigi " << iDigInd
            << ",  T " << pDigi->GetType() << ", Sm " << pDigi->GetSm()
            << ", R " << pDigi->GetRpc() << ", Ch " << pDigi->GetChannel()
            << ", S " << pDigi->GetSide() << ", T " << pDigi->GetTime()
            << ", Tot " << pDigi->GetTot() << ", TotGain "
            << fvCPTotGain[pDigi->GetType()]
                          [pDigi->GetSm()
                             * fDigiBdfPar->GetNbRpc(pDigi->GetType())
                           + pDigi->GetRpc()][pDigi->GetChannel()]
                          [pDigi->GetSide()]
            << ", Walk " << iWx << ": "
            << fvCPWalk[pDigi->GetType()]
                       [pDigi->GetSm() * fDigiBdfPar->GetNbRpc(pDigi->GetType())
                        + pDigi->GetRpc()][pDigi->GetChannel()]
                       [pDigi->GetSide()][iWx];

          LOG(info)
            << " dDTot " << dDTot << " BinSize: " << dTotBinSize << ", CPWalk "
            << fvCPWalk[pDigi->GetType()]
                       [pDigi->GetSm() * fDigiBdfPar->GetNbRpc(pDigi->GetType())
                        + pDigi->GetRpc()][pDigi->GetChannel()]
                       [pDigi->GetSide()][iWx - 1]
            << ", "
            << fvCPWalk[pDigi->GetType()]
                       [pDigi->GetSm() * fDigiBdfPar->GetNbRpc(pDigi->GetType())
                        + pDigi->GetRpc()][pDigi->GetChannel()]
                       [pDigi->GetSide()][iWx]
            << ", "
            << fvCPWalk[pDigi->GetType()]
                       [pDigi->GetSm() * fDigiBdfPar->GetNbRpc(pDigi->GetType())
                        + pDigi->GetRpc()][pDigi->GetChannel()]
                       [pDigi->GetSide()][iWx + 1]
            << " -> dWT = " << dWT;
        }
      } else {
        LOG(debug) << "CbmTofSimpBeamClusterizer::BuildClusters: Skip Digi "
                   << " Type " << pDigi->GetType() << " "
                   << fDigiBdfPar->GetNbSmTypes() << " Sm " << pDigi->GetSm()
                   << " " << fDigiBdfPar->GetNbSm(pDigi->GetType()) << " Rpc "
                   << pDigi->GetRpc() << " "
                   << fDigiBdfPar->GetNbRpc(pDigi->GetType()) << " Ch "
                   << pDigi->GetChannel() << " "
                   << fDigiBdfPar->GetNbChan(pDigi->GetType(), 0);
      }
    }  // for( Int_t iDigInd = 0; iDigInd < nTofDigi; iDigInd++ )
  }    // if( kTRUE == fDigiBdfPar->UseExpandedDigi() )

  // Then build clusters inside each RPC module
  // Assume only 0 or 1 Digi per channel/side in each event
  // Use simplest method possible, scan direction independent:
  // a) Loop over channels in the RPC starting from 0
  //   * If strips
  //     i) Loop over Digis to check if both ends of the channel have a Digi
  //    ii) Reconstruct a mean channel time and a mean position
  //     + If a Hit is currently filled & the mean position (space, time) is less than XXX from last channel position
  //   iii) Add the mean channel time and the mean position to the ones of the hit
  //     + else
  //   iii) Use nb of strips in cluster to cal. the hit mean time and pos (charge/tot weighting)
  //    iv) Save the hit
  //     v) Start a new hit with current channel
  //   * else (pads)
  //     i) Loop over Digis to find if this channel fired
  //    ii) FIXME: either scan all other channels to check for matching Digis or have more than 1 hit open
  Int_t iNbSmTypes = fDigiBdfPar->GetNbSmTypes();
  // Hit variables
  Double_t dWeightedTime    = 0.0;
  Double_t dWeightedPosX    = 0.0;
  Double_t dWeightedPosY    = 0.0;
  Double_t dWeightedPosZ    = 0.0;
  Double_t dWeightedTimeErr = 0.0;
  Double_t dWeightsSum      = 0.0;
  std::vector<CbmTofPoint*> vPtsRef;
  std::vector<Int_t> vDigiIndRef;
  CbmTofCell* fTrafoCell = NULL;
  Int_t iTrafoCell       = -1;
  Int_t iNbChanInHit     = 0;
  // Last Channel Temp variables
  Int_t iLastChan = -1;
  //   Double_t dLastPosX = 0.0; // -> Comment to remove warning because set but never used
  Double_t dLastPosY = 0.0;
  Double_t dLastTime = 0.0;
  // Channel Temp variables
  Double_t dPosX = 0.0;
  Double_t dPosY = 0.0;
  Double_t dPosZ = 0.0;
  Double_t dTime = 0.0;
  Double_t dTotS = 0.0;
  fiNbSameSide   = 0;
  /// Go to Top volume of the geometry in the GeoManager to make sure
  /// our nodes are found
  gGeoManager->CdTop();
  if (kTRUE == fDigiBdfPar->UseExpandedDigi()) {
    for (Int_t iSmType = 0; iSmType < iNbSmTypes; iSmType++) {
      Int_t iNbSm  = fDigiBdfPar->GetNbSm(iSmType);
      Int_t iNbRpc = fDigiBdfPar->GetNbRpc(iSmType);
      for (Int_t iSm = 0; iSm < iNbSm; iSm++)
        for (Int_t iRpc = 0; iRpc < iNbRpc; iRpc++) {
          Int_t iNbCh   = fDigiBdfPar->GetNbChan(iSmType, iRpc);
          Int_t iChType = fDigiBdfPar->GetChanType(iSmType, iRpc);
          LOG(debug2) << "CbmTofSimpClusterizer::BuildClusters: RPC - Loop  "
                      << Form(" %3d %3d %3d %3d ", iSmType, iSm, iRpc, iChType);
          fviClusterMul[iSmType][iSm][iRpc] = 0;
          Int_t iChId                       = 0;
          if (0 == iChType) {
            // Don't spread clusters over RPCs!!!
            dWeightedTime    = 0.0;
            dWeightedPosX    = 0.0;
            dWeightedPosY    = 0.0;
            dWeightedPosZ    = 0.0;
            dWeightedTimeErr = 0.0;
            dWeightsSum      = 0.0;
            iNbChanInHit     = 0;
            vPtsRef.clear();
            // For safety reinitialize everything
            iLastChan = -1;
            //                  dLastPosX = 0.0; // -> Comment to remove warning because set but never used
            dLastPosY  = 0.0;
            dLastTime  = 0.0;
            fTrafoCell = NULL;
            iTrafoCell = -1;
            LOG(debug2) << "CbmTofSimpClusterizer::BuildClusters: ChanOrient "
                        << Form(" %3d %3d %3d %3d %3d ",
                                iSmType,
                                iSm,
                                iRpc,
                                fDigiBdfPar->GetChanOrient(iSmType, iRpc),
                                iNbCh);

            if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc)) {
              // Horizontal strips => X comes from left right time difference
            }  // if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
            else {
              // Vertical strips => Y comes from bottom top time difference
              for (Int_t iCh = 0; iCh < iNbCh; iCh++) {
                LOG(debug3)
                  << "CbmTofSimpClusterizer::BuildClusters: VDigisize"
                  << Form(
                       " T %3d Sm %3d R %3d Ch %3d Size %3zu ",
                       iSmType,
                       iSm,
                       iRpc,
                       iCh,
                       fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh].size());

                if (0 < fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh].size())
                  fhNbDigiPerChan->Fill(
                    fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh].size());
                while (
                  1 < fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh].size()) {
                  LOG(debug2)
                    << "CbmTofSimpClusterizer::BuildClusters: digis processing "
                       "for "
                    << Form(" SmT %3d Sm %3d Rpc %3d Ch %3d # %3zu ",
                            iSmType,
                            iSm,
                            iRpc,
                            iCh,
                            fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh]
                              .size());
                  /*
                              if (3 < fStorDigiExp[iSmType][iSm*iNbRpc+iRpc][iCh].size()) // needs more work!
                               LOG(debug) << "CbmTofSimpClusterizer::BuildClusters: digis ignored for "
                               << Form(" SmT %3d Sm %3d Rpc %3d Ch %3d # %3d ",iSmType,iSm,iRpc,iCh,fStorDigiExp[iSmType][iSm*iNbRpc+iRpc][iCh].size())
                               ;
                               */

                  while ((fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh][0])
                           ->GetSide()
                         == (fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh][1])
                              ->GetSide()) {
                    // Not one Digi of each end!
                    fiNbSameSide++;
                    LOG(debug)
                      << "CbmTofSimpClusterizer::BuildClusters: SameSide Hits! "
                         "Times: "
                      << (fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh][0])
                           ->GetTime()
                      << ", "
                      << (fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh][1])
                           ->GetTime()
                      << ", DeltaT "
                      << (fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh][1])
                             ->GetTime()
                           - (fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh]
                                          [0])
                               ->GetTime();
                    LOG(debug2)
                      << " SameSide Erase fStor entries(d) " << iSmType
                      << ", SR " << iSm * iNbRpc + iRpc << ", Ch" << iCh;
                    fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                      fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh].begin());
                    fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                      fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].begin());
                    if (2 > fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh]
                              .size())
                      break;
                    continue;
                  }

                  LOG(debug2)
                    << "CbmTofSimpClusterizer::BuildClusters: digis processing "
                       "for "
                    << Form(" SmT %3d Sm %3d Rpc %3d Ch %3d # %3zu ",
                            iSmType,
                            iSm,
                            iRpc,
                            iCh,
                            fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh]
                              .size());
                  if (2
                      > fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh].size())
                    break;
                  /*                              Int_t iLastChId = iChId; // Save Last hit channel */

                  // 2 Digis = both sides present
                  Int_t iCh1 = iCh;
                  if (fGeoHandler->GetGeoVersion() < k14a)
                    iCh1 = iCh1 + 1;  //FIXME
                  CbmTofDetectorInfo xDetInfo(
                    ECbmModuleId::kTof, iSmType, iSm, iRpc, 0, iCh1);

                  iChId = fTofId->SetDetectorInfo(xDetInfo);
                  Int_t iUCellId =
                    CbmTofAddress::GetUniqueAddress(iSm, iRpc, iCh, 0, iSmType);

                  fChannelInfo = fDigiPar->GetCell(iChId);
                  if (NULL == fChannelInfo) {
                    LOG(error) << "CbmTofSimpClusterizer::BuildClusters: no "
                                  "geometry info! "
                               << Form(" %3d %3d %3d %3d 0x%08x 0x%08x ",
                                       iSmType,
                                       iSm,
                                       iRpc,
                                       iCh,
                                       iChId,
                                       iUCellId);
                    break;
                  }
                  LOG(debug1)
                    << "CbmTofSimpClusterizer::BuildClusters:"
                    << Form(
                         " T %3d Sm %3d R %3d Ch %3d size %3zu ",
                         iSmType,
                         iSm,
                         iRpc,
                         iCh,
                         fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh].size())
                    << Form(" ChId: 0x%08x 0x%08x %p",
                            iChId,
                            iUCellId,
                            fChannelInfo);

                  CbmTofDigi* xDigiA =
                    fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh][0];
                  CbmTofDigi* xDigiB =
                    fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh][1];


                  // The "Strip" time is the mean time between each end
                  dTime = 0.5 * (xDigiA->GetTime() + xDigiB->GetTime());

                  // Weight is the total charge => sum of both ends ToT
                  dTotS = xDigiA->GetTot() + xDigiB->GetTot();

                  // X position is just the center of the channel
                  //dPosX = fChannelInfo->GetX();

                  // Y position from strip ends time difference
                  //dPosY = fChannelInfo->GetY();

                  // For Z always just take the one of the channel itself( in fact its gap one)
                  //dPosZ = fChannelInfo->GetZ();

                  TGeoNode* fNode =  // prepare local->global trafo
                    gGeoManager->FindNode(fChannelInfo->GetX(),
                                          fChannelInfo->GetY(),
                                          fChannelInfo->GetZ());
                  if (NULL == fTrafoCell) {
                    fTrafoCell = fChannelInfo;
                    iTrafoCell = iCh;
                  }

                  //fNode->Print();
                  LOG(debug1)
                    << Form(" Node at (%6.1f,%6.1f,%6.1f) : %p, info %p, %p",
                            fChannelInfo->GetX(),
                            fChannelInfo->GetY(),
                            fChannelInfo->GetZ(),
                            fNode,
                            fChannelInfo,
                            fTrafoCell);
                  //        fNode->Print();


                  // switch to local coordinates, (0,0,0) is in the center of counter  ?
                  dPosX =
                    ((Double_t)(-iTrafoCell + iCh)) * fChannelInfo->GetSizex();
                  dPosY = 0.;
                  dPosZ = 0.;


                  if (1 == xDigiA->GetSide())

                    // 0 is the top side, 1 is the bottom side
                    dPosY += fvCPSigPropSpeed[iSmType][iRpc]
                             * (xDigiA->GetTime() - xDigiB->GetTime()) / 2.0;

                  else

                    // 0 is the bottom side, 1 is the top side
                    dPosY += fvCPSigPropSpeed[iSmType][iRpc]
                             * (xDigiB->GetTime() - xDigiA->GetTime()) / 2.0;

                  if (fChannelInfo->GetSizey() / 2.0 < dPosY
                      || -1 * fChannelInfo->GetSizey() / 2.0 > dPosY) {
                    // if outside of strip limits, the pair is bad => try to remove one end and check the next pair
                    // (if another possibility exist)
                    fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                      fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh].begin());
                    fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                      fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].begin());
                    continue;
                  }  // Pair leads to hit oustide of strip limits

                  LOG(debug1)
                    << "CbmTofSimpClusterizer::BuildClusters: NbChanInHit"
                    << Form(" %3d %3d %3d %p %2.0f Time %6.1f PosY %5.1f Svel "
                            "%5.1f",
                            iNbChanInHit,
                            iCh,
                            iLastChan,
                            xDigiA,
                            xDigiA->GetSide(),
                            dTime,
                            dPosY,
                            fvCPSigPropSpeed[iSmType][iRpc])
                    << Form(", Offs %5.1f, %5.1f",
                            fvCPTOff[iSmType][iSm * iNbRpc + iRpc][iCh][0],
                            fvCPTOff[iSmType][iSm * iNbRpc + iRpc][iCh][1]);

                  // Now check if a hit/cluster is already started
                  if (0 < iNbChanInHit) {


                    if (iLastChan == iCh - 1) {
                      fhDigTimeDifClust->Fill(dTime - dLastTime);
                      fhDigSpacDifClust->Fill(dPosY - dLastPosY);
                      fhDigDistClust->Fill(dPosY - dLastPosY,
                                           dTime - dLastTime);
                    }  // if( iLastChan == iCh - 1 )
                    // a cluster is already started => check distance in space/time
                    // For simplicity, just check along strip direction for now
                    // and break cluster when a not fired strip is found
                    if (TMath::Abs(dTime - dLastTime) < dMaxTimeDist
                        && iLastChan == iCh - 1
                        && TMath::Abs(dPosY - dLastPosY) < dMaxSpaceDist) {
                      // Add to cluster/hit
                      dWeightedTime += dTime * dTotS;
                      dWeightedPosX += dPosX * dTotS;
                      dWeightedPosY += dPosY * dTotS;
                      dWeightedPosZ += dPosZ * dTotS;
                      dWeightedTimeErr += dTotS * dTotS;
                      dWeightsSum += dTotS;
                      iNbChanInHit += 1;
                      // if one of the side digi comes from a CbmTofPoint not already found
                      // in this cluster, save its pointer
                      //                                    Bool_t bFoundA = kFALSE; // -> Comment to remove warning because set but never used
                      //                                    Bool_t bFoundB = kFALSE; // -> Comment to remove warning because set but never used
                      if (NULL != fTofPointsColl) {  // MC

                        /** **Comment the full Block as not used anymore** **/
                        /*
                                    if( kTRUE == fDigiBdfPar->ClustUseTrackId() )
                                       for( UInt_t uPtRef = 0; uPtRef < vPtsRef.size(); uPtRef++)
                                       {
                                             //if( ((CbmTofPoint*)(vPtsRef[uPtRef]))->GetTrackID() == ((CbmTofPoint*)(xDigiA->GetLinks()))->GetTrackID() )
//                                             bFoundA = kTRUE; // -> Comment to remove warning because set but never used
                                             //if( ((CbmTofPoint*)(vPtsRef[uPtRef]))->GetTrackID() == ((CbmTofPoint*)(xDigiB->GetLinks()))->GetTrackID() )
//                                             bFoundB = kTRUE; // -> Comment to remove warning because set but never used
                                       } // for( Int
                                       else for( UInt_t uPtRef = 0; uPtRef < vPtsRef.size(); uPtRef++)
                                       {
                                         //                                          if( vPtsRef[uPtRef] == (CbmTofPoint*)xDigiA->GetLinks() )
//                                             bFoundA = kTRUE; // -> Comment to remove warning because set but never used
                                         //                                          if( vPtsRef[uPtRef] == (CbmTofPoint*)xDigiB->GetLinks() )
//                                             bFoundB = kTRUE; // -> Comment to remove warning because set but never used
                                       } // for( Int_t uPtRef = 0; uPtRef < vPtsRef.size(); uPtRef++)
*/

                        // CbmTofPoint pointer for 1st digi not found => save it
                        //if( kFALSE == bFoundA )
                        //                                       vPtsRef.push_back( (CbmTofPoint*)(xDigiA->GetLinks()) );
                        // CbmTofPoint pointer for 2nd digi not found => save it
                        //                                    if( kFALSE == bFoundB )
                        //                                       vPtsRef.push_back( (CbmTofPoint*)(xDigiB->GetLinks()) );
                      }  // MC end
                      vDigiIndRef.push_back((Int_t)(
                        fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh][0]));
                      vDigiIndRef.push_back((Int_t)(
                        fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh][1]));

                      LOG(debug1)
                        << " Add Digi and erase fStor entries(a): NbChanInHit "
                        << iNbChanInHit << ", " << iSmType << ", SR "
                        << iSm * iNbRpc + iRpc << ", Ch" << iCh;

                      fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                        fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh]
                          .begin());
                      fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                        fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh]
                          .begin());
                      fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                        fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh]
                          .begin());
                      fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                        fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh]
                          .begin());

                    }  // if current Digis compatible with last fired chan
                    else {
                      // Save Hit
                      dWeightedTime /= dWeightsSum;
                      dWeightedPosX /= dWeightsSum;
                      dWeightedPosY /= dWeightsSum;
                      dWeightedPosZ /= dWeightsSum;
                      // simple error scaling with TOT
                      //                                    dWeightedTimeErr = TMath::Sqrt( dWeightedTimeErr ) * fdParSystTimeRes / dWeightsSum;
                      // OR harcoded value
                      dWeightedTimeErr = fdParSystTimeRes;

                      Double_t hitpos_local[3];
                      Double_t hitpos[3];

                      TGeoNode* tNode =  // prepare local->global trafo
                        gGeoManager->FindNode(fTrafoCell->GetX(),
                                              fTrafoCell->GetY(),
                                              fTrafoCell->GetZ());
                      TGeoNode* cNode = gGeoManager->GetCurrentNode();

                      TGeoRotation rotMatrix(*gGeoManager->GetCurrentMatrix());

                      hitpos[0] = fTrafoCell->GetX();
                      hitpos[1] = fTrafoCell->GetY();
                      hitpos[2] = fTrafoCell->GetZ();
                      gGeoManager->MasterToLocal(hitpos, hitpos_local);
                      LOG(debug1) << Form(" Node0 at (%6.1f,%6.1f,%6.1f) :  "
                                          "(%6.1f,%6.1f,%6.1f) pointer %p",
                                          fChannelInfo->GetX(),
                                          fChannelInfo->GetY(),
                                          fChannelInfo->GetZ(),
                                          hitpos_local[0],
                                          hitpos_local[1],
                                          hitpos_local[2],
                                          tNode);

                      hitpos_local[0] += dWeightedPosX;
                      hitpos_local[1] += dWeightedPosY;
                      hitpos_local[2] += dWeightedPosZ;

                      gGeoManager->LocalToMaster(hitpos_local, hitpos);
                      LOG(debug1)
                        << Form(" LTM for node %p, info %p: "
                                "(%6.1f,%6.1f,%6.1f) ->(%6.1f,%6.1f,%6.1f)",
                                cNode,
                                fChannelInfo,
                                hitpos_local[0],
                                hitpos_local[1],
                                hitpos_local[2],
                                hitpos[0],
                                hitpos[1],
                                hitpos[2]);

                      TVector3 hitPos(hitpos[0], hitpos[1], hitpos[2]);

                      // Simple errors, not properly done at all for now
                      // Right way of doing it should take into account the weight distribution
                      // and real system time resolution
                      Double_t hiterr_local[3];
                      Double_t hiterr[3];

                      hiterr_local[0] =
                        fChannelInfo->GetSizex()
                        / TMath::Sqrt(12.0);  // Single strips approximation
                      hiterr_local[1] =
                        fdParFeeTimeRes
                        * fvCPSigPropSpeed
                          [iSmType][iRpc];  // Use the electronics resolution
                      hiterr_local[2] =
                        fDigiBdfPar->GetNbGaps(iSmType, iRpc)
                        * fDigiBdfPar->GetGapSize(iSmType, iRpc)
                        / 10.0  // Change gap size in cm
                        / TMath::Sqrt(
                          12.0);  // Use full RPC thickness as "Channel" Z size

                      rotMatrix.LocalToMaster(hiterr_local, hiterr);
                      //                                    TVector3 hitPosErr( hiterr_local[0], hiterr_local[1], hiterr_local[2] );
                      TVector3 hitPosErr(hiterr[0], hiterr[1], hiterr[2]);

                      // Int_t iDetId = vPtsRef[0]->GetDetectorID();// detID = pt->GetDetectorID() <= from TofPoint
                      // calc mean ch from dPosX=((Double_t)(-iNbCh/2 + iCh)+0.5)*fChannelInfo->GetSizex();

                      Int_t iChm =
                        iTrafoCell
                        + floor(dWeightedPosX / fChannelInfo->GetSizex());
                      if (iChm < 0 || iChm > iNbCh) {
                        LOG(debug) << "CbmTofSimpClusterizer::BuildClusters: "
                                      "Invalid mean channel";
                      }
                      Int_t iDetId = CbmTofAddress::GetUniqueAddress(
                        iSm, iRpc, iChm, 0, iSmType);
                      Int_t iRefId = 0;  // Index of the correspondng TofPoint
                      // if(NULL != fTofPointsColl) {     iRefId = fTofPointsColl->IndexOf( vPtsRef[0] ); }
                      LOG(debug)
                        << "CbmTofSimpClusterizer::BuildClusters: Save Hit  "
                        << Form(" %3d %3d 0x%08x %3d %3d %3d %f %f",
                                fiNbHits,
                                iNbChanInHit,
                                iDetId,
                                iCh,
                                iLastChan,
                                iRefId,
                                dWeightedTime,
                                dWeightedPosY)
                        << ", DigiSize: " << vDigiIndRef.size()
                        << ", DigiInds: ";
                      fviClusterMul[iSmType][iSm][iRpc]++;
                      for (UInt_t i = 0; i < vDigiIndRef.size(); i++) {
                        LOG(debug) << " " << vDigiIndRef.at(i);
                      }
                      LOG(debug);

                      new ((*fTofHitsColl)[fiNbHits]) CbmTofHit(
                        iDetId,
                        hitPos,
                        hitPosErr,  //local detector coordinates
                        fiNbHits,
                        dWeightedTime * fOutTimeFactor,
                        dWeightedTimeErr,
                        vPtsRef
                          .size(),  // flag  = number of TofPoints generating the cluster
                        0);  //channel
                      //                vDigiIndRef);

                      CbmMatch* digiMatch = new CbmMatch();
                      for (UInt_t i = 0; i < vDigiIndRef.size(); i++) {
                        digiMatch->AddLink(
                          CbmLink(0., vDigiIndRef.at(i), iEventNr, iInputNr));
                      }
                      new ((*fTofDigiMatchColl)[fiNbHits]) CbmMatch(*digiMatch);
                      delete digiMatch;

                      // Using the SetLinks/GetLinks of the TofHit class seems to conflict
                      // with something in littrack QA
                      //                                    ((CbmTofHit*)fTofHitsColl->At(fiNbHits))->SetLinks(vPtsRef[0]);
                      fiNbHits++;
                      // For Histogramming
                      fviClusterSize[iSmType][iRpc].push_back(iNbChanInHit);
                      fviTrkMul[iSmType][iRpc].push_back(vPtsRef.size());
                      fvdX[iSmType][iRpc].push_back(dWeightedPosX);
                      fvdY[iSmType][iRpc].push_back(dWeightedPosY);
                      /*  no TofPoint available for data!
                                    fvdDifX[iSmType][iRpc].push_back( vPtsRef[0]->GetX() - dWeightedPosX);
                                    fvdDifY[iSmType][iRpc].push_back( vPtsRef[0]->GetY() - dWeightedPosY);
                                    fvdDifCh[iSmType][iRpc].push_back( fGeoHandler->GetCell( vPtsRef[0]->GetDetectorID() ) -1 -iLastChan );
                                    */
                      vPtsRef.clear();
                      vDigiIndRef.clear();

                      // Start a new hit
                      dWeightedTime    = dTime * dTotS;
                      dWeightedPosX    = dPosX * dTotS;
                      dWeightedPosY    = dPosY * dTotS;
                      dWeightedPosZ    = dPosZ * dTotS;
                      dWeightedTimeErr = dTotS * dTotS;
                      dWeightsSum      = dTotS;
                      iNbChanInHit     = 1;
                      // Save pointer on CbmTofPoint
                      //                                    vPtsRef.push_back( (CbmTofPoint*)(xDigiA->GetLinks()) );
                      // Save next digi address
                      LOG(DEBUG4)
                        << " Next fStor Digi " << iSmType << ", SR "
                        << iSm * iNbRpc + iRpc << ", Ch" << iCh << ", Dig0 "
                        << (fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh][0])
                        << ", Dig1 "
                        << (fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh][1]);

                      vDigiIndRef.push_back((Int_t)(
                        fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh][0]));
                      vDigiIndRef.push_back((Int_t)(
                        fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh][1]));
                      LOG(debug3)
                        << " Erase fStor entries(b) " << iSmType << ", SR "
                        << iSm * iNbRpc + iRpc << ", Ch" << iCh;
                      fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                        fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh]
                          .begin());
                      fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                        fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh]
                          .begin());
                      fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                        fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh]
                          .begin());
                      fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                        fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh]
                          .begin());

                      if (kTRUE == fDigiBdfPar->ClustUseTrackId()) {
                        //                                       if( ((CbmTofPoint*)(xDigiA->GetLinks()))->GetTrackID() !=
                        //                       ((CbmTofPoint*)(xDigiB->GetLinks()))->GetTrackID() )
                        // if other side come from a different Track,
                        // also save the pointer on CbmTofPoint
                        //  vPtsRef.push_back( (CbmTofPoint*)(xDigiB->GetLinks()) );
                      }  // if( kTRUE == fDigiBdfPar->ClustUseTrackId() )
                         //else if( xDigiA->GetLinks() != xDigiB->GetLinks() )
                         // if other side come from a different TofPoint,
                         // also save the pointer on CbmTofPoint
                      //    vPtsRef.push_back( (CbmTofPoint*)(xDigiB->GetLinks()) );
                    }  // else of if current Digis compatible with last fired chan
                  }    // if( 0 < iNbChanInHit)
                  else {
                    LOG(debug1)
                      << "CbmTofSimpClusterizer::BuildClusters: 1.Hit on "
                         "channel "
                      << iCh << ", time: " << dTime << ", x: " << dPosX
                      << ", y: " << dPosY << ", Tot: " << dTotS;

                    // first fired strip in this RPC
                    dWeightedTime    = dTime * dTotS;
                    dWeightedPosX    = dPosX * dTotS;
                    dWeightedPosY    = dPosY * dTotS;
                    dWeightedPosZ    = dPosZ * dTotS;
                    dWeightedTimeErr = dTotS * dTotS;
                    dWeightsSum      = dTotS;
                    iNbChanInHit     = 1;
                    // Save pointer on CbmTofPoint
                    //if(NULL != fTofPointsColl)
                    //                                    vPtsRef.push_back( (CbmTofPoint*)(xDigiA->GetLinks()) );
                    vDigiIndRef.push_back((Int_t)(
                      fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh][0]));
                    vDigiIndRef.push_back((Int_t)(
                      fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh][1]));

                    LOG(debug2)
                      << " Erase fStor entries(c) " << iSmType << ", SR "
                      << iSm * iNbRpc + iRpc << ", Ch" << iCh;
                    fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                      fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh].begin());
                    fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                      fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh].begin());
                    fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                      fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].begin());
                    fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                      fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].begin());

                    if (kTRUE == fDigiBdfPar->ClustUseTrackId()) {
                      //                                      if( ((CbmTofPoint*)(xDigiA->GetLinks()))->GetTrackID() !=
                      //     ((CbmTofPoint*)(xDigiB->GetLinks()))->GetTrackID() )
                      // if other side come from a different Track,
                      // also save the pointer on CbmTofPoint
                      //                                          vPtsRef.push_back( (CbmTofPoint*)(xDigiB->GetLinks()) );
                    }  // if( kTRUE == fDigiBdfPar->ClustUseTrackId() )
                       //  else if( xDigiA->GetLinks() != xDigiB->GetLinks() )
                       // if other side come from a different TofPoint,
                       // also save the pointer on CbmTofPoint
                    //    vPtsRef.push_back( (CbmTofPoint*)(xDigiB->GetLinks()) );
                  }  // else of if( 0 < iNbChanInHit)
                  iLastChan = iCh;
                  //                              dLastPosX = dPosX; // -> Comment to remove warning because set but never used
                  dLastPosY = dPosY;
                  dLastTime = dTime;
                }  // if( 2 == fStorDigiExp[iSmType][iSm*iNbRpc+iRpc][iCh].size() )
                fStorDigiExp[iSmType][iSm * iNbRpc + iRpc][iCh].clear();
                fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].clear();
              }  // for( Int_t iCh = 0; iCh < iNbCh; iCh++ )
              LOG(debug2)
                << "CbmTofSimpClusterizer::BuildClusters: finished V-RPC"
                << Form(" %3d %3d %3d %d",
                        iSmType,
                        iSm,
                        iRpc,
                        fTofHitsColl->GetEntries());
            }  // else of if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
          }    // if( 0 == iChType)
          else {
            LOG(error)
              << "CbmTofSimpClusterizer::BuildClusters => Cluster building "
              << "from digis to hits not implemented for pads, Sm type "
              << iSmType << " Rpc " << iRpc;
            return kFALSE;
          }  // else of if( 0 == iChType)

          // Now check if another hit/cluster is started
          // and save it if it's the case
          if (0 < iNbChanInHit) {
            LOG(debug1)
              << "CbmTofSimpClusterizer::BuildClusters: Process cluster "
              << iNbChanInHit;

            // Check orientation to properly assign errors
            if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc)) {
              LOG(debug1) << "CbmTofSimpClusterizer::BuildClusters: H-Hit ";
            }  // if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
            else {
              LOG(debug2) << "CbmTofSimpClusterizer::BuildClusters: V-Hit ";
              // Save Hit
              dWeightedTime /= dWeightsSum;
              dWeightedPosX /= dWeightsSum;
              dWeightedPosY /= dWeightsSum;
              dWeightedPosZ /= dWeightsSum;
              // simple error scaling with TOT
              //                     dWeightedTimeErr = TMath::Sqrt( dWeightedTimeErr ) * fdParSystTimeRes / dWeightsSum;
              // OR harcoded value
              dWeightedTimeErr = fdParSystTimeRes;

              Double_t hitpos_local[3];
              Double_t hitpos[3];

              TGeoNode* tNode =  // prepare local->global trafo
                gGeoManager->FindNode(
                  fTrafoCell->GetX(), fTrafoCell->GetY(), fTrafoCell->GetZ());
              //TGeoNode *cNode =
              gGeoManager->GetCurrentNode();

              TGeoRotation rotMatrix(*gGeoManager->GetCurrentMatrix());

              hitpos[0] = fTrafoCell->GetX();
              hitpos[1] = fTrafoCell->GetY();
              hitpos[2] = fTrafoCell->GetZ();
              gGeoManager->MasterToLocal(hitpos, hitpos_local);
              LOG(debug1) << Form(
                " Node0 at (%6.1f,%6.1f,%6.1f) :  (%6.1f,%6.1f,%6.1f)",
                fChannelInfo->GetX(),
                fChannelInfo->GetY(),
                fChannelInfo->GetZ(),
                hitpos_local[0],
                hitpos_local[1],
                hitpos_local[2]);

              hitpos_local[0] += dWeightedPosX;
              hitpos_local[1] += dWeightedPosY;
              hitpos_local[2] += dWeightedPosZ;

              gGeoManager->LocalToMaster(hitpos_local, hitpos);
              LOG(debug1) << Form(
                " LTM for V-node %p, info %p, tra %p: (%6.1f,%6.1f,%6.1f) "
                "->(%6.1f,%6.1f,%6.1f) [(%6.1f,%6.1f,%6.1f)]",
                tNode,
                fChannelInfo,
                fTrafoCell,
                hitpos_local[0],
                hitpos_local[1],
                hitpos_local[2],
                hitpos[0],
                hitpos[1],
                hitpos[2],
                fTrafoCell->GetX(),
                fTrafoCell->GetY(),
                fTrafoCell->GetZ());

              TVector3 hitPos(hitpos[0], hitpos[1], hitpos[2]);
              // TestBeam errors, not properly done at all for now
              // Right way of doing it should take into account the weight distribution
              // and real system time resolution
              Double_t hiterr_local[3];
              Double_t hiterr[3];

              hiterr_local[0] =
                fTrafoCell->GetSizex()
                / TMath::Sqrt(12.0);  // Single strips approximation
              hiterr_local[1] =
                fdParFeeTimeRes
                * fvCPSigPropSpeed[iSmType]
                                  [iRpc];  // Use the electronics resolution
              hiterr_local[2] =
                fDigiBdfPar->GetNbGaps(iSmType, iRpc)
                * fDigiBdfPar->GetGapSize(iSmType, iRpc)
                / 10.0  // Change gap size in cm
                / TMath::Sqrt(
                  12.0);  // Use full RPC thickness as "Channel" Z size

              rotMatrix.LocalToMaster(hiterr_local, hiterr);
              //                     TVector3 hitPosErr( hiterr_local[0], hiterr_local[1], hiterr_local[2] );
              TVector3 hitPosErr(hiterr[0], hiterr[1], hiterr[2]);
              /*
                     LOG(info)<< " Size X " << fTrafoCell->GetSizex()
                              ;
                     LOG(info)<< " Nb gaps " << fDigiBdfPar->GetNbGaps( iSmType, iRpc)
                              << " gap size " << fDigiBdfPar->GetGapSize( iSmType, iRpc)
                              ;
                     LOG(info)<<"CbmTofSimpClusterizer::BuildClusters: Errors in local  "
                              << hiterr_local[0] << " "<< hiterr_local[1] << " " << hiterr_local[2]
                              ;
                     LOG(info)<<"CbmTofSimpClusterizer::BuildClusters: Errors in master "
                              << hiterr[0] << " "<< hiterr[1] << " " << hiterr[2]
                              ;
*/
              //                     cout<<"a "<<vPtsRef.size()<<endl;
              //                     cout<<"b "<<vPtsRef[0]<<endl;
              //                     cout<<"c "<<vPtsRef[0]->GetDetectorID()<<endl;
              //                     Int_t iDetId = vPtsRef[0]->GetDetectorID();// detID = pt->GetDetectorID() <= from TofPoint
              //                     Int_t iDetId = iChId;

              Int_t iChm =
                iTrafoCell + floor(dWeightedPosX / fChannelInfo->GetSizex());
              if (iChm < 0 || iChm > iNbCh) {
                LOG(debug) << "CbmTofSimpClusterizer::BuildClusters: Invalid "
                              "mean channel "
                           << iChm << "(" << iNbCh << ")";
              }
              Int_t iDetId =
                CbmTofAddress::GetUniqueAddress(iSm, iRpc, iChm, 0, iSmType);
              Int_t iRefId = 0;  // Index of the correspondng TofPoint
              //                     if(NULL != fTofPointsColl) iRefId = fTofPointsColl->IndexOf( vPtsRef[0] );
              LOG(debug)
                << "CbmTofSimpClusterizer::BuildClusters: Save V-Hit  "
                //                     << Form(" %3d %3d 0x%08x %3d %3d %3d 0x%08x",
                << Form(" %3d %3d %3d %3d %3d ",
                        fiNbHits,
                        iNbChanInHit,
                        iDetId,
                        iLastChan,
                        iRefId)  //vPtsRef.size(),vPtsRef[0])
                                 //   dWeightedTime,dWeightedPosY)
                << ", DigiSize: " << vDigiIndRef.size();
              LOG(debug) << ", DigiInds: ";
              for (UInt_t i = 0; i < vDigiIndRef.size(); i++) {
                LOG(debug) << " " << vDigiIndRef.at(i);
              }
              LOG(debug);

              fviClusterMul[iSmType][iSm][iRpc]++;

              new ((*fTofHitsColl)[fiNbHits])
                CbmTofHit(iDetId,
                          hitPos,
                          hitPosErr,
                          fiNbHits,  //iRefId
                          dWeightedTime * fOutTimeFactor,
                          dWeightedTimeErr,
                          vPtsRef.size(),
                          0);
              //                                         vDigiIndRef);
              CbmMatch* digiMatch = new CbmMatch();
              for (UInt_t i = 0; i < vDigiIndRef.size(); i++) {
                digiMatch->AddLink(
                  CbmLink(0., vDigiIndRef.at(i), iEventNr, iInputNr));
              }
              new ((*fTofDigiMatchColl)[fiNbHits]) CbmMatch(*digiMatch);
              delete digiMatch;

              // Using the SetLinks/GetLinks of the TofHit class seems to conflict
              // with something in littrack QA
              //                     ((CbmTofHit*)fTofHitsColl->At(fiNbHits))->SetLinks(vPtsRef[0]);
              fiNbHits++;
              // For Histogramming
              fviClusterSize[iSmType][iRpc].push_back(iNbChanInHit);
              fviTrkMul[iSmType][iRpc].push_back(vPtsRef.size());
              fvdX[iSmType][iRpc].push_back(dWeightedPosX);
              fvdY[iSmType][iRpc].push_back(dWeightedPosY);
              /*
                     fvdDifX[iSmType][iRpc].push_back( vPtsRef[0]->GetX() - dWeightedPosX);
                     fvdDifY[iSmType][iRpc].push_back( vPtsRef[0]->GetY() - dWeightedPosY);
                     fvdDifCh[iSmType][iRpc].push_back( fGeoHandler->GetCell( vPtsRef[0]->GetDetectorID() ) -1 -iLastChan );
                     */
              vPtsRef.clear();
              vDigiIndRef.clear();
            }  // else of if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
          }    // if( 0 < iNbChanInHit)
          LOG(DEBUG4) << " Fini-A "
                      << Form(" %3d %3d %3d ", iSmType, iSm, iRpc);
        }  // for each sm/rpc pair
      LOG(debug3) << " Fini-B " << Form(" %3d ", iSmType);
    }  // for( Int_t iSmType = 0; iSmType < iNbSmTypes; iSmType++ )
  }    // if( kTRUE == fDigiBdfPar->UseExpandedDigi() )
  else {
    LOG(error) << " Compressed Digis not implemented ... ";
  }
  return kTRUE;
}

void CbmTofSimpClusterizer::GetEventInfo(Int_t& inputNr,
                                         Int_t& eventNr,
                                         Double_t& eventTime) {

  // --- In a FairRunAna, take the information from FairEventHeader
  if (FairRunAna::Instance()) {
    FairEventHeader* event = FairRunAna::Instance()->GetEventHeader();
    inputNr                = event->GetInputFileId();
    eventNr                = event->GetMCEntryNumber();
    eventTime              = event->GetEventTime();
  }

  // --- In a FairRunSim, the input number and event time are always zero;
  // --- only the event number is retrieved.
  else {
    if (!FairRunSim::Instance())
      LOG(fatal) << GetName() << ": neither SIM nor ANA run.";
    FairMCEventHeader* event = FairRunSim::Instance()->GetMCEventHeader();
    inputNr                  = 0;
    eventNr                  = event->GetEventID();
    eventTime                = 0.;
  }
}