Skip to content
Snippets Groups Projects
CbmDeviceHitBuilderTof.cxx 186.29 KiB
/* Copyright (C) 2018-2021 PI-UHd, GSI
   SPDX-License-Identifier: GPL-3.0-only
   Authors: Norbert Herrmann [committer] */

/**
 * CbmDeviceHitBuilderTof.cxx
 *
 * @since 2018-05-31
 * @author N. Herrmann
 */

#include "CbmDeviceHitBuilderTof.h"

// CBM Classes and includes
#include "CbmDigiManager.h"

// TOF Classes and includes
#include "CbmMatch.h"
#include "CbmTofAddress.h"  // in cbmdata/tof
#include "CbmTofCell.h"     // in tof/TofData
#include "CbmTofClusterizersDef.h"
#include "CbmTofCreateDigiPar.h"    // in tof/TofTools
#include "CbmTofDetectorId_v12b.h"  // in cbmdata/tof
#include "CbmTofDetectorId_v14a.h"  // in cbmdata/tof
#include "CbmTofDetectorId_v21a.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

#include "FairEventHeader.h"
#include "FairFileHeader.h"
#include "FairGeoParSet.h"
#include "FairMQLogger.h"
#include "FairMQProgOptions.h"  // device->fConfig
#include "FairRootFileSink.h"
#include "FairRootManager.h"
#include "FairRunOnline.h"
#include "FairRuntimeDb.h"
#include "FairSource.h"

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

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/vector.hpp>

#include <chrono>
#include <iomanip>
#include <stdexcept>
#include <string>
#include <thread>  // this_thread::sleep_for
struct InitTaskError : std::runtime_error {
  using std::runtime_error::runtime_error;
};

using namespace std;

// Constants definitions
static Int_t iMess                = 0;
static Int_t iIndexDut            = 0;
static Double_t StartAnalysisTime = 0.;
//const Double_t cLight             = 29.9792;  // in cm/ns
static FairRootManager* rootMgr = NULL;
static Int_t iRunId             = 1;
static Int_t SelMask            = DetMask;
static Double_t dTstart         = 0.;
static Double_t dTmax           = 0.;

CbmTofDigi* pRef;
CbmTofDigi* pRefCal;
CbmDigiManager* fDigiMan;

CbmDeviceHitBuilderTof::CbmDeviceHitBuilderTof()
  : fNumMessages(0)
  , fGeoMan(NULL)
  , fGeoHandler(new CbmTofGeoHandler())
  , fTofId(NULL)
  , fDigiPar(NULL)
  , fChannelInfo(NULL)
  , fDigiBdfPar(NULL)
  , fiNDigiIn(0)
  , fvDigiIn()
  , fEventHeader()
  , fEvtHeader(NULL)
  , fTofHitsColl(NULL)
  , fTofDigiMatchColl(NULL)
  , fTofHitsCollOut(NULL)
  , fTofDigiMatchCollOut(NULL)
  , fiNbHits(0)
  , fiNevtBuild(0)
  , fiMsgCnt(100)
  , fdTOTMax(50.)
  , fdTOTMin(0.)
  , fdTTotMean(2.)
  , fdMaxTimeDist(0.)
  , fdMaxSpaceDist(0.)
  , fdEvent(0)
  , fiMaxEvent(-1)
  , fiRunId(111)
  , fiOutputTreeEntry(0)
  , fiFileIndex(0)
  , fStorDigi()
  , fStorDigiInd()
  , vDigiIndRef()
  , fviClusterMul()
  , fviClusterSize()
  , fviTrkMul()
  , fvdX()
  , fvdY()
  , fvdDifX()
  , fvdDifY()
  , fvdDifCh()
  , fvCPDelTof()
  , fvCPTOff()
  , fvCPTotGain()
  , fvCPTotOff()
  , fvCPWalk()
  , fvLastHits()
  , fvDeadStrips()
  , fvPulserOffset()
  , fvPulserTimes()
  , fhEvDetMul(NULL)
  , fhEvDigiMul(NULL)
  , fhEvRateIn(NULL)
  , fhEvRateOut(NULL)
  , fhPulMul(NULL)
  , fhDigiTdif(NULL)
  , fhPulserTimesRaw()
  , fhPulserTimeRawEvo()
  , fhPulserTimesCor()
  , fhDigiTimesRaw()
  , fhDigiTimesCor()
  , fhRpcDigiTot()
  , fhRpcDigiCor()
  , fhRpcCluMul()
  , fhRpcCluRate()
  , fhRpcCluPosition()
  , fhRpcCluDelPos()
  , fhRpcCluDelMatPos()
  , fhRpcCluTOff()
  , fhRpcCluDelTOff()
  , fhRpcCluDelMatTOff()
  , fhRpcCluTrms()
  , fhRpcCluTot()
  , fhRpcCluSize()
  , fhRpcCluAvWalk()
  , fhRpcCluAvLnWalk()
  , fhRpcCluWalk()
  , fhSmCluPosition()
  , fhSmCluTOff()
  , fhSmCluSvel()
  , fhSmCluFpar()
  , fhRpcDTLastHits()
  , fhRpcDTLastHits_Tot()
  , fhRpcDTLastHits_CluSize()
  , fhTRpcCluMul()
  , fhTRpcCluPosition()
  , fhTRpcCluTOff()
  , fhTRpcCluTot()
  , fhTRpcCluSize()
  , fhTRpcCluAvWalk()
  , fhTRpcCluDelTof()
  , fhTRpcCludXdY()
  , fhTRpcCluWalk()
  , fhTSmCluPosition()
  , fhTSmCluTOff()
  , fhTSmCluTRun()
  , fhTRpcCluTOffDTLastHits()
  , fhTRpcCluTotDTLastHits()
  , fhTRpcCluSizeDTLastHits()
  , fhTRpcCluMemMulDTLastHits()
  , fhSeldT()
  , dTRef(0.)
  , fCalMode(0)
  , fdCaldXdYMax(0.)
  , fiCluMulMax(0)
  , fTRefMode(0)
  , fTRefHits(0)
  , fDutId(0)
  , fDutSm(0)
  , fDutRpc(0)
  , fDutAddr(0)
  , fSelId(0)
  , fSelSm(0)
  , fSelRpc(0)
  , fSelAddr(0)
  , fSel2Id(0)
  , fSel2Sm(0)
  , fSel2Rpc(0)
  , fSel2Addr(0)
  , fiMode(0)
  , fiPulserMode(0)
  , fiPulMulMin(0)
  , fiPulDetRef(0)
  , fiPulTotMin(0)
  , fiPulTotMax(1000)
  , fDetIdIndexMap()
  , fviDetId()
  , fPosYMaxScal(0.)
  , fTRefDifMax(0.)
  , fTotMax(0.)
  , fTotMin(0.)
  , fTotMean(0.)
  , fdDelTofMax(60.)
  , fMaxTimeDist(0.)
  , fdChannelDeadtime(0.)
  , fdMemoryTime(0.)
  , fEnableMatchPosScaling(kTRUE)
  , fbPs2Ns(kFALSE)
  , fCalParFileName("")
  , fOutHstFileName("")
  , fOutRootFileName("")
  , fCalParFile(NULL)
  , fOutRootFile(NULL)
{
}

CbmDeviceHitBuilderTof::~CbmDeviceHitBuilderTof()
{
  if (NULL != fOutRootFile) {
    LOG(info) << "Finally close root file " << fOutRootFile->GetName();
    fOutRootFile->cd();
    rootMgr->LastFill();
    rootMgr->Write();
    WriteHistograms();
    fOutRootFile->Write();
    fOutRootFile->Close();
  }
}

void CbmDeviceHitBuilderTof::InitTask()
try {
  // Get the information about created channels from the device
  // Check if the defined channels from the topology (by name)
  // are in the list of channels which are possible/allowed
  // for the device
  // The idea is to check at initilization if the devices are
  // properly connected. For the time beeing this is done with a
  // nameing convention. It is not avoided that someone sends other
  // data on this channel.
  int noChannel = fChannels.size();
  LOG(info) << "Number of defined input channels: " << noChannel;
  for (auto const& entry : fChannels) {
    LOG(info) << "Channel name: " << entry.first;
    if (!IsChannelNameAllowed(entry.first)) throw InitTaskError("Channel name does not match.");
    if (entry.first != "syscmd") OnData(entry.first, &CbmDeviceHitBuilderTof::HandleData);
    else
      OnData(entry.first, &CbmDeviceHitBuilderTof::HandleMessage);
  }
  InitWorkspace();
  InitContainers();
  LoadGeometry();
  InitRootOutput();
}
catch (InitTaskError& e) {
  LOG(error) << e.what();
  ChangeState(fair::mq::Transition::ErrorFound);
}

bool CbmDeviceHitBuilderTof::IsChannelNameAllowed(std::string channelName)
{
  for (auto const& entry : fAllowedChannels) {
    std::size_t pos1 = channelName.find(entry);
    if (pos1 != std::string::npos) {
      const vector<std::string>::const_iterator pos =
        std::find(fAllowedChannels.begin(), fAllowedChannels.end(), entry);
      const vector<std::string>::size_type idx = pos - fAllowedChannels.begin();
      LOG(info) << "Found " << entry << " in " << channelName;
      LOG(info) << "Channel name " << channelName << " found in list of allowed channel names at position " << idx;
      return true;
    }
  }
  LOG(info) << "Channel name " << channelName << " not found in list of allowed channel names.";
  LOG(error) << "Stop device.";
  return false;
}

Bool_t CbmDeviceHitBuilderTof::InitWorkspace()
{
  LOG(info) << "Init work space for CbmDeviceHitBuilderTof.";
  fOutRootFileName = fConfig->GetValue<string>("OutRootFile");
  fiMaxEvent       = fConfig->GetValue<int64_t>("MaxEvent");
  LOG(info) << "Max number of events to be processed: " << fiMaxEvent;
  fiRunId      = fConfig->GetValue<int64_t>("RunId");
  fiMode       = fConfig->GetValue<int64_t>("Mode");
  fiPulserMode = fConfig->GetValue<int64_t>("PulserMode");
  fiPulMulMin  = fConfig->GetValue<uint64_t>("PulMulMin");
  fiPulDetRef  = fConfig->GetValue<uint64_t>("PulDetRef");
  fiPulTotMin  = fConfig->GetValue<uint64_t>("PulTotMin");
  fiPulTotMax  = fConfig->GetValue<uint64_t>("PulTotMax");
  dTmax        = (Double_t) fConfig->GetValue<uint64_t>("ReqTint");

  //fTofCalDigisColl     = new TClonesArray("CbmTofDigi", 100);
  //fTofCalDigisCollOut  = new TClonesArray("CbmTofDigi", 100);
  fTofCalDigiVec = new std::vector<CbmTofDigi>();

  fTofHitsColl         = new TClonesArray("CbmTofHit", 100);
  fTofHitsCollOut      = new TClonesArray("CbmTofHit", 100);
  fTofDigiMatchColl    = new TClonesArray("CbmMatch", 100);
  fTofDigiMatchCollOut = new TClonesArray("CbmMatch", 100);

  /*
  fDigiMan = CbmDigiManager::Instance();
  fDigiMan->Init();
  if (!fDigiMan->IsPresent(ECbmModuleId::kTof)) {
    LOG(error) << "HitBuilder: No digi input!";
    //return kFALSE;
  }
  */
  if (fOutRootFileName != "") {  // prepare root output

    FairRunOnline* fRun = new FairRunOnline(0);
    rootMgr             = FairRootManager::Instance();
    //fOutRootFile = rootMgr->OpenOutFile(fOutRootFileName);
    if (rootMgr->InitSink()) {
      fRun->SetSink(new FairRootFileSink(fOutRootFileName));
      fOutRootFile = rootMgr->GetOutFile();
      if (NULL == fOutRootFile) LOG(fatal) << "could not open root file";
    }
    else
      LOG(fatal) << "could not init Sink";
  }

  // steering variables
  fDutId  = fConfig->GetValue<uint64_t>("DutType");
  fDutSm  = fConfig->GetValue<uint64_t>("DutSm");
  fDutRpc = fConfig->GetValue<uint64_t>("DutRpc");

  fSelId  = fConfig->GetValue<uint64_t>("SelType");
  fSelSm  = fConfig->GetValue<uint64_t>("SelSm");
  fSelRpc = fConfig->GetValue<uint64_t>("SelRpc");

  fSel2Id  = fConfig->GetValue<uint64_t>("Sel2Type");
  fSel2Sm  = fConfig->GetValue<uint64_t>("Sel2Sm");
  fSel2Rpc = fConfig->GetValue<uint64_t>("Sel2Rpc");

  fiBeamRefType = fConfig->GetValue<uint64_t>("BRefType");
  fiBeamRefSm   = fConfig->GetValue<uint64_t>("BRefSm");
  fiBeamRefDet  = fConfig->GetValue<uint64_t>("BRefDet");

  return kTRUE;
}

Bool_t CbmDeviceHitBuilderTof::InitRootOutput()
{
  if (NULL != fOutRootFile) {
    LOG(info) << "Init Root Output to " << fOutRootFile->GetName();

    /*
    fFileHeader->SetRunId(iRunId);
    rootMgr->WriteFileHeader(fFileHeader);
    */
    rootMgr->InitSink();
    fEvtHeader = new FairEventHeader();
    fEvtHeader->SetRunId(iRunId);
    rootMgr->Register("EventHeader.", "Event", fEvtHeader, kTRUE);
    auto source = rootMgr->GetSource();
    if (source) { source->FillEventHeader(fEvtHeader); }

    // rootMgr->Register("CbmTofDigi", "Tof raw Digi", fTofCalDigisColl, kTRUE);
    //    fOutRootFile->cd();
    // rootMgr->RegisterAny("TofCalDigi", fTofCalDigiVec, kTRUE);
    rootMgr->RegisterAny("TofDigi", fTofCalDigiVec, kTRUE);

    TTree* outTree = new TTree(FairRootManager::GetTreeName(), "/cbmout", 99);
    LOG(info) << "define Tree " << outTree->GetName();
    //rootMgr->TruncateBranchNames(outTree, "cbmout");
    //rootMgr->SetOutTree(outTree);
    rootMgr->GetSink()->SetOutTree(outTree);
    rootMgr->WriteFolder();
    LOG(info) << "Initialized outTree with rootMgr at " << rootMgr;
    /*
    /// Save old global file and folder pointer to avoid messing with FairRoot
    TFile* oldFile     = gFile;
    TDirectory* oldDir = gDirectory;
    fOutRootFile = new TFile(fOutRootFileName,"recreate");
    fRootEvent   = new TTree("CbmEvent","Cbm Event");
    fRootEvent->Branch("CbmDigi",fTofCalDigisColl);
    LOG(info)<<"Open Root Output file " << fOutRootFileName;
    fRootEvent->Write();
    /// Restore old global file and folder pointer to avoid messing with FairRoot
    gFile      = oldFile;
    gDirectory = oldDir;
    */
  }
  return kTRUE;
}


Bool_t CbmDeviceHitBuilderTof::InitContainers()
{
  LOG(info) << "Init parameter containers for CbmDeviceHitBuilderTof.";

  FairRuntimeDb* fRtdb = FairRuntimeDb::instance();
  if (NULL == fRtdb) LOG(error) << "No FairRuntimeDb found";

  // NewSimpleMessage creates a copy of the data and takes care of its destruction (after the transfer takes place).
  // Should only be used for small data because of the cost of an additional copy

  // Int_t fiRunId=1535700811;  // from *geo*.par.root file
  Int_t NSet = 3;
  std::string parSet[NSet];
  parSet[0]           = "CbmTofDigiPar";
  parSet[1]           = "CbmTofDigiBdfPar";
  parSet[2]           = "FairGeoParSet";
  std::string Channel = "parameters";

  Bool_t isSimulation = kFALSE;
  Int_t iGeoVersion;
  FairParSet* cont;

  for (Int_t iSet = 1; iSet < NSet; iSet++) {
    std::string message = parSet[iSet] + "," + to_string(fiRunId);
    LOG(info) << "Requesting parameter container, sending message: " << message;

    FairMQMessagePtr req(NewSimpleMessage(message));
    //FairMQMessagePtr req(NewSimpleMessage( "CbmTofDigiBdfPar,111" )); //original format
    FairMQMessagePtr rep(NewMessage());
    CbmTofCreateDigiPar* tofDigiPar = NULL;

    if (Send(req, Channel) > 0) {
      if (Receive(rep, Channel) >= 0) {
        if (rep->GetSize() != 0) {
          CbmMqTMessage tmsg(rep->GetData(), rep->GetSize());
          switch (iSet) {
            case 0:
              fDigiPar = static_cast<CbmTofDigiPar*>(tmsg.ReadObject(tmsg.GetClass()));
              //fDigiPar->print();
              break;
            case 1:
              fDigiBdfPar = static_cast<CbmTofDigiBdfPar*>(tmsg.ReadObject(tmsg.GetClass()));
              //fDigiBdfPar->print();
              LOG(info) << "Calib data file: " << fDigiBdfPar->GetCalibFileName();
              fdMaxTimeDist  = fDigiBdfPar->GetMaxTimeDist();     // in ns
              fdMaxSpaceDist = fDigiBdfPar->GetMaxDistAlongCh();  // in cm

              if (fMaxTimeDist != fdMaxTimeDist) {
                fdMaxTimeDist  = fMaxTimeDist;  // modify default
                fdMaxSpaceDist = fdMaxTimeDist * fDigiBdfPar->GetSignalSpeed()
                                 * 0.5;  // cut consistently on positions (with default signal velocity)
              }

              break;
            case 2:  // Geometry container
              cont = static_cast<FairParSet*>(tmsg.ReadObject(tmsg.GetClass()));
              cont->init();
              cont->Print();
              //fRtdb->InitContainer(parSet[iSet]);
              if (NULL == fGeoMan) fGeoMan = (TGeoManager*) ((FairGeoParSet*) cont)->GetGeometry();  //crashes
              LOG(info) << "GeoMan: " << fGeoMan << " " << gGeoManager;
              iGeoVersion = fGeoHandler->Init(isSimulation);
              if (k21a > iGeoVersion) {
                LOG(error) << "Incompatible geometry !!!";
                ChangeState(fair::mq::Transition::Stop);
              }
              switch (iGeoVersion) {
                case k14a: fTofId = new CbmTofDetectorId_v14a(); break;
                case k21a: fTofId = new CbmTofDetectorId_v21a(); break;
              }
              if (NULL == fDigiPar) {
                if (NULL == fRtdb) {
                  LOG(info) << "Instantiate FairRunDb";
                  fRtdb = FairRuntimeDb::instance();
                  assert(fRtdb);
                }
                // create digitization parameters from geometry file
                tofDigiPar = new CbmTofCreateDigiPar("TOF Digi Producer", "TOF task");
                LOG(info) << "Create DigiPar ";
                tofDigiPar->Init();
                fDigiPar = (CbmTofDigiPar*) (fRtdb->getContainer("CbmTofDigiPar"));
                if (NULL == fDigiPar) {
                  LOG(error) << "CbmTofEventClusterizer::InitParameters => Could not obtain CbmTofDigiPar";
                  return kFALSE;
                }
              }
              gGeoManager->Export("HitBuilder.geo.root");
              break;

            case 3:  // Calib
              break;
            default: LOG(warn) << "Parameter Set " << iSet << " not implemented ";
          }
          LOG(info) << "Received parameter from server:";
        }
        else {
          LOG(warn) << "Received empty reply. Parameter not available";
        }
      }
    }
  }
  Bool_t initOK = ReInitContainers();

  CreateHistograms();

  if (!InitCalibParameter()) return kFALSE;  // ChangeState(PAUSE); // for debugging

  fDutAddr  = CbmTofAddress::GetUniqueAddress(fDutSm, fDutRpc, 0, 0, fDutId);
  fSelAddr  = CbmTofAddress::GetUniqueAddress(fSelSm, fSelRpc, 0, 0, fSelId);
  fSel2Addr = CbmTofAddress::GetUniqueAddress(fSel2Sm, fSel2Rpc, 0, 0, fSel2Id);
  if (fiBeamRefType > -1) {
    if (fiBeamRefDet > -1) {
      fiBeamRefAddr = CbmTofAddress::GetUniqueAddress(fiBeamRefSm, fiBeamRefDet, 0, 0, fiBeamRefType);
    }
    else {
      SelMask       = ModMask;
      fiBeamRefAddr = CbmTofAddress::GetUniqueAddress(fiBeamRefSm, 0, 0, 0, fiBeamRefType);
    }
  }
  else
    fiBeamRefAddr = -1;

  iIndexDut = fDigiBdfPar->GetDetInd(fDutAddr);
  LOG(info) << Form("Use Dut 0x%08x, Sel 0x%08x, Sel2 0x%08x, BRef 0x%08x", fDutAddr, fSelAddr, fSel2Addr,
                    fiBeamRefAddr);
  return initOK;
}

Bool_t CbmDeviceHitBuilderTof::ReInitContainers()
{
  LOG(info) << "ReInit parameter containers for CbmDeviceHitBuilderTof.";

  return kTRUE;
}

// handler is called whenever a message arrives on "data", with a reference to the message and a sub-channel index (here 0)
//bool CbmDeviceHitBuilderTof::HandleData(FairMQMessagePtr& msg, int /*index*/)
bool CbmDeviceHitBuilderTof::HandleData(FairMQParts& parts, int /*index*/)
{
  // Don't do anything with the data
  // Maybe add an message counter which counts the incomming messages and add
  // an output
  fNumMessages++;
  LOG(debug) << "Received message " << fNumMessages << " with " << parts.Size() << " parts"
             << ", size0: " << parts.At(0)->GetSize();

  std::string msgStrE(static_cast<char*>(parts.At(0)->GetData()), (parts.At(0))->GetSize());
  std::istringstream issE(msgStrE);
  boost::archive::binary_iarchive inputArchiveE(issE);
  inputArchiveE >> fEventHeader;
  LOG(debug) << "EventHeader: " << fEventHeader[0] << " " << fEventHeader[1] << " " << fEventHeader[2] << " "
             << fEventHeader[3] << " " << fEventHeader[4];

  fiNDigiIn = 0;
  //  LOG(debug) << "Received message # "<<  fNumMessages
  //	     << " with size " << msg->GetSize()<<" at "<< msg->GetData();

  //std::string msgStr(static_cast<char*>(msg->GetData()), msg->GetSize());
  std::string msgStr(static_cast<char*>(parts.At(1)->GetData()), (parts.At(1))->GetSize());
  std::istringstream iss(msgStr);
  boost::archive::binary_iarchive inputArchive(iss);

  std::vector<CbmTofDigi*> vdigi;
  inputArchive >> vdigi;

  /*  ---- for debugging ----------------
  int *pData = static_cast <int *>(msg->GetData());
  for (int iData=0; iData<msg->GetSize()/NBytes; iData++) {
    LOG(info) << Form(" ind %d, poi %p, data: 0x%08x",iData,pData,*pData++);
  }
  */

  //vector descriptor and data separated -> transfer of vectors does not work reliably
  //std::vector<CbmTofDigi>* vdigi = static_cast<std::vector<CbmTofDigi>*>(msg->GetData());
  //  (*vdigi).resize(fiNDigiIn);
  LOG(debug) << "vdigi vector at " << vdigi.data() << " with size " << vdigi.size();

  for (UInt_t iDigi = 0; iDigi < vdigi.size(); iDigi++) {
    LOG(debug) << "#" << iDigi << " " << vdigi[iDigi]->ToString();
  }

  /*
  const Int_t iNDigiIn=100;
  std::array<CbmTofDigi,iNDigiIn> *aTofDigi = static_cast<std::array<CbmTofDigi,iNDigiIn>*>(msg->GetData());
  for (int iDigi=0; iDigi<fiNDigiIn; iDigi++) {
    LOG(info) << "#" << iDigi << " " <<(*aTofDigi)[iDigi].ToString();
  }


  pDigiIn=static_cast<CbmTofDigi*> (msg->GetData());
  CbmTofDigi*  pDigi=pDigiIn;
  CbmTofDigi  aTofDigi[fiNDigiIn];


  for (int iDigi=0; iDigi<fiNDigiIn; iDigi++) {
  //aTofDigi[iDigi] = *pDigi++;
    aTofDigi[iDigi] = *pDigi;
    fvDigiIn[iDigi] = *pDigi;
    LOG(info) << "#" << iDigi << " at "<<pDigi<< " " <<aTofDigi[iDigi].ToString();
    // LOG(info) << "#" << iDigi << " at "<<pDigi<< " " <<pDigi->ToString();   // does not work ???
    pDigi++;
  }
  */

  fiNDigiIn = vdigi.size();
  fvDigiIn.resize(fiNDigiIn);
  for (int iDigi = 0; iDigi < fiNDigiIn; iDigi++) {
    fvDigiIn[iDigi] = *vdigi[iDigi];

    // Remap Digis for v21a_cosmicHD
    if (1) {
      int iSmType       = 8;
      int iSm           = -1;
      int iRpc          = 0;
      int iDetId        = 0;
      CbmTofDigi* pDigi = &fvDigiIn[iDigi];

      if (pDigi->GetType() == 6 && pDigi->GetRpc() == 1) {
        switch ((int) (pDigi->GetChannel() * 2 + pDigi->GetSide())) {
          case 62:  //800
            iSm = 0;
            break;
          case 46:  //810
            iSm = 1;
            break;
          case 22:  //820
            iSm = 2;
            break;
          case 2:  //830
            iSm = 3;
            break;
          default:;
        }
        if (iSm > -1) {
          iDetId = CbmTofAddress::GetUniqueAddress(iSm, iRpc, 0, 0, iSmType);
          pDigi->SetAddress(iDetId);
        }
      }
    }  //remapping end

    delete vdigi[iDigi];
  }
  vdigi.clear();

  //  for( Int_t i = 0; i < fTofCalDigisColl->GetEntriesFast(); i++ ) ((CbmTofDigi*) fTofCalDigisColl->At(i))->Delete();
  // fTofCalDigisColl->Clear("C");

  //  for( Int_t i = 0; i < fTofHitsColl->GetEntriesFast(); i++ ) ((CbmTofHit*) fTofHitsColl->At(i))->Delete();
  fTofHitsColl->Clear("C");
  //fTofHitsColl->Delete(); // Are the elements deleted?
  //fTofHitsColl         = new TClonesArray("CbmTofHit",100);

  //for( Int_t i = 0; i < fTofDigiMatchColl->GetEntriesFast(); i++ ) ((CbmMatch*) fTofDigiMatchColl->At(i))->Delete();
  fTofDigiMatchColl->Clear("C");

  fiNbHits = 0;
  if (fNumMessages % 10000 == 0) LOG(info) << "Processed " << fNumMessages << " messages";
  if (fEventHeader.size() > 3) {
    fhPulMul->Fill((Double_t) fEventHeader[3]);
    if (fEventHeader[3] > 0) {
      //LOG(debug) << "Pulser event found, Mul "<< fEventHeader[3];
      if (!MonitorPulser()) return kFALSE;
      return kTRUE;  // separate events from pulser
    }
  }

  LOG(debug) << " Process msg " << fNumMessages << " at evt " << fdEvent << ", PulMode " << fiPulserMode;

  if (fiPulserMode > 0) {  // don't process events without valid pulser correction
    if (fvPulserTimes[fiPulDetRef][0].size() == 0) return kTRUE;
  }

  fdEvent++;
  fhEvDetMul->Fill((Double_t) fEventHeader[1]);
  fhEvDigiMul->Fill(fiNDigiIn);
  if (fiNDigiIn > 0) {
    if (dTstart == 0) {
      dTstart = fvDigiIn[0].GetTime() + fEventHeader[4];
      LOG(info) << "Start time set to " << dTstart / 1.E9 << " sec ";
    }
    fhEvRateIn->Fill((fvDigiIn[0].GetTime() + fEventHeader[4] - dTstart) / 1.E9);
  }
  if (!InspectRawDigis()) return kFALSE;

  if (fiPulserMode > 0)
    if (!ApplyPulserCorrection()) return kFALSE;

  if (!BuildClusters()) return kFALSE;
  //if(!MergeClusters())       return kFALSE;

  if (NULL != fOutRootFile) {  // CbmEvent output to root file
    fEvtHeader->SetEventTime((double) fEventHeader[4]);
    auto source = rootMgr->GetSource();
    if (source) { source->FillEventHeader(fEvtHeader); }
    //LOG(info) << "Fill WriteOutBuffer with rootMgr at " << rootMgr;
    fOutRootFile->cd();
    rootMgr->Fill();
    rootMgr->StoreWriteoutBufferData(rootMgr->GetEventTime());
    fhEvRateOut->Fill((fvDigiIn[0].GetTime() + fEventHeader[4] - dTstart) / 1.E9);
    //rootMgr->StoreAllWriteoutBufferData();
    rootMgr->DeleteOldWriteoutBufferData();
    if ((Int_t) fdEvent == fiMaxEvent) {
      rootMgr->Write();
      WriteHistograms();
      fOutRootFile->Close();
      LOG(info) << "File closed after " << fdEvent << " events. ";
      ChangeState(fair::mq::Transition::Stop);
    }
  }
  if (!FillHistos()) return kTRUE;  // event not selected for histogramming, skip sending it
  //if(!SendHits())      return kFALSE;
  if (!SendAll()) return kFALSE;

  return kTRUE;
}

/************************************************************************************/

bool CbmDeviceHitBuilderTof::HandleMessage(FairMQMessagePtr& msg, int /*index*/)
{
  const char* cmd    = (char*) (msg->GetData());
  const char cmda[4] = {*cmd};
  LOG(info) << "Handle message " << cmd << ", " << cmd[0];
  //LOG(info) << "Current State: " << fair::mq::StateMachine::GetCurrentStateName();

  // only one implemented so far "Stop"
  if (NULL != fOutRootFile) {
    LOG(info) << "Close root file " << fOutRootFile->GetName();
    fOutRootFile->cd();
    rootMgr->LastFill();
    rootMgr->Write();
    WriteHistograms();
    fOutRootFile->Write();
    fOutRootFile->Close();
  }

  if (strcmp(cmda, "STOP")) {
    LOG(info) << "STOP";
    /*  Invalid syntax
    ChangeState(internal_READY);
    LOG(info) << "Current State: " <<  FairMQStateMachine::GetCurrentStateName();
    ChangeState(internal_DEVICE_READY);
    LOG(info) << "Current State: " <<  FairMQStateMachine::GetCurrentStateName();
    ChangeState(internal_IDLE);
    LOG(info) << "Current State: " <<  FairMQStateMachine::GetCurrentStateName();
    ChangeState(END);
    LOG(info) << "Current State: " <<  FairMQStateMachine::GetCurrentStateName();
    */
    ChangeState(fair::mq::Transition::Stop);
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    ChangeState(fair::mq::Transition::End);
  }

  return true;
}

/************************************************************************************/
Bool_t CbmDeviceHitBuilderTof::InitCalibParameter()
{
  // dimension and initialize calib parameter
  // Int_t iNbDet     = fDigiBdfPar->GetNbDet();
  Int_t iNbSmTypes = fDigiBdfPar->GetNbSmTypes();

  fTotMean = 1.;
  fCalMode = -1;

  if (fTotMean != 0.) fdTTotMean = fTotMean;  // adjust target mean for TTT

  fvCPTOff.resize(iNbSmTypes);
  fvCPTotGain.resize(iNbSmTypes);
  fvCPTotOff.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);
    fvCPTotOff[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(iNSel);
          for (Int_t iSel = 0; iSel < iNSel; iSel++)
            fvCPDelTof[iSmType][iSm * iNbRpc + iRpc][iBx][iSel] = 0.;  // initialize
        }

        Int_t iNbChan = fDigiBdfPar->GetNbChan(iSmType, iRpc);
        fvCPTOff[iSmType][iSm * iNbRpc + iRpc].resize(iNbChan);
        fvCPTotGain[iSmType][iSm * iNbRpc + iRpc].resize(iNbChan);
        fvCPTotOff[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);
          fvCPTotOff[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
            fvCPTotOff[iSmType][iSm * iNbRpc + iRpc][iCh][iSide]  = 0.;  //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) << "defaults set";

  /// Save old global file and folder pointer to avoid messing with FairRoot
  // <= To prevent histos from being sucked in by the param file of the TRootManager!
  TFile* oldFile     = gFile;
  TDirectory* oldDir = gDirectory;

  if (0 < fCalMode) {
    fCalParFileName = fDigiBdfPar->GetCalibFileName();
    LOG(info) << "InitCalibParameter: read histos from "
              << "file " << fCalParFileName;

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

    fCalParFile = new TFile(fCalParFileName, "");
    if (NULL == fCalParFile) {
      LOG(error) << "InitCalibParameter: "
                 << "file " << fCalParFileName << " does not exist!";
      ChangeState(fair::mq::Transition::Stop);
    }
    /*
    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);
      TProfile* hSvel = (TProfile*) gDirectory->FindObjectAny(Form("cl_SmT%01d_Svel", iSmType));

      // copy Histo to memory
      TDirectory* curdir = gDirectory;
      if (NULL != hSvel) {
        gDirectory->cd(oldDir->GetPath());
        //TProfile *hSvelmem =
        //(TProfile*) hSvel->Clone();
        gDirectory->cd(curdir->GetPath());
      }
      else {
        LOG(info) << "Svel histogram not found for module type " << iSmType;
      }

      for (Int_t iPar = 0; iPar < 4; iPar++) {
        TProfile* hFparcur = (TProfile*) gDirectory->FindObjectAny(Form("cl_SmT%01d_Fpar%1d", iSmType, iPar));
        if (NULL != hFparcur) {
          gDirectory->cd(oldDir->GetPath());
          //TProfile *hFparmem =
          //(TProfile*) hFparcur->Clone();
          gDirectory->cd(curdir->GetPath());
        }
      }

      for (Int_t iSm = 0; iSm < iNbSm; iSm++)
        for (Int_t iRpc = 0; iRpc < iNbRpc; iRpc++) {
          // update default parameter
          if (NULL != hSvel) {
            Double_t Vscal = 1.;  //hSvel->GetBinContent(iSm*iNbRpc+iRpc+1);
            if (Vscal == 0.) Vscal = 1.;
            fDigiBdfPar->SetSigVel(iSmType, iSm, iRpc, fDigiBdfPar->GetSigVel(iSmType, iSm, iRpc) * Vscal);
            LOG(info) << "Modify " << iSmType << iSm << iRpc << " Svel by " << Vscal << " to "
                      << fDigiBdfPar->GetSigVel(iSmType, iSm, 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));
          TH1D* htempTot_Mean =
            (TH1D*) gDirectory->FindObjectAny(Form("cl_CorSmT%01d_sm%03d_rpc%03d_Tot_Mean", iSmType, iSm, iRpc));
          TH1D* htempTot_Off =
            (TH1D*) gDirectory->FindObjectAny(Form("cl_CorSmT%01d_sm%03d_rpc%03d_Tot_Off", iSmType, iSm, iRpc));
          if (NULL != htempPos_pfx && NULL != htempTOff_pfx && NULL != htempTot_Mean && NULL != htempTot_Off) {
            Int_t iNbCh    = fDigiBdfPar->GetNbChan(iSmType, iRpc);
            Int_t iNbinTot = htempTot_Mean->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/fDigiBdfPar->GetSignalSpeed() ;
              Double_t dTYOff = YMean / fDigiBdfPar->GetSigVel(iSmType, iSm, iRpc);
              fvCPTOff[iSmType][iSm * iNbRpc + iRpc][iCh][0] += -dTYOff + TMean;
              fvCPTOff[iSmType][iSm * iNbRpc + iRpc][iCh][1] += +dTYOff + TMean;

              for (Int_t iSide = 0; iSide < 2; iSide++) {
                Double_t TotMean = htempTot_Mean->GetBinContent(iCh * 2 + 1 + iSide);  //nh +1 empirical(?)
                if (0.001 < TotMean) { fvCPTotGain[iSmType][iSm * iNbRpc + iRpc][iCh][iSide] *= fdTTotMean / TotMean; }
                fvCPTotOff[iSmType][iSm * iNbRpc + iRpc][iCh][iSide] = htempTot_Off->GetBinContent(iCh * 2 + 1 + iSide);
              }
              if (5 == iSmType || 8 == iSmType) {
                fvCPTOff[iSmType][iSm * iNbRpc + iRpc][iCh][1]    = fvCPTOff[iSmType][iSm * iNbRpc + iRpc][iCh][0];
                fvCPTotGain[iSmType][iSm * iNbRpc + iRpc][iCh][1] = fvCPTotGain[iSmType][iSm * iNbRpc + iRpc][iCh][0];
                fvCPTotOff[iSmType][iSm * iNbRpc + iRpc][iCh][1]  = fvCPTotOff[iSmType][iSm * iNbRpc + iRpc][iCh][0];
              }

              LOG(debug) << "InitCalibParameter:"
                         << " SmT " << iSmType << " Sm " << iSm << " Rpc " << iRpc << " Ch " << iCh
                         << Form(": YMean %f, TMean %f", YMean, TMean) << " -> "
                         << Form(" %f, %f, %f, %f ", fvCPTOff[iSmType][iSm * iNbRpc + iRpc][iCh][0],
                                 fvCPTOff[iSmType][iSm * iNbRpc + iRpc][iCh][1],
                                 fvCPTotGain[iSmType][iSm * iNbRpc + iRpc][iCh][0],
                                 fvCPTotGain[iSmType][iSm * iNbRpc + iRpc][iCh][1])
                         << ", 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(debug) << "Initialize Walk correction for "
                           << Form(" SmT%01d_sm%03d_rpc%03d_Ch%03d", iSmType, iSm, iRpc, iCh);
                if (htempWalk0->GetNbinsX() != nbClWalkBinX)
                  LOG(error) << "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(debug)<<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]);
                  if (5 == iSmType || 8 == iSmType) {  // Pad structure
                    fvCPWalk[iSmType][iSm * iNbRpc + iRpc][iCh][1][iBin] =
                      fvCPWalk[iSmType][iSm * iNbRpc + iRpc][iCh][0][iBin];
                  }
                }
              }
            }
          }
          else {
            LOG(warn) << " Calibration histos " << Form("cl_SmT%01d_sm%03d_rpc%03d_XXX", iSmType, iSm, iRpc)
                      << " not found. ";
          }
          for (Int_t iSel = 0; iSel < iNSel; iSel++) {
            TH1D* htmpDelTof = (TH1D*) gDirectory->FindObjectAny(
              Form("cl_CorSmT%01d_sm%03d_rpc%03d_Sel%02d_DelTof", iSmType, iSm, iRpc, iSel));
            if (NULL == htmpDelTof) {
              LOG(debug) << " Histos " << Form("cl_CorSmT%01d_sm%03d_rpc%03d_Sel%02d_DelTof", iSmType, iSm, iRpc, iSel)
                         << " not found. ";
              continue;
            }
            LOG(debug) << " Load DelTof from histos "
                       << Form("cl_CorSmT%01d_sm%03d_rpc%03d_Sel%02d_DelTof", iSmType, iSm, iRpc, iSel) << ".";
            for (Int_t iBx = 0; iBx < nbClDelTofBinX; iBx++) {
              fvCPDelTof[iSmType][iSm * iNbRpc + iRpc][iBx][iSel] += htmpDelTof->GetBinContent(iBx + 1);
            }

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

            LOG(debug) << " copy histo " << h1DelTof->GetName() << " to directory " << oldDir->GetName();
            gDirectory->cd(curdir->GetPath());
          }
        }
    }
  }
  //   fCalParFile->Delete();
  /// Restore old global file and folder pointer to avoid messing with FairRoot
  // <= To prevent histos from being sucked in by the param file of the TRootManager!
  gFile      = oldFile;
  gDirectory = oldDir;

  LOG(info) << "InitCalibParameter: initialization done";
  return kTRUE;
}

static TH2F* fhBucDigiCor = NULL;
/************************************************************************************/
// Histogram definitions
void CbmDeviceHitBuilderTof::CreateHistograms()
{
  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 !
  // process event header info
  fhEvDetMul  = new TH1F("hEvDetMul", "Detector multiplicity of Selector; Mul", 50, 0, 50);
  fhEvDigiMul = new TH1F("hEvDigiMul", "Digi multiplicity of Selector; Mul", 1000, 0, 10000);
  fhEvRateIn  = new TH1F("hEvRateIn", "Incoming Event rate; time (s); rate (Hz)", 10000, 0, 10000);
  fhEvRateOut = new TH1F("hEvRateOut", "Outgoing Event rate; time (s); rate (Hz)", 10000, 0, 10000);
  fhPulMul    = new TH1F("hPulMul", "Pulser multiplicity; Mul", 110, 0, 110);
  fhDigiTdif  = new TH1F("hDigiTdif", "Digi time difference; #Deltat ns)", 8000, -20, 20);

  Int_t iNDet = 0;
  dTmax *= 2;  // cover full range of selector

  for (Int_t iModTyp = 0; iModTyp < 10; iModTyp++)
    iNDet += fDigiBdfPar->GetNbSm(iModTyp) * fDigiBdfPar->GetNbRpc(iModTyp);

  fhPulserTimesRaw = new TH2F(Form("hPulserTimesRaw"), Form("Pulser Times uncorrected; Det# []; t - t0 [ns]"),
                              iNDet * 2, 0, iNDet * 2, 999, -dTmax, dTmax);

  fhPulserTimeRawEvo.resize(iNDet * 2);
  for (Int_t iDetSide = 0; iDetSide < iNDet * 2; iDetSide++) {
    fhPulserTimeRawEvo[iDetSide] = new TProfile(
      Form("hPulserTimeRawEvo_%d", iDetSide),
      Form("Raw Pulser TimeEvolution  %d; PulserEvent# ; DeltaT [ns] ", iDetSide), 1000, 0., 1.E5, -dTmax, dTmax);
  }

  fhPulserTimesCor = new TH2F(Form("hPulserTimesCor"), Form("Pulser Times corrected; Det# []; t - t0 [ns]"), iNDet * 2,
                              0, iNDet * 2, 999, -10., 10.);

  fhDigiTimesRaw = new TH2F(Form("hDigiTimesRaw"), Form("Digi Times uncorrected; Det# []; t - t0 [ns]"), iNDet * 2, 0,
                            iNDet * 2, 999, -dTmax, dTmax);

  fhDigiTimesCor = new TH2F(Form("hDigiTimesCor"), Form("Digi Times corrected; Det# []; t - t0 [ns]"), iNDet * 2, 0,
                            iNDet * 2, 999, -dTmax, dTmax);

  fhBucDigiCor = new TH2F(Form("hBucDigiCor"), Form("Buc Digi Correlation; ch1 []; ch2 []"), 128, 0, 128, 128, 0, 128);

  Int_t iNbDet = fDigiBdfPar->GetNbDet();
  fDetIdIndexMap.clear();
  fhRpcDigiTot.resize(iNbDet);
  fhRpcDigiCor.resize(iNbDet);
  fviDetId.resize(iNbDet);
  for (Int_t iDetIndx = 0; iDetIndx < iNbDet; iDetIndx++) {
    Int_t iUniqueId           = fDigiBdfPar->GetDetUId(iDetIndx);
    fDetIdIndexMap[iUniqueId] = iDetIndx;
    fviDetId[iDetIndx]        = iUniqueId;
    Int_t iSmType             = CbmTofAddress::GetSmType(iUniqueId);
    Int_t iSmId               = CbmTofAddress::GetSmId(iUniqueId);
    Int_t iRpcId              = CbmTofAddress::GetRpcId(iUniqueId);
    LOG(info) << "Index map entry " << iDetIndx << ": TSR " << iSmType << iSmId << iRpcId
              << Form(", addr 0x%08x", iUniqueId);

    fhRpcDigiTot[iDetIndx] = new TH2F(
      Form("hDigiTot_SmT%01d_sm%03d_rpc%03d", iSmType, iSmId, iRpcId),
      Form("Digi Tot of Rpc #%03d in Sm %03d of type %d; digi 0; digi 1", iRpcId, iSmId, iSmType),
      2 * fDigiBdfPar->GetNbChan(iSmType, iRpcId), 0, 2 * fDigiBdfPar->GetNbChan(iSmType, iRpcId), 256, 0, 256);

    fhRpcDigiCor[iDetIndx] =
      new TH2F(Form("cl_SmT%01d_sm%03d_rpc%03d_DigiCor", iSmType, iSmId, iRpcId),
               Form("Digi Correlation of Rpc #%03d in Sm %03d of type %d; digi 0; digi 1", iRpcId, iSmId, iSmType),
               fDigiBdfPar->GetNbChan(iSmType, iRpcId), 0, fDigiBdfPar->GetNbChan(iSmType, iRpcId),
               fDigiBdfPar->GetNbChan(iSmType, iRpcId), 0, fDigiBdfPar->GetNbChan(iSmType, iRpcId));
  }

  if (0 == fiMode) return;  // no cluster histograms needed

  // Sm related distributions
  fhSmCluPosition.resize(fDigiBdfPar->GetNbSmTypes());
  fhSmCluTOff.resize(fDigiBdfPar->GetNbSmTypes());
  fhSmCluSvel.resize(fDigiBdfPar->GetNbSmTypes());
  fhSmCluFpar.resize(fDigiBdfPar->GetNbSmTypes());
  fhTSmCluPosition.resize(fDigiBdfPar->GetNbSmTypes());
  fhTSmCluTOff.resize(fDigiBdfPar->GetNbSmTypes());
  fhTSmCluTRun.resize(fDigiBdfPar->GetNbSmTypes());

  for (Int_t iS = 0; iS < fDigiBdfPar->GetNbSmTypes(); iS++) {
    Double_t YSCAL = 50.;
    if (fPosYMaxScal != 0.) YSCAL = fPosYMaxScal;

    Int_t iUCellId(0);
    fChannelInfo = NULL;

    // Cover the case that the geometry file does not contain the module
    // indexed with 0 of a certain module type BUT modules with higher indices.
    for (Int_t iSM = 0; iSM < fDigiBdfPar->GetNbSm(iS); iSM++) {
      iUCellId     = CbmTofAddress::GetUniqueAddress(iSM, 0, 0, 0, iS);
      fChannelInfo = fDigiPar->GetCell(iUCellId);

      // Retrieve geometry information from the first module of a certain
      // module type that is found in the geometry file.
      if (NULL != fChannelInfo) { break; }
    }

    if (NULL == fChannelInfo) {
      LOG(warn) << "No DigiPar for SmType " << Form("%d, 0x%08x", iS, iUCellId);
      continue;
    }
    Double_t YDMAX = TMath::Max(2., fChannelInfo->GetSizey()) * YSCAL;

    fhSmCluPosition[iS] =
      new TH2F(Form("cl_SmT%01d_Pos", iS), Form("Clu position of SmType %d; Sm+Rpc# []; ypos [cm]", iS),
               fDigiBdfPar->GetNbSm(iS) * fDigiBdfPar->GetNbRpc(iS), 0,
               fDigiBdfPar->GetNbSm(iS) * fDigiBdfPar->GetNbRpc(iS), 99, -YDMAX, YDMAX);

    Double_t TSumMax = 1.E3;
    if (fTRefDifMax != 0.) TSumMax = fTRefDifMax;
    fhSmCluTOff[iS] =
      new TH2F(Form("cl_SmT%01d_TOff", iS), Form("Clu TimeZero in SmType %d; Sm+Rpc# []; TOff [ns]", iS),
               fDigiBdfPar->GetNbSm(iS) * fDigiBdfPar->GetNbRpc(iS), 0,
               fDigiBdfPar->GetNbSm(iS) * fDigiBdfPar->GetNbRpc(iS), 99, -TSumMax, TSumMax);

    TProfile* hSvelcur = (TProfile*) gDirectory->FindObjectAny(Form("cl_SmT%01d_Svel", iS));
    if (NULL == hSvelcur) {
      fhSmCluSvel[iS] =
        new TProfile(Form("cl_SmT%01d_Svel", iS), Form("Clu Svel in SmType %d; Sm+Rpc# []; v/v_{nominal} ", iS),
                     fDigiBdfPar->GetNbSm(iS) * fDigiBdfPar->GetNbRpc(iS), 0,
                     fDigiBdfPar->GetNbSm(iS) * fDigiBdfPar->GetNbRpc(iS), 0.8, 1.2);
      fhSmCluSvel[iS]->Sumw2();
    }
    else
      fhSmCluSvel[iS] = (TProfile*) hSvelcur->Clone();

    fhSmCluFpar[iS].resize(4);
    for (Int_t iPar = 0; iPar < 4; iPar++) {
      TProfile* hFparcur = (TProfile*) gDirectory->FindObjectAny(Form("cl_SmT%01d_Fpar%1d", iS, iPar));
      if (NULL == hFparcur) {
        LOG(info) << "Histo " << Form("cl_SmT%01d_Fpar%1d", iS, iPar) << " not found, recreate ...";
        fhSmCluFpar[iS][iPar] = new TProfile(Form("cl_SmT%01d_Fpar%1d", iS, iPar),
                                             Form("Clu Fpar %d in SmType %d; Sm+Rpc# []; value ", iPar, iS),
                                             fDigiBdfPar->GetNbSm(iS) * fDigiBdfPar->GetNbRpc(iS), 0,
                                             fDigiBdfPar->GetNbSm(iS) * fDigiBdfPar->GetNbRpc(iS), -dTmax, dTmax);
      }
      else
        fhSmCluFpar[iS][iPar] = (TProfile*) hFparcur->Clone();
    }

    fhTSmCluPosition[iS].resize(iNSel);
    fhTSmCluTOff[iS].resize(iNSel);
    fhTSmCluTRun[iS].resize(iNSel);
    for (Int_t iSel = 0; iSel < iNSel; iSel++) {  // Loop over selectors
      fhTSmCluPosition[iS][iSel] = new TH2F(Form("cl_TSmT%01d_Sel%02d_Pos", iS, iSel),
                                            Form("Clu position of SmType %d under Selector %02d; Sm+Rpc# "
                                                 "[]; ypos [cm]",
                                                 iS, iSel),
                                            fDigiBdfPar->GetNbSm(iS) * fDigiBdfPar->GetNbRpc(iS), 0,
                                            fDigiBdfPar->GetNbSm(iS) * fDigiBdfPar->GetNbRpc(iS), 99, -YDMAX, YDMAX);
      fhTSmCluTOff[iS][iSel]     = new TH2F(Form("cl_TSmT%01d_Sel%02d_TOff", iS, iSel),
                                        Form("Clu TimeZero in SmType %d under Selector %02d; Sm+Rpc# "
                                             "[]; TOff [ns]",
                                             iS, iSel),
                                        fDigiBdfPar->GetNbSm(iS) * fDigiBdfPar->GetNbRpc(iS), 0,
                                        fDigiBdfPar->GetNbSm(iS) * fDigiBdfPar->GetNbRpc(iS), 99, -TSumMax, TSumMax);
      fhTSmCluTRun[iS][iSel]     = new TH2F(Form("cl_TSmT%01d_Sel%02d_TRun", iS, iSel),
                                        Form("Clu TimeZero in SmType %d under Selector %02d; Event# "
                                             "[]; TMean [ns]",
                                             iS, iSel),
                                        100, 0, MaxNbEvent, 99, -TSumMax, TSumMax);
    }
  }

  // RPC related distributions
  LOG(info) << " Define Clusterizer histos for " << iNbDet << " detectors ";

  fhRpcCluMul.resize(iNbDet);
  fhRpcCluRate.resize(iNbDet);
  fhRpcCluPosition.resize(iNbDet);
  fhRpcCluDelPos.resize(iNbDet);
  fhRpcCluDelMatPos.resize(iNbDet);
  fhRpcCluTOff.resize(iNbDet);
  fhRpcCluDelTOff.resize(iNbDet);
  fhRpcCluDelMatTOff.resize(iNbDet);
  fhRpcCluTrms.resize(iNbDet);
  fhRpcCluTot.resize(iNbDet);
  fhRpcCluSize.resize(iNbDet);
  fhRpcCluAvWalk.resize(iNbDet);
  fhRpcCluAvLnWalk.resize(iNbDet);
  fhRpcCluWalk.resize(iNbDet);
  fhRpcDTLastHits.resize(iNbDet);
  fhRpcDTLastHits_Tot.resize(iNbDet);
  fhRpcDTLastHits_CluSize.resize(iNbDet);


  if (fTotMax != 0.) fdTOTMax = fTotMax;
  if (fTotMin != 0.) fdTOTMin = fTotMin;

  for (Int_t iDetIndx = 0; iDetIndx < iNbDet; iDetIndx++) {
    Int_t iUniqueId = fDigiBdfPar->GetDetUId(iDetIndx);
    Int_t iSmType   = CbmTofAddress::GetSmType(iUniqueId);
    Int_t iSmId     = CbmTofAddress::GetSmId(iUniqueId);
    Int_t iRpcId    = CbmTofAddress::GetRpcId(iUniqueId);
    Int_t iUCellId  = CbmTofAddress::GetUniqueAddress(iSmId, iRpcId, 0, 0, iSmType);
    fChannelInfo    = fDigiPar->GetCell(iUCellId);
    if (NULL == fChannelInfo) {
      LOG(warn) << "No DigiPar for Det " << Form("0x%08x", iUCellId);
      continue;
    }
    LOG(info) << "DetIndx " << iDetIndx << ", SmType " << iSmType << ", SmId " << iSmId << ", RpcId " << iRpcId
              << " => UniqueId " << Form("(0x%08x, 0x%08x)", iUniqueId, iUCellId) << ", dx " << fChannelInfo->GetSizex()
              << ", dy " << fChannelInfo->GetSizey() << Form(" ChPoi: %p ", fChannelInfo) << ", nbCh "
              << fDigiBdfPar->GetNbChan(iSmType, 0);

    // check access to all channel infos
    for (Int_t iCh = 0; iCh < fDigiBdfPar->GetNbChan(iSmType, iRpcId); iCh++) {
      Int_t iCCellId = CbmTofAddress::GetUniqueAddress(iSmId, iRpcId, iCh, 0, iSmType);
      fChannelInfo   = fDigiPar->GetCell(iCCellId);
      if (NULL == fChannelInfo) LOG(warn) << Form("missing ChannelInfo for ch %d addr 0x%08x", iCh, iCCellId);
    }

    fChannelInfo = fDigiPar->GetCell(iUCellId);

    fhRpcCluMul[iDetIndx] =
      new TH1F(Form("cl_SmT%01d_sm%03d_rpc%03d_Mul", iSmType, iSmId, iRpcId),
               Form("Clu multiplicity of Rpc #%03d in Sm %03d of type %d; M []; Cnts", iRpcId, iSmId, iSmType),
               2. + 2. * fDigiBdfPar->GetNbChan(iSmType, iRpcId), 0, 2. + 2. * fDigiBdfPar->GetNbChan(iSmType, iRpcId));

    fhRpcCluRate[iDetIndx] =
      new TH1F(Form("cl_SmT%01d_sm%03d_rpc%03d_rate", iSmType, iSmId, iRpcId),
               Form("Clu rate of Rpc #%03d in Sm %03d of type %d; Time (s); Rate (Hz)", iRpcId, iSmId, iSmType), 3600.,
               0., 3600.);

    fhRpcDTLastHits[iDetIndx] = new TH1F(Form("cl_SmT%01d_sm%03d_rpc%03d_DTLastHits", iSmType, iSmId, iRpcId),
                                         Form("Clu #DeltaT to last hits  of Rpc #%03d in Sm %03d of type %d; log( "
                                              "#DeltaT (ns)); counts",
                                              iRpcId, iSmId, iSmType),
                                         100., 0., 10.);

    fhRpcDTLastHits_Tot[iDetIndx] = new TH2F(Form("cl_SmT%01d_sm%03d_rpc%03d_Tot_DTLH", iSmType, iSmId, iRpcId),
                                             Form("Clu Tot of Rpc #%03d in Sm %03d of type %d; log(#DeltaT (ns)); TOT "
                                                  "[ns]",
                                                  iRpcId, iSmId, iSmType),
                                             100, 0., 10., 100, fdTOTMin, 4. * fdTOTMax);

    fhRpcDTLastHits_CluSize[iDetIndx] = new TH2F(Form("cl_SmT%01d_sm%03d_rpc%03d_CluSize_DTLH", iSmType, iSmId, iRpcId),
                                                 Form("Clu Size of Rpc #%03d in Sm %03d of type %d; log(#DeltaT (ns)); "
                                                      "CluSize []",
                                                      iRpcId, iSmId, iSmType),
                                                 100, 0., 10., 16, 0.5, 16.5);

    Double_t YSCAL = 50.;
    if (fPosYMaxScal != 0.) YSCAL = fPosYMaxScal;
    Double_t YDMAX = TMath::Max(2., fChannelInfo->GetSizey()) * YSCAL;
    fhRpcCluPosition[iDetIndx] =
      new TH2F(Form("cl_SmT%01d_sm%03d_rpc%03d_Pos", iSmType, iSmId, iRpcId),
               Form("Clu position of Rpc #%03d in Sm %03d of type %d; Strip []; ypos [cm]", iRpcId, iSmId, iSmType),
               fDigiBdfPar->GetNbChan(iSmType, iRpcId), 0, fDigiBdfPar->GetNbChan(iSmType, iRpcId), 99, -YDMAX, YDMAX);

    fhRpcCluDelPos[iDetIndx] =
      new TH2F(Form("cl_SmT%01d_sm%03d_rpc%03d_DelPos", iSmType, iSmId, iRpcId),
               Form("Clu position difference of Rpc #%03d in Sm %03d of type "
                    "%d; Strip []; #Deltaypos(clu) [cm]",
                    iRpcId, iSmId, iSmType),
               fDigiBdfPar->GetNbChan(iSmType, iRpcId), 0, fDigiBdfPar->GetNbChan(iSmType, iRpcId), 99, -10., 10.);

    fhRpcCluDelMatPos[iDetIndx] =
      new TH2F(Form("cl_SmT%01d_sm%03d_rpc%03d_DelMatPos", iSmType, iSmId, iRpcId),
               Form("Matched Clu position difference of Rpc #%03d in Sm %03d of type "
                    "%d; Strip []; #Deltaypos(mat) [cm]",
                    iRpcId, iSmId, iSmType),
               fDigiBdfPar->GetNbChan(iSmType, iRpcId), 0, fDigiBdfPar->GetNbChan(iSmType, iRpcId), 99, -5., 5.);

    Double_t TSumMax = 1.E3;
    if (fTRefDifMax != 0.) TSumMax = fTRefDifMax;
    fhRpcCluTOff[iDetIndx] = new TH2F(
      Form("cl_SmT%01d_sm%03d_rpc%03d_TOff", iSmType, iSmId, iRpcId),
      Form("Clu TimeZero of Rpc #%03d in Sm %03d of type %d; Strip []; TOff [ns]", iRpcId, iSmId, iSmType),
      fDigiBdfPar->GetNbChan(iSmType, iRpcId), 0, fDigiBdfPar->GetNbChan(iSmType, iRpcId), 99, -TSumMax, TSumMax);

    fhRpcCluDelTOff[iDetIndx] =
      new TH2F(Form("cl_SmT%01d_sm%03d_rpc%03d_DelTOff", iSmType, iSmId, iRpcId),
               Form("Clu TimeZero Difference of Rpc #%03d in Sm %03d of type %d; Strip "
                    "[]; #DeltaTOff(clu) [ns]",
                    iRpcId, iSmId, iSmType),
               fDigiBdfPar->GetNbChan(iSmType, iRpcId), 0, fDigiBdfPar->GetNbChan(iSmType, iRpcId), 99, -0.6, 0.6);

    fhRpcCluDelMatTOff[iDetIndx] =
      new TH2F(Form("cl_SmT%01d_sm%03d_rpc%03d_DelMatTOff", iSmType, iSmId, iRpcId),
               Form("Clu TimeZero Difference of Rpc #%03d in Sm %03d of type %d; Strip "
                    "[]; #DeltaTOff(mat) [ns]",
                    iRpcId, iSmId, iSmType),
               fDigiBdfPar->GetNbChan(iSmType, iRpcId), 0, fDigiBdfPar->GetNbChan(iSmType, iRpcId), 99, -0.6, 0.6);

    fhRpcCluTrms[iDetIndx] =
      new TH2F(Form("cl_SmT%01d_sm%03d_rpc%03d_Trms", iSmType, iSmId, iRpcId),
               Form("Clu Time RMS of Rpc #%03d in Sm %03d of type %d; Strip []; Trms [ns]", iRpcId, iSmId, iSmType),
               fDigiBdfPar->GetNbChan(iSmType, iRpcId), 0, fDigiBdfPar->GetNbChan(iSmType, iRpcId), 99, 0., 0.5);

    fhRpcCluTot[iDetIndx] =
      new TH2F(Form("cl_SmT%01d_sm%03d_rpc%03d_Tot", iSmType, iSmId, iRpcId),
               Form("Clu Tot of Rpc #%03d in Sm %03d of type %d; StripSide []; TOT [ns]", iRpcId, iSmId, iSmType),
               2 * fDigiBdfPar->GetNbChan(iSmType, iRpcId), 0, 2 * fDigiBdfPar->GetNbChan(iSmType, iRpcId), 100,
               fdTOTMin, fdTOTMax);

    fhRpcCluSize[iDetIndx] =
      new TH2F(Form("cl_SmT%01d_sm%03d_rpc%03d_Size", iSmType, iSmId, iRpcId),
               Form("Clu size of Rpc #%03d in Sm %03d of type %d; Strip []; size [strips]", iRpcId, iSmId, iSmType),
               fDigiBdfPar->GetNbChan(iSmType, iRpcId), 0, fDigiBdfPar->GetNbChan(iSmType, iRpcId), 16, 0.5, 16.5);

    // Walk histos
    fhRpcCluAvWalk[iDetIndx] = new TH2F(Form("cl_SmT%01d_sm%03d_rpc%03d_AvWalk", iSmType, iSmId, iRpcId),
                                        Form("Walk in SmT%01d_sm%03d_rpc%03d_AvWalk", iSmType, iSmId, iRpcId),
                                        nbClWalkBinX, fdTOTMin, fdTOTMax, nbClWalkBinY, -TSumMax, TSumMax);

    fhRpcCluAvLnWalk[iDetIndx] =
      new TH2D(Form("cl_SmT%01d_sm%03d_rpc%03d_AvLnWalk", iSmType, iSmId, iRpcId),
               Form("Walk in SmT%01d_sm%03d_rpc%03d_AvLnWalk", iSmType, iSmId, iRpcId), nbClWalkBinX,
               TMath::Log10(fdTOTMax / 50.), TMath::Log10(fdTOTMax), nbClWalkBinY, -TSumMax, TSumMax);

    fhRpcCluWalk[iDetIndx].resize(fDigiBdfPar->GetNbChan(iSmType, iRpcId));
    for (Int_t iCh = 0; iCh < fDigiBdfPar->GetNbChan(iSmType, iRpcId); iCh++) {
      fhRpcCluWalk[iDetIndx][iCh].resize(2);
      for (Int_t iSide = 0; iSide < 2; iSide++) {
        fhRpcCluWalk[iDetIndx][iCh][iSide] =
          new TH2D(Form("cl_SmT%01d_sm%03d_rpc%03d_Ch%03d_S%01d_Walk", iSmType, iSmId, iRpcId, iCh, iSide),
                   Form("Walk in SmT%01d_sm%03d_rpc%03d_Ch%03d_S%01d_Walk", iSmType, iSmId, iRpcId, iCh, iSide),
                   nbClWalkBinX, fdTOTMin, fdTOTMax, nbClWalkBinY, -TSumMax, TSumMax);
      }
      /*
         (fhRpcCluWalk[iDetIndx]).push_back( hTemp );
       */
    }
  }

  // Trigger selected histograms
  if (0 < iNSel) {

    fhSeldT.resize(iNSel);
    for (Int_t iSel = 0; iSel < iNSel; iSel++) {
      fhSeldT[iSel] = new TH2F(Form("cl_dt_Sel%02d", iSel), Form("Selector time %02d; dT [ns]", iSel), 99,
                               -fdDelTofMax * 10., fdDelTofMax * 10., 16, -0.5, 15.5);
    }

    fhTRpcCluMul.resize(iNbDet);
    fhTRpcCluPosition.resize(iNbDet);
    fhTRpcCluTOff.resize(iNbDet);
    fhTRpcCluTot.resize(iNbDet);
    fhTRpcCluSize.resize(iNbDet);
    fhTRpcCluAvWalk.resize(iNbDet);
    fhTRpcCluDelTof.resize(iNbDet);
    fhTRpcCludXdY.resize(iNbDet);
    fhTRpcCluWalk.resize(iNbDet);
    fhTRpcCluTOffDTLastHits.resize(iNbDet);
    fhTRpcCluTotDTLastHits.resize(iNbDet);
    fhTRpcCluSizeDTLastHits.resize(iNbDet);
    fhTRpcCluMemMulDTLastHits.resize(iNbDet);

    for (Int_t iDetIndx = 0; iDetIndx < iNbDet; iDetIndx++) {
      Int_t iUniqueId = fDigiBdfPar->GetDetUId(iDetIndx);
      Int_t iSmType   = CbmTofAddress::GetSmType(iUniqueId);
      Int_t iSmId     = CbmTofAddress::GetSmId(iUniqueId);
      Int_t iRpcId    = CbmTofAddress::GetRpcId(iUniqueId);
      Int_t iUCellId  = CbmTofAddress::GetUniqueAddress(iSmId, iRpcId, 0, 0, iSmType);
      fChannelInfo    = fDigiPar->GetCell(iUCellId);
      if (NULL == fChannelInfo) {
        LOG(warn) << "No DigiPar for Det " << Form("0x%08x", iUCellId);
        continue;
      }
      LOG(debug) << "DetIndx " << iDetIndx << ", SmType " << iSmType << ", SmId " << iSmId << ", RpcId " << iRpcId
                 << " => UniqueId " << Form("(0x%08x, 0x%08x)", iUniqueId, iUCellId) << ", dx "
                 << fChannelInfo->GetSizex() << ", dy " << fChannelInfo->GetSizey() << Form(" poi: 0x%p ", fChannelInfo)
                 << ", nbCh " << fDigiBdfPar->GetNbChan(iSmType, iRpcId);

      fhTRpcCluMul[iDetIndx].resize(iNSel);
      fhTRpcCluPosition[iDetIndx].resize(iNSel);
      fhTRpcCluTOff[iDetIndx].resize(iNSel);
      fhTRpcCluTot[iDetIndx].resize(iNSel);
      fhTRpcCluSize[iDetIndx].resize(iNSel);
      fhTRpcCluAvWalk[iDetIndx].resize(iNSel);
      fhTRpcCluDelTof[iDetIndx].resize(iNSel);
      fhTRpcCludXdY[iDetIndx].resize(iNSel);
      fhTRpcCluWalk[iDetIndx].resize(iNSel);
      fhTRpcCluTOffDTLastHits[iDetIndx].resize(iNSel);
      fhTRpcCluTotDTLastHits[iDetIndx].resize(iNSel);
      fhTRpcCluSizeDTLastHits[iDetIndx].resize(iNSel);
      fhTRpcCluMemMulDTLastHits[iDetIndx].resize(iNSel);

      for (Int_t iSel = 0; iSel < iNSel; iSel++) {
        fhTRpcCluMul[iDetIndx][iSel] =
          new TH1F(Form("cl_SmT%01d_sm%03d_rpc%03d_Sel%02d_Mul", iSmType, iSmId, iRpcId, iSel),
                   Form("Clu multiplicity of Rpc #%03d in Sm %03d of type %d "
                        "under Selector %02d; M []; cnts",
                        iRpcId, iSmId, iSmType, iSel),
                   fDigiBdfPar->GetNbChan(iSmType, iRpcId), 0., fDigiBdfPar->GetNbChan(iSmType, iRpcId));

        if (NULL == fhTRpcCluMul[iDetIndx][iSel]) LOG(error) << " Histo not generated !";

        Double_t YSCAL = 50.;
        if (fPosYMaxScal != 0.) YSCAL = fPosYMaxScal;
        Double_t YDMAX                    = TMath::Max(2., fChannelInfo->GetSizey()) * YSCAL;
        fhTRpcCluPosition[iDetIndx][iSel] = new TH2F(
          Form("cl_SmT%01d_sm%03d_rpc%03d_Sel%02d_Pos", iSmType, iSmId, iRpcId, iSel),
          Form("Clu position of Rpc #%03d in Sm %03d of type %d under "
               "Selector %02d; Strip []; ypos [cm]",
               iRpcId, iSmId, iSmType, iSel),
          fDigiBdfPar->GetNbChan(iSmType, iRpcId), 0, fDigiBdfPar->GetNbChan(iSmType, iRpcId), 100, -YDMAX, YDMAX);

        Double_t TSumMax = 1.E4;
        if (fTRefDifMax != 0.) TSumMax = fTRefDifMax;
        fhTRpcCluTOff[iDetIndx][iSel] = new TH2F(
          Form("cl_SmT%01d_sm%03d_rpc%03d_Sel%02d_TOff", iSmType, iSmId, iRpcId, iSel),
          Form("Clu TimeZero of Rpc #%03d in Sm %03d of type %d under "
               "Selector %02d; Strip []; TOff [ns]",
               iRpcId, iSmId, iSmType, iSel),
          fDigiBdfPar->GetNbChan(iSmType, iRpcId), 0, fDigiBdfPar->GetNbChan(iSmType, iRpcId), 99, -TSumMax, TSumMax);

        if (fTotMax != 0.) fdTOTMax = fTotMax;
        fhTRpcCluTot[iDetIndx][iSel] =
          new TH2F(Form("cl_SmT%01d_sm%03d_rpc%03d_Sel%02d_Tot", iSmType, iSmId, iRpcId, iSel),
                   Form("Clu Tot of Rpc #%03d in Sm %03d of type %d under "
                        "Selector %02d; StripSide []; TOT [ns]",
                        iRpcId, iSmId, iSmType, iSel),
                   fDigiBdfPar->GetNbChan(iSmType, iRpcId) * 2, 0, fDigiBdfPar->GetNbChan(iSmType, iRpcId) * 2, 100,
                   fdTOTMin, fdTOTMax);

        fhTRpcCluSize[iDetIndx][iSel] =
          new TH2F(Form("cl_SmT%01d_sm%03d_rpc%03d_Sel%02d_Size", iSmType, iSmId, iRpcId, iSel),
                   Form("Clu size of Rpc #%03d in Sm %03d of type %d under "
                        "Selector %02d; Strip []; size [strips]",
                        iRpcId, iSmId, iSmType, iSel),
                   fDigiBdfPar->GetNbChan(iSmType, iRpcId), 0, fDigiBdfPar->GetNbChan(iSmType, iRpcId), 16, 0.5, 16.5);

        // Walk histos
        fhTRpcCluAvWalk[iDetIndx][iSel] =
          new TH2D(Form("cl_SmT%01d_sm%03d_rpc%03d_Sel%02d_AvWalk", iSmType, iSmId, iRpcId, iSel),
                   Form("Walk in SmT%01d_sm%03d_rpc%03d_Sel%02d_AvWalk; TOT; T-TSel", iSmType, iSmId, iRpcId, iSel),
                   nbClWalkBinX, fdTOTMin, fdTOTMax, nbClWalkBinY, -TSumMax, TSumMax);

        // Tof Histos
        fhTRpcCluDelTof[iDetIndx][iSel] =
          new TH2F(Form("cl_SmT%01d_sm%03d_rpc%03d_Sel%02d_DelTof", iSmType, iSmId, iRpcId, iSel),
                   Form("SmT%01d_sm%03d_rpc%03d_Sel%02d_DelTof; TRef-TSel; T-TSel", iSmType, iSmId, iRpcId, iSel),
                   nbClDelTofBinX, -fdDelTofMax, fdDelTofMax, nbClDelTofBinY, -TSumMax, TSumMax);

        // Position deviation histos
        fhTRpcCludXdY[iDetIndx][iSel] =
          new TH2F(Form("cl_SmT%01d_sm%03d_rpc%03d_Sel%02d_dXdY", iSmType, iSmId, iRpcId, iSel),
                   Form("SmT%01d_sm%03d_rpc%03d_Sel%02d_dXdY; #Delta x [cm]; "
                        "#Delta y [cm];",
                        iSmType, iSmId, iRpcId, iSel),
                   nbCldXdYBinX, -dXdYMax, dXdYMax, nbCldXdYBinY, -dXdYMax, dXdYMax);

        fhTRpcCluWalk[iDetIndx][iSel].resize(fDigiBdfPar->GetNbChan(iSmType, iRpcId));
        for (Int_t iCh = 0; iCh < fDigiBdfPar->GetNbChan(iSmType, iRpcId); iCh++) {
          fhTRpcCluWalk[iDetIndx][iSel][iCh].resize(2);
          for (Int_t iSide = 0; iSide < 2; iSide++) {
            fhTRpcCluWalk[iDetIndx][iSel][iCh][iSide] = new TH2D(
              Form("cl_SmT%01d_sm%03d_rpc%03d_Ch%03d_S%01d_Sel%02d_Walk", iSmType, iSmId, iRpcId, iCh, iSide, iSel),
              Form("Walk in SmT%01d_sm%03d_rpc%03d_Ch%03d_S%01d_Sel%02d_Walk", iSmType, iSmId, iRpcId, iCh, iSide,
                   iSel),
              nbClWalkBinX, fdTOTMin, fdTOTMax, nbClWalkBinY, -TSumMax, TSumMax);
          }
        }

        fhTRpcCluTOffDTLastHits[iDetIndx][iSel] =
          new TH2F(Form("cl_SmT%01d_sm%03d_rpc%03d_Sel%02d_TOff_DTLH", iSmType, iSmId, iRpcId, iSel),
                   Form("Clu TimeZero of Rpc #%03d in Sm %03d of type %d under "
                        "Selector %02d; log(#DeltaT (ns)); TOff [ns]",
                        iRpcId, iSmId, iSmType, iSel),
                   100, 0., 10., 99, -TSumMax, TSumMax);

        fhTRpcCluTotDTLastHits[iDetIndx][iSel] =
          new TH2F(Form("cl_SmT%01d_sm%03d_rpc%03d_Sel%02d_Tot_DTLH", iSmType, iSmId, iRpcId, iSel),
                   Form("Clu Tot of Rpc #%03d in Sm %03d of type %d under "
                        "Selector %02d; log(#DeltaT (ns)); TOT [ns]",
                        iRpcId, iSmId, iSmType, iSel),
                   100, 0., 10., 100, fdTOTMin, fdTOTMax);

        fhTRpcCluSizeDTLastHits[iDetIndx][iSel] =
          new TH2F(Form("cl_SmT%01d_sm%03d_rpc%03d_Sel%02d_Size_DTLH", iSmType, iSmId, iRpcId, iSel),
                   Form("Clu size of Rpc #%03d in Sm %03d of type %d under "
                        "Selector %02d; log(#DeltaT (ns)); size [strips]",
                        iRpcId, iSmId, iSmType, iSel),
                   100, 0., 10., 10, 0.5, 10.5);

        fhTRpcCluMemMulDTLastHits[iDetIndx][iSel] =
          new TH2F(Form("cl_SmT%01d_sm%03d_rpc%03d_Sel%02d_MemMul_DTLH", iSmType, iSmId, iRpcId, iSel),
                   Form("Clu Memorized Multiplicity of Rpc #%03d in Sm %03d of type %d "
                        "under Selector %02d; log(#DeltaT (ns)); TOff [ns]",
                        iRpcId, iSmId, iSmType, iSel),
                   100, 0., 10., 10, 0, 10);
      }
    }
  }

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

  return;
}
/************************************************************************************/
void CbmDeviceHitBuilderTof::WriteHistograms()
{
  TList* tHistoList(NULL);
  tHistoList = gROOT->GetList();

  TIter next(tHistoList);
  // Write histogramms to the file
  fOutRootFile->cd();
  {
    TH1* h;
    TObject* obj;
    while ((obj = (TObject*) next())) {
      if (obj->InheritsFrom(TH1::Class())) {
        h = (TH1*) obj;
        //         cout << "Write histo " << h->GetTitle() << endl;
        h->Write();
      }
    }
  }
}

/************************************************************************************/
Bool_t CbmDeviceHitBuilderTof::BuildClusters()
{
  fiNevtBuild++;
  if (!CalibRawDigis()) return kFALSE;
  if (0 == fiMode) return kTRUE;  // no customer yet
  if (!FillDigiStor()) return kFALSE;
  if (!BuildHits()) return kFALSE;
  return kTRUE;
}

/************************************************************************************/
Bool_t CbmDeviceHitBuilderTof::InspectRawDigis()
{
  Int_t iNbTofDigi = fiNDigiIn;
  pRef             = NULL;
  for (Int_t iDigInd = 0; iDigInd < fiNDigiIn; iDigInd++) {
    CbmTofDigi* pDigi = &fvDigiIn[iDigInd];
    //LOG(debug)<<iDigInd<<" "<<pDigi;
    Int_t iAddr    = pDigi->GetAddress() & DetMask;
    Int_t iDetIndx = fDigiBdfPar->GetDetInd(iAddr);
    /*
    LOG(info)<<iDigInd
	      //<<Form(" Address : 0x%08x ",pDigi->GetAddress())
  	      <<Form(" TSRCS %d%d%d%02d%d ", (int)pDigi->GetType(),
  	    		  (int)pDigi->GetSm(),(int)pDigi->GetRpc(),(int)pDigi->GetChannel(),(int)pDigi->GetSide())
    	  <<" : " << Form("Ind %2d, T %15.3f, Tot %5.1f",iDetIndx,pDigi->GetTime(),pDigi->GetTot());
    */

    if (fiBeamRefAddr < 0 || iAddr == fiBeamRefAddr) {
      //LOG(debug) << Form("Ref digi found for 0x%08x, Mask  0x%08x ", fiBeamRefAddr, DetMask);
      if (NULL == pRef) pRef = pDigi;
      else {
        if (pDigi->GetTime() < pRef->GetTime()) pRef = pDigi;
      }
    }

    if (fDigiBdfPar->GetNbDet() - 1 < iDetIndx || iDetIndx < 0) {
      LOG(warn) << Form(" Wrong DetIndx %d >< %d,0 ", iDetIndx, fDigiBdfPar->GetNbDet());
      break;
    }

    fhRpcDigiTot[iDetIndx]->Fill(2 * pDigi->GetChannel() + pDigi->GetSide(), pDigi->GetTot());

    if (NULL == fhRpcDigiCor[iDetIndx]) {
      if (100 < iMess++)
        LOG(warn) << Form(" DigiCor Histo for  DetIndx %d derived from 0x%08x not found", iDetIndx,
                          pDigi->GetAddress());
      continue;
    }

    Double_t dTDifMin     = dDoubleMax;
    CbmTofDigi* pDigi2Min = NULL;
    //       for (Int_t iDigI2 =iDigInd+1; iDigI2<iNbTofDigi;iDigI2++){
    for (Int_t iDigI2 = 0; iDigI2 < iNbTofDigi; iDigI2++) {
      CbmTofDigi* pDigi2 = &fvDigiIn[iDigI2];
      if (pDigi != pDigi2) { fhDigiTdif->Fill(pDigi->GetTime() - pDigi2->GetTime()); }
      if (pDigi->GetAddress() != pDigi2->GetAddress())
        if (pDigi->GetType() == 6 && pDigi2->GetType() == 6)
          fhBucDigiCor->Fill(pDigi->GetRpc() * 64 + pDigi->GetChannel() * 2 + pDigi->GetSide(),
                             pDigi2->GetRpc() * 64 + pDigi2->GetChannel() * 2 + pDigi2->GetSide());

      if (iDetIndx == fDigiBdfPar->GetDetInd(pDigi2->GetAddress())) {
        /*
    	LOG(info) <<" Correlate DetIndx "<<iDetIndx
	    	      <<Form(", TSRCS %d%d%d%02d%d ", (int)pDigi->GetType(),
	    	    		  (int)pDigi->GetSm(),(int)pDigi->GetRpc(),(int)pDigi->GetChannel(),(int)pDigi->GetSide())
			      <<Form(" with %d%d%d%02d%d ", (int)pDigi2->GetType(),
			    	    (int)pDigi2->GetSm(),(int)pDigi2->GetRpc(),(int)pDigi2->GetChannel(),(int)pDigi2->GetSide());
        */
        if (0. == pDigi->GetSide() && 1. == pDigi2->GetSide()) {
          fhRpcDigiCor[iDetIndx]->Fill(pDigi->GetChannel(), pDigi2->GetChannel());
        }
        else {
          if (1. == pDigi->GetSide() && 0. == pDigi2->GetSide()) {
            fhRpcDigiCor[iDetIndx]->Fill(pDigi2->GetChannel(), pDigi->GetChannel());
          }
        }
        if (pDigi->GetSide() != pDigi2->GetSide()) {
          if (pDigi->GetChannel() == pDigi2->GetChannel()) {
            Double_t dTDif = TMath::Abs(pDigi->GetTime() - pDigi2->GetTime());
            if (dTDif < dTDifMin) {
              dTDifMin  = dTDif;
              pDigi2Min = pDigi2;
              //LOG(debug) << "Digi2 found at "<<iDigI2<<" with TDif = "<<dTDifMin<<" ns";
            }
          }
          else if (TMath::Abs(pDigi->GetChannel() - pDigi2->GetChannel())
                   == 1) {  // opposite side missing, neighbouring channel has hit on opposite side // FIXME
            // check that same side digi of neighbouring channel is absent
            Int_t iDigI3 = 0;
            for (; iDigI3 < iNbTofDigi; iDigI3++) {
              CbmTofDigi* pDigi3 = &fvDigiIn[iDigI3];
              if (pDigi3->GetSide() == pDigi->GetSide() && pDigi2->GetChannel() == pDigi3->GetChannel()) break;
            }
            if (iDigI3 == iNbTofDigi) {  // same side neighbour did not fire
              Int_t iCorMode = 0;        // Missing hit correction mode
              switch (iCorMode) {
                case 0:  // no action
                  break;
                case 1:  // shift found hit
                  LOG(debug) << Form("shift channel %d%d%d%d%d and  ", (Int_t) pDigi->GetType(), (Int_t) pDigi->GetSm(),
                                     (Int_t) pDigi->GetRpc(), (Int_t) pDigi->GetChannel(), (Int_t) pDigi->GetSide())
                             << Form(" %d%d%d%d%d ", (Int_t) pDigi2->GetType(), (Int_t) pDigi2->GetSm(),
                                     (Int_t) pDigi2->GetRpc(), (Int_t) pDigi2->GetChannel(), (Int_t) pDigi2->GetSide());
                  //if(pDigi->GetTime() < pDigi2->GetTime())
                  if (pDigi->GetSide() == 0)
                    pDigi2->SetAddress(pDigi->GetSm(), pDigi->GetRpc(), pDigi->GetChannel(), 1 - pDigi->GetSide(),
                                       pDigi->GetType());
                  else
                    pDigi->SetAddress(pDigi2->GetSm(), pDigi2->GetRpc(), pDigi2->GetChannel(), 1 - pDigi2->GetSide(),
                                      pDigi2->GetType());

                  LOG(debug) << Form("resultchannel %d%d%d%d%d and  ", (Int_t) pDigi->GetType(), (Int_t) pDigi->GetSm(),
                                     (Int_t) pDigi->GetRpc(), (Int_t) pDigi->GetChannel(), (Int_t) pDigi->GetSide())
                             << Form(" %d%d%d%d%d ", (Int_t) pDigi2->GetType(), (Int_t) pDigi2->GetSm(),
                                     (Int_t) pDigi2->GetRpc(), (Int_t) pDigi2->GetChannel(), (Int_t) pDigi2->GetSide());
                  break;
                case 2:  // insert missing hits
                  CbmTofDigi* pDigiN = new CbmTofDigi(*pDigi);
                  pDigiN->SetAddress(pDigi->GetSm(), pDigi->GetRpc(), pDigi2->GetChannel(), pDigi->GetSide(),
                                     pDigi->GetType());
                  pDigiN->SetTot(pDigi2->GetTot());
                  fvDigiIn.push_back(*pDigiN);

                  CbmTofDigi* pDigiN2 = new CbmTofDigi(*pDigi2);
                  pDigiN2->SetAddress(pDigi2->GetSm(), pDigi2->GetRpc(), pDigi->GetChannel(), pDigi2->GetSide(),
                                      pDigi2->GetType());
                  pDigiN2->SetTot(pDigi->GetTot());
                  fvDigiIn.push_back(*pDigiN2);

                  break;
              }
            }
          }
        }
      }
    }
    if (pDigi2Min != NULL) {
      CbmTofDetectorInfo xDetInfo(ECbmModuleId::kTof, pDigi->GetType(), pDigi->GetSm(), pDigi->GetRpc(), 0,
                                  pDigi->GetChannel());
      Int_t iChId  = fTofId->SetDetectorInfo(xDetInfo);
      fChannelInfo = fDigiPar->GetCell(iChId);
      if (NULL == fChannelInfo) {
        LOG(warn) << Form("Invalid ChannelInfo for 0x%08x, 0x%08x", iChId, pDigi2Min->GetAddress()) << " TSRC "
                  << pDigi->GetType() << pDigi->GetSm() << pDigi->GetRpc() << pDigi->GetChannel();
        continue;
      }
      if (fDigiBdfPar->GetSigVel(pDigi->GetType(), pDigi->GetSm(), pDigi->GetRpc()) * dTDifMin * 0.5
          < fPosYMaxScal * fChannelInfo->GetSizey()) {
        //check consistency
        if (8 == pDigi->GetType() || 5 == pDigi->GetType()) {
          if (pDigi->GetTime() != pDigi2Min->GetTime()) {
            if (fiMsgCnt-- > 0) {
              LOG(warn) << "Inconsistent duplicated digis in event " << fiNevtBuild << ", Ind: " << iDigInd;
              LOG(warn) << "   " << pDigi->ToString();
              LOG(warn) << "   " << pDigi2Min->ToString();
            }
            pDigi2Min->SetTot(pDigi->GetTot());
            pDigi2Min->SetTime(pDigi->GetTime());
          }
        }
      }
    }
  }

  if (NULL != pRef) {
    // LOG(debug) << Form("pRef from 0x%08x ",pRef->GetAddress());

    for (Int_t iDigInd = 0; iDigInd < fiNDigiIn; iDigInd++) {
      CbmTofDigi* pDigi = &fvDigiIn[iDigInd];
      Int_t iAddr       = pDigi->GetAddress() & DetMask;
      Int_t iDet        = fDetIdIndexMap[iAddr];  // Detector Index
      Int_t iSide       = pDigi->GetSide();
      fhDigiTimesRaw->Fill(iDet * 2 + iSide, pDigi->GetTime() - pRef->GetTime());
    }
  }
  return kTRUE;
}
/************************************************************************************/
Bool_t CbmDeviceHitBuilderTof::CalibRawDigis()
{
  CbmTofDigi* pDigi;
  CbmTofDigi* pCalDigi = NULL;
  Int_t iDigIndCal     = -1;
  // channel deadtime map
  std::map<Int_t, Double_t> mChannelDeadTime;
  fTofCalDigiVec->clear();

  Int_t iNbTofDigi = fvDigiIn.size();
  for (Int_t iDigInd = 0; iDigInd < iNbTofDigi; iDigInd++) {
    pDigi       = (CbmTofDigi*) &fvDigiIn[iDigInd];
    Int_t iAddr = pDigi->GetAddress();
    /*
    LOG(debug)<<"BC "  // Before Calibration
	      <<Form("0x%08x",pDigi->GetAddress())<<" TSRC "
	      <<pDigi->GetType()
	      <<pDigi->GetSm()
	      <<pDigi->GetRpc()
	      <<Form("%2d",(Int_t)pDigi->GetChannel())<<" "
	      <<pDigi->GetSide()<<" "
	      <<Form("%f",pDigi->GetTime())<<" "
	      <<pDigi->GetTot();
    */
    if (pDigi->GetType() == 5 || pDigi->GetType() == 8)  // for Pad counters generate fake digi to mockup a strip
      if (pDigi->GetSide() == 1) continue;               // skip one side to avoid double entries

    Bool_t bValid = kTRUE;
    std::map<Int_t, Double_t>::iterator it;
    it = mChannelDeadTime.find(iAddr);
    if (it != mChannelDeadTime.end()) {
      /*
      LOG(debug)<<"CCT found valid ChannelDeadtime entry "<<mChannelDeadTime[iAddr]
		<<", DeltaT "<<pDigi->GetTime()-mChannelDeadTime[iAddr];
      */
      if ((bValid = (pDigi->GetTime() > mChannelDeadTime[iAddr] + fdChannelDeadtime))) {
        //  pCalDigi =
        //	new ((*fTofCalDigisColl)[++iDigIndCal]) CbmTofDigi(*pDigi);
        fTofCalDigiVec->push_back(CbmTofDigi(*pDigi));
        pCalDigi = &(fTofCalDigiVec->back());
        iDigIndCal++;
      }
    }
    else {
      // pCalDigi = new ((*fTofCalDigisColl)[++iDigIndCal]) CbmTofDigi(*pDigi);
      fTofCalDigiVec->push_back(CbmTofDigi(*pDigi));
      pCalDigi = &(fTofCalDigiVec->back());
      iDigIndCal++;
    }
    mChannelDeadTime[iAddr] = pDigi->GetTime();
    if (!bValid) continue;
    if (pRef != NULL)
      if (pDigi == pRef) pRefCal = pCalDigi;
    /*
    LOG(debug)<<"DC "  // After deadtime check. before Calibration
	      <<Form("0x%08x",pDigi->GetAddress())<<" TSRC "
	      <<pDigi->GetType()
	      <<pDigi->GetSm()
	      <<pDigi->GetRpc()
	      <<Form("%2d",(Int_t)pDigi->GetChannel())<<" "
	      <<pDigi->GetSide()<<" "
	      <<Form("%f",pDigi->GetTime())<<" "
	      <<pDigi->GetTot();
    */

    if (fbPs2Ns) {
      pCalDigi->SetTime(pCalDigi->GetTime() / 1000.);  // for backward compatibility
      pCalDigi->SetTot(pCalDigi->GetTot() / 1000.);    // for backward compatibility
    }
    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(), pDigi->GetRpc()) > pDigi->GetChannel()) {
      // apply calibration vectors
      pCalDigi->SetTime(pCalDigi->GetTime() -  // calibrate Digi Time
                        fvCPTOff[pDigi->GetType()][pDigi->GetSm() * fDigiBdfPar->GetNbRpc(pDigi->GetType())
                                                   + pDigi->GetRpc()][pDigi->GetChannel()][pDigi->GetSide()]);
      //      LOG(debug)<<" CluCal-TOff: "<<pCalDigi->ToString();

      Double_t dTot = pCalDigi->GetTot() -  // subtract Offset
                      fvCPTotOff[pDigi->GetType()][pDigi->GetSm() * fDigiBdfPar->GetNbRpc(pDigi->GetType())
                                                   + pDigi->GetRpc()][pDigi->GetChannel()][pDigi->GetSide()];
      if (dTot < 0.001) dTot = 0.001;
      pCalDigi->SetTot(dTot *  // calibrate Digi ToT
                       fvCPTotGain[pDigi->GetType()][pDigi->GetSm() * fDigiBdfPar->GetNbRpc(pDigi->GetType())
                                                     + pDigi->GetRpc()][pDigi->GetChannel()][pDigi->GetSide()]);

      // walk correction
      Double_t dTotBinSize = (fdTOTMax - fdTOTMin) / nbClWalkBinX;
      Int_t iWx            = (Int_t)((pCalDigi->GetTot() - fdTOTMin) / dTotBinSize);
      if (0 > iWx) iWx = 0;
      if (iWx >= nbClWalkBinX) iWx = nbClWalkBinX - 1;
      Double_t dDTot = (pCalDigi->GetTot() - fdTOTMin) / dTotBinSize - (Double_t) iWx - 0.5;
      Double_t dWT =
        fvCPWalk[pCalDigi->GetType()][pCalDigi->GetSm() * fDigiBdfPar->GetNbRpc(pCalDigi->GetType())
                                      + pCalDigi->GetRpc()][pCalDigi->GetChannel()][pCalDigi->GetSide()][iWx];
      if (dDTot > 0) {                 // linear interpolation to next bin
        if (iWx < nbClWalkBinX - 1) {  // linear interpolation to next bin

          dWT +=
            dDTot
            * (fvCPWalk[pCalDigi->GetType()][pCalDigi->GetSm() * fDigiBdfPar->GetNbRpc(pCalDigi->GetType())
                                             + pCalDigi->GetRpc()][pCalDigi->GetChannel()][pCalDigi->GetSide()][iWx + 1]
               - fvCPWalk[pCalDigi->GetType()]
                         [pCalDigi->GetSm() * fDigiBdfPar->GetNbRpc(pCalDigi->GetType()) + pCalDigi->GetRpc()]
                         [pCalDigi->GetChannel()][pCalDigi->GetSide()][iWx]);  //memory leak???
        }
      }
      else  // dDTot < 0,  linear interpolation to next bin
      {
        if (0 < iWx) {  // linear interpolation to next bin
          dWT -=
            dDTot
            * (fvCPWalk[pCalDigi->GetType()][pCalDigi->GetSm() * fDigiBdfPar->GetNbRpc(pCalDigi->GetType())
                                             + pCalDigi->GetRpc()][pCalDigi->GetChannel()][pCalDigi->GetSide()][iWx - 1]
               - fvCPWalk[pCalDigi->GetType()]
                         [pCalDigi->GetSm() * fDigiBdfPar->GetNbRpc(pCalDigi->GetType()) + pCalDigi->GetRpc()]
                         [pCalDigi->GetChannel()][pCalDigi->GetSide()][iWx]);  //memory leak???
        }
      }
      pCalDigi->SetTime(pCalDigi->GetTime() - dWT);  // calibrate Digi Time
      // LOG(debug)<<" CluCal-Walk: "<<pCalDigi->ToString();
    }
    else {
      LOG(info) << "Skip1 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);
    }
    if (pCalDigi->GetType() == 5
        || pCalDigi->GetType() == 8) {  // for Pad counters generate fake digi to mockup a strip
      //CbmTofDigi* pCalDigi2 =
      //  new ((*fTofCalDigisColl)[++iDigIndCal]) CbmTofDigi(*pCalDigi);
      fTofCalDigiVec->push_back(CbmTofDigi(*pCalDigi));
      CbmTofDigi* pCalDigi2 = &(fTofCalDigiVec->back());
      iDigIndCal++;
      if (pCalDigi->GetSide() == 0)
        pCalDigi2->SetAddress(pCalDigi->GetSm(), pCalDigi->GetRpc(), pCalDigi->GetChannel(), 1, pCalDigi->GetType());
      else
        pCalDigi2->SetAddress(pCalDigi->GetSm(), pCalDigi->GetRpc(), pCalDigi->GetChannel(), 0, pCalDigi->GetType());
    }
  }  // for( Int_t iDigInd = 0; iDigInd < nTofDigi; iDigInd++ )

  iNbTofDigi = fTofCalDigiVec->size();
  //  fTofCalDigisColl->GetEntriesFast();  // update because of added duplicted digis
  LOG(debug) << "CbmTofHitBuilder: Sort " << fTofCalDigiVec->size() << " calibrated digis ";
  if (iNbTofDigi > 1) {
    //    fTofCalDigisColl->Sort(iNbTofDigi); // Time order again, in case modified by the calibration
    /// Sort the buffers of hits due to the time offsets applied
    std::sort(fTofCalDigiVec->begin(), fTofCalDigiVec->end(),
              [](const CbmTofDigi& a, const CbmTofDigi& b) -> bool { return a.GetTime() < b.GetTime(); });
    //    std::sort(fTofCalDigiVec->begin(), fTofCalDigiVec->end());
    //    if(!fTofCalDigisColl->IsSorted()){
    //    if ( ! std::is_sorted(fTofCalDigiVec->begin(), fTofCalDigiVec->end()))
    if (!std::is_sorted(fTofCalDigiVec->begin(), fTofCalDigiVec->end(),
                        [](const CbmTofDigi& a, const CbmTofDigi& b) -> bool { return a.GetTime() < b.GetTime(); }))
      LOG(warning) << "CbmTofHitBuilder: Digi sorting not successful ";
  }

  if (NULL != pRef) {
    // LOG(debug) << Form("pRef from 0x%08x ",pRef->GetAddress());

    for (Int_t iDigInd = 0; iDigInd < iNbTofDigi; iDigInd++) {
      // pDigi       = (CbmTofDigi*) fTofCalDigisColl->At(iDigInd);
      pDigi       = &(fTofCalDigiVec->at(iDigInd));
      Int_t iAddr = pDigi->GetAddress() & DetMask;
      Int_t iDet  = fDetIdIndexMap[iAddr];  // Detector Index
      Int_t iSide = pDigi->GetSide();
      fhDigiTimesCor->Fill(iDet * 2 + iSide, pDigi->GetTime() - pRefCal->GetTime());
    }
  }
  return kTRUE;
}

/************************************************************************************/
Bool_t CbmDeviceHitBuilderTof::BuildHits()
{
  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 dWeightsSum   = 0.0;
  //vPtsRef.clear();
  vDigiIndRef.clear();
  //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 dTimeDif  = 0.0;
  Double_t dTotS     = 0.0;
  Int_t fiNbSameSide = 0;

  //  gGeoManager->SetTopVolume( gGeoManager->FindVolumeFast("tof_v14a") );
  gGeoManager->SetTopVolume(gGeoManager->FindVolumeFast("cave"));
  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(debug)<<"RPC - Loop  "
		    << Form(" %3d %3d %3d %3d ",iSmType,iSm,iRpc,iChType);
	  */
          fviClusterMul[iSmType][iSm][iRpc] = 0;
          Int_t iChId                       = 0;
          Int_t iDetId                      = CbmTofAddress::GetUniqueAddress(iSm, iRpc, 0, 0, iSmType);
          ;
          Int_t iDetIndx = fDetIdIndexMap[iDetId];  // Detector Index
          if (0 == iChType) {
            // Don't spread clusters over RPCs!!!
            dWeightedTime = 0.0;
            dWeightedPosX = 0.0;
            dWeightedPosY = 0.0;
            dWeightedPosZ = 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;
            //LOG(debug2)<<"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)<<"VDigisize "
                //	    << Form(" T %3d Sm %3d R %3d Ch %3d Size %3lu ",
                //		    iSmType,iSm,iRpc,iCh,fStorStorDigi[iSmType][iSm*iNbRpc+iRpc][iCh].size());
                if (0 == fStorDigi[iSmType][iSm * iNbRpc + iRpc].size()) continue;
                if (fvDeadStrips[iDetIndx] & (1 << iCh)) continue;  // skip over dead channels
                //if( 0 < fStorDigi[iSmType][iSm*iNbRpc+iRpc][iCh].size() )
                //  fhNbDigiPerChan->Fill( fStorDigi[iSmType][iSm*iNbRpc+iRpc][iCh].size() );

                while (1 < fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].size()) {

                  while ((fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh][0])->GetSide()
                         == (fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh][1])->GetSide()) {
                    // Not one Digi of each end!
                    fiNbSameSide++;
                    if (fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].size() > 2) {
                      LOG(debug) << "SameSide Digis! on TSRC " << iSmType << iSm << iRpc << iCh << ", Times: "
                                 << Form("%f", (fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh][0])->GetTime()) << ", "
                                 << Form("%f", (fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh][1])->GetTime())
                                 << ", DeltaT "
                                 << (fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh][1])->GetTime()
                                      - (fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh][0])->GetTime()
                                 << ", array size: " << fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].size();
                      if (fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh][2]->GetSide()
                          == fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh][0]->GetSide()) {
                        LOG(debug) << "3 consecutive SameSide Digis! on TSRC " << iSmType << iSm << iRpc << iCh
                                   << ", Times: " << (fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh][0])->GetTime()
                                   << ", " << (fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh][1])->GetTime()
                                   << ", DeltaT "
                                   << (fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh][1])->GetTime()
                                        - (fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh][0])->GetTime()
                                   << ", array size: " << fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].size();
                        fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                          fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].begin());
                        fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                          fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].begin());
                      }
                      else {
                        if (fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh][2]->GetTime()
                              - fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh][0]->GetTime()
                            > fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh][2]->GetTime()
                                - fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh][1]->GetTime()) {
                          fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                            fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].begin());
                          fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                            fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].begin());
                        }
                        else {
                          LOG(debug) << Form("Ev %8.0f, digis not properly time ordered, TSRCS "
                                             "%d%d%d%d%d ",
                                             fdEvent, iSmType, iSm, iRpc, iCh,
                                             (Int_t) fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh][0]->GetSide());
                          fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                            fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].begin() + 1);
                          fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                            fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].begin() + 1);
                        }
                      }
                    }
                    else {
                      LOG(debug) << "SameSide Erase fStor entries(d) " << iSmType << ", SR " << iSm * iNbRpc + iRpc
                                 << ", Ch" << iCh;
                      fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                        fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].begin());
                      fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                        fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].begin());
                    }
                    if (2 > fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].size()) break;
                    continue;
                  }  // same condition side end
                  LOG(debug) << "digis processing for "
                             << Form(" SmT %3d Sm %3d Rpc %3d Ch %3d # %3lu ", iSmType, iSm, iRpc, iCh,
                                     fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].size());
                  if (2 > fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].size()) {
                    LOG(debug) << Form("Leaving digi processing for TSRC %d%d%d%d, size  %3lu", iSmType, iSm, iRpc, iCh,
                                       fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].size());
                    break;
                  }
                  /* Int_t iLastChId = iChId; // Save Last hit channel*/

                  // 2 Digis = both sides present
                  CbmTofDetectorInfo xDetInfo(ECbmModuleId::kTof, iSmType, iSm, iRpc, 0, iCh);
                  iChId          = fTofId->SetDetectorInfo(xDetInfo);
                  Int_t iUCellId = CbmTofAddress::GetUniqueAddress(iSm, iRpc, iCh, 0, iSmType);
                  LOG(debug) << Form("TSRC %d%d%d%d size %3lu ", iSmType, iSm, iRpc, iCh,
                                     fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].size())
                             << Form(" ChId: 0x%08x 0x%08x ", iChId, iUCellId);
                  fChannelInfo = fDigiPar->GetCell(iChId);

                  if (NULL == fChannelInfo) {
                    LOG(error) << "BuildHits: no geometry info! "
                               << Form(" %3d %3d %3d %3d 0x%08x 0x%08x ", iSmType, iSm, iRpc, iCh, iChId, iUCellId);
                    break;
                  }

                  TGeoNode* fNode =  // prepare local->global trafo
                    gGeoManager->FindNode(fChannelInfo->GetX(), fChannelInfo->GetY(), fChannelInfo->GetZ());
                  //          fNode->Print();
                  if (NULL == fNode) {  // Transformation matrix not available !!!??? - Check
                    LOG(error) << Form("Node at (%6.1f,%6.1f,%6.1f) : %p", fChannelInfo->GetX(), fChannelInfo->GetY(),
                                       fChannelInfo->GetZ(), fNode);
                    ChangeState(fair::mq::Transition::Stop);
                  }

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

                  dTimeDif = (xDigiA->GetTime() - xDigiB->GetTime());
                  if (5 == iSmType && dTimeDif != 0.) {
                    // FIXME -> Overflow treatment in calib/tdc/TMbsCalibTdcTof.cxx
                    LOG(debug) << "BuildHits: Diamond hit in " << iSm << " with inconsistent digits "
                               << xDigiA->GetTime() << ", " << xDigiB->GetTime() << " -> " << dTimeDif;
                    /*
		    LOG(debug) << "    "<<xDigiA->ToString();
		    LOG(debug) << "    "<<xDigiB->ToString();
		    */
                  }
                  if (1 == xDigiA->GetSide())
                    // 0 is the top side, 1 is the bottom side
                    dPosY = fDigiBdfPar->GetSigVel(iSmType, iSm, iRpc) * dTimeDif * 0.5;
                  else
                    // 0 is the bottom side, 1 is the top side
                    dPosY = -fDigiBdfPar->GetSigVel(iSmType, iSm, iRpc) * dTimeDif * 0.5;

                  if (TMath::Abs(dPosY) > fChannelInfo->GetSizey()
                      && fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].size() > 2) {
                    LOG(debug) << "Hit candidate outside correlation window, check for "
                                  "better possible digis, "
                               << " mul " << fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].size();

                    CbmTofDigi* xDigiC = fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh][2];
                    Double_t dPosYN    = 0.;
                    Double_t dTimeDifN = 0;
                    if (xDigiC->GetSide() == xDigiA->GetSide()) dTimeDifN = xDigiC->GetTime() - xDigiB->GetTime();
                    else
                      dTimeDifN = xDigiA->GetTime() - xDigiC->GetTime();

                    if (1 == xDigiA->GetSide()) dPosYN = fDigiBdfPar->GetSigVel(iSmType, iSm, iRpc) * dTimeDifN * 0.5;
                    else
                      dPosYN = -fDigiBdfPar->GetSigVel(iSmType, iSm, iRpc) * dTimeDifN * 0.5;

                    if (TMath::Abs(dPosYN) < TMath::Abs(dPosY)) {
                      LOG(debug) << "Replace digi on side " << xDigiC->GetSide() << ", yPosNext " << dPosYN
                                 << " old: " << dPosY;
                      dTimeDif = dTimeDifN;
                      dPosY    = dPosYN;
                      if (xDigiC->GetSide() == xDigiA->GetSide()) {
                        xDigiA = xDigiC;
                        fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                          fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].begin());
                        fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                          fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].begin());
                      }
                      else {
                        xDigiB = xDigiC;
                        fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                          ++(fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].begin() + 1));
                        fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                          ++(fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].begin() + 1));
                      }
                    }
                  }
                  if (xDigiA->GetSide() == xDigiB->GetSide()) {
                    LOG(error) << "Wrong combinations of digis " << fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh][0]
                               << "," << fStorDigiInd[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();

                  // use local coordinates, (0,0,0) is in the center of counter  ?
                  dPosX = ((Double_t)(-iNbCh / 2 + iCh) + 0.5) * fChannelInfo->GetSizex();
                  dPosZ = 0.;

                  /*
		  LOG(debug)
		    <<"NbChanInHit  "
		    << Form(" %3d %3d %3d %3d %3d 0x%p %1.0f Time %f PosX %f PosY %f Svel %f ",
			    iNbChanInHit,iSmType,iRpc,iCh,iLastChan,xDigiA,xDigiA->GetSide(),
			    dTime,dPosX,dPosY,fDigiBdfPar->GetSigVel(iSmType,iSm,iRpc))
		    //  << Form( ", Offs %f, %f ",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) < fdMaxTimeDist && iLastChan == iCh - 1
                        && TMath::Abs(dPosY - dLastPosY) < fdMaxSpaceDist) {
                      // Add to cluster/hit
                      dWeightedTime += dTime * dTotS;
                      dWeightedPosX += dPosX * dTotS;
                      dWeightedPosY += dPosY * dTotS;
                      dWeightedPosZ += dPosZ * dTotS;
                      dWeightsSum += dTotS;
                      iNbChanInHit += 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(debug) << " Add Digi and erase fStor entries(a): NbChanInHit " << iNbChanInHit << ", "
                                 << iSmType << ", SR " << iSm * iNbRpc + iRpc << ", Ch" << iCh;

                      fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                        fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].begin());
                      fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                        fStorDigi[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;
                      //  TVector3 hitPosLocal(dWeightedPosX, dWeightedPosY, dWeightedPosZ);
                      //TVector3 hitPos;
                      Double_t hitpos_local[3];
                      hitpos_local[0] = dWeightedPosX;
                      hitpos_local[1] = dWeightedPosY;
                      hitpos_local[2] = dWeightedPosZ;

                      Double_t hitpos[3];
                      //TGeoNode*         cNode   =
                      gGeoManager->GetCurrentNode();
                      /*TGeoHMatrix* cMatrix =*/gGeoManager->GetCurrentMatrix();
                      //cNode->Print();
                      //cMatrix->Print();
                      gGeoManager->LocalToMaster(hitpos_local, hitpos);
                      /*
		      LOG(debug)<<
			Form("LocalToMaster for node %p: (%6.1f,%6.1f,%6.1f) ->(%6.1f,%6.1f,%6.1f)",
			     cNode, 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
                      TVector3 hitPosErr(0.5, 0.5, 0.5);  // including positioning uncertainty
                      /*
			TVector3 hitPosErr( fChannelInfo->GetSizex()/TMath::Sqrt(12.0),   // Single strips approximation
			0.5, // Use generic value
			1.);

		      */
                      //fDigiBdfPar->GetFeeTimeRes() * fDigiBdfPar->GetSigVel(iSmType,iRpc), // Use the electronics resolution
                      //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

                      // 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 = floor(dWeightedPosX / fChannelInfo->GetSizex()) + iNbCh / 2;
                      if (iChm < 0) iChm = 0;
                      if (iChm > iNbCh - 1) iChm = iNbCh - 1;
                      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)<<"Save Hit  "
				<< Form(" %3d %3d 0x%08x %3d %3d %3d %f %f",
					fiNbHits,iNbChanInHit,iDetId,iChm,iLastChan,iRefId,
					dWeightedTime,dWeightedPosY)
				<<", DigiSize: "<<vDigiIndRef.size()
				<<", DigiInds: ";
		      for (UInt_t i=0; i<vDigiIndRef.size();i++){
			LOG(debug)<<" "<<vDigiIndRef.at(i)<<"(M"<<fviClusterMul[iSmType][iSm][iRpc]<<")";
		      }
		      */

                      fviClusterMul[iSmType][iSm][iRpc]++;
                      if (vDigiIndRef.size() < 2) {
                        LOG(warn) << "Digi refs for Hit " << fiNbHits << ": " << vDigiIndRef.size();
                      }
                      if (fiNbHits > 0) {
                        CbmTofHit* pHitL = (CbmTofHit*) fTofHitsColl->At(fiNbHits - 1);
                        if (iDetId == pHitL->GetAddress() && dWeightedTime == pHitL->GetTime()) {
                          LOG(debug) << "Store Hit twice? "
                                     << " fiNbHits " << fiNbHits << ", " << Form("0x%08x", iDetId);
                        }
                      }
                      CbmTofHit* pHit =
                        new CbmTofHit(iDetId, hitPos,
                                      hitPosErr,  //local detector coordinates
                                      fiNbHits,   // this number is used as reference!!
                                      dWeightedTime,
                                      vDigiIndRef.size(),  // number of linked digis =  2*CluSize
                                      //vPtsRef.size(), // flag  = number of TofPoints generating the cluster
                                      Int_t(dWeightsSum * 10.));  //channel -> Tot
                      //0) ; //channel
                      // output hit
                      new ((*fTofHitsColl)[fiNbHits]) CbmTofHit(*pHit);
                      // memorize hit
                      if (fdMemoryTime > 0.) { LH_store(iSmType, iSm, iRpc, iChm, pHit); }
                      else {
                        pHit->Delete();
                      }
                      /*
			new((*fTofDigiMatchColl)[fiNbHits]) CbmMatch();
			CbmMatch* digiMatch = (CbmMatch *)fTofDigiMatchColl->At(fiNbHits);
		      */
                      CbmMatch* digiMatch = new ((*fTofDigiMatchColl)[fiNbHits]) CbmMatch();
                      for (UInt_t i = 0; i < vDigiIndRef.size(); i++) {
                        Double_t dTot = ((CbmTofDigi*) (&(fTofCalDigiVec->at(vDigiIndRef.at(i)))))->GetTot();
                        digiMatch->AddLink(CbmLink(dTot, vDigiIndRef.at(i), fiOutputTreeEntry, fiFileIndex));
                      }

                      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;
                      dWeightsSum   = dTotS;
                      iNbChanInHit  = 1;
                      // Save pointer on CbmTofPoint
                      // vPtsRef.push_back( (CbmTofPoint*)(xDigiA->GetLinks()) );
                      // Save next digi address

                      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(b) "<<iSmType<<", SR "<<iSm*iNbRpc+iRpc<<", Ch"<<iCh;

                      fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                        fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].begin());
                      fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                        fStorDigi[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());
                    }  // else of if current Digis compatible with last fired chan
                  }    // if( 0 < iNbChanInHit)
                  else {
                    LOG(debug) << Form("1.Hit on channel %d, time: %f, PosY %f", iCh, dTime, dPosY);

                    // first fired strip in this RPC
                    dWeightedTime = dTime * dTotS;
                    dWeightedPosX = dPosX * dTotS;
                    dWeightedPosY = dPosY * dTotS;
                    dWeightedPosZ = dPosZ * 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(debug)<<"Erase fStor entries(c) "<<iSmType<<", SR "<<iSm*iNbRpc+iRpc<<", Ch"<<iCh;

                    fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                      fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].begin());
                    fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                      fStorDigi[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());

                  }  // else of if( 0 < iNbChanInHit)
                  iLastChan = iCh;
                  dLastPosX = dPosX;
                  dLastPosY = dPosY;
                  dLastTime = dTime;
                  if (AddNextChan(iSmType, iSm, iRpc, iLastChan, dLastPosX, dLastPosY, dLastTime, dWeightsSum)) {
                    iNbChanInHit = 0;  // cluster already stored
                  }
                }  // while( 1 < fStorDigi[iSmType][iSm*iNbRpc+iRpc][iCh].size() )
                fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].clear();
                fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].clear();
              }  // for( Int_t iCh = 0; iCh < iNbCh; iCh++ )
              //LOG(debug2)<<"finished V-RPC"
              //		  << Form(" %3d %3d %3d %d %f %fx",iSmType,iSm,iRpc,fTofHitsColl->GetEntriesFast(),dLastPosX,dLastPosY);
            }  // else of if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
          }    // if( 0 == iChType)
          else {
            LOG(error) << "=> 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(debug)<<"Process cluster "
		      <<iNbChanInHit;
	    */
            // Check orientation to properly assign errors
            if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc)) {
              // LOG(debug1)<<"H-Hit ";
            }  // if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
            else {
              //LOG(debug2)<<"V-Hit ";
              // Save Hit
              dWeightedTime /= dWeightsSum;
              dWeightedPosX /= dWeightsSum;
              dWeightedPosY /= dWeightsSum;
              dWeightedPosZ /= dWeightsSum;
              //TVector3 hitPos(dWeightedPosX, dWeightedPosY, dWeightedPosZ);

              Double_t hitpos_local[3] = {3 * 0.};
              hitpos_local[0]          = dWeightedPosX;
              hitpos_local[1]          = dWeightedPosY;
              hitpos_local[2]          = dWeightedPosZ;

              Double_t hitpos[3];
              //TGeoNode*        cNode=
              gGeoManager->GetCurrentNode();
              /*TGeoHMatrix* cMatrix =*/gGeoManager->GetCurrentMatrix();
              //cNode->Print();
              //cMatrix->Print();

              gGeoManager->LocalToMaster(hitpos_local, hitpos);
              /*
	      LOG(debug)<<
		Form(" LocalToMaster for V-node %p: (%6.1f,%6.1f,%6.1f) ->(%6.1f,%6.1f,%6.1f)",
		     cNode, hitpos_local[0], hitpos_local[1], hitpos_local[2],
		     hitpos[0], hitpos[1], hitpos[2])
		;
	      */
              TVector3 hitPos(hitpos[0], hitpos[1], hitpos[2]);
              // Event 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
              TVector3 hitPosErr(0.5, 0.5, 0.5);  // including positioning uncertainty
              /*
		TVector3 hitPosErr( fChannelInfo->GetSizex()/TMath::Sqrt(12.0),   // Single strips approximation
		0.5, // Use generic value
		1.);
	      */
              Int_t iChm = floor(dWeightedPosX / fChannelInfo->GetSizex()) + iNbCh / 2;
              if (iChm < 0) iChm = 0;
              if (iChm > iNbCh - 1) iChm = iNbCh - 1;
              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)<<"Save V-Hit  "
			<< Form(" %3d %3d 0x%08x %3d 0x%08x", // %3d %3d
				fiNbHits,iNbChanInHit,iDetId,iLastChan,iRefId) //vPtsRef.size(),vPtsRef[0])
		//   dWeightedTime,dWeightedPosY)
			<<", DigiSize: "<<vDigiIndRef.size();
	      for (UInt_t i=0; i<vDigiIndRef.size();i++){
		LOG(debug)<<"DigiIndRef "<<i<<" "<<vDigiIndRef.at(i)<<"(M"<<fviClusterMul[iSmType][iSm][iRpc]<<")";
	      }
	      */
              fviClusterMul[iSmType][iSm][iRpc]++;
              if (vDigiIndRef.size() < 2) {
                LOG(warn) << "Digi refs for Hit " << fiNbHits << ":  " << vDigiIndRef.size();
              }
              if (fiNbHits > 0) {
                CbmTofHit* pHitL = (CbmTofHit*) fTofHitsColl->At(fiNbHits - 1);
                if (iDetId == pHitL->GetAddress() && dWeightedTime == pHitL->GetTime())
                  LOG(debug) << "Store Hit twice? "
                             << " fiNbHits " << fiNbHits << ", " << Form("0x%08x", iDetId);
              }

              CbmTofHit* pHit = new CbmTofHit(iDetId, hitPos,
                                              hitPosErr,  //local detector coordinates
                                              fiNbHits,   // this number is used as reference!!
                                              dWeightedTime,
                                              vDigiIndRef.size(),  // number of linked digis =  2*CluSize
                                              //vPtsRef.size(), // flag  = number of TofPoints generating the cluster
                                              Int_t(dWeightsSum * 10.));  //channel -> Tot
              //                0) ; //channel
              //                vDigiIndRef);
              // output hit
              new ((*fTofHitsColl)[fiNbHits]) CbmTofHit(*pHit);
              // memorize hit
              if (fdMemoryTime > 0.) { LH_store(iSmType, iSm, iRpc, iChm, pHit); }
              else {
                pHit->Delete();
              }
              /*
		new((*fTofDigiMatchColl)[fiNbHits]) CbmMatch();
		CbmMatch* digiMatch = (CbmMatch *)fTofDigiMatchColl->At(fiNbHits);
	      */
              CbmMatch* digiMatch = new ((*fTofDigiMatchColl)[fiNbHits]) CbmMatch();
              for (UInt_t i = 0; i < vDigiIndRef.size(); i++) {
                Double_t dTot = ((CbmTofDigi*) (&(fTofCalDigiVec->at(vDigiIndRef.at(i)))))->GetTot();
                digiMatch->AddLink(CbmLink(dTot, vDigiIndRef.at(i), fiOutputTreeEntry, fiFileIndex));
              }

              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)
        }      // for each sm/rpc pair
    }          // for( Int_t iSmType = 0; iSmType < iNbSmTypes; iSmType++ )
  }

  return kTRUE;
}

/************************************************************************************/
Bool_t CbmDeviceHitBuilderTof::MergeClusters() { return kTRUE; }

void CbmDeviceHitBuilderTof::LH_store(Int_t iSmType, Int_t iSm, Int_t iRpc, Int_t iChm, CbmTofHit* pHit)
{

  if (fvLastHits[iSmType][iSm][iRpc][iChm].size() == 0) fvLastHits[iSmType][iSm][iRpc][iChm].push_back(pHit);
  else {
    Double_t dLastTime = pHit->GetTime();
    if (dLastTime >= fvLastHits[iSmType][iSm][iRpc][iChm].back()->GetTime()) {
      fvLastHits[iSmType][iSm][iRpc][iChm].push_back(pHit);
      LOG(debug) << Form(" Store LH from Ev  %8.0f for TSRC %d%d%d%d, size %lu, addr 0x%08x, "
                         "time %f, dt %f",
                         fdEvent, iSmType, iSm, iRpc, iChm, fvLastHits[iSmType][iSm][iRpc][iChm].size(),
                         pHit->GetAddress(), dLastTime,
                         dLastTime - fvLastHits[iSmType][iSm][iRpc][iChm].front()->GetTime());
    }
    else {
      if (dLastTime
          >= fvLastHits[iSmType][iSm][iRpc][iChm].front()->GetTime()) {  // hit has to be inserted in the proper place
        std::list<CbmTofHit*>::iterator it;
        for (it = fvLastHits[iSmType][iSm][iRpc][iChm].begin(); it != fvLastHits[iSmType][iSm][iRpc][iChm].end(); ++it)
          if ((*it)->GetTime() > dLastTime) break;
        fvLastHits[iSmType][iSm][iRpc][iChm].insert(--it, pHit);
        Double_t deltaTime = dLastTime - (*it)->GetTime();
        LOG(debug) << Form("Hit inserted into LH from Ev  %8.0f for TSRC "
                           "%d%d%d%d, size %lu, addr 0x%08x, delta time %f  ",
                           fdEvent, iSmType, iSm, iRpc, iChm, fvLastHits[iSmType][iSm][iRpc][iChm].size(),
                           pHit->GetAddress(), deltaTime);
      }
      else {  // this hit is first
        Double_t deltaTime = dLastTime - fvLastHits[iSmType][iSm][iRpc][iChm].front()->GetTime();
        LOG(debug) << Form("first LH from Ev  %8.0f for TSRC %d%d%d%d, size "
                           "%lu, addr 0x%08x, delta time %f ",
                           fdEvent, iSmType, iSm, iRpc, iChm, fvLastHits[iSmType][iSm][iRpc][iChm].size(),
                           pHit->GetAddress(), deltaTime);
        if (deltaTime == 0.) {
          // remove hit, otherwise double entry?
          pHit->Delete();
        }
        else {
          fvLastHits[iSmType][iSm][iRpc][iChm].push_front(pHit);
        }
      }
    }
  }
}

void CbmDeviceHitBuilderTof::CheckLHMemory()
{
  if ((Int_t) fvLastHits.size() != fDigiBdfPar->GetNbSmTypes())
    LOG(error) << Form("Inconsistent LH Smtype size %lu, %d ", fvLastHits.size(), fDigiBdfPar->GetNbSmTypes());

  for (Int_t iSmType = 0; iSmType < fDigiBdfPar->GetNbSmTypes(); iSmType++) {
    if ((Int_t) fvLastHits[iSmType].size() != fDigiBdfPar->GetNbSm(iSmType))
      LOG(error) << Form("Inconsistent LH Sm size %lu, %d T %d", fvLastHits[iSmType].size(),
                         fDigiBdfPar->GetNbSm(iSmType), iSmType);
    for (Int_t iSm = 0; iSm < fDigiBdfPar->GetNbSm(iSmType); iSm++) {
      if ((Int_t) fvLastHits[iSmType][iSm].size() != fDigiBdfPar->GetNbRpc(iSmType))
        LOG(error) << Form("Inconsistent LH Rpc size %lu, %d TS %d%d ", fvLastHits[iSmType][iSm].size(),
                           fDigiBdfPar->GetNbRpc(iSmType), iSmType, iSm);
      for (Int_t iRpc = 0; iRpc < fDigiBdfPar->GetNbRpc(iSmType); iRpc++) {
        if ((Int_t) fvLastHits[iSmType][iSm][iRpc].size() != fDigiBdfPar->GetNbChan(iSmType, iRpc))
          LOG(error) << Form("Inconsistent LH RpcChannel size %lu, %d TSR %d%d%d ",
                             fvLastHits[iSmType][iSm][iRpc].size(), fDigiBdfPar->GetNbChan(iSmType, iRpc), iSmType, iSm,
                             iRpc);
        for (Int_t iCh = 0; iCh < fDigiBdfPar->GetNbChan(iSmType, iRpc); iCh++)
          if (fvLastHits[iSmType][iSm][iRpc][iCh].size() > 0) {
            CbmTofDetectorInfo xDetInfo(ECbmModuleId::kTof, iSmType, iSm, iRpc, 0, iCh);
            Int_t iAddr = fTofId->SetDetectorInfo(xDetInfo);
            if (fvLastHits[iSmType][iSm][iRpc][iCh].front()->GetAddress() != iAddr)
              LOG(error) << Form("Inconsistent address for Ev %8.0f in list of size %lu for "
                                 "TSRC %d%d%d%d: 0x%08x, time  %f",
                                 fdEvent, fvLastHits[iSmType][iSm][iRpc][iCh].size(), iSmType, iSm, iRpc, iCh,
                                 fvLastHits[iSmType][iSm][iRpc][iCh].front()->GetAddress(),
                                 fvLastHits[iSmType][iSm][iRpc][iCh].front()->GetTime());
          }
      }
    }
  }
  LOG(debug) << Form("LH check passed for event %8.0f", fdEvent);
}

void CbmDeviceHitBuilderTof::CleanLHMemory()
{
  if ((Int_t) fvLastHits.size() != fDigiBdfPar->GetNbSmTypes())
    LOG(error) << Form("Inconsistent LH Smtype size %lu, %d ", fvLastHits.size(), fDigiBdfPar->GetNbSmTypes());
  for (Int_t iSmType = 0; iSmType < fDigiBdfPar->GetNbSmTypes(); iSmType++) {
    if ((Int_t) fvLastHits[iSmType].size() != fDigiBdfPar->GetNbSm(iSmType))
      LOG(error) << Form("Inconsistent LH Sm size %lu, %d T %d", fvLastHits[iSmType].size(),
                         fDigiBdfPar->GetNbSm(iSmType), iSmType);
    for (Int_t iSm = 0; iSm < fDigiBdfPar->GetNbSm(iSmType); iSm++) {
      if ((Int_t) fvLastHits[iSmType][iSm].size() != fDigiBdfPar->GetNbRpc(iSmType))
        LOG(error) << Form("Inconsistent LH Rpc size %lu, %d TS %d%d ", fvLastHits[iSmType][iSm].size(),
                           fDigiBdfPar->GetNbRpc(iSmType), iSmType, iSm);
      for (Int_t iRpc = 0; iRpc < fDigiBdfPar->GetNbRpc(iSmType); iRpc++) {
        if ((Int_t) fvLastHits[iSmType][iSm][iRpc].size() != fDigiBdfPar->GetNbChan(iSmType, iRpc))
          LOG(error) << Form("Inconsistent LH RpcChannel size %lu, %d TSR %d%d%d ",
                             fvLastHits[iSmType][iSm][iRpc].size(), fDigiBdfPar->GetNbChan(iSmType, iRpc), iSmType, iSm,
                             iRpc);
        for (Int_t iCh = 0; iCh < fDigiBdfPar->GetNbChan(iSmType, iRpc); iCh++)
          while (fvLastHits[iSmType][iSm][iRpc][iCh].size() > 0) {
            CbmTofDetectorInfo xDetInfo(ECbmModuleId::kTof, iSmType, iSm, iRpc, 0, iCh);
            Int_t iAddr = fTofId->SetDetectorInfo(xDetInfo);
            if (fvLastHits[iSmType][iSm][iRpc][iCh].front()->GetAddress() != iAddr)
              LOG(error) << Form("Inconsistent address for Ev %8.0f in list of size %lu for "
                                 "TSRC %d%d%d%d: 0x%08x, time  %f",
                                 fdEvent, fvLastHits[iSmType][iSm][iRpc][iCh].size(), iSmType, iSm, iRpc, iCh,
                                 fvLastHits[iSmType][iSm][iRpc][iCh].front()->GetAddress(),
                                 fvLastHits[iSmType][iSm][iRpc][iCh].front()->GetTime());
            fvLastHits[iSmType][iSm][iRpc][iCh].front()->Delete();
            fvLastHits[iSmType][iSm][iRpc][iCh].pop_front();
          }
      }
    }
  }
  LOG(info) << Form("LH cleaning done after %8.0f events", fdEvent);
}

Bool_t CbmDeviceHitBuilderTof::AddNextChan(Int_t iSmType, Int_t iSm, Int_t iRpc, Int_t iLastChan, Double_t dLastPosX,
                                           Double_t dLastPosY, Double_t dLastTime, Double_t dLastTotS)
{
  //Int_t iNbSm  = fDigiBdfPar->GetNbSm(  iSmType);
  Int_t iNbRpc = fDigiBdfPar->GetNbRpc(iSmType);
  Int_t iNbCh  = fDigiBdfPar->GetNbChan(iSmType, iRpc);
  //  Int_t iChType = fDigiBdfPar->GetChanType( iSmType, iRpc );

  Int_t iCh = iLastChan + 1;
  LOG(debug) << Form("Inspect channel TSRC %d%d%d%d at time %f, pos %f, size ", iSmType, iSm, iRpc, iCh, dLastTime,
                     dLastPosY)
             << fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].size();
  if (iCh == iNbCh) return kFALSE;
  if (0 == fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].size()) return kFALSE;
  //if( 0 < fStorDigi[iSmType][iSm*iNbRpc+iRpc][iCh].size() )
  //   fhNbDigiPerChan->Fill( fStorDigi[iSmType][iSm*iNbRpc+iRpc][iCh].size() );
  if (1 < fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].size()) {
    Bool_t AddedHit = kFALSE;
    for (Int_t i1 = 0; i1 < (Int_t) fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].size() - 1; i1++) {
      if (AddedHit) break;
      Int_t i2 = i1 + 1;
      while (!AddedHit && i2 < (Int_t) fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].size()) {
        // LOG(debug)<<"check digi pair "<<i1<<","<<i2<<" with size "<<fStorDigi[iSmType][iSm*iNbRpc+iRpc][iCh].size();

        if ((fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh][i1])->GetSide()
            == (fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh][i2])->GetSide()) {
          i2++;
          continue;
        }  // endif same side
           // 2 Digis, both sides present
        CbmTofDigi* xDigiA = fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh][i1];
        CbmTofDigi* xDigiB = fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh][i2];
        Double_t dTime     = 0.5 * (xDigiA->GetTime() + xDigiB->GetTime());
        if (TMath::Abs(dTime - dLastTime) < fdMaxTimeDist) {
          CbmTofDetectorInfo xDetInfo(ECbmModuleId::kTof, iSmType, iSm, iRpc, 0, iCh);
          Int_t iChId  = fTofId->SetDetectorInfo(xDetInfo);
          fChannelInfo = fDigiPar->GetCell(iChId);
          gGeoManager->FindNode(fChannelInfo->GetX(), fChannelInfo->GetY(), fChannelInfo->GetZ());

          Double_t dTimeDif = xDigiA->GetTime() - xDigiB->GetTime();
          Double_t dPosY    = 0.;
          if (1 == xDigiA->GetSide()) dPosY = fDigiBdfPar->GetSigVel(iSmType, iSm, iRpc) * dTimeDif * 0.5;
          else
            dPosY = -fDigiBdfPar->GetSigVel(iSmType, iSm, iRpc) * dTimeDif * 0.5;

          if (TMath::Abs(dPosY - dLastPosY) < fdMaxSpaceDist) {  // append digi pair to current cluster

            Double_t dNClHits = (Double_t)(vDigiIndRef.size() / 2);
            Double_t dPosX    = ((Double_t)(-iNbCh / 2 + iCh) + 0.5) * fChannelInfo->GetSizex();
            Double_t dTotS    = xDigiA->GetTot() + xDigiB->GetTot();
            Double_t dNewTotS = (dLastTotS + dTotS);
            dLastPosX         = (dLastPosX * dLastTotS + dPosX * dTotS) / dNewTotS;
            dLastPosY         = (dLastPosY * dLastTotS + dPosY * dTotS) / dNewTotS;
            dLastTime         = (dLastTime * dLastTotS + dTime * dTotS) / dNewTotS;
            dLastTotS         = dNewTotS;
            // attach selected digis from pool
            Int_t Ind1 = fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh][i1];
            Int_t Ind2 = fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh][i2];
            vDigiIndRef.push_back(Ind1);
            vDigiIndRef.push_back(Ind2);
            // remove selected digis from pool
            fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].erase(fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].begin()
                                                               + i1);
            fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
              fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].begin() + i1);

            std::vector<int>::iterator it;
            it = find(fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].begin(),
                      fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].end(), Ind2);
            if (it != fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].end()) {
              auto ipos = it - fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].begin();
              LOG(debug) << "Found i2 " << i2 << " with Ind2 " << Ind2 << " at position " << ipos;
              fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].erase(fStorDigi[iSmType][iSm * iNbRpc + iRpc][iCh].begin()
                                                                 + ipos);
              fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].erase(
                fStorDigiInd[iSmType][iSm * iNbRpc + iRpc][iCh].begin() + ipos);
            }
            else {
              LOG(error) << " Did not find  i2 " << i2 << " with Ind2 " << Ind2;
            }

            //if(iCh == iNbCh-1) break;  //Last strip reached
            if (iCh != (iNbCh - 1)
                && AddNextChan(iSmType, iSm, iRpc, iCh, dLastPosX, dLastPosY, dLastTime, dLastTotS)) {
              LOG(debug) << "Added Strip " << iCh << " to cluster of size " << dNClHits;
              return kTRUE;  // signal hit was already added
            }
            AddedHit = kTRUE;
          }  //TMath::Abs(dPosY - dLastPosY) < fdMaxSpaceDist
        }    //TMath::Abs(dTime-dLastTime)<fdMaxTimeDist)
        i2++;
      }  //  while(i2 < fStorDigi[iSmType][iSm*iNbRpc+iRpc][iCh].size()-1 )
    }    // end for i1
  }      // end if size
  Double_t hitpos_local[3] = {3 * 0.};
  hitpos_local[0]          = dLastPosX;
  hitpos_local[1]          = dLastPosY;
  hitpos_local[2]          = 0.;
  Double_t hitpos[3];

  TGeoNode* cNode = gGeoManager->GetCurrentNode();
  if (NULL == cNode) {  // Transformation matrix not available !!!??? - Check
    LOG(error) << Form("Node at (%6.1f,%6.1f,%6.1f) : %p", fChannelInfo->GetX(), fChannelInfo->GetY(),
                       fChannelInfo->GetZ(), cNode);
    ChangeState(fair::mq::Transition::Stop);
  }

  /*TGeoHMatrix* cMatrix = */ gGeoManager->GetCurrentMatrix();
  gGeoManager->LocalToMaster(hitpos_local, hitpos);
  TVector3 hitPos(hitpos[0], hitpos[1], hitpos[2]);
  TVector3 hitPosErr(0.5, 0.5, 0.5);  // FIXME including positioning uncertainty
  Int_t iChm = floor(dLastPosX / fChannelInfo->GetSizex()) + iNbCh / 2;
  if (iChm < 0) iChm = 0;
  if (iChm > iNbCh - 1) iChm = iNbCh - 1;
  Int_t iDetId = CbmTofAddress::GetUniqueAddress(iSm, iRpc, iChm, 0, iSmType);

  //  Int_t iNbChanInHit=vDigiIndRef.size()/2;
  fviClusterMul[iSmType][iSm][iRpc]++;
  /*
  LOG(debug)<<"Save A-Hit "
            << Form("%2d %2d 0x%08x %3d t %f, y %f ",
		    fiNbHits,iNbChanInHit,iDetId,iLastChan,dLastTime,dLastPosY)
            <<", DigiSize: "<<vDigiIndRef.size();
  for (UInt_t i=0; i<vDigiIndRef.size();i++){
    LOG(debug)<<"DigiIndRef "<<i<<" "<<vDigiIndRef.at(i)<<"(M"<<fviClusterMul[iSmType][iSm][iRpc]<<")";
  }
  */
  CbmTofHit* pHit = new CbmTofHit(iDetId, hitPos,
                                  hitPosErr,  //local detector coordinates
                                  fiNbHits,   // this number is used as reference!!
                                  dLastTime,
                                  vDigiIndRef.size(),  // number of linked digis =  2*CluSize
                                  //vPtsRef.size(), // flag  = number of TofPoints generating the cluster
                                  Int_t(dLastTotS * 10.));  //channel -> Tot
  // output hit
  new ((*fTofHitsColl)[fiNbHits]) CbmTofHit(*pHit);
  if (fdMemoryTime > 0.) {  // memorize hit
    LH_store(iSmType, iSm, iRpc, iChm, pHit);
  }
  else {
    pHit->Delete();
  }
  CbmMatch* digiMatch = new ((*fTofDigiMatchColl)[fiNbHits]) CbmMatch();
  for (Int_t i = 0; i < (Int_t) vDigiIndRef.size(); i++) {
    Double_t dTot = ((CbmTofDigi*) (&(fTofCalDigiVec->at(vDigiIndRef.at(i)))))->GetTot();
    digiMatch->AddLink(CbmLink(dTot, vDigiIndRef.at(i), fiOutputTreeEntry, fiFileIndex));
  }
  fiNbHits++;
  vDigiIndRef.clear();

  return kTRUE;
}

static Double_t f1_xboxe(double* x, double* par)
{
  double xx    = x[0];
  double wx    = 1. - par[4] * TMath::Power(xx + par[5], 2);
  double xboxe = par[0] * 0.25 * (1. + TMath::Erf((xx + par[1] - par[3]) / par[2]))
                 * (1. + TMath::Erf((-xx + par[1] + par[3]) / par[2]));
  return xboxe * wx;
}

void CbmDeviceHitBuilderTof::fit_ybox(const char* hname)
{
  TH1* h1;
  h1 = (TH1*) gROOT->FindObjectAny(hname);
  if (NULL != h1) { fit_ybox(h1, 0.); }
}

void CbmDeviceHitBuilderTof::fit_ybox(TH1* h1, Double_t ysize)
{
  Double_t* fpar = NULL;
  fit_ybox(h1, ysize, fpar);
}

void CbmDeviceHitBuilderTof::fit_ybox(TH1* h1, Double_t ysize, Double_t* fpar = NULL)
{
  TAxis* xaxis  = h1->GetXaxis();
  Double_t Ymin = xaxis->GetXmin();
  Double_t Ymax = xaxis->GetXmax();
  TF1* f1       = new TF1("YBox", f1_xboxe, Ymin, Ymax, 6);
  Double_t yini = (h1->GetMaximum() + h1->GetMinimum()) * 0.5;
  if (ysize == 0.) ysize = Ymax * 0.8;
  f1->SetParameters(yini, ysize * 0.5, 1., 0., 0., 0.);
  //  f1->SetParLimits(1,ysize*0.8,ysize*1.2);
  f1->SetParLimits(2, 0.2, 3.);
  f1->SetParLimits(3, -4., 4.);
  if (fpar != NULL) {
    Double_t fp[4];
    for (Int_t i = 0; i < 4; i++)
      fp[i] = *fpar++;
    for (Int_t i = 0; i < 4; i++)
      f1->SetParameter(2 + i, fp[i]);
    LOG(debug) << "Ini Fpar for " << h1->GetName() << " with "
               << Form(" %6.3f %6.3f %6.3f %6.3f ", fp[0], fp[1], fp[2], fp[3]);
  }

  h1->Fit("YBox", "Q");

  double res[10];
  double err[10];
  res[9] = f1->GetChisquare();

  for (int i = 0; i < 6; i++) {
    res[i] = f1->GetParameter(i);
    err[i] = f1->GetParError(i);
    //cout << " FPar "<< i << ": " << res[i] << ", " << err[i] << endl;
  }
  LOG(debug) << "YBox Fit of " << h1->GetName() << " ended with chi2 = " << res[9]
             << Form(", strip length %7.2f +/- %5.2f, position resolution "
                     "%7.2f +/- %5.2f at y_cen = %7.2f +/- %5.2f",
                     2. * res[1], 2. * err[1], res[2], err[2], res[3], err[3]);
}

Bool_t CbmDeviceHitBuilderTof::LoadGeometry()
{
  LOG(info) << "LoadGeometry starting for  " << fDigiBdfPar->GetNbDet() << " described detectors, "
            << fDigiPar->GetNrOfModules() << " geometrically known modules ";

  //gGeoManager->Export("HitBuilder.loadgeo.root");  // write current status to file

  Int_t iNrOfCells = fDigiPar->GetNrOfModules();
  LOG(info) << "Digi Parameter container contains " << iNrOfCells << " cells.";

  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(debug) << "-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;

    TGeoNode* fNode =  // prepare local->global trafo
      gGeoManager->FindNode(fChannelInfo->GetX(), fChannelInfo->GetY(), fChannelInfo->GetZ());

    if (NULL == fNode) {  // Transformation matrix not available !!!??? - Check
      LOG(error) << Form("Node at (%6.1f,%6.1f,%6.1f) : %p", fChannelInfo->GetX(), fChannelInfo->GetY(),
                         fChannelInfo->GetZ(), fNode);
      ChangeState(fair::mq::Transition::Stop);
    }
    if (icell == 0) {
      TGeoHMatrix* cMatrix = gGeoManager->GetCurrentMatrix();
      //cNode->Print();
      cMatrix->Print();
    }
  }

  Int_t iNbDet = fDigiBdfPar->GetNbDet();
  fvDeadStrips.resize(iNbDet);
  fvPulserOffset.resize(iNbDet);
  fvPulserTimes.resize(iNbDet);

  for (Int_t iDetIndx = 0; iDetIndx < iNbDet; iDetIndx++) {
    Int_t iUniqueId = fDigiBdfPar->GetDetUId(iDetIndx);
    Int_t iSmType   = CbmTofAddress::GetSmType(iUniqueId);
    Int_t iSmId     = CbmTofAddress::GetSmId(iUniqueId);
    Int_t iRpcId    = CbmTofAddress::GetRpcId(iUniqueId);
    LOG(info) << " DetIndx " << iDetIndx << "(" << iNbDet << "), SmType " << iSmType << ", SmId " << iSmId << ", RpcId "
              << iRpcId << " => UniqueId " << Form("0x%08x ", iUniqueId)
              << Form(" Svel %6.6f, DeadStrips 0x%08x ", fDigiBdfPar->GetSigVel(iSmType, iSmId, iRpcId),
                      fvDeadStrips[iDetIndx]);

    Int_t iCell = -1;
    while (kTRUE) {
      Int_t iUCellId = CbmTofAddress::GetUniqueAddress(iSmId, iRpcId, ++iCell, 0, iSmType);
      fChannelInfo   = fDigiPar->GetCell(iUCellId);
      if (NULL == fChannelInfo) break;
    }

    fvPulserOffset[iDetIndx].resize(2);  // provide vector for both sides
    for (Int_t i = 0; i < 2; i++)
      fvPulserOffset[iDetIndx][i] = 0.;  // initialize
    fvPulserTimes[iDetIndx].resize(2);   // provide vector for both sides
  }

  //   return kTRUE;

  Int_t iNbSmTypes = fDigiBdfPar->GetNbSmTypes();

  if (kTRUE == fDigiBdfPar->UseExpandedDigi()) {
    fStorDigi.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);
    fvLastHits.resize(iNbSmTypes);

    for (Int_t iSmType = 0; iSmType < iNbSmTypes; iSmType++) {
      Int_t iNbSm  = fDigiBdfPar->GetNbSm(iSmType);
      Int_t iNbRpc = fDigiBdfPar->GetNbRpc(iSmType);
      fStorDigi[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);
        fvLastHits[iSmType].resize(iNbSm);
        for (Int_t iRpc = 0; iRpc < iNbRpc; iRpc++) {
          fviClusterMul[iSmType][iSm].resize(iNbRpc);
          fvLastHits[iSmType][iSm].resize(iNbRpc);
          Int_t iNbChan = fDigiBdfPar->GetNbChan(iSmType, iRpc);
          if (iNbChan == 0) {
            LOG(warn) << "LoadGeometry: StoreDigi without channels "
                      << Form("SmTy %3d, Sm %3d, NbRpc %3d, Rpc, %3d ", iSmType, iSm, iNbRpc, iRpc);
          }
          fStorDigi[iSmType][iSm * iNbRpc + iRpc].resize(iNbChan);
          fStorDigiInd[iSmType][iSm * iNbRpc + iRpc].resize(iNbChan);
          fvLastHits[iSmType][iSm][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() )
  else {
    fStorDigi.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);
    for (Int_t iSmType = 0; iSmType < iNbSmTypes; iSmType++) {
      Int_t iNbSm  = fDigiBdfPar->GetNbSm(iSmType);
      Int_t iNbRpc = fDigiBdfPar->GetNbRpc(iSmType);
      fStorDigi[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++) {
        for (Int_t iRpc = 0; iRpc < iNbRpc; iRpc++) {
          Int_t iNbChan = fDigiBdfPar->GetNbChan(iSmType, iRpc);
          fStorDigi[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++ )
  }        // else of if( kTRUE == fDigiBdfPar->UseExpandedDigi() )
  return kTRUE;
}

Bool_t CbmDeviceHitBuilderTof::FillDigiStor()
{

  // Loop over the digis array and store the Digis in separate vectors for
  // each RPC modules

  CbmTofDigi* pDigi;

  Int_t iNbTofDigi = (Int_t) fTofCalDigiVec->size();
  //fTofCalDigisColl->GetEntriesFast();
  for (Int_t iDigInd = 0; iDigInd < iNbTofDigi; iDigInd++) {
    //pDigi = (CbmTofDigi*) fTofCalDigisColl->At(iDigInd);
    pDigi = &(fTofCalDigiVec->at(iDigInd));

    /*
    LOG(info)<<"AC " // After Calibration
	      <<Form("0x%08x",pDigi->GetAddress())<<" TSRC "
	      <<pDigi->GetType()
	      <<pDigi->GetSm()
	      <<pDigi->GetRpc()
	      <<Form("%2d",(Int_t)pDigi->GetChannel())<<" "
	      <<pDigi->GetSide()<<" "
	      <<Form("%f",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(), pDigi->GetRpc()) > pDigi->GetChannel()) {
      fStorDigi[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);
    }
    else {
      LOG(info) << "Skip2 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++ )
  return kTRUE;
}

Bool_t CbmDeviceHitBuilderTof::SendHits()
{
  //Output Log
  for (Int_t iHit = 0; iHit < fiNbHits; iHit++) {
    CbmTofHit* pHit = (CbmTofHit*) fTofHitsColl->At(iHit);
    LOG(debug) << Form("Found Hit %d, addr 0x%08x, X %6.2f, Y %6.2f Z %6.2f T %6.2f CLS %d", iHit, pHit->GetAddress(),
                       pHit->GetX(), pHit->GetY(), pHit->GetZ(), pHit->GetTime(), pHit->GetFlag());
  }
  // prepare output hit vector
  std::vector<CbmTofHit*> vhit;
  vhit.resize(fiNbHits);
  for (Int_t iHit = 0; iHit < fiNbHits; iHit++) {
    CbmTofHit* pHit = (CbmTofHit*) fTofHitsColl->At(iHit);
    vhit[iHit]      = pHit;
  }

  // prepare output string streams
  std::stringstream ossE;
  boost::archive::binary_oarchive oaE(ossE);
  oaE << fEventHeader;
  std::string* strMsgE = new std::string(ossE.str());

  std::stringstream oss;
  boost::archive::binary_oarchive oa(oss);
  oa << vhit;
  std::string* strMsg = new std::string(oss.str());

  FairMQParts parts;
  parts.AddPart(NewMessage(
    const_cast<char*>(strMsgE->c_str()),  // data
    strMsgE->length(),                    // size
    [](void*, void* object) { delete static_cast<std::string*>(object); },
    strMsgE));  // object that manages the data

  parts.AddPart(NewMessage(
    const_cast<char*>(strMsg->c_str()),  // data
    strMsg->length(),                    // size
    [](void*, void* object) { delete static_cast<std::string*>(object); },
    strMsg));  // object that manages the data

  if (Send(parts, "tofhits")) {
    LOG(error) << "Problem sending data ";
    return false;
  }

  return kTRUE;
}

Bool_t CbmDeviceHitBuilderTof::SendAll() { return kTRUE; }

Bool_t CbmDeviceHitBuilderTof::FillHistos()
{
  Int_t iNbTofHits = fTofHitsColl->GetEntriesFast();
  CbmTofHit* pHit;
  //gGeoManager->SetTopVolume( gGeoManager->FindVolumeFast("tof_v14a") );
  gGeoManager->CdTop();

  if (0 < iNbTofHits) {
    Bool_t BSel[iNSel];
    Double_t dTTrig[iNSel];
    CbmTofHit* pTrig[iNSel];
    Double_t ddXdZ[iNSel];
    Double_t ddYdZ[iNSel];
    Double_t dSel2dXdYMin[iNSel];

    Int_t iBeamRefMul    = 0;
    Int_t iBeamAddRefMul = 0;

    if (0 < iNSel) {  // check software triggers

      LOG(debug) << "FillHistos() for " << iNSel << " triggers"
                 << ", Dut " << fDutId << fDutSm << fDutRpc << Form(", 0x%08x", fDutAddr) << ", Sel " << fSelId
                 << fSelSm << fSelRpc << Form(", 0x%08x", fSelAddr) << ", Sel2 " << fSel2Id << fSel2Sm << fSel2Rpc
                 << Form(", 0x%08x", fSel2Addr);
      /*
      LOG(debug) <<"FillHistos: Muls: "
		 <<fviClusterMul[fDutId][fDutSm][fDutRpc]
		 <<", "<<fviClusterMul[fSelId][fSelSm][fSelRpc]
	;
      */
      // monitor multiplicities
      Int_t iNbDet = fDigiBdfPar->GetNbDet();
      for (Int_t iDetIndx = 0; iDetIndx < iNbDet; iDetIndx++) {
        Int_t iDetId  = fviDetId[iDetIndx];
        Int_t iSmType = CbmTofAddress::GetSmType(iDetId);
        Int_t iSm     = CbmTofAddress::GetSmId(iDetId);
        Int_t iRpc    = CbmTofAddress::GetRpcId(iDetId);
        //LOG(info) << Form(" indx %d, Id 0x%08x, TSR %d %d %d", iDetIndx, iDetId, iSmType, iSm, iRpc)
        //          ;
        if (NULL != fhRpcCluMul[iDetIndx]) fhRpcCluMul[iDetIndx]->Fill(fviClusterMul[iSmType][iSm][iRpc]);  //
      }

      // do input distributions first
      for (Int_t iHitInd = 0; iHitInd < iNbTofHits; iHitInd++) {
        pHit = (CbmTofHit*) fTofHitsColl->At(iHitInd);
        if (NULL == pHit) continue;
        if (StartAnalysisTime == 0.) {
          StartAnalysisTime = pHit->GetTime();
          LOG(info) << "StartAnalysisTime set to " << StartAnalysisTime << " ns. ";
        }
        Int_t iDetId                          = (pHit->GetAddress() & DetMask);
        std::map<UInt_t, UInt_t>::iterator it = fDetIdIndexMap.find(iDetId);
        if (it == fDetIdIndexMap.end()) continue;  // continue for invalid detector index
        Int_t iDetIndx = it->second;               //fDetIdIndexMap[iDetId];

        Int_t iSmType = CbmTofAddress::GetSmType(iDetId);
        Int_t iSm     = CbmTofAddress::GetSmId(iDetId);
        Int_t iRpc    = CbmTofAddress::GetRpcId(iDetId);
        Int_t iCh     = CbmTofAddress::GetChannelId(pHit->GetAddress());

        Double_t dTimeAna = (pHit->GetTime() - StartAnalysisTime) / 1.E9;
        //LOG(debug)<<"TimeAna "<<StartAnalysisTime<<", "<< pHit->GetTime()<<", "<<dTimeAna;
        fhRpcCluRate[iDetIndx]->Fill(dTimeAna);

        if (fdMemoryTime > 0. && fvLastHits[iSmType][iSm][iRpc][iCh].size() == 0)
          LOG(error) << Form(" <E> hit not stored in memory for TSRC %d%d%d%d", iSmType, iSm, iRpc, iCh);
        //CheckLHMemory();

        if (fvLastHits[iSmType][iSm][iRpc][iCh].size() > 1) {  // check for outdated hits
          //std::list<CbmTofHit *>::iterator it0=fvLastHits[iSmType][iSm][iRpc][iCh].begin();
          //std::list<CbmTofHit *>::iterator itL=fvLastHits[iSmType][iSm][iRpc][iCh].end();
          //CbmTofHit* pH0 = *it0;
          //CbmTofHit* pHL = *(--itL);
          CbmTofHit* pH0 = fvLastHits[iSmType][iSm][iRpc][iCh].front();
          CbmTofHit* pHL = fvLastHits[iSmType][iSm][iRpc][iCh].back();
          if (pH0->GetTime() > pHL->GetTime())
            LOG(warn) << Form("Invalid time ordering in ev %8.0f in list of "
                              "size %lu for TSRC %d%d%d%d: Delta t %f  ",
                              fdEvent, fvLastHits[iSmType][iSm][iRpc][iCh].size(), iSmType, iSm, iRpc, iCh,
                              pHL->GetTime() - pH0->GetTime());
          //while( (*((std::list<CbmTofHit *>::iterator) fvLastHits[iSmType][iSm][iRpc][iCh].begin()))->GetTime()+fdMemoryTime < pHit->GetTime()
          while (fvLastHits[iSmType][iSm][iRpc][iCh].size() > 2.
                 || fvLastHits[iSmType][iSm][iRpc][iCh].front()->GetTime() + fdMemoryTime < pHit->GetTime()) {
            LOG(debug) << " pop from list size " << fvLastHits[iSmType][iSm][iRpc][iCh].size()
                       << Form(" outdated hits for ev %8.0f in TSRC %d%d%d%d", fdEvent, iSmType, iSm, iRpc, iCh)
                       << Form(" with tHit - tLast %f ",
                               pHit->GetTime() - fvLastHits[iSmType][iSm][iRpc][iCh].front()->GetTime())
              //(*((std::list<CbmTofHit *>::iterator) fvLastHits[iSmType][iSm][iRpc][iCh].begin()))->GetTime())
              ;
            if (fvLastHits[iSmType][iSm][iRpc][iCh].front()->GetAddress() != pHit->GetAddress())
              LOG(error) << Form("Inconsistent address in list of size %lu for TSRC %d%d%d%d: "
                                 "0x%08x, time  %f",
                                 fvLastHits[iSmType][iSm][iRpc][iCh].size(), iSmType, iSm, iRpc, iCh,
                                 fvLastHits[iSmType][iSm][iRpc][iCh].front()->GetAddress(),
                                 fvLastHits[iSmType][iSm][iRpc][iCh].front()->GetTime());
            fvLastHits[iSmType][iSm][iRpc][iCh].front()->Delete();
            fvLastHits[iSmType][iSm][iRpc][iCh].pop_front();
          }
        }  //fvLastHits[iSmType][iSm][iRpc][iCh].size()>1)

        // plot remaining time difference to previous hits
        if (fvLastHits[iSmType][iSm][iRpc][iCh].size() > 1) {  // check for previous hits in memory time interval
          CbmMatch* digiMatch = (CbmMatch*) fTofDigiMatchColl->At(iHitInd);
          Double_t dTotSum    = 0.;
          for (Int_t iLink = 0; iLink < digiMatch->GetNofLinks(); iLink += 2) {  // loop over digis
            CbmLink L0        = digiMatch->GetLink(iLink);
            Int_t iDigInd0    = L0.GetIndex();
            Int_t iDigInd1    = (digiMatch->GetLink(iLink + 1)).GetIndex();
            CbmTofDigi* pDig0 = (CbmTofDigi*) (&(fTofCalDigiVec->at(iDigInd0)));
            CbmTofDigi* pDig1 = (CbmTofDigi*) (&(fTofCalDigiVec->at(iDigInd1)));
            dTotSum += pDig0->GetTot() + pDig1->GetTot();
          }

          std::list<CbmTofHit*>::iterator itL = fvLastHits[iSmType][iSm][iRpc][iCh].end();
          itL--;
          for (UInt_t iH = 0; iH < fvLastHits[iSmType][iSm][iRpc][iCh].size() - 1; iH++) {
            itL--;
            fhRpcDTLastHits[iDetIndx]->Fill(TMath::Log10(pHit->GetTime() - (*itL)->GetTime()));
            fhRpcDTLastHits_CluSize[iDetIndx]->Fill(TMath::Log10(pHit->GetTime() - (*itL)->GetTime()),
                                                    digiMatch->GetNofLinks() / 2.);
            fhRpcDTLastHits_Tot[iDetIndx]->Fill(TMath::Log10(pHit->GetTime() - (*itL)->GetTime()), dTotSum);
          }
        }
      }  // iHitInd loop end

      // do reference first
      dTRef     = dDoubleMax;
      fTRefHits = 0;
      for (Int_t iHitInd = 0; iHitInd < iNbTofHits; iHitInd++) {
        pHit = (CbmTofHit*) fTofHitsColl->At(iHitInd);
        if (NULL == pHit) continue;
        Int_t iDetId = (pHit->GetAddress() & DetMask);

        if (fiBeamRefAddr == iDetId) {
          if (fviClusterMul[fiBeamRefType][fiBeamRefSm][fiBeamRefDet] > fiBeamRefMulMax) break;
          // Check Tot
          CbmMatch* digiMatch = (CbmMatch*) fTofDigiMatchColl->At(iHitInd);
          Double_t TotSum     = 0.;
          for (Int_t iLink = 0; iLink < digiMatch->GetNofLinks(); iLink += 2) {  // loop over digis
            CbmLink L0     = digiMatch->GetLink(iLink);                          //vDigish.at(ivDigInd);
            Int_t iDigInd0 = L0.GetIndex();
            if (iDigInd0 < (Int_t) fTofCalDigiVec->size()) {
              CbmTofDigi* pDig0 = &(fTofCalDigiVec->at(iDigInd0));
              TotSum += pDig0->GetTot();
            }
          }
          TotSum /= (0.5 * digiMatch->GetNofLinks());
          if (TotSum > fhRpcCluTot[iIndexDut]->GetYaxis()->GetXmax()) continue;  // ignore too large clusters

          fTRefHits = 1;
          if (pHit->GetTime() < dTRef) { dTRef = pHit->GetTime(); }
          iBeamRefMul++;
        }
        else {  //additional reference type multiplicity
          if (fiBeamRefType == CbmTofAddress::GetSmType(iDetId)) iBeamAddRefMul++;
        }
      }
      LOG(debug) << "FillHistos: BRefMul: " << iBeamRefMul << ", " << iBeamAddRefMul;
      if (iBeamRefMul == 0) return kFALSE;                  // don't fill histos without reference time
      if (iBeamAddRefMul < fiBeamAddRefMul) return kFALSE;  // ask for confirmation by other beam counters

      for (Int_t iSel = 0; iSel < iNSel; iSel++) {
        BSel[iSel]         = kFALSE;
        pTrig[iSel]        = NULL;
        Int_t iDutMul      = 0;
        Int_t iRefMul      = 0;
        Int_t iR0          = 0;
        Int_t iRl          = 0;
        ddXdZ[iSel]        = 0.;
        ddYdZ[iSel]        = 0.;
        dSel2dXdYMin[iSel] = 1.E300;

        switch (iSel) {
          case 0:  //  Detector under Test (Dut) && Diamonds,BeamRef
            iRl = fviClusterMul[fDutId][fDutSm].size();
            if (fDutRpc > -1) {
              iR0 = fDutRpc;
              iRl = fDutRpc + 1;
            }
            for (Int_t iRpc = iR0; iRpc < iRl; iRpc++)
              iDutMul += fviClusterMul[fDutId][fDutSm][iRpc];
            LOG(debug) << "Selector 0: DutMul " << fviClusterMul[fDutId][fDutSm][fDutRpc] << ", " << iDutMul
                       << ", BRefMul " << iBeamRefMul << " TRef: " << dTRef << ", BeamAddRefMul " << iBeamAddRefMul
                       << ", " << fiBeamAddRefMul;
            if (iDutMul > 0 && iDutMul < fiCluMulMax) {
              dTTrig[iSel] = dDoubleMax;
              // LOG(debug1)<<"Found selector 0, NbHits  "<<iNbTofHits;
              for (Int_t iHitInd = 0; iHitInd < iNbTofHits; iHitInd++) {
                pHit = (CbmTofHit*) fTofHitsColl->At(iHitInd);
                if (NULL == pHit) continue;
                Int_t iDetId = (pHit->GetAddress() & DetMask);
                // LOG(debug1)<<Form(" Det 0x%08x, Dut 0x%08x, T %f, TTrig %f",
                // 		iDetId, fDutAddr, pHit->GetTime(),  dTTrig[iSel])
                // 		 ;
                //if( fDutId == CbmTofAddress::GetSmType( iDetId ))
                if (fDutAddr == iDetId) {
                  if (pHit->GetTime() < dTTrig[iSel]) {
                    dTTrig[iSel] = pHit->GetTime();
                    pTrig[iSel]  = pHit;
                    BSel[iSel]   = kTRUE;
                  }
                }
              }
              LOG(debug) << Form("Found selector 0 with mul %d from 0x%08x at %f ", iDutMul, pTrig[iSel]->GetAddress(),
                                 dTTrig[iSel]);
            }
            break;

          case 1:  // MRef & BRef
            iRl = fviClusterMul[fSelId][fSelSm].size();
            if (fSelRpc > -1) {
              iR0 = fSelRpc;
              iRl = fSelRpc + 1;
            }
            for (Int_t iRpc = iR0; iRpc < iRl; iRpc++)
              iRefMul += fviClusterMul[fSelId][fSelSm][iRpc];
            LOG(debug) << "FillHistos(): selector 1: RefMul " << fviClusterMul[fSelId][fSelSm][fSelRpc] << ", "
                       << iRefMul << ", BRefMul " << iBeamRefMul;
            if (iRefMul > 0 && iRefMul < fiCluMulMax) {
              // LOG(debug1)<<"FillHistos(): Found selector 1";
              dTTrig[iSel] = dDoubleMax;
              for (Int_t iHitInd = 0; iHitInd < iNbTofHits; iHitInd++) {
                pHit = (CbmTofHit*) fTofHitsColl->At(iHitInd);
                if (NULL == pHit) continue;

                Int_t iDetId = (pHit->GetAddress() & DetMask);
                if (fSelAddr == iDetId) {
                  if (pHit->GetTime() < dTTrig[iSel]) {
                    dTTrig[iSel] = pHit->GetTime();
                    pTrig[iSel]  = pHit;
                    BSel[iSel]   = kTRUE;
                  }
                }
              }
              LOG(debug) << Form("Found selector 1 with mul %d from 0x%08x at %f ", iRefMul, pTrig[iSel]->GetAddress(),
                                 dTTrig[iSel]);
            }
            break;

          default: LOG(info) << "FillHistos: selection not implemented " << iSel; ;
        }  // switch end
        if (fTRefMode > 10) { dTTrig[iSel] = dTRef; }
      }  // iSel - loop end

      if (fSel2Id > 0) {  // confirm selector by independent match
        for (Int_t iSel = 0; iSel < iNSel; iSel++) {
          if (BSel[iSel]) {
            BSel[iSel] = kFALSE;
            if (fviClusterMul[fSel2Id][fSel2Sm][fSel2Rpc] > 0
                && fviClusterMul[fSel2Id][fSel2Sm][fSel2Rpc] < fiCluMulMax)
              for (Int_t iHitInd = 0; iHitInd < iNbTofHits; iHitInd++) {
                pHit = (CbmTofHit*) fTofHitsColl->At(iHitInd);
                if (NULL == pHit) continue;
                Int_t iDetId = (pHit->GetAddress() & DetMask);
                if (fSel2Addr == iDetId) {
                  Double_t dzscal = 1.;
                  if (fEnableMatchPosScaling) dzscal = pHit->GetZ() / pTrig[iSel]->GetZ();
                  Double_t dSEl2dXdz = (pHit->GetX() - pTrig[iSel]->GetX()) / (pHit->GetZ() - pTrig[iSel]->GetZ());
                  Double_t dSEl2dYdz = (pHit->GetY() - pTrig[iSel]->GetY()) / (pHit->GetZ() - pTrig[iSel]->GetZ());

                  if (TMath::Sqrt(TMath::Power(pHit->GetX() - dzscal * pTrig[iSel]->GetX(), 2.)
                                  + TMath::Power(pHit->GetY() - dzscal * pTrig[iSel]->GetY(), 2.))
                      < fdCaldXdYMax) {
                    BSel[iSel]     = kTRUE;
                    Double_t dX2Y2 = TMath::Sqrt(dSEl2dXdz * dSEl2dXdz + dSEl2dYdz * dSEl2dYdz);
                    if (dX2Y2 < dSel2dXdYMin[iSel]) {
                      ddXdZ[iSel]        = dSEl2dXdz;
                      ddYdZ[iSel]        = dSEl2dYdz;
                      dSel2dXdYMin[iSel] = dX2Y2;
                    }
                    break;
                  }
                }
              }
          }  // BSel condition end
        }    // iSel lopp end
      }      // Sel2Id condition end
      UInt_t uTriggerPattern = 1;

      for (Int_t iSel = 0; iSel < iNSel; iSel++)
        if (BSel[iSel]) {
          uTriggerPattern |= (0x1 << (iSel * 3 + CbmTofAddress::GetRpcId(pTrig[iSel]->GetAddress() & DetMask)));
        }

      for (Int_t iSel = 0; iSel < iNSel; iSel++) {
        if (BSel[iSel]) {
          if (dTRef != 0. && fTRefHits > 0) {
            for (UInt_t uChannel = 0; uChannel < 16; uChannel++) {
              if (uTriggerPattern & (0x1 << uChannel)) { fhSeldT[iSel]->Fill(dTTrig[iSel] - dTRef, uChannel); }
            }
          }
        }
      }
    }  // 0<iNSel software triffer check end

    for (Int_t iHitInd = 0; iHitInd < iNbTofHits; iHitInd++) {
      pHit = (CbmTofHit*) fTofHitsColl->At(iHitInd);
      if (NULL == pHit) continue;

      Int_t iDetId                          = (pHit->GetAddress() & DetMask);
      std::map<UInt_t, UInt_t>::iterator it = fDetIdIndexMap.find(iDetId);
      if (it == fDetIdIndexMap.end()) continue;  // continue for invalid detector index
      Int_t iDetIndx = it->second;               //fDetIdIndexMap[iDetId];

      Int_t iSmType = CbmTofAddress::GetSmType(iDetId);
      Int_t iSm     = CbmTofAddress::GetSmId(iDetId);
      Int_t iRpc    = CbmTofAddress::GetRpcId(iDetId);
      Int_t iNbRpc  = fDigiBdfPar->GetNbRpc(iSmType);
      if (-1 < fviClusterMul[iSmType][iSm][iRpc]) {
        for (Int_t iSel = 0; iSel < iNSel; iSel++)
          if (BSel[iSel]) {
            Double_t w = fviClusterMul[iSmType][iSm][iRpc];
            if (w == 0.) w = 1.;
            else
              w = 1. / w;
            fhTRpcCluMul[iDetIndx][iSel]->Fill(fviClusterMul[iSmType][iSm][iRpc], w);
          }
      }

      if (fviClusterMul[iSmType][iSm][iRpc] > fiCluMulMax) continue;  // skip this event
      if (iBeamRefMul == 0) break;

      Int_t iChId  = pHit->GetAddress();
      fChannelInfo = fDigiPar->GetCell(iChId);
      Int_t iCh    = CbmTofAddress::GetChannelId(iChId);
      if (NULL == fChannelInfo) {
        LOG(error) << "Invalid Channel Pointer for ChId " << Form(" 0x%08x ", iChId) << ", Ch " << iCh;
        continue;
      }
      /*TGeoNode *fNode=*/  // prepare global->local trafo
      gGeoManager->FindNode(fChannelInfo->GetX(), fChannelInfo->GetY(), fChannelInfo->GetZ());
      /*
	LOG(debug1)<<"Hit info: "
	<<Form(" 0x%08x %d %f %f %f %f %f %d",iChId,iCh,
	pHit->GetX(),pHit->GetY(),pHit->GetTime(),fChannelInfo->GetX(),fChannelInfo->GetY(), iHitInd )
	;
      */
      Double_t hitpos[3];
      hitpos[0] = pHit->GetX();
      hitpos[1] = pHit->GetY();
      hitpos[2] = pHit->GetZ();
      Double_t hitpos_local[3];
      //TGeoNode* cNode=
      gGeoManager->GetCurrentNode();
      gGeoManager->MasterToLocal(hitpos, hitpos_local);
      /*
	LOG(debug1)<< Form(" MasterToLocal for %d, %d%d%d, node %p: (%6.1f,%6.1f,%6.1f) ->(%6.1f,%6.1f,%6.1f)",
		      iDetIndx, iSmType, iSm, iRpc,
                 cNode, hitpos[0], hitpos[1], hitpos[2],
                 hitpos_local[0], hitpos_local[1], hitpos_local[2])
              ;
      */
      fhRpcCluPosition[iDetIndx]->Fill((Double_t) iCh, hitpos_local[1]);  //pHit->GetY()-fChannelInfo->GetY());
      fhSmCluPosition[iSmType]->Fill((Double_t)(iSm * iNbRpc + iRpc), hitpos_local[1]);

      for (Int_t iSel = 0; iSel < iNSel; iSel++)
        if (BSel[iSel]) {
          fhTRpcCluPosition[iDetIndx][iSel]->Fill((Double_t) iCh,
                                                  hitpos_local[1]);  //pHit->GetY()-fChannelInfo->GetY());
          fhTSmCluPosition[iSmType][iSel]->Fill((Double_t)(iSm * iNbRpc + iRpc), hitpos_local[1]);
        }

      if (TMath::Abs(hitpos_local[1]) > fChannelInfo->GetSizey() * fPosYMaxScal) continue;
      /*
	LOG(debug1)<<" TofDigiMatchColl entries:"
                <<fTofDigiMatchColl->GetEntriesFast()
                ;
      */
      if (iHitInd > fTofDigiMatchColl->GetEntriesFast()) {
        LOG(error) << " Inconsistent DigiMatches for Hitind " << iHitInd
                   << ", TClonesArraySize: " << fTofDigiMatchColl->GetEntriesFast();
      }
      CbmMatch* digiMatch = (CbmMatch*) fTofDigiMatchColl->At(iHitInd);
      /*
	LOG(debug1)<<" got "
                <<digiMatch->GetNofLinks()<< " matches for iCh "<<iCh<<" at iHitInd "<<iHitInd
                ;
      */
      fhRpcCluSize[iDetIndx]->Fill((Double_t) iCh, digiMatch->GetNofLinks() / 2.);

      for (Int_t iSel = 0; iSel < iNSel; iSel++)
        if (BSel[iSel]) {
          fhTRpcCluSize[iDetIndx][iSel]->Fill((Double_t) iCh, digiMatch->GetNofLinks() / 2.);
          if (fvLastHits[iSmType][iSm][iRpc][iCh].size() > 1) {  // check for previous hits in memory time interval
            std::list<CbmTofHit*>::iterator itL = fvLastHits[iSmType][iSm][iRpc][iCh].end();
            itL--;
            for (UInt_t iH = 0; iH < fvLastHits[iSmType][iSm][iRpc][iCh].size() - 1; iH++) {
              itL--;
              fhTRpcCluSizeDTLastHits[iDetIndx][iSel]->Fill(TMath::Log10(pHit->GetTime() - (*itL)->GetTime()),
                                                            digiMatch->GetNofLinks() / 2.);
            }
          }
        }

      Double_t TotSum = 0.;
      for (Int_t iLink = 0; iLink < digiMatch->GetNofLinks(); iLink++) {  // loop over digis
        CbmLink L0     = digiMatch->GetLink(iLink);                       //vDigish.at(ivDigInd);
        Int_t iDigInd0 = L0.GetIndex();
        if (iDigInd0 < (Int_t) fTofCalDigiVec->size()) {
          CbmTofDigi* pDig0 = &(fTofCalDigiVec->at(iDigInd0));
          TotSum += pDig0->GetTot();
        }
      }
      Double_t dMeanTimeSquared = 0.;
      Double_t dNstrips         = 0.;

      Double_t dDelTof = 0.;
      Double_t dTcor[iNSel];
      Double_t dTTcor[iNSel];
      Double_t dZsign[iNSel];
      Double_t dzscal = 1.;
      //Double_t dDist=0.;

      for (Int_t iLink = 0; iLink < digiMatch->GetNofLinks(); iLink += 2) {  // loop over digis
        CbmLink L0     = digiMatch->GetLink(iLink);                          //vDigish.at(ivDigInd);
        Int_t iDigInd0 = L0.GetIndex();
        Int_t iDigInd1 = (digiMatch->GetLink(iLink + 1)).GetIndex();  //vDigish.at(ivDigInd+1);
        //LOG(debug1)<<" " << iDigInd0<<", "<<iDigInd1;

        if (iDigInd0 < (Int_t) fTofCalDigiVec->size() && iDigInd1 < (Int_t) fTofCalDigiVec->size()) {
          CbmTofDigi* pDig0 = &(fTofCalDigiVec->at(iDigInd0));
          CbmTofDigi* pDig1 = &(fTofCalDigiVec->at(iDigInd1));
          if ((Int_t) pDig0->GetType() != iSmType) {
            LOG(error) << Form(" Wrong Digi SmType for Tofhit %d in iDetIndx "
                               "%d, Ch %d with %3.0f strips at Indx %d, %d",
                               iHitInd, iDetIndx, iCh, dNstrips, iDigInd0, iDigInd1);
          }
          /*
	    LOG(debug1)<<" fhRpcCluTot:  Digi 0 "<<iDigInd0<<": Ch "<<pDig0->GetChannel()<<", Side "<<pDig0->GetSide()
	               <<", StripSide "<<(Double_t)iCh*2.+pDig0->GetSide()
                       <<" Digi 1 "<<iDigInd1<<": Ch "<<pDig1->GetChannel()<<", Side "<<pDig1->GetSide()
		       <<" , StripSide "<<(Double_t)iCh*2.+pDig1->GetSide()
		       <<", Tot0 " << pDig0->GetTot() <<", Tot1 "<<pDig1->GetTot();
	  */
          fhRpcCluTot[iDetIndx]->Fill(pDig0->GetChannel() * 2. + pDig0->GetSide(), pDig0->GetTot());
          fhRpcCluTot[iDetIndx]->Fill(pDig1->GetChannel() * 2. + pDig1->GetSide(), pDig1->GetTot());

          Int_t iCh0 = pDig0->GetChannel();
          Int_t iCh1 = pDig1->GetChannel();
          Int_t iS0  = pDig0->GetSide();
          Int_t iS1  = pDig1->GetSide();
          if (iCh0 != iCh1 || iS0 == iS1) {
            LOG(error) << Form(" MT2 for Tofhit %d in iDetIndx %d, Ch %d from %3.0f strips: ", iHitInd, iDetIndx, iCh,
                               dNstrips)
                       << Form(" Dig0: Ind %d, Ch %d, Side %d, T: %6.1f ", iDigInd0, iCh0, iS0, pDig0->GetTime())
                       << Form(" Dig1: Ind %d, Ch %d, Side %d, T: %6.1f ", iDigInd1, iCh1, iS1, pDig1->GetTime());
            continue;
          }

          if (0 > iCh0 || fDigiBdfPar->GetNbChan(iSmType, iRpc) <= iCh0) {
            LOG(error) << Form(" Wrong Digi for Tofhit %d in iDetIndx %d, Ch %d at Indx %d, %d "
                               "from %3.0f strips:  %d, %d, %d, %d",
                               iHitInd, iDetIndx, iCh, iDigInd0, iDigInd1, dNstrips, iCh0, iCh1, iS0, iS1);
            continue;
          }

          if (digiMatch->GetNofLinks() > 2)  //&& digiMatch->GetNofLinks()<8 ) // FIXME: hardcoded limits on CluSize
          {
            dNstrips += 1.;
            dMeanTimeSquared += TMath::Power(0.5 * (pDig0->GetTime() + pDig1->GetTime()) - pHit->GetTime(), 2);
            //             fhRpcCluAvWalk[iDetIndx]->Fill(0.5*(pDig0->GetTot()+pDig1->GetTot()),
            //                        0.5*(pDig0->GetTime()+pDig1->GetTime())-pHit->GetTime());
            fhRpcCluAvLnWalk[iDetIndx]->Fill(TMath::Log10(0.5 * (pDig0->GetTot() + pDig1->GetTot())),
                                             0.5 * (pDig0->GetTime() + pDig1->GetTime()) - pHit->GetTime());

            Double_t dTotWeigth = (pDig0->GetTot() + pDig1->GetTot()) / TotSum;
            Double_t dCorWeigth = 1. - dTotWeigth;

            fhRpcCluDelTOff[iDetIndx]->Fill(
              pDig0->GetChannel(), dCorWeigth * (0.5 * (pDig0->GetTime() + pDig1->GetTime()) - pHit->GetTime()));

            Double_t dDelPos = 0.5 * (pDig0->GetTime() - pDig1->GetTime()) * fDigiBdfPar->GetSigVel(iSmType, iSm, iRpc);
            if (0 == pDig0->GetSide()) dDelPos *= -1.;
            fhRpcCluDelPos[iDetIndx]->Fill(pDig0->GetChannel(), dCorWeigth * (dDelPos - hitpos_local[1]));

            fhRpcCluWalk[iDetIndx][iCh0][iS0]->Fill(
              pDig0->GetTot(),
              pDig0->GetTime()
                - (pHit->GetTime()
                   - (1. - 2. * pDig0->GetSide()) * hitpos_local[1] / fDigiBdfPar->GetSigVel(iSmType, iSm, iRpc)));
            fhRpcCluWalk[iDetIndx][iCh1][iS1]->Fill(
              pDig1->GetTot(),
              pDig1->GetTime()
                - (pHit->GetTime()
                   - (1. - 2. * pDig1->GetSide()) * hitpos_local[1] / fDigiBdfPar->GetSigVel(iSmType, iSm, iRpc)));

            fhRpcCluAvWalk[iDetIndx]->Fill(pDig0->GetTot(), pDig0->GetTime()
                                                              - (pHit->GetTime()
                                                                 - (1. - 2. * pDig0->GetSide()) * hitpos_local[1]
                                                                     / fDigiBdfPar->GetSigVel(iSmType, iSm, iRpc)));
            fhRpcCluAvWalk[iDetIndx]->Fill(pDig1->GetTot(), pDig1->GetTime()
                                                              - (pHit->GetTime()
                                                                 - (1. - 2. * pDig1->GetSide()) * hitpos_local[1]
                                                                     / fDigiBdfPar->GetSigVel(iSmType, iSm, iRpc)));
          }  // end of Clustersize > 1 condition
          /*
	    LOG(debug1)<<" fhTRpcCluTot: Digi 0 "<<iDigInd0<<": Ch "<<pDig0->GetChannel()<<", Side "<<pDig0->GetSide()
		    <<", StripSide "<<(Double_t)iCh*2.+pDig0->GetSide()
                    <<" Digi 1 "<<iDigInd1<<": Ch "<<pDig1->GetChannel()<<", Side "<<pDig1->GetSide()
		    <<", StripSide "<<(Double_t)iCh*2.+pDig1->GetSide()
		    ;
	  */
          for (Int_t iSel = 0; iSel < iNSel; iSel++)
            if (BSel[iSel]) {
              if (NULL == pHit || NULL == pTrig[iSel]) {
                LOG(info) << " invalid pHit, iSel " << iSel << ", iDetIndx " << iDetIndx;
                break;
              }
              if (pHit->GetAddress() == pTrig[iSel]->GetAddress()) continue;

              fhTRpcCluTot[iDetIndx][iSel]->Fill(pDig0->GetChannel() * 2. + pDig0->GetSide(), pDig0->GetTot());
              fhTRpcCluTot[iDetIndx][iSel]->Fill(pDig1->GetChannel() * 2. + pDig1->GetSide(), pDig1->GetTot());
              if (fvLastHits[iSmType][iSm][iRpc][iCh].size() > 1) {  // check for previous hits in memory time interval
                std::list<CbmTofHit*>::iterator itL = fvLastHits[iSmType][iSm][iRpc][iCh].end();
                itL--;
                for (UInt_t iH = 0; iH < fvLastHits[iSmType][iSm][iRpc][iCh].size() - 1; iH++) {
                  itL--;
                  fhTRpcCluTotDTLastHits[iDetIndx][iSel]->Fill(TMath::Log10(pHit->GetTime() - (*itL)->GetTime()),
                                                               pDig0->GetTot());
                  fhTRpcCluTotDTLastHits[iDetIndx][iSel]->Fill(TMath::Log10(pHit->GetTime() - (*itL)->GetTime()),
                                                               pDig1->GetTot());
                }
              }
              if (iLink == 0) {  // Fill histo only once (for 1. digi entry)
                if (fEnableMatchPosScaling) dzscal = pHit->GetZ() / pTrig[iSel]->GetZ();
                fhTRpcCludXdY[iDetIndx][iSel]->Fill(pHit->GetX() - dzscal * pTrig[iSel]->GetX(),
                                                    pHit->GetY() - dzscal * pTrig[iSel]->GetY());
                dZsign[iSel] = 1.;
                if (pHit->GetZ() < pTrig[iSel]->GetZ()) dZsign[iSel] = -1.;
              }
              // look for geometrical match  with selector hit
              //if(  iSmType==fiBeamRefType      // to get entries in diamond/BeamRef histos
              if (iSmType == 5  // FIXME, to get entries in diamond histos
                  || TMath::Sqrt(TMath::Power(pHit->GetX() - dzscal * pTrig[iSel]->GetX(), 2.)
                                 + TMath::Power(pHit->GetY() - dzscal * pTrig[iSel]->GetY(), 2.))
                       < fdCaldXdYMax) {
                if (!fEnableMatchPosScaling && dSel2dXdYMin[iSel] < 1.E300)
                  if (TMath::Sqrt(
                        TMath::Power(pHit->GetX()
                                       - (pTrig[iSel]->GetX() + ddXdZ[iSel] * (pHit->GetZ() - (pTrig[iSel]->GetZ()))),
                                     2.)
                        + TMath::Power(pHit->GetY()
                                         - (pTrig[iSel]->GetY() + ddYdZ[iSel] * (pHit->GetZ() - (pTrig[iSel]->GetZ()))),
                                       2.))
                      > 0.5 * fdCaldXdYMax)
                    continue;      // refine position selection cut in cosmic measurement
                dTcor[iSel] = 0.;  // precaution
                if (dTRef != 0.
                    && TMath::Abs(dTRef - dTTrig[iSel]) < fdDelTofMax) {  // correct times for DelTof - velocity spread
                  if (iLink == 0) {  // do calculations only once (at 1. digi entry) // interpolate!
                    // calculate spatial distance to trigger hit
                    /*
		 dDist=TMath::Sqrt(TMath::Power(pHit->GetX()-pTrig[iSel]->GetX(),2.)
                                  +TMath::Power(pHit->GetY()-pTrig[iSel]->GetY(),2.)
	       		          +TMath::Power(pHit->GetZ()-pTrig[iSel]->GetZ(),2.));
		 */
                    // determine correction value
                    //if(fiBeamRefAddr  != iDetId) // do not do this for reference counter itself
                    if (fTRefMode < 11)  // do not do this for trigger counter itself
                    {
                      Double_t dTentry = dTRef - dTTrig[iSel] + fdDelTofMax;
                      Int_t iBx        = dTentry / 2. / fdDelTofMax * nbClDelTofBinX;
                      if (iBx < 0) iBx = 0;
                      if (iBx > nbClDelTofBinX - 1) iBx = nbClDelTofBinX - 1;
                      Double_t dBinWidth = 2. * fdDelTofMax / nbClDelTofBinX;
                      Double_t dDTentry  = dTentry - ((Double_t) iBx) * dBinWidth;
                      Int_t iBx1         = 0;
                      dDTentry < 0 ? iBx1 = iBx - 1 : iBx1 = iBx + 1;
                      Double_t w0 = 1. - TMath::Abs(dDTentry) / dBinWidth;
                      Double_t w1 = 1. - w0;
                      if (iBx1 < 0) iBx1 = 0;
                      if (iBx1 > nbClDelTofBinX - 1) iBx1 = nbClDelTofBinX - 1;
                      dDelTof = fvCPDelTof[iSmType][iSm * iNbRpc + iRpc][iBx][iSel] * w0
                                + fvCPDelTof[iSmType][iSm * iNbRpc + iRpc][iBx1][iSel] * w1;
                      //dDelTof *= dDist; // has to be consistent with fhTRpcCluDelTof filling
                      /*
			LOG(debug1)<<Form(" DelTof for SmT %d, Sm %d, R %d, T %d, dTRef %6.1f, Bx %d, Bx1 %d, DTe %6.1f -> DelT %6.1f",
				     iSmType, iSm, iRpc, iSel, dTRef-dTTrig[iSel], iBx, iBx1, dDTentry, dDelTof)
			      ;
		      */
                    }
                    dTTcor[iSel] = dDelTof * dZsign[iSel];
                    dTcor[iSel]  = pHit->GetTime() - dDelTof - dTTrig[iSel];
                    //		    Double_t dAvTot=0.5*(pDig0->GetTot()+pDig1->GetTot());
                  }  // if(iLink==0)

                  LOG(debug) << Form(" TRpcCluWalk for Ev %d, Link %d(%d), Sel %d, TSR %d%d%d, "
                                     "Ch %d,%d, S %d,%d T %f, DelTof %6.1f, W-ent:  %6.0f,%6.0f",
                                     fiNevtBuild, iLink, (Int_t) digiMatch->GetNofLinks(), iSel, iSmType, iSm, iRpc,
                                     iCh0, iCh1, iS0, iS1, dTTrig[iSel], dDelTof,
                                     fhTRpcCluWalk[iDetIndx][iSel][iCh0][iS0]->GetEntries(),
                                     fhTRpcCluWalk[iDetIndx][iSel][iCh1][iS1]->GetEntries());

                  if (fhTRpcCluWalk[iDetIndx][iSel][iCh0][iS0]->GetEntries()
                      != fhTRpcCluWalk[iDetIndx][iSel][iCh1][iS1]->GetEntries())
                    LOG(error) << Form(" Inconsistent walk histograms -> debugging "
                                       "necessary ... for %d, %d, %d, %d, %d, %d, %d ",
                                       fiNevtBuild, iDetIndx, iSel, iCh0, iCh1, iS0, iS1);
                  /*
		    LOG(debug1)<<Form(" TRpcCluWalk values side %d: %f, %f, side %d:  %f, %f ",
				 iS0,pDig0->GetTot(),pDig0->GetTime()
				 +((1.-2.*pDig0->GetSide())*hitpos_local[1]/fDigiBdfPar->GetSigVel(iSmType,iSm,iRpc))-dTTcor[iSel]-dTTrig[iSel],
				 iS1,pDig1->GetTot(),pDig1->GetTime()
				 +((1.-2.*pDig1->GetSide())*hitpos_local[1]/fDigiBdfPar->GetSigVel(iSmType,iSm,iRpc))-dTTcor[iSel]-dTTrig[iSel])
			  ;
		  */
                  fhTRpcCluWalk[iDetIndx][iSel][iCh0][iS0]->Fill(
                    pDig0->GetTot(),
                    //(pDig0->GetTime()+((1.-2.*pDig0->GetSide())*hitpos_local[1]/fDigiBdfPar->GetSigVel(iSmType,iSm,iRpc))-dTTrig[iSel])-dTTcor[iSel]);
                    //dTcor[iSel]+(1.-2.*pDig0->GetSide())*hitpos_local[1]/fDigiBdfPar->GetSigVel(iSmType,iSm,iRpc));
                    dTcor[iSel]);
                  fhTRpcCluWalk[iDetIndx][iSel][iCh1][iS1]->Fill(
                    pDig1->GetTot(),
                    //(pDig1->GetTime()+((1.-2.*pDig1->GetSide())*hitpos_local[1]/fDigiBdfPar->GetSigVel(iSmType,iSm,iRpc))-dTTrig[iSel])-dTTcor[iSel]);
                    //dTcor[iSel]+(1.-2.*pDig1->GetSide())*hitpos_local[1]/fDigiBdfPar->GetSigVel(iSmType,iSm,iRpc));
                    dTcor[iSel]);

                  fhTRpcCluAvWalk[iDetIndx][iSel]->Fill(
                    pDig0->GetTot(),
                    //(pDig0->GetTime()+((1.-2.*pDig0->GetSide())*hitpos_local[1]/fDigiBdfPar->GetSigVel(iSmType,iSm,iRpc))-dTTrig[iSel])-dTTcor[iSel]);
                    //dTcor[iSel]+(1.-2.*pDig0->GetSide())*hitpos_local[1]/fDigiBdfPar->GetSigVel(iSmType,iSm,iRpc));
                    dTcor[iSel]);
                  fhTRpcCluAvWalk[iDetIndx][iSel]->Fill(
                    pDig1->GetTot(),
                    //(pDig1->GetTime()+((1.-2.*pDig1->GetSide())*hitpos_local[1]/fDigiBdfPar->GetSigVel(iSmType,iSm,iRpc))-dTTrig[iSel])-dTTcor[iSel]);
                    //dTcor[iSel]+(1.-2.*pDig1->GetSide())*hitpos_local[1]/fDigiBdfPar->GetSigVel(iSmType,iSm,iRpc));
                    dTcor[iSel]);

                  if (iLink == 0) {  // Fill histo only once (for 1. digi entry)
                    //fhTRpcCluDelTof[iDetIndx][iSel]->Fill(dTRef-dTTrig[iSel],dTcor[iSel]/dDist);
                    fhTRpcCluDelTof[iDetIndx][iSel]->Fill(dTRef - dTTrig[iSel], dTcor[iSel]);
                    fhTSmCluTOff[iSmType][iSel]->Fill((Double_t)(iSm * iNbRpc + iRpc), dTcor[iSel]);
                    fhTSmCluTRun[iSmType][iSel]->Fill(fdEvent, dTcor[iSel]);
                    if (iDetId
                        != (pTrig[iSel]->GetAddress()
                            & DetMask)) {  // transform matched hit-pair back into detector frame
                      hitpos[0] = pHit->GetX() - dzscal * pTrig[iSel]->GetX() + fChannelInfo->GetX();
                      hitpos[1] = pHit->GetY() - dzscal * pTrig[iSel]->GetY() + fChannelInfo->GetY();
                      hitpos[2] = pHit->GetZ();
                      gGeoManager->MasterToLocal(hitpos, hitpos_local);  //  transform into local frame
                      fhRpcCluDelMatPos[iDetIndx]->Fill((Double_t) iCh, hitpos_local[1]);
                      fhRpcCluDelMatTOff[iDetIndx]->Fill((Double_t) iCh,
                                                         (pHit->GetTime() - dTTrig[iSel]) - dTTcor[iSel]);
                    }
                  }  // iLink==0 condition end
                }    // position condition end
              }      // Match condition end
            }        // closing of selector loop
        }
        else {
          LOG(error) << "FillHistos: invalid digi index " << iDetIndx << " digi0,1" << iDigInd0 << ", " << iDigInd1
                     << " - max:" << fTofCalDigiVec->size()
            //                       << " in event " << XXX
            ;
        }
      }  // iLink digi loop end;
      if (1 < dNstrips) {
        //           Double_t dVar=dMeanTimeSquared/dNstrips - TMath::Power(pHit->GetTime(),2);
        Double_t dVar = dMeanTimeSquared / (dNstrips - 1);
        //if(dVar<0.) dVar=0.;
        Double_t dTrms = TMath::Sqrt(dVar);
        LOG(debug) << Form(" Trms for Tofhit %d in iDetIndx %d, Ch %d from "
                           "%3.0f strips: %6.3f ns",
                           iHitInd, iDetIndx, iCh, dNstrips, dTrms);
        fhRpcCluTrms[iDetIndx]->Fill((Double_t) iCh, dTrms);
        pHit->SetTimeError(dTrms);
      }
      /*
	LOG(debug1)<<" Fill Time of iDetIndx "<<iDetIndx<<", hitAddr "
	        <<Form(" %08x, y = %5.2f",pHit->GetAddress(),hitpos_local[1])
		<<" for |y| <"
                <<fhRpcCluPosition[iDetIndx]->GetYaxis()->GetXmax()
                ;
      */
      if (TMath::Abs(hitpos_local[1]) < (fhRpcCluPosition[iDetIndx]->GetYaxis()->GetXmax())) {
        if (dTRef != 0. && fTRefHits == 1) {
          fhRpcCluTOff[iDetIndx]->Fill((Double_t) iCh, pHit->GetTime() - dTRef);
          fhSmCluTOff[iSmType]->Fill((Double_t)(iSm * iNbRpc + iRpc), pHit->GetTime() - dTRef);

          for (Int_t iSel = 0; iSel < iNSel; iSel++)
            if (BSel[iSel]) {
              /*
		LOG(debug1)<<" TRpcCluTOff "<< iDetIndx <<", Sel "<< iSel
                           <<Form(", Dt %7.3f, LHsize %lu ",
			     pHit->GetTime()-dTTrig[iSel],fvLastHits[iSmType][iSm][iRpc][iCh].size());
	     */
              if (pHit->GetAddress() == pTrig[iSel]->GetAddress()) continue;

              if (fvLastHits[iSmType][iSm][iRpc][iCh].size() > 1) {  // check for previous hits in memory time interval
                std::list<CbmTofHit*>::iterator itL = fvLastHits[iSmType][iSm][iRpc][iCh].end();
                itL--;
                for (UInt_t iH = 0; iH < fvLastHits[iSmType][iSm][iRpc][iCh].size() - 1; iH++) {
                  itL--;
                  //LOG(debug1)<<Form(" %f,",pHit->GetTime()-(*itL)->GetTime());
                }
              }

              // fill Time Offset histograms without velocity spread (DelTof) correction
              fhTRpcCluTOff[iDetIndx][iSel]->Fill((Double_t) iCh,
                                                  pHit->GetTime()
                                                    - dTTrig[iSel]);  // -dTTcor[iSel] only valid for matches
              if (fvLastHits[iSmType][iSm][iRpc][iCh].size() > 1) {   // check for previous hits in memory time interval
                std::list<CbmTofHit*>::iterator itL = fvLastHits[iSmType][iSm][iRpc][iCh].end();
                itL--;
                for (Int_t iH = 0; iH < 1; iH++) {  // use only last hit
                  //  for(Int_t iH=0; iH<fvLastHits[iSmType][iSm][iRpc][iCh].size()-1; iH++){//fill for all memorized hits
                  itL--;
                  Double_t dTsinceLast = pHit->GetTime() - (*itL)->GetTime();
                  if (dTsinceLast > fdMemoryTime)
                    LOG(error) << Form("Invalid Time since last hit on channel "
                                       "TSRC %d%d%d%d: %f > %f",
                                       iSmType, iSm, iRpc, iCh, dTsinceLast, fdMemoryTime);

                  fhTRpcCluTOffDTLastHits[iDetIndx][iSel]->Fill(TMath::Log10(dTsinceLast),
                                                                pHit->GetTime() - dTTrig[iSel]);
                  fhTRpcCluMemMulDTLastHits[iDetIndx][iSel]->Fill(TMath::Log10(dTsinceLast),
                                                                  fvLastHits[iSmType][iSm][iRpc][iCh].size() - 1);
                }
              }
            }
        }
      }
    }
  }
  return kTRUE;
}

static Int_t iNPulserFound = 0;
Bool_t CbmDeviceHitBuilderTof::MonitorPulser()
{
  iNPulserFound++;
  const Int_t iDet0   = fiPulDetRef;  // Define reference detector
  const Double_t Tlim = 0.5;
  Int_t iDigi0        = -1;
  switch (fiPulserMode) {
    case 1:                                             // mcbm :
      if ((UInt_t) fiNDigiIn != fiPulMulMin * 2 + 2) {  // 2 * working RPCs + 1 Diamond
        LOG(debug) << "Incomplete or distorted pulser event " << iNPulserFound << " with " << fiNDigiIn
                   << " digis instead of " << fiPulMulMin * 2 + 2;
        if ((UInt_t) fiNDigiIn < fiPulMulMin * 2) return kTRUE;
      }
      break;
    case 2:  // micro CBM cosmic
      if ((UInt_t) fiNDigiIn < fiPulMulMin * 2) return kTRUE;
      break;
      ;
    default:;
  }

  for (Int_t iDigi = 0; iDigi < (Int_t) fiNDigiIn; iDigi++) {
    Int_t iCh = fvDigiIn[iDigi].GetChannel();
    if (iCh != 0 && iCh != 31) continue;

    Int_t iAddr = fvDigiIn[iDigi].GetAddress() & DetMask;
    Int_t iDet  = fDetIdIndexMap[iAddr];
    if (iDet == iDet0) {
      Int_t iSide = fvDigiIn[iDigi].GetSide();
      if (iSide == 1) {  // for pulser mode 1
        iDigi0 = iDigi;
        break;
      }
    }
  }

  if (iDigi0 == -1) {
    LOG(debug) << Form("Pulser reference %d not found in pulser event %d of mul %d, return", iDet0, iNPulserFound,
                       fiNDigiIn);
    return kTRUE;
  }

  if (fvPulserTimes[iDet0][0].size() > 0)
    LOG(debug) << fiNDigiIn << " pulser digis with ref in "
               << Form("0x%08x at %d with deltaT %12.3f", fvDigiIn[iDigi0].GetAddress(), iDigi0,
                       fvDigiIn[iDigi0].GetTime() - fvPulserTimes[iDet0][0].back());

  for (Int_t iDigi = 0; iDigi < fiNDigiIn; iDigi++) {
    Int_t iCh = fvDigiIn[iDigi].GetChannel();

    Int_t iDetIndx = fDigiBdfPar->GetDetInd(fvDigiIn[iDigi].GetAddress() & DetMask);
    fhRpcDigiTot[iDetIndx]->Fill(2 * iCh + fvDigiIn[iDigi].GetSide(), fvDigiIn[iDigi].GetTot());

    Int_t iAddr = fvDigiIn[iDigi].GetAddress() & DetMask;
    Int_t iDet  = fDetIdIndexMap[iAddr];
    Int_t iSide = fvDigiIn[iDigi].GetSide();

    switch (fiPulserMode) {
      case 0:
      case 1:  // mCBM
        if (fvDigiIn[iDigi].GetType() != 5) {
          if (iCh != 0 && iCh != 31) continue;
          if (fvDigiIn[iDigi].GetTot() > fiPulTotMax || fvDigiIn[iDigi].GetTot() < fiPulTotMin) continue;
        }
        else {
          LOG(debug) << "Found PulHit of Type 5 in Ch " << iCh;
          //    if (iCh == 5)    iSide=1; // Special case for diamond, pulser for channels 5-8 in channel 5, stored as side 1
          //    if (iCh !=0 && iCh != 5) continue;
          if (iCh > 39) iSide = 1;  // Special case for diamond in Mar2019
          if (iCh != 0 && iCh != 40) continue;
        }
        break;

      case 2:
        if (fvDigiIn[iDigi].GetType() == 8)  // ceramic RPC
          if (fvDigiIn[iDigi].GetRpc() != 7) continue;
        if (iCh != 0 && iCh != 31) continue;
        break;
    }

    if (fvPulserTimes[iDet][iSide].size() == (UInt_t) NPulserTimes) fvPulserTimes[iDet][iSide].pop_front();
    if (iDet == iDet0 && 1 == iSide) {
      // check consistency of latest hit
      if (fvPulserTimes[iDet][iSide].size() > 1) {
        Double_t TDif = (fvPulserTimes[iDet][iSide].back() - fvPulserTimes[iDet][iSide].front())
                        / (fvPulserTimes[iDet][iSide].size() - 1);
        if (TMath::Abs(fvDigiIn[iDigi].GetTime() - fvPulserTimes[iDet][iSide].back() - TDif)
            > 1.E3) {  // probably due to parallel processing

          // action, reset
          fvPulserTimes[iDet][iSide].clear();
        }
        else {
          if (TMath::Abs(fvDigiIn[iDigi].GetTime() - fvPulserTimes[iDet][iSide].back() - TDif) > 10.) {
            LOG(info) << Form("Unexpected Pulser Time for event %d, pulser %d: "
                              "%15.1f instead %15.1f, TDif: %10.1f != %10.1f",
                              (int) fdEvent, iNPulserFound, fvDigiIn[iDigi].GetTime(),
                              fvPulserTimes[iDet][iSide].back() + TDif,
                              fvDigiIn[iDigi].GetTime() - fvPulserTimes[iDet][iSide].back(), TDif);
            // append dummy entry
            fvPulserTimes[iDet][iSide].push_back((Double_t)(fvPulserTimes[iDet][iSide].back() + TDif));
            continue;
          }
        }
      }
      // append new entry
      fvPulserTimes[iDet][iSide].push_back((Double_t)(fvDigiIn[iDigi].GetTime()));
    }
    else {
      Double_t dDeltaT0 = (Double_t)(fvDigiIn[iDigi].GetTime() - fvDigiIn[iDigi0].GetTime());

      // check consistency of latest hit
      if (fvPulserOffset[iDet][iSide] != 0.)
        if (TMath::Abs(dDeltaT0 - fvPulserOffset[iDet][iSide]) > Tlim) {
          LOG(info) << "Unexpected pulser offset at ev " << fdEvent << ", pulcnt " << iNPulserFound << " for Det "
                    << iDet << Form(", addr 0x%08x", iAddr) << ", side " << iSide << ": "
                    << dDeltaT0 - fvPulserOffset[iDet][iSide] << " ( " << fvPulserTimes[iDet][iSide].size() << " ) ";
          fvPulserTimes[iDet][iSide].clear();
          // skip this event
          // continue;
        }

      // fill monitoring histo
      if (fvPulserOffset[iDet][iSide] != 0.) {
        fhPulserTimesRaw->Fill(iDet * 2 + iSide, dDeltaT0 - fvPulserOffset[iDet][iSide]);
        fhPulserTimeRawEvo[iDet * 2 + iSide]->Fill(iNPulserFound, dDeltaT0 - fvPulserOffset[iDet][iSide]);
      }
      // append new entry
      fvPulserTimes[iDet][iSide].push_back(dDeltaT0);
    }
  }

  for (Int_t iDet = 0; iDet < (Int_t) fvPulserTimes.size(); iDet++) {
    for (Int_t iSide = 0; iSide < 2; iSide++) {
      if (iDet == iDet0 && iSide == 1) continue;  // skip reference counter
      if (fvPulserTimes[iDet][iSide].size() > 0) {
        Double_t Tmean = 0.;
        std::list<Double_t>::iterator it;
        for (it = fvPulserTimes[iDet][iSide].begin(); it != fvPulserTimes[iDet][iSide].end(); ++it)
          Tmean += *it;
        Tmean /= fvPulserTimes[iDet][iSide].size();

        if (TMath::Abs(Tmean - fvPulserOffset[iDet][iSide]) > Tlim)
          LOG(debug) << "New pulser offset at ev " << fdEvent << ", pulcnt " << iNPulserFound << " for Det " << iDet
                     << ", side " << iSide << ": " << Tmean << " ( " << fvPulserTimes[iDet][iSide].size() << " ) ";

        fvPulserOffset[iDet][iSide] = Tmean;
      }
    }
  }

  for (Int_t iDigi = 0; iDigi < fiNDigiIn; iDigi++) {

    Int_t iCh   = fvDigiIn[iDigi].GetChannel();
    Int_t iAddr = fvDigiIn[iDigi].GetAddress() & DetMask;
    Int_t iDet  = fDetIdIndexMap[iAddr];
    Int_t iSide = fvDigiIn[iDigi].GetSide();

    switch (fiPulserMode) {
      case 1:
        if (fvDigiIn[iDigi].GetType() != 5) {
          if (iCh != 0 && iCh != 31) continue;
        }
        else {
          //if (iCh == 5)    iSide=1; // Special case for diamond, pulser for channels 5-8 in channel 5, stored as side 1
          if (iCh > 39) iSide = 1;  // Special case for diamond in Mar2019
          //	if(iCh !=0 && iCh != 5) continue;
          if (iCh != 0 && iCh != 40) continue;
        }
        break;
      case 2:
        if (fvDigiIn[iDigi].GetType() == 8)  // ceramic RPC
          if (fvDigiIn[iDigi].GetRpc() != 7) continue;
        if (iCh != 0 && iCh != 31) continue;
        break;
    }

    Double_t dDeltaT0 =
      (Double_t)(fvDigiIn[iDigi].GetTime() - fvDigiIn[iDigi0].GetTime()) - fvPulserOffset[iDet][iSide];

    // fill monitoring histo
    fhPulserTimesCor->Fill(iDet * 2 + iSide, dDeltaT0);
  }
  return kTRUE;
}

Bool_t CbmDeviceHitBuilderTof::ApplyPulserCorrection()
{
  for (Int_t iDigi = 0; iDigi < fiNDigiIn; iDigi++) {
    Int_t iAddr = fvDigiIn[iDigi].GetAddress() & DetMask;
    Int_t iDet  = fDetIdIndexMap[iAddr];
    Int_t iSide = fvDigiIn[iDigi].GetSide();
    switch (fiPulserMode) {
      case 1:  // diamond has pulser in ch 0 and 5
        if (5 == fvDigiIn[iDigi].GetType()) {
          continue;  // no pulser correction for diamond, mapping to be resolved
          Int_t iCh = fvDigiIn[iDigi].GetChannel();
          if (iCh > 4) iSide = 1;
        }
        break;
      case 2:  // correct all cer pads by same rpc/side 0
        if (8 == fvDigiIn[iDigi].GetType() || 5 == fvDigiIn[iDigi].GetType()) {
          const Int_t iRefAddr = 0x00078006;
          iDet                 = fDetIdIndexMap[iRefAddr];
        }
        break;
    }
    fvDigiIn[iDigi].SetTime(fvDigiIn[iDigi].GetTime() - fvPulserOffset[iDet][iSide]);
  }
  return kTRUE;
}