Skip to content
Snippets Groups Projects
CbmTofCalibrator.cxx 23.69 KiB
/** @file CbmTofCalibrator.cxx
 ** @author nh
 ** @date 28.02.2020
 ** 
 **/

// CBMroot classes and includes
#include "CbmTofCalibrator.h"
#include "CbmMatch.h"
#include "CbmTofAddress.h"  // in cbmdata/tof
#include "CbmTofCell.h"     // in tof/TofData
#include "CbmTofClusterizersDef.h"
#include "CbmTofDetectorId_v12b.h"  // in cbmdata/tof
#include "CbmTofDetectorId_v14a.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"
#include "CbmTofTracklet.h"

// FAIR classes and includes
#include "FairLogger.h"
#include "FairRunAna.h"
#include "FairRuntimeDb.h"

// ROOT Classes and includes
#include <TClonesArray.h>
#include <TDirectory.h>
#include <TFile.h>
#include <TFitResult.h>
#include <TGeoManager.h>
#include <TH1.h>
#include <TH2.h>
#include <TProfile.h>
#include <TROOT.h>

CbmTofCalibrator::CbmTofCalibrator()
  : fDigiMan(NULL)
  , fTofClusterizer(NULL)
  , fTofFindTracks(NULL)
  , fTrackletTools(NULL)
  , fDigiPar(NULL)
  , fDigiBdfPar(NULL)
  , fTofDigiMatchColl(NULL)
  , fhCalR0(NULL)
  , fhCalDX0(NULL)
  , fhCalDY0(NULL)
  , fhCalPos()
  , fhCalTOff()
  , fhCalTot()
  , fhCalWalk()
  , fhCorPos()
  , fhCorTOff()
  , fhCorTot()
  , fhCorTotOff()
  , fhCorSvel()
  , fhCorWalk()
  , fDetIdIndexMap() {}

CbmTofCalibrator::~CbmTofCalibrator() {}

InitStatus CbmTofCalibrator::Init() {

  FairRootManager* fManager = FairRootManager::Instance();
  // check for availability of digis
  fDigiMan = CbmDigiManager::Instance();
  if (NULL == fDigiMan) {
    LOG(warning) << "No CbmDigiManager";
    return kFATAL;
  }
  fDigiMan->Init();

  if (!fDigiMan->IsPresent(ECbmModuleId::kTof)) {
    LOG(warn) << "CbmTofCalibrator: No digi input!";
  }

  // check for access to current calibration file
  fTofClusterizer = CbmTofEventClusterizer::Instance();
  if (NULL == fTofClusterizer) {
    LOG(warn) << "CbmTofCalibrator: no access to active calibration";
  } else {
    TString CalParFileName = fTofClusterizer->GetCalParFileName();
    LOG(info) << "Current calibration file: " << CalParFileName;
  }
  fTofFindTracks = CbmTofFindTracks::Instance();
  if (NULL == fTofFindTracks) {
    LOG(warn) << "CbmTofCalibrator: no access to tof tracker ";
  }

  // Get Access to MatchCollection
  fTofDigiMatchColl = (TClonesArray*) fManager->GetObject("TofDigiMatch");
  if (NULL == fTofDigiMatchColl)
    fTofDigiMatchColl = (TClonesArray*) fManager->GetObject("TofCalDigiMatch");

  if (NULL == fTofDigiMatchColl) {
    LOG(error) << "CbmTofCalibrator: no access to DigiMatch ";
    return kFATAL;
  }

  // Get Parameters
  if (!InitParameters()) { LOG(error) << "CbmTofCalibrator: No parameters!"; }
  // generate deviation histograms
  if (!CreateCalHist()) {
    LOG(error) << "CbmTofCalibrator: No histograms!";
    return kFATAL;
  }

  fTrackletTools = new CbmTofTrackletTools();  // initialize tools

  LOG(info) << "TofCalibrator initialized successfully";
  return kSUCCESS;
}

Bool_t CbmTofCalibrator::InitParameters() {
  LOG(info) << "InitParameters: get par pointers from RTDB";
  // Get Base Container
  FairRun* ana        = FairRun::Instance();
  FairRuntimeDb* rtdb = ana->GetRuntimeDb();

  fDigiPar = (CbmTofDigiPar*) (rtdb->getContainer("CbmTofDigiPar"));
  if (NULL == fDigiPar) return kFALSE;

  fDigiBdfPar = (CbmTofDigiBdfPar*) (rtdb->getContainer("CbmTofDigiBdfPar"));
  if (NULL == fDigiBdfPar) return kFALSE;

  return kTRUE;
}

Bool_t CbmTofCalibrator::CreateCalHist() {
  // detector related distributions
  Int_t iNbDet = fDigiBdfPar->GetNbDet();
  LOG(info) << "Define Calibrator histos for " << iNbDet << " detectors ";

  fhCalR0 = new TH1D(
    "hCalR0", "Tracklet distance to nominal vertex; R_0 [cm]", 100, 0., 0.5);
  fhCalDX0 = new TH1D(
    "hCalDX0", "Tracklet distance to nominal vertex; #DeltaX_0 [cm]", 100, -0.5, 0.5);
  fhCalDY0 = new TH1D(
    "hCalDY0", "Tracklet distance to nominal vertex; #DeltaY_0 [cm]", 100, -0.5, 0.5);
  fhCalPos.resize(iNbDet);
  fhCalTOff.resize(iNbDet);
  fhCalTot.resize(iNbDet);
  fhCalWalk.resize(iNbDet);

  fDetIdIndexMap.clear();

  for (Int_t iDetIndx = 0; iDetIndx < iNbDet; iDetIndx++) {
    Int_t iUniqueId           = fDigiBdfPar->GetDetUId(iDetIndx);
    fDetIdIndexMap[iUniqueId] = 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);
    CbmTofCell* fChannelInfo = fDigiPar->GetCell(iUCellId);
    if (NULL == fChannelInfo) {
      LOG(warning) << "No DigiPar for Det " << Form("0x%08x", iUCellId);
      continue;
    }
    Double_t YDMAX     = 5;
    fhCalPos[iDetIndx] = new TH2F(
      Form("cal_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);

    Double_t TSumMax = 2.;
    //if(iSmType == 5) TSumMax *= 2.; // enlarge for diamond / beamcounter
    fhCalTOff[iDetIndx] = new TH2F(
      Form("cal_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);

    Double_t TotMax    = 20.;  //FIXME: has to be consistent with Clusterizer!
    fhCalTot[iDetIndx] = new TH2F(
      Form("cal_SmT%01d_sm%03d_rpc%03d_Tot", iSmType, iSmId, iRpcId),
      Form(
        "Clu Tot of Rpc #%03d in Sm %03d of type %d; StripSide []; TOT [a.u.]",
        iRpcId,
        iSmId,
        iSmType),
      2 * fDigiBdfPar->GetNbChan(iSmType, iRpcId),
      0,
      2 * fDigiBdfPar->GetNbChan(iSmType, iRpcId),
      100,
      0.,
      TotMax);

    TSumMax = 0.6;
    fhCalWalk[iDetIndx].resize(fDigiBdfPar->GetNbChan(iSmType, iRpcId));
    for (Int_t iCh = 0; iCh < fDigiBdfPar->GetNbChan(iSmType, iRpcId); iCh++) {
      fhCalWalk[iDetIndx][iCh].resize(2);
      for (Int_t iSide = 0; iSide < 2; iSide++) {
        fhCalWalk[iDetIndx][iCh][iSide] =
          new TH2D(Form("cal_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; Tot "
                        "[a.u.];  #DeltaT [ns]",
                        iSmType,
                        iSmId,
                        iRpcId,
                        iCh,
                        iSide),
                   nbClWalkBinX,
                   0.,
                   TotMax,
                   nbClWalkBinY,
                   -TSumMax,
                   TSumMax);
      }
    }
  }

  return kTRUE;
}

void CbmTofCalibrator::FillCalHist(CbmTofTracklet* pTrk, Int_t iOpt) {
  // fill deviation histograms on walk level
  if (pTrk->GetTt() < 0) return;  // take tracks with positive velocity only
  if (fbBeam
      && !pTrk->ContainsAddr(CbmTofAddress::GetUniqueAddress(0, 0, 0, 0, 5)))
    return;  // request beam counter hit for calibration

  if (
    fbBeam
    && fdR0Lim
         > 0.)  // consider only tracks originating from nominal interaction point
  {
    fhCalR0->Fill(pTrk->GetR0());
    if (pTrk->GetR0() > fdR0Lim) return;
  }
  fhCalDX0->Fill(pTrk->GetFitX(0.));
  fhCalDY0->Fill(pTrk->GetFitY(0.));

  for (Int_t iHit = 0; iHit < pTrk->GetNofHits(); iHit++) {
    CbmTofHit* pHit = pTrk->GetTofHitPointer(iHit);
    Int_t iDetId    = (pHit->GetAddress() & DetMask);
    Int_t iSmType   = CbmTofAddress::GetSmType(iDetId);
    Int_t iSm       = CbmTofAddress::GetSmId(iDetId);
    Int_t iRpc      = CbmTofAddress::GetRpcId(iDetId);

    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 iChId              = pHit->GetAddress();
    Int_t iCh                = CbmTofAddress::GetChannelId(iChId);
    CbmTofCell* fChannelInfo = fDigiPar->GetCell(iChId);
    if (NULL == fChannelInfo) {
      LOG(error) << "Invalid Channel Pointer for ChId "
                 << Form(" 0x%08x ", iChId) << ", Ch " << iCh;
      continue;
    }
    gGeoManager->FindNode(
      fChannelInfo->GetX(), fChannelInfo->GetY(), fChannelInfo->GetZ());
    Double_t hitpos[3];
    hitpos[0] = pHit->GetX();
    hitpos[1] = pHit->GetY();
    hitpos[2] = pHit->GetZ();
    Double_t hlocal_p[3];
    //TGeoNode* cNode=
    gGeoManager->GetCurrentNode();
    gGeoManager->MasterToLocal(hitpos, hlocal_p);
    hitpos[0] = pTrk->GetFitX(pHit->GetZ());
    hitpos[1] = pTrk->GetFitY(pHit->GetZ());
    Double_t hlocal_f[3];
    gGeoManager->MasterToLocal(hitpos, hlocal_f);

    fhCalPos[iDetIndx]->Fill(
      (Double_t) iCh, hlocal_p[1] - hlocal_f[1]);  // transformed into LRF
    fhCalTOff[iDetIndx]->Fill(
      (Double_t) iCh,
      pHit->GetTime()
        - pTrk->GetFitT(pHit->GetZ()));  // residuals transformed into LRF
    //fhCalTOff[iDetIndx]->Fill((Double_t)iCh,fTrackletTools->GetTdif(pTrk, iDetId, pHit));   // prediction by other hits

    Int_t iMA = pTrk->GetTofHitIndex(iHit);
    if (iMA > fTofDigiMatchColl->GetEntries()) {
      LOG(error) << " Inconsistent DigiMatches for Hitind " << iMA
                 << ", TClonesArraySize: " << fTofDigiMatchColl->GetEntries();
    }
    CbmMatch* digiMatch = (CbmMatch*) fTofDigiMatchColl->At(iMA);

    Double_t hlocal_d[3];
    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();

      const CbmTofDigi* tDigi0 = fDigiMan->Get<CbmTofDigi>(iDigInd0);
      Int_t iCh0               = tDigi0->GetChannel();
      Int_t iSide0             = tDigi0->GetSide();
      LOG(debug) << "Fill Walk for " << iDetIndx << ", TSRCS " << iSmType << iSm
                 << iRpc << iCh0 << iSide0 << ", " << tDigi0 << ", " << pTrk;
      if (iDetIndx > (Int_t) fhCalWalk.size()) {
        LOG(error) << "Invalid DetIndx " << iDetIndx;
        continue;
      }
      if (iCh0 > (Int_t) fhCalWalk[iDetIndx].size()) {
        LOG(error) << "Invalid Ch0 " << iCh0;
        continue;
      }
      if (iSide0 > (Int_t) fhCalWalk[iDetIndx][iCh0].size()) {
        LOG(error) << "Invalid Side0 " << iSide0;
        continue;
      }

      const CbmTofDigi* tDigi1 = fDigiMan->Get<CbmTofDigi>(iDigInd1);
      Int_t iCh1               = tDigi1->GetChannel();
      Int_t iSide1             = tDigi1->GetSide();
      LOG(debug) << "Fill Walk for " << iDetIndx << ", TSRCS " << iSmType << iSm
                 << iRpc << iCh1 << iSide1 << ", " << tDigi1 << ", " << pTrk;
      if (iCh1 > (Int_t) fhCalWalk[iDetIndx].size()) {
        LOG(error) << "Invalid Ch1 " << iCh1;
        continue;
      }
      if (iSide1 > (Int_t) fhCalWalk[iDetIndx][iCh1].size()) {
        LOG(error) << "Invalid Side1 " << iSide1;
        continue;
      }

      if (iCh0 != iCh1 || iSide0 == iSide1) {
        LOG(error) << "Invalid digi pair for TSR " << iSmType << iSm << iRpc
                   << " Ch " << iCh0 << " " << iCh1 << ", Side " << iSide0
                   << " " << iSide1;
        continue;
      }

      hlocal_d[1] = -0.5
                    * ((1. - 2. * tDigi0->GetSide()) * tDigi0->GetTime()
                       + (1. - 2. * tDigi1->GetSide()) * tDigi1->GetTime())
                    * fDigiBdfPar->GetSigVel(iSmType, iSm, iRpc);

      if (TMath::Abs(hlocal_d[1] - hlocal_p[1]) > 10.) {
        LOG(warn) << "CMPY for TSRC " << iSmType << iSm << iRpc << iCh0 << ": "
                  << hlocal_f[1] << ", " << hlocal_p[1] << ", " << hlocal_d[1]
                  << ", TOT: " << tDigi0->GetTot() << " " << tDigi1->GetTot();
      }
      Int_t iWalkMode = (iOpt - iOpt % 10) / 10;
      switch (iWalkMode) {
        case 1:
          fhCalWalk[iDetIndx][iCh0][iSide0]->Fill(
            tDigi0->GetTot(),
            tDigi0->GetTime()
              + (1. - 2. * tDigi0->GetSide()) * hlocal_d[1]
                  / fDigiBdfPar->GetSigVel(iSmType, iSm, iRpc)
              - pTrk->GetFitT(
                pHit
                  ->GetZ())  //-fTrackletTools->GetTexpected(pTrk, iDetId, pHit)
	              + fTofFindTracks->GetTOff(iDetId)
              + 2. * (1. - 2. * tDigi0->GetSide()) * (hlocal_d[1] - hlocal_f[1])
                  / fDigiBdfPar->GetSigVel(iSmType, iSm, iRpc));
          /*
        LOG(info)<<"TSRCS "<<iSmType<<iSm<<iRpc<<iCh<<iSide0<<Form(": digi0 %f, ex %f, prop %f, Off %f, res %f",
                            tDigi0->GetTime(),
                            fTrackletTools->GetTexpected(pTrk, iDetId, pHit) ,
                            fTofFindTracks->GetTOff(iDetId),
                            (1.-2.*tDigi0->GetSide())*hlocal_f[1]/fDigiBdfPar->GetSigVel(iSmType,iSm,iRpc),
                            tDigi0->GetTime()-fTrackletTools->GetTexpected(pTrk, iDetId, pHit) 
                            -(1.-2.*tDigi0->GetSide())*hlocal_f[1]/fDigiBdfPar->GetSigVel(iSmType,iSm,iRpc));
        */

          fhCalWalk[iDetIndx][iCh1][iSide1]->Fill(
            tDigi1->GetTot(),
            tDigi1->GetTime()
              + (1. - 2. * tDigi1->GetSide()) * hlocal_d[1]
                  / fDigiBdfPar->GetSigVel(iSmType, iSm, iRpc)
              - pTrk->GetFitT(
                pHit
                  ->GetZ())  //-fTrackletTools->GetTexpected(pTrk, iDetId, pHit)
              + fTofFindTracks->GetTOff(iDetId)
              + 2. * (1. - 2. * tDigi1->GetSide()) * (hlocal_d[1] - hlocal_f[1])
                  / fDigiBdfPar->GetSigVel(iSmType, iSm, iRpc));
          break;

        case 0: {
          Double_t dDeltaT = 0.5 * (tDigi0->GetTime() + tDigi1->GetTime())
                           + fTofFindTracks->GetTOff(iDetId)
                           - pTrk->GetFitT(pHit->GetZ());
          fhCalWalk[iDetIndx][iCh0][iSide0]->Fill(tDigi0->GetTot(), dDeltaT);
          fhCalWalk[iDetIndx][iCh1][iSide1]->Fill(tDigi1->GetTot(), dDeltaT);
        } break;
      }
    }
  }
}

Bool_t CbmTofCalibrator::UpdateCalHist(Int_t iOpt) {
  // get current calibration histos
  LOG(info) << "CbmTofCalibrator:: update histos from "
            << "file "
            << CbmTofEventClusterizer::Instance()->GetCalParFileName()
            << " with option " << iOpt;
  TFile* fCalParFile =
    new TFile(CbmTofEventClusterizer::Instance()->GetCalParFileName(), "");
  if (NULL == fCalParFile) {
    LOG(warn)
      << "Could not open TofClusterizer calibration file, abort Update ";
    return kFALSE;
  }
  assert(fCalParFile);
  ReadHist(fCalParFile);

  const Double_t MINCTS = 100.;  //FIXME, numerical constant in code
  // modify calibration histograms
  for (Int_t iDetIndx = 0; iDetIndx < fDigiBdfPar->GetNbDet(); iDetIndx++) {
    Int_t iUniqueId = fDigiBdfPar->GetDetUId(iDetIndx);
    // Int_t iSmAddr   = iUniqueId & DetMask;
    Int_t iSmType = CbmTofAddress::GetSmType(iUniqueId);
    Int_t iSm     = CbmTofAddress::GetSmId(iUniqueId);
    Int_t iRpc    = CbmTofAddress::GetRpcId(iUniqueId);
    if (NULL == fhCorTOff[iDetIndx]) {
      LOG(warn) << "hCorTOff for TSR " << iSmType << iSm << iRpc
                << " not available";
      continue;
    }

    switch (iOpt % 10) {
      case 0:  // none
        break;
      case 1:  // update channel mean
      {
        LOG(info) << "Update Offsets for TSR " << iSmType << iSm << iRpc;

        TProfile* hpP = fhCalPos[iDetIndx]->ProfileX();
        TProfile* hpT = fhCalTOff[iDetIndx]->ProfileX();
        TH1* hCalT    = fhCalTOff[iDetIndx]->ProjectionX();
        //fhCorPos[iDetIndx]->Add((TH1 *)hpP,-1.);
        //fhCorTOff[iDetIndx]->Add((TH1*)hpT,-1.);
        Double_t dAvOff = 0.;  //hpT->GetMean(2);
        for (Int_t iBin = 0; iBin < fhCorTOff[iDetIndx]->GetNbinsX(); iBin++) {
          Double_t dDt   = hpT->GetBinContent(iBin + 1);
          Double_t dCorT = fhCorTOff[iDetIndx]->GetBinContent(iBin + 1);
          Double_t dCts  = hCalT->GetBinContent(iBin + 1);
          if (iDetIndx == -1) {
            LOG(info) << Form(
              "Update %s: bin %02d, Cts: %d, Old %f, dev %f, av %f, new %f",
              fhCorTOff[iDetIndx]->GetName(),
              iBin,
              (Int_t) dCts,
              dCorT,
              dDt,
              dAvOff,
              dCorT - dDt + dAvOff);
          }
          Double_t dDp   = hpP->GetBinContent(iBin + 1);
          Double_t dCorP = fhCorPos[iDetIndx]->GetBinContent(iBin + 1);
          if (dCts > MINCTS) {
            // Fit Gaussian around peak
            TH1* hpPy = (TH1*) fhCalPos[iDetIndx]->ProjectionY(
              Form("PosPy_%d_%d", iDetIndx, iBin), iBin + 1, iBin + 1);
            Double_t dFMean   = hpPy->GetBinCenter(hpPy->GetMaximumBin());
            Double_t dFLim    = 0.5;  // CAUTION, fixed numeric value
            Double_t dBinSize = hpPy->GetBinWidth(1);
            dFLim             = TMath::Max(dFLim, 5. * dBinSize);
            TFitResultPtr fRes =
              hpPy->Fit("gaus", "S", "", dFMean - dFLim, dFMean + dFLim);
            dDp = fRes->Parameter(1);  //overwrite mean
            // Double_t dDpRes = fRes->Parameter(2);

            fhCorTOff[iDetIndx]->SetBinContent(iBin + 1, dCorT + dDt + dAvOff);
            fhCorPos[iDetIndx]->SetBinContent(iBin + 1, dCorP + dDp);
          }
        }
      } break;
      case 2:  // update individual channel walks
    	if(iSmType==5) continue; // no walk correction for beam counter
        const Double_t MinCounts = 10.;
        Int_t iNbCh              = fDigiBdfPar->GetNbChan(iSmType, iRpc);
        for (Int_t iCh = 0; iCh < iNbCh; iCh++) {
          for (Int_t iSide = 0; iSide < 2; iSide++) {
            //LOG(info) << "Get walk histo pointer for TSRCS " << iSmType<<iSm<<iRpc<<iCh<<iSide;
            TProfile* hpW =
              fhCalWalk[iDetIndx][iCh][iSide]->ProfileX();  // mean deviation
            TH1* hCW = fhCalWalk[iDetIndx][iCh][iSide]
                         ->ProjectionX();  // contributing counts

            Double_t dCorT = 0;
            for (Int_t iBin = 0;
                 iBin < fhCorWalk[iDetIndx][iCh][iSide]->GetNbinsX();
                 iBin++) {
              Double_t dCts  = hCW->GetBinContent(iBin + 1);
              Double_t dWOff = fhCorWalk[iDetIndx][iCh][iSide]->GetBinContent(
                iBin + 1);  // current value
              if (iBin > 0 && dCts == 0)
                fhCorWalk[iDetIndx][iCh][iSide]->SetBinContent(
                  iBin + 1,
                  fhCorWalk[iDetIndx][iCh][iSide]->GetBinContent(iBin));
              if (dCts > MinCounts) { dCorT = hpW->GetBinContent(iBin + 1); }
              fhCorWalk[iDetIndx][iCh][iSide]->SetBinContent(
                iBin + 1, dWOff + dCorT);  //set new value
            }
            // determine effective/count rate weighted mean
            Double_t dMean   = 0;
            Double_t dCtsAll = 0.;
            for (Int_t iBin = 0;
                 iBin < fhCorWalk[iDetIndx][iCh][iSide]->GetNbinsX();
                 iBin++) {
              Double_t dCts = hCW->GetBinContent(iBin + 1);
              Double_t dWOff =
                fhCorWalk[iDetIndx][iCh][iSide]->GetBinContent(iBin + 1);
              if (dCts > MinCounts) {
                dCtsAll += dCts;
                dMean += dCts * dWOff;
              }
            }
            if (dCtsAll > 0.) dMean /= dCtsAll;
            /*
            LOG(info)<<"Mean shift for TSRCS "<<iSmType<<iSm<<iRpc<<iCh<<iSide
            		<<": "<<dMean;
            */
            // keep mean value at 0
            for (Int_t iBin = 0;
                 iBin < fhCorWalk[iDetIndx][iCh][iSide]->GetNbinsX();
                 iBin++) {
              Double_t dWOff = fhCorWalk[iDetIndx][iCh][iSide]->GetBinContent(
                iBin + 1);  // current value
              fhCorWalk[iDetIndx][iCh][iSide]->SetBinContent(
                iBin + 1, dWOff - dMean);  //set new value
              if (iCh == 5 && iBin == 10)  // debugging
                LOG(info) << "New Walk for "
                          << fhCorWalk[iDetIndx][iCh][iSide]->GetName()
                          << " bin " << iBin << ": "
                          << fhCorWalk[iDetIndx][iCh][iSide]->GetBinContent(iBin
                                                                            + 1)
                          << ", Mean " << dMean << ", WOff " << dWOff;
            }
          }
        }
        break;
    }  //switch( iOpt) end
  }

  TFile* fCalParFileNew =
    new TFile(Form("New_%s", fCalParFile->GetName()), "RECREATE");
  WriteHist(fCalParFileNew);
  fCalParFileNew->Close();

  return kTRUE;
}

void CbmTofCalibrator::ReadHist(TFile* fHist) {
  LOG(info) << "Read Cor histos from file " << fHist->GetName();
  if (0 == fhCorPos.size()) {
    Int_t iNbDet = fDigiBdfPar->GetNbDet();
    //LOG(info) << "resize histo vector for " << iNbDet << " detectors ";
    fhCorPos.resize(iNbDet);
    fhCorTOff.resize(iNbDet);
    fhCorTot.resize(iNbDet);
    fhCorTotOff.resize(iNbDet);
    fhCorSvel.resize(iNbDet);
    fhCorWalk.resize(iNbDet);
  }

  for (Int_t iDetIndx = 0; iDetIndx < fDigiBdfPar->GetNbDet(); iDetIndx++) {
    Int_t iUniqueId = fDigiBdfPar->GetDetUId(iDetIndx);
    //Int_t iSmAddr   = iUniqueId & DetMask;
    Int_t iSmType = CbmTofAddress::GetSmType(iUniqueId);
    Int_t iSm     = CbmTofAddress::GetSmId(iUniqueId);
    Int_t iRpc    = CbmTofAddress::GetRpcId(iUniqueId);
    //LOG(info) << "Get histo pointer for TSR " << iSmType<<iSm<<iRpc;

    fhCorPos[iDetIndx] = (TH1*) gDirectory->FindObjectAny(
      Form("cl_CorSmT%01d_sm%03d_rpc%03d_Pos_pfx", iSmType, iSm, iRpc));
    if (NULL == fhCorPos[iDetIndx]) {
      LOG(error) << "hCorPos not found for TSR " << iSmType << iSm << iRpc;
      continue;
    }
    fhCorTOff[iDetIndx] = (TH1*) gDirectory->FindObjectAny(
      Form("cl_CorSmT%01d_sm%03d_rpc%03d_TOff_pfx", iSmType, iSm, iRpc));
    fhCorTot[iDetIndx] = (TH1*) gDirectory->FindObjectAny(
      Form("cl_CorSmT%01d_sm%03d_rpc%03d_Tot_Mean", iSmType, iSm, iRpc));
    fhCorTotOff[iDetIndx] = (TH1*) gDirectory->FindObjectAny(
      Form("cl_CorSmT%01d_sm%03d_rpc%03d_Tot_Off", iSmType, iSm, iRpc));

    Int_t iNbCh = fDigiBdfPar->GetNbChan(iSmType, iRpc);
    fhCorWalk[iDetIndx].resize(iNbCh);
    for (Int_t iCh = 0; iCh < iNbCh; iCh++) {
      fhCorWalk[iDetIndx][iCh].resize(2);
      for (Int_t iSide = 0; iSide < 2; iSide++) {
        //LOG(info) << "Get walk histo pointer for TSRCS " << iSmType<<iSm<<iRpc<<iCh<<iSide;
        fhCorWalk[iDetIndx][iCh][iSide] = (TH1*) gDirectory->FindObjectAny(
          Form("Cor_SmT%01d_sm%03d_rpc%03d_Ch%03d_S%d_Walk_px",
               iSmType,
               iSm,
               iRpc,
               iCh,
               iSide));
        if (NULL == fhCorWalk[iDetIndx][iCh][iSide])
          LOG(warn) << "No Walk histo for TSRCS " << iSmType << iSm << iRpc
                    << iCh << iSide;
      }
    }
  }
}

void CbmTofCalibrator::WriteHist(TFile* fHist) {
  LOG(info) << "Write Cor histos to file " << fHist->GetName();
  TDirectory* oldir = gDirectory;
  fHist->cd();
  for (Int_t iDetIndx = 0; iDetIndx < fDigiBdfPar->GetNbDet(); iDetIndx++) {
    if (NULL == fhCorPos[iDetIndx]) continue;
    fhCorPos[iDetIndx]->Write();
    fhCorTOff[iDetIndx]->Write();
    fhCorTot[iDetIndx]->Write();
    fhCorTotOff[iDetIndx]->Write();

    Int_t iNbCh = (Int_t) fhCorWalk[iDetIndx].size();
    for (Int_t iCh = 0; iCh < iNbCh; iCh++) {
      for (Int_t iSide = 0; iSide < 2; iSide++) {
        fhCorWalk[iDetIndx][iCh][iSide]->Write();
      }
    }
  }
  oldir->cd();
}

ClassImp(CbmTofCalibrator)