diff --git a/fles/mcbm2018/tasks/CbmMcbmCheckTimingAlgo.cxx b/fles/mcbm2018/tasks/CbmMcbmCheckTimingAlgo.cxx index 219f32f1978cf30036dd8ac44faa59c473b24a44..025d21f88f2d55d459c550e52c0714c070f0751d 100644 --- a/fles/mcbm2018/tasks/CbmMcbmCheckTimingAlgo.cxx +++ b/fles/mcbm2018/tasks/CbmMcbmCheckTimingAlgo.cxx @@ -1,9 +1,10 @@ -/* Copyright (C) 2020-2021 Facility for Antiproton and Ion Research in Europe, Darmstadt +/* Copyright (C) 2020-2024 Facility for Antiproton and Ion Research in Europe, Darmstadt SPDX-License-Identifier: GPL-3.0-only - Authors: Pierre-Alain Loizeau [committer], Andreas Redelbach */ + Authors: Pierre-Alain Loizeau [committer], Andreas Redelbach, Alexandru Bercuci */ #include "CbmMcbmCheckTimingAlgo.h" +#include "CbmBmonDigi.h" #include "CbmDigiManager.h" #include "CbmFlesHistosTools.h" #include "CbmMuchBeamTimeDigi.h" @@ -13,16 +14,16 @@ #include "CbmTofDigi.h" #include "CbmTrdDigi.h" -#include "FairRootManager.h" -#include "FairRunOnline.h" +#include <FairRootManager.h> +#include <FairRunOnline.h> #include <Logger.h> -#include "TF1.h" -#include "TH1.h" -#include "TH2.h" -#include "THttpServer.h" #include <TDirectory.h> +#include <TF1.h> #include <TFile.h> +#include <TH1.h> +#include <TH2.h> +#include <THttpServer.h> #include <iomanip> #include <iostream> @@ -82,7 +83,7 @@ void CbmMcbmCheckTimingAlgo::CheckDataPresence(CheckTimingDetector detToCheck) /// Handle special case for Bmon as not yet supported in DigiManager if (ECbmModuleId::kBmon == detToCheck.detId) { // Get a pointer to the previous already existing data level - fpBmonDigiVec = ioman->InitObjectAs<std::vector<CbmTofDigi> const*>("BmonDigi"); + fpBmonDigiVec = ioman->InitObjectAs<std::vector<CbmBmonDigi> const*>("BmonDigi"); if (!fpBmonDigiVec) { LOG(fatal) << "No storage with Bmon digis found while it should be used. " "Stopping there!"; @@ -210,7 +211,7 @@ void CbmMcbmCheckTimingAlgo::ProcessTs() break; } // case ECbmModuleId::kPsd: case ECbmModuleId::kBmon: { - CheckInterSystemOffset<CbmTofDigi>(); + CheckInterSystemOffset<CbmBmonDigi>(); break; } // case ECbmModuleId::kBmon: default: { @@ -317,7 +318,7 @@ void CbmMcbmCheckTimingAlgo::CheckInterSystemOffset() break; } // case ECbmModuleId::kPsd: case ECbmModuleId::kBmon: { - FillTimeOffsetHistos<CbmTofDigi>(dRefTime, dRefCharge, uDetIdx); + FillTimeOffsetHistos<CbmBmonDigi>(dRefTime, dRefCharge, uDetIdx); break; } // case ECbmModuleId::kBmon: default: { @@ -427,7 +428,7 @@ void CbmMcbmCheckTimingAlgo::FillTimeOffsetHistos(const Double_t dRefTime, const fvDets[uDetIdx].iPrevRefFirstDigi = uFirstDigiInWin; } -// ---- GetDigiTime ------------------------------------------------------ +// ---- GetDigiInfo ------------------------------------------------------ template<class Digi> uint CbmMcbmCheckTimingAlgo::GetDigiInfo(UInt_t uDigi, std::vector<std::tuple<double, double, uint>>* vec, ECbmModuleId) { @@ -437,22 +438,21 @@ uint CbmMcbmCheckTimingAlgo::GetDigiInfo(UInt_t uDigi, std::vector<std::tuple<do vec->push_back(std::make_tuple(digi->GetTime(), digi->GetCharge(), digi->GetAddress())); return 1; } +// --- STS specific digi info --------------------- template<> -uint CbmMcbmCheckTimingAlgo::GetDigiInfo<CbmTofDigi>(UInt_t uDigi, std::vector<std::tuple<double, double, uint>>* vec, - ECbmModuleId detId) +uint CbmMcbmCheckTimingAlgo::GetDigiInfo<CbmStsDigi>(UInt_t uDigi, std::vector<std::tuple<double, double, uint>>* vec, + ECbmModuleId) { - /** Template specialization for ToF in order to distinguish Bmon digis. - */ + const CbmStsDigi* digi = fDigiMan->Get<CbmStsDigi>(uDigi); vec->clear(); - const CbmTofDigi* pDigi(nullptr); - if (detId == ECbmModuleId::kBmon) pDigi = &fpBmonDigiVec->at(uDigi); - else - pDigi = fDigiMan->Get<CbmTofDigi>(uDigi); - - if (pDigi == nullptr) return 0; - vec->push_back(std::make_tuple(pDigi->GetTime(), pDigi->GetCharge(), pDigi->GetAddress())); + if (digi == nullptr) return 0; + int32_t add = digi->GetAddress(), uId(CbmStsAddress::GetElementId(add, EStsElementLevel::kStsUnit)), + lId(CbmStsAddress::GetElementId(add, EStsElementLevel::kStsLadder)), + mId(CbmStsAddress::GetElementId(add, EStsElementLevel::kStsModule)); + vec->push_back(std::make_tuple(digi->GetTime(), digi->GetCharge(), uId * 10 + lId * 3 + mId)); return 1; } +// --- TRD(1D,2D) specific digi info --------------------- template<> uint CbmMcbmCheckTimingAlgo::GetDigiInfo<CbmTrdDigi>(UInt_t uDigi, std::vector<std::tuple<double, double, uint>>* vec, ECbmModuleId) @@ -491,29 +491,40 @@ uint CbmMcbmCheckTimingAlgo::GetDigiInfo<CbmTrdDigi>(UInt_t uDigi, std::vector<s } return n; } +// --- ToF specific digi info --------------------- +template<> +uint CbmMcbmCheckTimingAlgo::GetDigiInfo<CbmTofDigi>(UInt_t uDigi, std::vector<std::tuple<double, double, uint>>* vec, + ECbmModuleId) +{ + const CbmTofDigi* digi = fDigiMan->Get<CbmTofDigi>(uDigi); + vec->clear(); + if (digi == nullptr) return 0; + int32_t add = digi->GetAddress(), smID(CbmTofAddress::GetSmId(add)), smTyp(CbmTofAddress::GetSmType(add)), + rpcID(CbmTofAddress::GetRpcId(add)); + // chID(CbmTofAddress::GetChannelId(add)) + // chSd(CbmTofAddress::GetChannelSide(add)); + vec->push_back(std::make_tuple(digi->GetTime(), digi->GetCharge(), smTyp * 100 + smID * 10 + rpcID)); + return 1; +} // ---- GetViewId ------------------------------------------------------ template<class Digi> -int CbmMcbmCheckTimingAlgo::GetViewId(CheckTimingDetector, std::tuple<double, double, uint>) +int CbmMcbmCheckTimingAlgo::GetViewId(CheckTimingDetector det, std::tuple<double, double, uint> info) { - return 0; -} -template<> -int CbmMcbmCheckTimingAlgo::GetViewId<CbmTrdDigi>(CheckTimingDetector det, std::tuple<double, double, uint> info) -{ - uint moduleId = std::get<2>(info); + if (det.vName.size() == 1) return 0; + + uint modId = std::get<2>(info); uint iview = 0; for (auto view : det.vName) { - if (view.compare(std::to_string(moduleId)) == 0) return iview; + if (view.compare(std::to_string(modId)) == 0) return iview; iview++; } - std::string sFullModId = det.sName + " module " + std::to_string(moduleId); - if (0 == fUnimplementedTrdViewWarned.count(sFullModId)) { - LOG(warning) << "Trd condition not implemented for " << sFullModId << ". Skipping it from now on."; - fUnimplementedTrdViewWarned.insert(sFullModId); + std::string sFullId = det.sName + " mod " + std::to_string(modId); + if (0 == fUnimplementedView[det.detId].count(sFullId)) { + LOG(warning) << det.sName << " condition not implemented for " << sFullId << ". Skipping it from now on."; + fUnimplementedView[det.detId].insert(sFullId); } - return -1; } diff --git a/fles/mcbm2018/tasks/CbmMcbmCheckTimingAlgo.h b/fles/mcbm2018/tasks/CbmMcbmCheckTimingAlgo.h index 13e4c0b52a934f20c590f78b221418564439840b..7aebc36b614e9acbf45388a2248c01902101c66b 100644 --- a/fles/mcbm2018/tasks/CbmMcbmCheckTimingAlgo.h +++ b/fles/mcbm2018/tasks/CbmMcbmCheckTimingAlgo.h @@ -1,6 +1,6 @@ -/* Copyright (C) 2020-2021 Facility for Antiproton and Ion Research in Europe, Darmstadt +/* Copyright (C) 2020-2024 Facility for Antiproton and Ion Research in Europe, Darmstadt SPDX-License-Identifier: GPL-3.0-only - Authors: Pierre-Alain Loizeau [committer], Andreas Redelbach */ + Authors: Pierre-Alain Loizeau [committer], Andreas Redelbach, Alexandru Bercuci */ #ifndef CBMMCBMCHECKTIMINGALGO_H #define CBMMCBMCHECKTIMINGALGO_H @@ -24,6 +24,7 @@ class CbmTrdDigi; class CbmTofDigi; class CbmRichDigi; class CbmPsdDigi; +class CbmBmonDigi; class CheckTimingDetector { public: CheckTimingDetector() { ; } @@ -108,7 +109,8 @@ private: void CheckInterSystemOffset(); template<class Digi> void FillTimeOffsetHistos(const Double_t dRefTime, const Double_t dRefCharge, UInt_t uDetIdx); - /** @brief Retrieve digi (time,charge,addres) info. Use template specialization for special cases (e.g. Bmon, TRD, PSD) + /** @brief Retrieve digi (time,charge,addres) info. + * SHOULD BE IMPLEMENTED BY DETECTORS IF MORE DIFFERENTIAL STUDIES ARE NEEDED * @param iDigi digi index in the digi array * @param vec on return contains the signal(s), time(s) and address pairs. Should be allocated by the user * @param detId if needed spec @@ -117,9 +119,9 @@ private: template<class Digi> UInt_t GetDigiInfo(UInt_t iDigi, std::vector<std::tuple<double, double, UInt_t>>* vec, ECbmModuleId detId = ECbmModuleId::kNotExist); - /** @brief Retrieve the detector view corresponding to the digi data (@see CheckTimingDetector::vName) + /** @brief Retrieve the detector view corresponding to the digi data (@see CheckTimingDetector::vName). * @param det detector definitions - * @param info tuple of digi info (time, charge address) + * @param info tuple of digi info (time, charge, address or more specific info) * @return the view index for the curent data or -1 if there is none */ template<class Digi> @@ -129,7 +131,7 @@ private: CbmDigiManager* fDigiMan = nullptr; //! /** Bmon is not included in CbmDigiManager, so add it explicitly here **/ - const std::vector<CbmTofDigi>* fpBmonDigiVec = nullptr; //! + const std::vector<CbmBmonDigi>* fpBmonDigiVec = nullptr; //! /** @brief Pointer to the Timeslice start time used to write it to the output tree @remark since we hand this to the FairRootManager it also wants to delete it and we do not have to take care of deletion @@ -164,7 +166,7 @@ private: Double_t fRichPeakWidthNs = 40.; Double_t fPsdPeakWidthNs = 20.; - std::unordered_set<std::string> fUnimplementedTrdViewWarned = {}; + std::map<ECbmModuleId, std::unordered_set<std::string>> fUnimplementedView = {}; ClassDefNV(CbmMcbmCheckTimingAlgo, 1); }; diff --git a/macro/beamtime/mcbm2024/CMakeLists.txt b/macro/beamtime/mcbm2024/CMakeLists.txt index 56a2a539ab95c2c89735c29663c9eae51a8f17bd..a24c93a4f6d220a94678994f0e3742002824b02d 100644 --- a/macro/beamtime/mcbm2024/CMakeLists.txt +++ b/macro/beamtime/mcbm2024/CMakeLists.txt @@ -8,19 +8,19 @@ Install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PATTERN "*.sh" ) # # RICH calibration file, resolve symlink to get the full file -# Get_filename_component(_resolvedRichFile ${CMAKE_CURRENT_SOURCE_DIR}/icd_offset_it_0.data REALPATH) +# get_filename_component(_resolvedRichFile ${CMAKE_CURRENT_SOURCE_DIR}/icd_offset_it_0.data REALPATH) # Install(FILES ${_resolvedRichFile} # DESTINATION share/cbmroot/macro/beamtime/mcbm2022 # ) -# -# # SLURM scripts, bash scripts -# Install(DIRECTORY online -# DESTINATION share/cbmroot/macro/beamtime/mcbm2022 -# FILES_MATCHING PATTERN "*.sbatch" -# PATTERN "*.sh" -# ) -# -# # Just the empty folder for output -# Install(DIRECTORY data -# DESTINATION share/cbmroot/macro/beamtime/mcbm2022 -# PATTERN "*" EXCLUDE) + +# SLURM scripts, bash scripts +Install(DIRECTORY online + DESTINATION share/cbmroot/macro/beamtime/mcbm2024 + FILES_MATCHING PATTERN "*.sbatch" + PATTERN "*.sh" + ) + +# Just the empty folder for output +Install(DIRECTORY data + DESTINATION share/cbmroot/macro/beamtime/mcbm2024 + PATTERN "*" EXCLUDE) diff --git a/macro/beamtime/mcbm2024/check_timing_any.C b/macro/beamtime/mcbm2024/check_timing_any.C new file mode 100644 index 0000000000000000000000000000000000000000..f2d458bf9b96979c695e7a37171662cd572c0de6 --- /dev/null +++ b/macro/beamtime/mcbm2024/check_timing_any.C @@ -0,0 +1,101 @@ +/* Copyright (C) 2024 Facility for Antiproton and Ion Research in Europe, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pierre-Alain Loizeau [committer], Alexandru Bercuci*/ + +void check_timing_any(TString fileName, UInt_t uRunId = 0, Int_t nEvents = 0, TString outDir = "data/") +{ + + // ======================================================================== + // Adjust this part according to your requirements + + // Verbosity level (0=quiet, 1=event level, 2=track level, 3=debug) + Int_t iVerbose = 3; + + // MC file + + TString srcDir = gSystem->Getenv("VMCWORKDIR"); + TString outFileName = fileName(0, fileName.Index(".digi.root")); + + // ----- Timer -------------------------------------------------------- + TStopwatch timer; + timer.Start(); + // ------------------------------------------------------------------------ + + // ----- Analysis run -------------------------------------------------- + FairRunOnline* fRun = new FairRunOnline(); + fRun->ActivateHttpServer(100, 8080); // refresh each 100 events + fRun->SetSink(new FairRootFileSink(Form("%s/%s.sink.root", outDir.Data(), outFileName.Data()))); + FairFileSource* inputSource = new FairFileSource(fileName); + fRun->SetSource(inputSource); + // ------------------------------------------------------------------------ + + CbmMcbmCheckTimingTask* timeChecker = new CbmMcbmCheckTimingTask(); + /// Default is using Bmon as reference + timeChecker->SetReferenceDetector(ECbmModuleId::kBmon, "Bmon", -1000., 1000., 320., 182, 190); + /// Remove detectors not present in 03-2024 + timeChecker->RemoveCheckDetector(ECbmModuleId::kMuch); + timeChecker->RemoveCheckDetector(ECbmModuleId::kPsd); + /// Add detectors with wider range + timeChecker->AddCheckDetector(ECbmModuleId::kSts, "Sts", -100., 150., 2500); + timeChecker->AddCheckDetector(ECbmModuleId::kRich, "Rich", -40., 40., 800); + timeChecker->AddCheckDetector(ECbmModuleId::kTrd, "Trd", -300., 300., 150); + timeChecker->AddCheckDetector(ECbmModuleId::kTof, "Tof", -40, 40, 800); + /// Add extra differential analysis on specific detectors + /// The modifications have to be accompanied by a parallel implementation of + /// the template function CbmMcbmCheckTimingAlgo::GetDigiInfo<CbmDetDigi> + /// TODO Should be implemented as function pointer defined in this macro + timeChecker->SetDetectorDifferential(ECbmModuleId::kSts, + {"0", "1", "3", "4", "10", "11", "13", "14", "16", "17", + "18"}); // select STS modules based on general expression U*10 + L*3 + M + timeChecker->SetDetectorDifferential(ECbmModuleId::kTrd, {"5", "21", "37"}); // select modules + timeChecker->SetDetectorDifferential( + ECbmModuleId::kTof, + {"0", "1", "2", "3", "4", "10", "11", "12", "13", "14", "20", "21", "22", + "23", "24", "30", "31", "32", "33", "34", "40", "41", "42", "43", "44", "200", + "201", "202", "203", "204", "600", "601", "900", "901", "910", "911"}); // select ToF RPCs based on the general expression Typ*100 + SmId * 10 + RpcId + if (0 < uRunId) timeChecker->SetOutFilename(Form("%s/%s.tck.root", outDir.Data(), outFileName.Data())); + fRun->AddTask(timeChecker); + + + // ----- Intialise and run -------------------------------------------- + fRun->Init(); + cout << "Starting run" << endl; + if (nEvents < 0) { + fRun->Run(0, 0); // run until end of input file + } + else { + fRun->Run(0, nEvents); // process N Events + } + // ------------------------------------------------------------------------ + + + // ----- Finish ------------------------------------------------------- + timer.Stop(); + Double_t rtime = timer.RealTime(); + Double_t ctime = timer.CpuTime(); + cout << endl << endl; + cout << "Macro finished successfully." << endl; + cout << "Real time " << rtime << " s, CPU time " << ctime << " s" << endl; + cout << endl; + // ------------------------------------------------------------------------ + + // Extract the maximal used memory an add is as Dart measurement + // This line is filtered by CTest and the value send to CDash + FairSystemInfo sysInfo; + Float_t maxMemory = sysInfo.GetMaxMemory(); + cout << "<DartMeasurement name=\"MaxMemory\" type=\"numeric/double\">"; + cout << maxMemory; + cout << "</DartMeasurement>" << endl; + + Float_t cpuUsage = ctime / rtime; + cout << "<DartMeasurement name=\"CpuLoad\" type=\"numeric/double\">"; + cout << cpuUsage; + cout << "</DartMeasurement>" << endl; + /* + FairMonitor* tempMon = FairMonitor::GetMonitor(); + tempMon->Print(); +*/ + // RemoveGeoManager(); + cout << " Test passed" << endl; + cout << " All ok " << endl; +} diff --git a/macro/beamtime/mcbm2024/mcbm_event_reco_L1.C b/macro/beamtime/mcbm2024/mcbm_event_reco_L1.C new file mode 100644 index 0000000000000000000000000000000000000000..69714abdcb84706b2d06011247433f635871dbfa --- /dev/null +++ b/macro/beamtime/mcbm2024/mcbm_event_reco_L1.C @@ -0,0 +1,746 @@ +/* Copyright (C) 2024 Facility for Antiproton and Ion Research in Europe, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pierre-Alain Loizeau, Adrian Weber [committer], Alexandru Bercuci*/ + +// -------------------------------------------------------------------------- +// +// Macro for reconstruction of mcbm data (2024) +// Combined reconstruction (event builder + cluster + hit finder + CA) for different subsystems. +// +// -------------------------------------------------------------------------- + +#include <math.h> +#include <stdio.h> +#include <string.h> + +/// FIXME: Disable clang formatting to keep easy parameters overview +/* clang-format off */ +Bool_t mcbm_event_reco_L1(UInt_t uRunId = 3105, + Int_t nTimeslices = 10, + TString sInpDir = "./data/", + TString sOutDir = "./data/", + Int_t iUnpFileIndex = -1, + Bool_t bMVD = kFALSE, + Bool_t bSTS = kTRUE, + Bool_t bTRD = kTRUE, + Bool_t bTRD2d = kTRUE, + Bool_t bRICH = kTRUE, + Bool_t bMUCH = kTRUE, + Bool_t bTOF = kTRUE, + Bool_t bTOFtr = kTRUE, + Bool_t bPSD = kFALSE, + Bool_t bAli = kTRUE, + Bool_t bEvB = kTRUE, + Bool_t bL1 = kFALSE, + Bool_t bQA = kFALSE, + Bool_t bFSD = kFALSE, + TString sInpFile = "" + ) +{ + /// FIXME: Re-enable clang formatting after parameters initial values setting + /* clang-format on */ + + // --- Logger settings ---------------------------------------------------- + TString logLevel = "INFO"; //"INFO"; + TString logVerbosity = "VERYLOW"; //"VERYLOW"; + // ------------------------------------------------------------------------ + + // ----- Environment -------------------------------------------------- + TString myName = "mcbm_event_reco"; // this macro's name for screen output + TString srcDir = gSystem->Getenv("VMCWORKDIR"); // top source directory + // ------------------------------------------------------------------------ + + + // ----- In- and output file names ------------------------------------ + /// Standardized RUN ID + TString sRunId = TString::Format("%04u", uRunId); + + gSystem->Exec("mkdir " + sOutDir); + gSystem->Exec("cp $VMCWORKDIR/macro/run/.rootrc ."); + + TString outFile = sOutDir + "/" + sRunId; + /// Initial pattern + TString inFile = sInpDir + sRunId + ".digi"; + + /// Add index of splitting at unpacking level if needed + if (0 <= iUnpFileIndex) { + inFile += TString::Format("_%02u", iUnpFileIndex); + // the input par file is not split during unpacking! + outFile += TString::Format("_%02u", iUnpFileIndex); + } // if ( 0 <= uUnpFileIndex ) + /// Add ROOT file suffix + inFile += ".root"; + TString parFileOut = outFile + ".par.root"; + TString geoFileOut = outFile + ".geo.root"; + outFile += ".rec.root"; + + if ("" != sInpFile) { + inFile = sInpFile; + outFile = inFile; + outFile.ReplaceAll(".digi.root", ""); + parFileOut = outFile + ".par.root"; + geoFileOut = outFile + ".geo.root"; + outFile += ".rec.root"; + } + // --------------------------------------------- + + + // ----- TOF defaults ------------------------ + // Your folder with the Tof Calibration files; + TString cFileId = sRunId + ".5.000"; + TString TofFileFolder = ""; + + // ===> PAL 2022/11/04: overwriten by block around l.510! + Int_t calMode = 93; + Int_t calSel = 1; + Int_t calSm = 2; + Int_t RefSel = 11; + Double_t dDeadtime = 50.; + Int_t iSel2 = -1; + + // Tracking + Int_t iSel = 22002; + Int_t iTrackingSetup = 1; // 2 for checking without beam counter; + Int_t iGenCor = 1; + Double_t dScalFac = 2.5; + Double_t dChi2Lim2 = 4.; + Bool_t bUseSigCalib = kFALSE; + Int_t iCalOpt = 110; // 0=do not call CbmTofCalibrator + Int_t iTrkPar = 0; // 4 for check without beam counter + Double_t dTOffScal = 1.; + // ------------------------------------------------------------------------ + + // ----- TOF Calibration Settings --------------------------------------- + TString cCalId = "490.100.5.0"; + if (uRunId >= 759) cCalId = "759.100.4.0"; + if (uRunId >= 812) cCalId = "831.100.4.0"; + if (uRunId >= 1588) cCalId = "1588.50.6.0"; + if (uRunId >= 2160) cCalId = "2160.50.4.0"; + if (uRunId >= 2352) cCalId = "2391.5.000"; + if (uRunId >= 2700) cCalId = "2912.1"; + + Int_t iCalSet = 30040500; // calibration settings + if (uRunId >= 759) iCalSet = 10020500; + if (uRunId >= 812) iCalSet = 10020500; + if (uRunId >= 1588) iCalSet = 12002002; + if (uRunId >= 2160) iCalSet = 700900500; + if (uRunId >= 2352) iCalSet = 22002500; + if (uRunId >= 2700) iCalSet = 12032500; + + Double_t Tint = 100.; // coincidence time interval + Int_t iTrackMode = 2; // 2 for TofTracker + const Int_t iTofCluMode = 1; + // ------------------------------------------------------------------------ + + // --- Load the geometry setup ---- + // This is currently only required by the TRD (parameters) + cbm::mcbm::ToForceLibLoad dummy; /// Needed to trigger loading of the library as no fct dict in ROOT6 and CLING + TString geoSetupTag = ""; + try { + geoSetupTag = cbm::mcbm::GetSetupFromRunId(uRunId); + } + catch (const std::invalid_argument& e) { + std::cout << "Error in mapping from runID to setup name: " << e.what() << std::endl; + return kFALSE; + } + + TString geoFile = sInpDir + geoSetupTag + ".geo.root"; + CbmSetup* geoSetup = CbmSetup::Instance(); + geoSetup->LoadSetup(geoSetupTag); + + // You can modify the pre-defined setup by using + geoSetup->SetActive(ECbmModuleId::kMvd, bMVD); + geoSetup->SetActive(ECbmModuleId::kSts, bSTS); + geoSetup->SetActive(ECbmModuleId::kMuch, bMUCH); + geoSetup->SetActive(ECbmModuleId::kRich, bRICH); + geoSetup->SetActive(ECbmModuleId::kTrd, bTRD); + geoSetup->SetActive(ECbmModuleId::kTrd2d, bTRD2d); + geoSetup->SetActive(ECbmModuleId::kTof, bTOF); + geoSetup->SetActive(ECbmModuleId::kPsd, bPSD); + geoSetup->SetActive(ECbmModuleId::kFsd, bFSD); + + + //----- Load Parameters -------------------------------------------------- + TList* parFileList = new TList(); + TofFileFolder = Form("%s/%s", TofFileFolder.Data(), cCalId.Data()); + + // ----- TRD digitisation parameters ------------------------------------- + TString geoTagTrd; + if (geoSetup->IsActive(ECbmModuleId::kTrd)) { + if (geoSetup->GetGeoTag(ECbmModuleId::kTrd, geoTagTrd)) { + TString paramFilesTrd(Form("%s/parameters/trd/trd_%s", srcDir.Data(), geoTagTrd.Data())); + std::vector<TString> paramFilesVecTrd = {"asic", "digi", "gas", "gain"}; + for (auto parIt : paramFilesVecTrd) { + parFileList->Add(new TObjString(Form("%s.%s.par", paramFilesTrd.Data(), parIt.Data()))); + } + } + for (auto parFileVecIt : *parFileList) { + LOG(debug) << Form("TrdParams - %s - added to parameter file list\n", parFileVecIt->GetName()); + } + } + // ----- TOF digitisation parameters ------------------------------------- + TString geoTagTof; + if (geoSetup->IsActive(ECbmModuleId::kTof)) { + geoSetup->GetGeoTag(ECbmModuleId::kTof, geoTagTof); + TObjString* tofBdfFile = new TObjString(srcDir + "/parameters/tof/tof_" + geoTagTof + ".digibdf.par"); + parFileList->Add(tofBdfFile); + std::cout << "-I- " << myName << ": Using parameter file " << tofBdfFile->GetString() << std::endl; + + // TFile* fgeo = new TFile(geoFile); + // TGeoManager* geoMan = (TGeoManager*) fgeo->Get("FAIRGeom"); + // if (NULL == geoMan) { + // cout << "<E> FAIRGeom not found in geoFile " << geoFile.Data() << endl; + // return 1; + // } + } + // ------------------------------------------------------------------------ + + // ----- Timer -------------------------------------------------------- + TStopwatch timer; + timer.Start(); + // ------------------------------------------------------------------------ + + + // ----- FairRunAna --------------------------------------------------- + FairRunAna* run = new FairRunAna(); + FairFileSource* inputSource = new FairFileSource(inFile); + run->SetSource(inputSource); + + FairRootFileSink* outputSink = new FairRootFileSink(outFile); + run->SetSink(outputSink); + run->SetGeomFile(geoFile); + + // Define output file for FairMonitor histograms + TString monitorFile{outFile}; + monitorFile.ReplaceAll(".rec.", ".rec.monitor."); + FairMonitor::GetMonitor()->EnableMonitor(kTRUE, monitorFile); + // ------------------------------------------------------------------------ + + + // ----- Logger settings ---------------------------------------------- + FairLogger::GetLogger()->SetLogScreenLevel(logLevel.Data()); + FairLogger::GetLogger()->SetLogVerbosityLevel(logVerbosity.Data()); + //FairLogger::GetLogger()->SetLogScreenLevel("DEBUG"); + // ------------------------------------------------------------------------ + + + // ========================================================================= + // === Alignment Correction === + // ========================================================================= + // (Fairsoft Apr21p2 or newer is needed) + if (bAli) { + + TString alignmentMatrixFileName = srcDir + "/parameters/mcbm/AlignmentMatrices_" + geoSetupTag + ".root"; + + if (alignmentMatrixFileName.Length() != 0) { + + std::cout << "-I- " << myName << ": Applying alignment for file " << alignmentMatrixFileName << std::endl; + + // Define the basic structure which needs to be filled with information + // This structure is stored in the output file and later passed to the + // FairRoot framework to do the (miss)alignment + std::map<std::string, TGeoHMatrix>* matrices{nullptr}; + + // read matrices from disk + LOG(info) << "Filename: " << alignmentMatrixFileName; + TFile* misalignmentMatrixRootfile = new TFile(alignmentMatrixFileName, "READ"); + if (misalignmentMatrixRootfile->IsOpen()) { + gDirectory->GetObject("MisalignMatrices", matrices); + misalignmentMatrixRootfile->Close(); + } + else { + LOG(error) << "Could not open file " << alignmentMatrixFileName << "\n Exiting"; + exit(1); + } + + if (matrices) { + run->AddAlignmentMatrices(*matrices); + } + else { + LOG(error) << "Alignment required but no matrices found." + << "\n Exiting"; + exit(1); + } + } + } + // ------------------------------------------------------------------------ + + + // --------------------event builder--------------------------------------- + // ----- EventBuilder Settings---------------- + // mCbm track trigger Tof, Bmon & STS (case 4 of mcbm_unp_event.C) + const Int_t eb_TriggerMinNumberBmon{1}; + const Int_t eb_TriggerMaxNumberBmon{2}; + const Int_t eb_TriggerMinNumberSts{2}; + const Int_t eb_TriggerMinNumberStsLayers{1}; + const Int_t eb_TriggerMinNumberMuch{1}; + const Int_t eb_TriggerMinNumberTof{8}; + const Int_t eb_TriggerMinNumberTofLayers{4}; + const Int_t eb_TriggerMinNumberRich{0}; + + const Int_t eb_TrigWinMinBmon{-50}; + const Int_t eb_TrigWinMaxBmon{50}; + const Int_t eb_TrigWinMinSts{-60}; + const Int_t eb_TrigWinMaxSts{60}; + const Int_t eb_TrigWinMinMuch{-100}; + const Int_t eb_TrigWinMaxMuch{100}; + const Int_t eb_TrigWinMinTrd1d{-300}; + const Int_t eb_TrigWinMaxTrd1d{300}; + const Int_t eb_TrigWinMinTrd2d{-200}; + const Int_t eb_TrigWinMaxTrd2d{200}; + const Int_t eb_TrigWinMinTof{-20}; + const Int_t eb_TrigWinMaxTof{60}; + const Int_t eb_TrigWinMinRich{-60}; + const Int_t eb_TrigWinMaxRich{60}; + + if (bEvB) { + CbmTaskBuildRawEvents* evBuildRaw = new CbmTaskBuildRawEvents(); + evBuildRaw->SetVerbose(3); + //Choose between NoOverlap, MergeOverlap, AllowOverlap + evBuildRaw->SetEventOverlapMode(EOverlapModeRaw::AllowOverlap); + //For time being it is needed. We will remove CbmMuchBeamTimeDigi. + evBuildRaw->ChangeMuchBeamtimeDigiFlag(); + // Remove detectors where digis not found + if (!bRICH || !geoSetup->IsActive(ECbmModuleId::kRich)) evBuildRaw->RemoveDetector(kRawEventBuilderDetRich); + if (!bMUCH || !geoSetup->IsActive(ECbmModuleId::kMuch)) evBuildRaw->RemoveDetector(kRawEventBuilderDetMuch); + if (!bPSD || !geoSetup->IsActive(ECbmModuleId::kPsd)) evBuildRaw->RemoveDetector(kRawEventBuilderDetPsd); + if (!bTRD || !geoSetup->IsActive(ECbmModuleId::kTrd)) evBuildRaw->RemoveDetector(kRawEventBuilderDetTrd); + //TODO temporary exclude 2D from event building (asked by M. Beyer) + if (!bTRD2d) evBuildRaw->RemoveDetector(kRawEventBuilderDetTrd2D); + if (!bSTS || !geoSetup->IsActive(ECbmModuleId::kSts)) evBuildRaw->RemoveDetector(kRawEventBuilderDetSts); + if (!bTOF || !geoSetup->IsActive(ECbmModuleId::kTof)) evBuildRaw->RemoveDetector(kRawEventBuilderDetTof); + if (!bFSD || !geoSetup->IsActive(ECbmModuleId::kFsd)) evBuildRaw->RemoveDetector(kRawEventBuilderDetFsd); + + // Set Bmon as reference detector. + // Select only Bmon1 [newly installed for mcbm2024 data] (AB) + evBuildRaw->SetReferenceDetector(kRawEventBuilderDetBmon, {0, 1}); + // For making MuCh as seed detector + // evBuildRaw->SetReferenceDetector(kRawEventBuilderDetMuch); + + // Use sliding window seed builder with STS + //evBuildRaw->SetReferenceDetector(kRawEventBuilderDetUndef); + //evBuildRaw->AddSeedTimeFillerToList(kRawEventBuilderDetTof); + //evBuildRaw->SetSlidingWindowSeedFinder(10, 10, 50); + //evBuildRaw->SetSeedFinderQa(true); // optional QA information for seed finder + //evBuildRaw->SetTriggerMinNumber(ECbmModuleId::kSts, 1000); + //evBuildRaw->SetTriggerMaxNumber(ECbmModuleId::kSts, -1); + //evBuildRaw->SetTriggerWindow(ECbmModuleId::kSts, -500, 500); + + // void SetTsParameters(double TsStartTime, double TsLength, double TsOverLength): + // => TsStartTime=0, TsLength=128 + 1.28 ms in 2022, TsOverLength=1.28 ms (1MS) in mCBM2022 + evBuildRaw->SetTsParameters(0.0, 1.28e8, 1.28e6); + + if (geoSetup->IsActive(ECbmModuleId::kTof)) { + evBuildRaw->SetTriggerMinNumber(ECbmModuleId::kTof, eb_TriggerMinNumberTof); + evBuildRaw->SetTriggerMinLayersNumber(ECbmModuleId::kTof, eb_TriggerMinNumberTofLayers); + evBuildRaw->SetTriggerMaxNumber(ECbmModuleId::kTof, -1); + } + + evBuildRaw->SetTriggerMinNumber(ECbmModuleId::kBmon, eb_TriggerMinNumberBmon); + evBuildRaw->SetTriggerMaxNumber(ECbmModuleId::kBmon, eb_TriggerMaxNumberBmon); + + if (geoSetup->IsActive(ECbmModuleId::kSts)) { + evBuildRaw->SetTriggerMinNumber(ECbmModuleId::kSts, eb_TriggerMinNumberSts); + evBuildRaw->SetTriggerMinLayersNumber(ECbmModuleId::kSts, eb_TriggerMinNumberStsLayers); + evBuildRaw->SetTriggerMaxNumber(ECbmModuleId::kSts, -1); + } + if (bMUCH && geoSetup->IsActive(ECbmModuleId::kMuch)) { + evBuildRaw->SetTriggerMinNumber(ECbmModuleId::kMuch, eb_TriggerMinNumberMuch); + evBuildRaw->SetTriggerMaxNumber(ECbmModuleId::kMuch, -1); + } + if (geoSetup->IsActive(ECbmModuleId::kRich)) { + evBuildRaw->SetTriggerMinNumber(ECbmModuleId::kRich, eb_TriggerMinNumberRich); + evBuildRaw->SetTriggerMaxNumber(ECbmModuleId::kRich, -1); + } + + evBuildRaw->SetTriggerWindow(ECbmModuleId::kBmon, eb_TrigWinMinBmon, eb_TrigWinMaxBmon); + if (geoSetup->IsActive(ECbmModuleId::kTof)) + evBuildRaw->SetTriggerWindow(ECbmModuleId::kTof, eb_TrigWinMinTof, eb_TrigWinMaxTof); + if (geoSetup->IsActive(ECbmModuleId::kSts)) + evBuildRaw->SetTriggerWindow(ECbmModuleId::kSts, eb_TrigWinMinSts, eb_TrigWinMaxSts); + if (bMUCH && geoSetup->IsActive(ECbmModuleId::kMuch)) + evBuildRaw->SetTriggerWindow(ECbmModuleId::kMuch, eb_TrigWinMinMuch, eb_TrigWinMaxMuch); + if (geoSetup->IsActive(ECbmModuleId::kTrd)) + evBuildRaw->SetTriggerWindow(ECbmModuleId::kTrd, eb_TrigWinMinTrd1d, eb_TrigWinMaxTrd1d); + if (geoSetup->IsActive(ECbmModuleId::kTrd)) + evBuildRaw->SetTriggerWindow(ECbmModuleId::kTrd2d, eb_TrigWinMinTrd2d, eb_TrigWinMaxTrd2d); + if (geoSetup->IsActive(ECbmModuleId::kRich)) + evBuildRaw->SetTriggerWindow(ECbmModuleId::kRich, eb_TrigWinMinRich, eb_TrigWinMaxRich); + + run->AddTask(evBuildRaw); + } + // ------------------------------------------------------------------------ + + + // ----- Reconstruction tasks ----------------------------------------- + + + // ========================================================================= + // === local STS Reconstruction === + // ========================================================================= + + if (bSTS && geoSetup->IsActive(ECbmModuleId::kSts)) { + CbmRecoSts* recoSts = new CbmRecoSts(); + if (bEvB) { + recoSts->SetMode(ECbmRecoMode::EventByEvent); + } + else { + recoSts->SetMode(ECbmRecoMode::Timeslice); + } + recoSts->SetVerbose(3); + recoSts->SetTimeCutDigisAbs(20.0); // cluster finder: time cut in ns + recoSts->SetTimeCutClustersAbs(20.0); // hit finder: time cut in ns + + // Sensor params + CbmStsParSensor sensor6cm(CbmStsSensorClass::kDssdStereo); + sensor6cm.SetPar(0, 6.2092); // Extension in x + sensor6cm.SetPar(1, 6.2); // Extension in y + sensor6cm.SetPar(2, 0.03); // Extension in z + sensor6cm.SetPar(3, 5.9692); // Active size in y + sensor6cm.SetPar(4, 1024.); // Number of strips front side + sensor6cm.SetPar(5, 1024.); // Number of strips back side + sensor6cm.SetPar(6, 0.0058); // Strip pitch front side + sensor6cm.SetPar(7, 0.0058); // Strip pitch back side + sensor6cm.SetPar(8, 0.0); // Stereo angle front side + sensor6cm.SetPar(9, 7.5); // Stereo angle back side + + CbmStsParSensor sensor12cm(sensor6cm); // copy all parameters, change then only the y size + sensor12cm.SetPar(1, 12.4); // Extension in y + sensor12cm.SetPar(3, 12.1692); // Active size in y + + // --- Addresses for sensors + // --- They are defined in each station as sensor 1, module 1, halfladderD (2), ladder 1 + // Int_t GetAddress(UInt_t unit = 0, UInt_t ladder = 0, UInt_t halfladder = 0, UInt_t module = 0, UInt_t sensor = 0, + // UInt_t side = 0, UInt_t version = kCurrentVersion); + + // setup available starting with sts_v24b. Available if reconstructing from rra files (AB 14.05.2024) + Int_t stsAddress00 = CbmStsAddress::GetAddress(0, 0, 0, 0, 0, 0); // U0 L0 M0 6 cm + Int_t stsAddress01 = CbmStsAddress::GetAddress(1, 0, 1, 0, 0, 0); // U1 L0 M0 6 cm + Int_t stsAddress02 = CbmStsAddress::GetAddress(1, 0, 1, 1, 0, 0); // U1 L0 M1 6 cm + Int_t stsAddress03 = CbmStsAddress::GetAddress(1, 1, 1, 0, 0, 0); // U1 L1 M0 6 cm + Int_t stsAddress04 = CbmStsAddress::GetAddress(1, 1, 1, 1, 0, 0); // U1 L1 M1 6 cm + Int_t stsAddress05 = CbmStsAddress::GetAddress(2, 0, 1, 0, 0, 0); // U2 L0 M0 6 cm + Int_t stsAddress06 = CbmStsAddress::GetAddress(2, 0, 1, 1, 0, 0); // U2 L0 M1 12 cm + Int_t stsAddress07 = CbmStsAddress::GetAddress(2, 1, 1, 0, 0, 0); // U2 L1 M0 6 cm + Int_t stsAddress08 = CbmStsAddress::GetAddress(2, 1, 1, 1, 0, 0); // U2 L1 M1 12 cm + Int_t stsAddress09 = CbmStsAddress::GetAddress(2, 2, 1, 0, 0, 0); // U2 L2 M0 6 cm + Int_t stsAddress10 = CbmStsAddress::GetAddress(2, 2, 1, 1, 0, 0); // U2 L2 M1 6 cm + Int_t stsAddress11 = CbmStsAddress::GetAddress(2, 2, 1, 2, 0, 0); // U2 L2 M2 6 cm + + // // setup available up to sts_v22f. Available if reconstructing from tsa files (AB 14.05.2024) + // Int_t stsAddress00 = 0; + // Int_t stsAddress01 = CbmStsAddress::GetAddress(0, 0, 1, 0, 0, 0); // U0 L0 M0 6 cm + // Int_t stsAddress02 = CbmStsAddress::GetAddress(0, 0, 1, 1, 0, 0); // U0 L0 M1 6 cm + // Int_t stsAddress03 = CbmStsAddress::GetAddress(0, 1, 1, 0, 0, 0); // U0 L1 M0 6 cm + // Int_t stsAddress04 = CbmStsAddress::GetAddress(0, 1, 1, 1, 0, 0); // U0 L1 M1 6 cm + // Int_t stsAddress05 = CbmStsAddress::GetAddress(1, 0, 1, 0, 0, 0); // U1 L0 M0 6 cm + // Int_t stsAddress06 = CbmStsAddress::GetAddress(1, 0, 1, 1, 0, 0); // U1 L0 M1 12 cm + // Int_t stsAddress07 = CbmStsAddress::GetAddress(1, 1, 1, 0, 0, 0); // U1 L1 M0 6 cm + // Int_t stsAddress08 = CbmStsAddress::GetAddress(1, 1, 1, 1, 0, 0); // U1 L1 M1 12 cm + // Int_t stsAddress09 = CbmStsAddress::GetAddress(1, 2, 1, 0, 0, 0); // U1 L2 M0 6 cm + // Int_t stsAddress10 = CbmStsAddress::GetAddress(1, 2, 1, 1, 0, 0); // U1 L2 M1 6 cm + // Int_t stsAddress11 = CbmStsAddress::GetAddress(1, 2, 1, 2, 0, 0); // U1 L2 M2 6 cm + + std::cout << "STS address00 " << std::dec << stsAddress00 << " " << std::hex << stsAddress00 << std::endl; + std::cout << "STS address01 " << std::dec << stsAddress01 << " " << std::hex << stsAddress01 << std::endl; + std::cout << "STS address02 " << std::dec << stsAddress02 << " " << std::hex << stsAddress02 << std::endl; + std::cout << "STS address03 " << std::dec << stsAddress03 << " " << std::hex << stsAddress03 << std::endl; + std::cout << "STS address04 " << std::dec << stsAddress04 << " " << std::hex << stsAddress04 << std::endl; + std::cout << "STS address05 " << std::dec << stsAddress05 << " " << std::hex << stsAddress05 << std::endl; + std::cout << "STS address06 " << std::dec << stsAddress06 << " " << std::hex << stsAddress06 << std::endl; + std::cout << "STS address07 " << std::dec << stsAddress07 << " " << std::hex << stsAddress07 << std::endl; + std::cout << "STS address08 " << std::dec << stsAddress08 << " " << std::hex << stsAddress08 << std::endl; + std::cout << "STS address09 " << std::dec << stsAddress09 << " " << std::hex << stsAddress09 << std::endl; + std::cout << "STS address10 " << std::dec << stsAddress10 << " " << std::hex << stsAddress10 << std::endl; + std::cout << "STS address11 " << std::dec << stsAddress11 << " " << std::hex << stsAddress11 << std::endl; + + // --- Now we can define the sensor parameter set and tell recoSts to use it + auto sensorParSet = new CbmStsParSetSensor("CbmStsParSetSensor", "STS sensor parameters" + "mcbm2024"); + if (stsAddress00) sensorParSet->SetParSensor(stsAddress00, sensor6cm); + sensorParSet->SetParSensor(stsAddress01, sensor6cm); + sensorParSet->SetParSensor(stsAddress02, sensor6cm); + sensorParSet->SetParSensor(stsAddress03, sensor6cm); + sensorParSet->SetParSensor(stsAddress04, sensor6cm); + sensorParSet->SetParSensor(stsAddress05, sensor6cm); + sensorParSet->SetParSensor(stsAddress06, sensor12cm); + sensorParSet->SetParSensor(stsAddress07, sensor6cm); + sensorParSet->SetParSensor(stsAddress08, sensor12cm); + sensorParSet->SetParSensor(stsAddress09, sensor6cm); + sensorParSet->SetParSensor(stsAddress10, sensor6cm); + sensorParSet->SetParSensor(stsAddress11, sensor6cm); + recoSts->UseSensorParSet(sensorParSet); + + // ASIC params: #ADC channels, dyn. range, threshold, time resol., dead time, + // noise RMS, zero-threshold crossing rate + auto parAsic = new CbmStsParAsic(128, 31, 75000., 3000., 5., 800., 1000., 3.9789e-3); + + // Module params: number of channels, number of channels per ASIC + auto parMod = new CbmStsParModule(2048, 128); + parMod->SetAllAsics(*parAsic); + recoSts->UseModulePar(parMod); + + // Sensor conditions: full depletion voltage, bias voltage, temperature, + // coupling capacitance, inter-strip capacitance + auto sensorCond = new CbmStsParSensorCond(70., 140., 268., 17.5, 1.); + recoSts->UseSensorCond(sensorCond); + + run->AddTask(recoSts); + std::cout << "-I- : Added task " << recoSts->GetName() << std::endl; + // ------------------------------------------------------------------------ + } + + // ========================================================================= + // === local MUCH Reconstruction === + // ========================================================================= + if (bMUCH) { + TString muchGeoTag; + if (geoSetup->GetGeoTag(ECbmModuleId::kMuch, muchGeoTag)) { + // --- Parameter file name + TString geoTag; + geoSetup->GetGeoTag(ECbmModuleId::kMuch, geoTag); + Int_t muchFlag = 0; + if (geoTag.Contains("mcbm")) muchFlag = 1; + TString sectorFile = gSystem->Getenv("VMCWORKDIR"); + sectorFile += "/parameters/much/much_" + geoTag(0, 4) + "_mcbm_digi_sector.root"; + //sectorFile += "/parameters/much/much_v22j_mcbm_digi_sector.root"; + std::cout << "Using parameter file " << sectorFile << std::endl; + + // --- Initialization of the digi scheme + auto muchGeoScheme = CbmMuchGeoScheme::Instance(); + if (!muchGeoScheme->IsInitialized()) { + muchGeoScheme->Init(sectorFile.Data(), muchFlag); + } + // --- Hit finder for GEMs + FairTask* muchReco = new CbmMuchFindHitsGem(sectorFile.Data(), muchFlag); + run->AddTask(muchReco); + std::cout << "-I- " << myName << ": Added task " << muchReco->GetName() << " with parameter file " << sectorFile + << std::endl; + } + } + // ------------------------------------------------------------------------ + + // ========================================================================= + // === local TRD Reconstruction === + // ========================================================================= + + if (bTRD && geoSetup->IsActive(ECbmModuleId::kTrd)) { + CbmTrdClusterFinder* trdCluster; + Double_t triggerThreshold = 0.5e-6; // SIS100 + + trdCluster = new CbmTrdClusterFinder(); + trdCluster->SetNeighbourEnable(true, false); + trdCluster->SetMinimumChargeTH(triggerThreshold); + trdCluster->SetRowMerger(true); + CbmTrdClusterFinder::UseRecoHelpers(); + run->AddTask(trdCluster); + std::cout << "-I- : Added task " << trdCluster->GetName() << std::endl; + + CbmTrdHitProducer* trdHit = new CbmTrdHitProducer(); + //trdHit->SetHitTimeOffset(363); // hit time synchronization for TRD2D determined on run 2391 + trdHit->SetHitTimeOffset(80); // hit time synchronization for TRD2D determined on run 2914 + run->AddTask(trdHit); + std::cout << "-I- : Added task " << trdHit->GetName() << std::endl; + } + + // ========================================================================= + // === RICH Reconstruction === + // ========================================================================= + + if (bRICH && geoSetup->IsActive(ECbmModuleId::kRich)) { + // ----- Local reconstruction of RICH Hits ------------------------------ + CbmRichMCbmHitProducer* hitProd = new CbmRichMCbmHitProducer(); + hitProd->SetMappingFile(std::string(srcDir.Data()) + + "/macro/rich/mcbm/beamtime/mRICH_Mapping_vert_20190318_elView.geo"); + hitProd->SetIcdFilenameBase(std::string(srcDir.Data()) + "/macro/beamtime/mcbm2022/icd_offset_it"); + hitProd->setToTLimits(23.7, 30.0); + hitProd->applyToTCut(); + hitProd->applyICDCorrection(); + run->AddTask(hitProd); + // ------------------------------------------------------------------------ + + // ----- Local reconstruction in RICh -> Finding of Rings --------------- + CbmRichReconstruction* richReco = new CbmRichReconstruction(); + richReco->UseMCbmSetup(); + run->AddTask(richReco); + // ------------------------------------------------------------------------ + } + + // ========================================================================= + // === TOF Hitfinding === + // ========================================================================= + + TString parPath = srcDir + "/parameters/mcbm/"; + if (bTOF && geoSetup->IsActive(ECbmModuleId::kTof)) { + TString cFname; + switch (iTofCluMode) { + case 1: { + // ----- TOF defaults ------------------------ + Int_t calMode = 93; + Int_t calSel = 1; + Int_t calSm = 0; + Int_t RefSel = 0; + Double_t dDeadtime = 50.; + Int_t iSel2 = 500; + Bool_t bOut = kTRUE; + + // ------------------------------------------------------------------------ + gROOT->LoadMacro(srcDir + "/macro/beamtime/mcbm2022/ini_tof_clusterizer.C"); + Char_t* cCmd = + Form("ini_tof_clusterizer(%d,%d,%d,%d,\"%s\",%d,%d,%d,%f,\"%s\",\"%s\")", calMode, calSel, calSm, RefSel, + cFileId.Data(), iCalSet, (Int_t) bOut, iSel2, dDeadtime, cCalId.Data(), parPath.Data()); + + cout << "<I> " << cCmd << endl; + gInterpreter->ProcessLine(cCmd); + // disable histogramming + CbmTofEventClusterizer* tofClust = CbmTofEventClusterizer::Instance(); + tofClust->SetDutId(-1); // to disable histogramming + } break; + + default: { + ; + } + } + // ------------------------------------------------------------------------- + + // ========================================================================= + // === Tof Tracking === + // ========================================================================= + + if (bTOFtr) { + cout << "<I> Initialize Tof tracker by ini_trks" << endl; + + gROOT->LoadMacro(srcDir + "/macro/beamtime/mcbm2022/ini_tof_trks.C"); + Char_t* cCmd = + Form("ini_tof_trks(%d,%d,%d,%6.2f,%8.1f,\"%s\",%d,%d,%d,%f,\"%s\")", iSel, iTrackingSetup, iGenCor, dScalFac, + dChi2Lim2, cCalId.Data(), (Int_t) bUseSigCalib, iCalOpt, iTrkPar, dTOffScal, parPath.Data()); + cout << "<I> " << cCmd << endl; + gInterpreter->ProcessLine(cCmd); + + CbmTofFindTracks* tofFindTracks = CbmTofFindTracks::Instance(); + Int_t iNStations = tofFindTracks->GetNStations(); + } + } + + + //Constant Field + // CbmConstField *fMagField = new CbmConstField(); + // fMagField->SetFieldXYZ(0, 0 ,0 ); // values are in kG + // fMagField->SetFieldRegions(-10, -10 ,-10 , 10, 10 , 10 ); + // run->SetField(fMagField); + + // ========================================================================= + // === L1 === + // ========================================================================= + if (bL1) { + run->AddTask(new CbmTrackingDetectorInterfaceInit()); + + CbmL1* l1 = new CbmL1("L1"); + l1->SetMcbmMode(); + l1->SetVerbose(3); + run->AddTask(l1); + + CbmL1GlobalTrackFinder* globalTrackFinder = new CbmL1GlobalTrackFinder(); + FairTask* globalFindTracks = new CbmL1GlobalFindTracksEvents(globalTrackFinder); + run->AddTask(globalFindTracks); + } + // ========================================================================= + // === QA === + // ========================================================================= + if (bQA) { + // e.g for RICH: + CbmRichMCbmQaReal* qaTask = new CbmRichMCbmQaReal(); + Int_t taskId = 1; + if (taskId < 0) { + qaTask->SetOutputDir(Form("result_run%d", uRunId)); + } + else { + qaTask->SetOutputDir(Form("result_run%d_%05d", uRunId, taskId)); + } + //qaTask->XOffsetHistos(+25.0); + qaTask->XOffsetHistos(-4.1); + if (uRunId > 2351) qaTask->XOffsetHistos(0.0); + qaTask->SetMaxNofDrawnEvents(100); + qaTask->SetTotRich(23.7, 30.0); + qaTask->SetTriggerRichHits(eb_TriggerMinNumberRich); + qaTask->SetTriggerTofHits(0); // eb_TriggerMinNumberTof); + qaTask->SetSEDisplayRingOnly(); + run->AddTask(qaTask); + } + // ------------------------------------------------------------------------ + + // ----- Parameter database -------------------------------------------- + std::cout << std::endl << std::endl; + std::cout << "-I- " << myName << ": Set runtime DB" << std::endl; + FairRuntimeDb* rtdb = run->GetRuntimeDb(); + FairParRootFileIo* parIo1 = new FairParRootFileIo(); + FairParAsciiFileIo* parIo2 = new FairParAsciiFileIo(); + FairParRootFileIo* parIo3 = new FairParRootFileIo(); + //parIo1->open(parFileIn.Data(), "READ"); + //rtdb->setFirstInput(parIo1); + parIo2->open(parFileList, "in"); + rtdb->setSecondInput(parIo2); + parIo3->open(parFileOut.Data(), "RECREATE"); + // ------------------------------------------------------------------------ + rtdb->setOutput(parIo3); + + // ----- Run initialisation ------------------------------------------- + std::cout << std::endl; + std::cout << "-I- " << myName << ": Initialise run" << std::endl; + run->Init(); + rtdb->print(); + // ------------------------------------------------------------------------ + + + // ----- Start run ---------------------------------------------------- + std::cout << std::endl << std::endl; + std::cout << "-I- " << myName << ": Starting run" << std::endl; + run->Run(0, nTimeslices); + // ------------------------------------------------------------------------ + + + // ----- Finish ------------------------------------------------------- + + rtdb->print(); + rtdb->saveOutput(); + run->CreateGeometryFile(geoFileOut); + + timer.Stop(); + FairMonitor::GetMonitor()->Print(); + Double_t rtime = timer.RealTime(); + Double_t ctime = timer.CpuTime(); + std::cout << std::endl << std::endl; + std::cout << "Macro finished successfully." << std::endl; + std::cout << "Output file is " << outFile << std::endl; + std::cout << "Parameter file is " << parFileOut << std::endl; + std::cout << "Real time " << rtime << " s, CPU time " << ctime << " s" << std::endl; + std::cout << std::endl; + // ------------------------------------------------------------------------ + + + // ----- Resource monitoring ------------------------------------------ + // Extract the maximal used memory an add is as Dart measurement + // This line is filtered by CTest and the value send to CDash + FairSystemInfo sysInfo; + Float_t maxMemory = sysInfo.GetMaxMemory(); + std::cout << "<DartMeasurement name=\"MaxMemory\" type=\"numeric/double\">"; + std::cout << maxMemory; + std::cout << "</DartMeasurement>" << std::endl; + + Float_t cpuUsage = ctime / rtime; + std::cout << "<DartMeasurement name=\"CpuLoad\" type=\"numeric/double\">"; + std::cout << cpuUsage; + std::cout << "</DartMeasurement>" << std::endl; + // ------------------------------------------------------------------------ + + + // ----- Function needed for CTest runtime dependency ----------------- + // RemoveGeoManager(); + // ------------------------------------------------------------------------ + + /// --- Screen output for automatic tests + std::cout << " Test passed" << std::endl; + std::cout << " All ok " << std::endl; + + return kTRUE; +} diff --git a/macro/qa/run_recoQa.C b/macro/qa/run_recoQa.C index 5243739d3705bbe9d4b9de6cdc754133997ef31d..b93f19c8b6e2106c34af7d810c34fc09f35d3069 100644 --- a/macro/qa/run_recoQa.C +++ b/macro/qa/run_recoQa.C @@ -36,7 +36,7 @@ #include <TStopwatch.h> #endif -void run_recoQa(Int_t nEvents = -1, TString dataset = "2391_node8_0_0000", +void run_recoQa(Int_t nEvents = -1, TString recFile = "2391_node8_0_0000.rec.root", TString setupName = "mcbm_beam_2022_05_23_nickel", Bool_t bUseMC = kFALSE) { @@ -44,7 +44,7 @@ void run_recoQa(Int_t nEvents = -1, TString dataset = "2391_node8_0_0000", // Adjust this part according to your requirements // ----- Logger settings ---------------------------------------------- - FairLogger::GetLogger()->SetLogScreenLevel("DEBUG"); + FairLogger::GetLogger()->SetLogScreenLevel("INFO"); FairLogger::GetLogger()->SetLogVerbosityLevel("LOW"); // ------------------------------------------------------------------------ @@ -55,10 +55,11 @@ void run_recoQa(Int_t nEvents = -1, TString dataset = "2391_node8_0_0000", // ------------------------------------------------------------------------ // ----- In- and output file names ------------------------------------ + TString dataset = recFile; + dataset.ReplaceAll(".rec.root", ""); TString traFile = dataset + ".tra.root"; //TString rawFile = dataset + ".event.raw.root"; TString parFile = dataset + ".par.root"; - TString recFile = dataset + ".rec.root"; TString sinkFile = dataset + ".rqa.root"; TString geoFile = setupName + ".geo.root"; @@ -69,6 +70,8 @@ void run_recoQa(Int_t nEvents = -1, TString dataset = "2391_node8_0_0000", CbmSetup* setup = CbmSetup::Instance(); setup->LoadSetup(setupName); + //setup->SetActive(ECbmModuleId::kSts, false); + //setup->SetActive(ECbmModuleId::kTof, false); // In general, the following parts need not be touched // ======================================================================== @@ -82,6 +85,15 @@ void run_recoQa(Int_t nEvents = -1, TString dataset = "2391_node8_0_0000", gDebug = 0; // ------------------------------------------------------------------------ + std::map<std::string, TGeoHMatrix>* matrices{nullptr}; + TFile* misalignmentMatrixRootfile = TFile::Open(Form("AlignmentMatrices_%s.root", setupName.Data()), "READ"); + if (misalignmentMatrixRootfile && misalignmentMatrixRootfile->IsOpen()) { + gDirectory->GetObject("MisalignMatrices", matrices); + misalignmentMatrixRootfile->Close(); + } + else + LOG(warning) << "Could not find usable alignment file. Skip."; + // ----- FairRunAna --------------------------------------------------- FairFileSource* inputSource = new FairFileSource(recFile); if (bUseMC) { @@ -102,6 +114,8 @@ void run_recoQa(Int_t nEvents = -1, TString dataset = "2391_node8_0_0000", FairMonitor::GetMonitor()->EnableMonitor(kTRUE, monitorFile); // ------------------------------------------------------------------------ + if (matrices) run->AddAlignmentMatrices(*matrices); + // ----- MCDataManager (legacy mode) ----------------------------------- if (bUseMC) { std::cout << "-I- " << myName << ": Adding MC manager and MC to reco matching tasks\n"; @@ -141,10 +155,21 @@ void run_recoQa(Int_t nEvents = -1, TString dataset = "2391_node8_0_0000", run->AddTask(l1); // ----- Reco QA -------------------------------------------- + CbmRecoQaTask::Detector* det(nullptr); + CbmRecoQaTask::Detector::View* view(nullptr); CbmRecoQaTask* recoQa = new CbmRecoQaTask(); - recoQa->SetSetupClass(CbmRecoQaTask::kMcbm22); - double cos25 = TMath::Cos(TMath::DegToRad() * 25.); - recoQa->SetProjections({15.1 * cos25, 0., -20 * cos25, -38 * cos25, -50.5 * cos25}); + // recoQa->SetSetupClass(CbmRecoQaTask::kMcbm22); + recoQa->SetSetupClass(CbmRecoQaTask::kMcbm24); + recoQa->AddEventFilter(CbmRecoQaTask::EventFilter::eEventCut::kMultTrk)->SetFilter({1, 2}); + recoQa->AddTrackFilter(CbmRecoQaTask::TrackFilter::eTrackCut::kSts)->SetFilter({3}); + recoQa->AddTrackFilter(CbmRecoQaTask::TrackFilter::eTrackCut::kTrd)->SetFilter({2}); + recoQa->AddTrackFilter(CbmRecoQaTask::TrackFilter::eTrackCut::kTof)->SetFilter({1}); + // if ((det = recoQa->GetDetector(ECbmModuleId:kSts))) { + // view = det->GetView("U0L0M0"); + // view->SetProjection(); + // } + // double cos25 = TMath::Cos(TMath::DegToRad() * 25.); + // recoQa->SetProjections({15.1 * cos25, 0., -20 * cos25, -38 * cos25, -50.5 * cos25}); run->AddTask(recoQa); run->SetGenerateRunInfo(kFALSE); diff --git a/macro/run/run_unpack_tsa.C b/macro/run/run_unpack_tsa.C index afe3c100314468967e4a676c92a44adc090e4224..4072f0dd45bf8c5d37cf26e6fb5d8868dc542cc8 100644 --- a/macro/run/run_unpack_tsa.C +++ b/macro/run/run_unpack_tsa.C @@ -315,6 +315,24 @@ void run_unpack_tsa(std::vector<std::string> infile = {"test.tsa"}, UInt_t runid if (2350 <= runid) { trd1Dconfig->SetSystemTimeOffset(1300); // [ns] value to be updated } + if (runid >= 2700) //mCBM2024 + { + for (int elinkId = 0; elinkId < 36; ++elinkId) { + trd1Dconfig->SetElinkTimeOffset(20736, elinkId, -36); + trd1Dconfig->SetElinkTimeOffset(20737, elinkId, -37); + trd1Dconfig->SetElinkTimeOffset(20738, elinkId, -65); + trd1Dconfig->SetElinkTimeOffset(20739, elinkId, -52); + trd1Dconfig->SetElinkTimeOffset(20740, elinkId, -50); + trd1Dconfig->SetElinkTimeOffset(20741, elinkId, -49); + + //trd1Dconfig->SetElinkTimeOffset(20992, elinkId, 0); //no correlation + trd1Dconfig->SetElinkTimeOffset(20993, elinkId, -50); + trd1Dconfig->SetElinkTimeOffset(20994, elinkId, -57); + trd1Dconfig->SetElinkTimeOffset(20995, elinkId, -52); + trd1Dconfig->SetElinkTimeOffset(20996, elinkId, -52); + trd1Dconfig->SetElinkTimeOffset(20997, elinkId, -53); + } + } } // ------------- diff --git a/reco/eventbuilder/digis/CbmAlgoBuildRawEvents.cxx b/reco/eventbuilder/digis/CbmAlgoBuildRawEvents.cxx index 51cffc37a3a6203c1f30b5211a6c6aca530feb80..b687c94fc406232355892efb3ec29059df218783 100644 --- a/reco/eventbuilder/digis/CbmAlgoBuildRawEvents.cxx +++ b/reco/eventbuilder/digis/CbmAlgoBuildRawEvents.cxx @@ -1,6 +1,6 @@ -/* Copyright (C) 2020-2021 Facility for Antiproton and Ion Research in Europe, Darmstadt +/* Copyright (C) 2020-2024 Facility for Antiproton and Ion Research in Europe, Darmstadt SPDX-License-Identifier: GPL-3.0-only - Authors: Pierre-Alain Loizeau [committer], Dominik Smith */ + Authors: Pierre-Alain Loizeau [committer], Dominik Smith, Alexandru Bercuci */ #include "CbmAlgoBuildRawEvents.h" @@ -14,8 +14,8 @@ #include "CbmRichDigi.h" #include "CbmStsDigi.h" #include "CbmTofDigi.h" +#include "CbmTrdAddress.h" #include "CbmTrdDigi.h" - #include "TimesliceMetaData.h" /// FAIRROOT headers @@ -26,7 +26,7 @@ /// FAIRSOFT headers (geant, boost, ...) #include <TCanvas.h> #include <TClonesArray.h> -#include <TFolder.h> +#include <TDirectoryFile.h> #include <TH1.h> #include <TH2.h> #include <THttpServer.h> @@ -36,6 +36,8 @@ /// C/C++ headers #include <algorithm> +#define VERBOSE 0 + template<> void CbmAlgoBuildRawEvents::LoopOnSeeds<Double_t>(); @@ -284,7 +286,10 @@ void CbmAlgoBuildRawEvents::LoopOnSeeds<Double_t>() Double_t dTime = fSeedTimes->at(uSeed); /// Check if seed in acceptance window (is this needed here?) - if (dTime < fdSeedWindowBeg) { continue; } + if (dTime < fdSeedWindowBeg) { + LOG(debug4) << Form("CbmAlgoBuildRawEvents :: reject for time %f < %f\n", dTime, fdSeedWindowBeg); + continue; + } else if (fdSeedWindowEnd < dTime) { break; } @@ -305,10 +310,17 @@ void CbmAlgoBuildRawEvents::LoopOnSeeds() for (UInt_t uDigi = 0; uDigi < uNbRefDigis; ++uDigi) { LOG(debug) << Form("Checking seed %6u / %6u", uDigi, uNbRefDigis); const DigiSeed* pDigi = GetDigi<DigiSeed>(uDigi); + // hack for mCBM2024 data and Bmon station selection + if (fRefDet.detId == ECbmModuleId::kBmon && !filterBmon(pDigi->GetAddress())) continue; + const Double_t dTime = pDigi->GetTime(); + //printf("time = %f %d %d\n", dTime, CbmTofAddress::GetChannelSide(add), CbmTofAddress::GetChannelId(add)); /// Check if seed in acceptance window - if (dTime < fdSeedWindowBeg) { continue; } + if (dTime < fdSeedWindowBeg) { + LOG(debug4) << Form("CbmAlgoBuildRawEvents :: reject for time %f < %f\n", dTime, fdSeedWindowBeg); + continue; + } else if (fdSeedWindowEnd < dTime) { break; } @@ -329,6 +341,8 @@ void CbmAlgoBuildRawEvents::CheckSeed(Double_t dSeedTime, UInt_t uSeedDigiIdx) { /// If previous event valid and event overlap not allowed, check if we are in overlap /// and react accordingly + + LOG(debug4) << Form("CbmAlgoBuildRawEvents :: CheckSeed(%f, %d)\n", dSeedTime, uSeedDigiIdx); if (nullptr != fCurrentEvent && (EOverlapModeRaw::AllowOverlap != fOverMode || dSeedTime - fdPrevEvtTime < GetSeedTimeWinRange()) && dSeedTime - fdPrevEvtTime < fdWidestTimeWinRange) { @@ -552,7 +566,7 @@ void CbmAlgoBuildRawEvents::SearchMatches(Double_t dSeedTime, RawEventBuilderDet /// This algo relies on time sorted vectors for the selected detectors UInt_t uLocalIndexStart = detMatch.fuStartIndex; UInt_t uLocalIndexEnd = detMatch.fuStartIndex; - + LOG(debug4) << Form("CbmAlgoBuildRawEvents :: SearchMatches(%f, %s)\n", dSeedTime, detMatch.sName.data()); /// Check the Digis until out of window const UInt_t uNbSelDigis = GetNofDigis(detMatch.detId); /// Loop on size of vector @@ -561,6 +575,31 @@ void CbmAlgoBuildRawEvents::SearchMatches(Double_t dSeedTime, RawEventBuilderDet const Double_t dTime = pDigi->GetTime(); const Double_t dTimeDiff = dTime - dSeedTime; LOG(debug4) << detMatch.sName << Form(" => Checking match %6u / %6u, dt %f", uDigi, uNbSelDigis, dTimeDiff); + // int32_t add = pDigi->GetAddress(), dId[3] = {-1, -1, -1}; + // switch (detMatch.detId) { + // case ECbmModuleId::kBmon: + // dId[0] = CbmTofAddress::GetChannelSide(add); + // dId[1] = CbmTofAddress::GetChannelId(add); + // break; + // case ECbmModuleId::kSts: + // dId[0] = CbmStsAddress::GetElementId(add, EStsElementLevel::kStsUnit); + // dId[1] = CbmStsAddress::GetElementId(add, EStsElementLevel::kStsLadder); + // dId[2] = CbmStsAddress::GetElementId(add, EStsElementLevel::kStsModule); + // break; + // case ECbmModuleId::kTrd: + // case ECbmModuleId::kTrd2d: + // dId[0] = CbmTrdAddress::GetLayerId(add); + // dId[1] = CbmTrdAddress::GetModuleId(add); + // dId[2] = CbmTrdAddress::GetModuleAddress(add); + // break; + // case ECbmModuleId::kTof: + // dId[0] = CbmTofAddress::GetSmId(add); + // dId[1] = CbmTofAddress::GetSmType(add); + // dId[2] = CbmTofAddress::GetRpcId(add); + // break; + // default: break; + // } + // LOG(debug4) << Form("CbmAlgoBuildRawEvents :: Checking match %6u / %6u, dt=%f %s[%d %d %d]\n", uDigi, uNbSelDigis, dTimeDiff, detMatch.sName.data(), dId[0], dId[1], dId[2]); /// Check if within time window, update start/stop indices if needed if (dTimeDiff < detMatch.fdTimeWinBeg) { @@ -597,15 +636,18 @@ void CbmAlgoBuildRawEvents::SearchMatches(Double_t dSeedTime, RawEventBuilderDet /// Update the StartIndex and EndIndex for the next event seed detMatch.fuStartIndex = uLocalIndexStart; detMatch.fuEndIndex = uLocalIndexEnd; + LOG(debug4) << Form("CbmAlgoBuildRawEvents :: SearchMatches(%d, %d)\n", uLocalIndexStart, uLocalIndexEnd); } void CbmAlgoBuildRawEvents::AddDigiToEvent(const RawEventBuilderDetector& det, Int_t _entry) { + LOG(debug4) << Form("CbmAlgoBuildRawEvents :: :: AddDigiToEvent(%s)\n", det.sName.data()); fCurrentEvent->AddData(det.dataType, _entry); } void CbmAlgoBuildRawEvents::CheckTriggerCondition(Double_t dSeedTime) { + LOG(debug4) << Form("CbmAlgoBuildRawEvents :: :: CheckTriggerCondition(%f)\n", dSeedTime); /// Check if event is filling trigger conditions and clear it if not if (HasTrigger(fCurrentEvent)) { fdPrevEvtTime = dSeedTime; @@ -642,51 +684,65 @@ Bool_t CbmAlgoBuildRawEvents::HasTrigger(CbmEvent* event) return kTRUE; } -void CbmAlgoBuildRawEvents::SetBmonEventTime(CbmEvent* event) +bool CbmAlgoBuildRawEvents::SetBmonEventTime(CbmEvent* event) { const int32_t iNbDigis = event->GetNofData(ECbmDataType::kBmonDigi); + double eventTime(0.); + bool timeSet(false); - if (0 < iNbDigis) { - uint idx = event->GetIndex(ECbmDataType::kBmonDigi, 0); + LOG(debug4) << Form("CbmAlgoBuildRawEvents :: SetBmonEventTime(%p, %d)\n", (void*) event, iNbDigis); + for (int idigi = 0; idigi < iNbDigis; ++idigi) { + uint idx = event->GetIndex(ECbmDataType::kBmonDigi, idigi); const CbmBmonDigi* pDigi = GetDigi<CbmBmonDigi>(idx); - double eventTime = pDigi->GetTime(); + if (nullptr == pDigi) continue; + if (!filterBmon(pDigi->GetAddress())) continue; - for (int idigi = 1; idigi < iNbDigis; ++idigi) { - idx = event->GetIndex(ECbmDataType::kBmonDigi, idigi); - pDigi = GetDigi<CbmBmonDigi>(idx); - if (nullptr == pDigi) continue; - eventTime = std::min(pDigi->GetTime(), eventTime); + if (!timeSet) { + eventTime = pDigi->GetTime(); + timeSet = true; } - event->SetStartTime(eventTime); + else + eventTime = std::min(pDigi->GetTime(), eventTime); } + + if (timeSet) + event->SetStartTime(eventTime); + else + LOG(warning) << "CbmAlgoBuildRawEvents::SetBmonEventTime : failed"; + + return timeSet; } Bool_t CbmAlgoBuildRawEvents::CheckTriggerConditions(CbmEvent* event, const RawEventBuilderDetector& det) { + LOG(debug4) << Form("CbmAlgoBuildRawEvents :: :: CheckTriggerConditions(%p, %s)\n", (void*) event, det.sName.data()); /// Check if both Trigger conditions disabled for this detector if (0 == det.fuTriggerMinDigis && det.fiTriggerMaxDigis < 0) { return kTRUE; } /// Check if detector present if (!CheckDataAvailable(det.detId)) { - LOG(warning) << "Event does not have digis storage for " << det.sName - << " while the following trigger min/max are defined: " << det.fuTriggerMinDigis << " " - << det.fiTriggerMaxDigis; + LOG(debug2) << "Event does not have digis storage for " << det.sName + << " while the following trigger min/max are defined: " << det.fuTriggerMinDigis << " " + << det.fiTriggerMaxDigis; return kFALSE; } /// Check trigger rejection by minimal/maximal number or absence, if enabled/requested - int32_t iNbDigis = event->GetNofData(det.dataType); + int32_t iNbDigis = event->GetNofData(det.dataType); + int32_t iNbFilteredDigis = (det.detId == ECbmModuleId::kBmon ? getNofFilteredBmonDigis(event) : iNbDigis); /// a.Check trigger rejection by minimal number (if enabled) - if (0 < det.fuTriggerMinDigis && ((-1 == iNbDigis) || (static_cast<UInt_t>(iNbDigis) < det.fuTriggerMinDigis))) { - LOG(debug2) << "Event does not have enough digis: " << iNbDigis << " vs " << det.fuTriggerMinDigis << " for " - << det.sName; + if (0 < det.fuTriggerMinDigis + && ((-1 == iNbFilteredDigis) || (static_cast<UInt_t>(iNbFilteredDigis) < det.fuTriggerMinDigis))) { + LOG(debug2) << "Event does not have enough digis: " << iNbFilteredDigis << " vs " << det.fuTriggerMinDigis + << " for " << det.sName; return kFALSE; } /// b.Check trigger rejection by maximal number (if enabled) - if (0 <= det.fiTriggerMaxDigis && det.fiTriggerMaxDigis < iNbDigis) { - LOG(debug2) << "Event Has too many digis: " << iNbDigis << " vs " << det.fiTriggerMaxDigis << " for " << det.sName; + if (0 <= det.fiTriggerMaxDigis && det.fiTriggerMaxDigis < iNbFilteredDigis) { + LOG(debug2) << "Event Has too many digis: " << iNbFilteredDigis << " vs " << det.fiTriggerMaxDigis << " for " + << det.sName; return kFALSE; } @@ -959,7 +1015,7 @@ uint64_t CbmAlgoBuildRawEvents::GetSizeFromDigisNb(ECbmModuleId detId, uint64_t //---------------------------------------------------------------------- void CbmAlgoBuildRawEvents::CreateHistograms() { - outFolder = new TFolder("AlgoBuildRawEventsHist", " AlgoBuildRawEvents Histos"); + outFolder = new TDirectoryFile("AlgoBuildRawEventsHist", " AlgoBuildRawEvents Histos"); outFolder->Clear(); fhEventTime = new TH1F("hEventTime", "seed time of the events; Seed time within TS [s]; Events", 100000, 0, 0.2); @@ -1587,7 +1643,7 @@ void CbmAlgoBuildRawEvents::AddDetector(ECbmModuleId selDet, ECbmDataType dataTy fdTimeWinBegIn, fdTimeWinEndIn)); } -void CbmAlgoBuildRawEvents::SetReferenceDetector(RawEventBuilderDetector refDetIn) +void CbmAlgoBuildRawEvents::SetReferenceDetector(RawEventBuilderDetector refDetIn, std::vector<bool> select) { /// Loop on selection detectors for (std::vector<RawEventBuilderDetector>::iterator det = fvDets.begin(); det != fvDets.end(); ++det) { @@ -1627,6 +1683,21 @@ void CbmAlgoBuildRawEvents::SetReferenceDetector(RawEventBuilderDetector refDetI UpdateWidestTimeWinRange(); /// Detect usage of BMon to set Event StartTime CheckBmonInUse(); + + if (fbBmonInUse) { + if (select.size()) { + LOG(info) << "CbmAlgoBuildRawEvents::SetReferenceDetector => Detected Bmon station selection."; + fUseBmonMap.assign(select.size(), false); + int it0(0); + for (auto t0 : select) + SwitchBmonStation(it0++, (t0 > 0)); + } + } + else { + if (select.size()) + LOG(warning) << "CbmAlgoBuildRawEvents::SetReferenceDetector => Detected use of selector\nfor a reference " + "detector which does not support this option. Skip selection for the moment."; + } } void CbmAlgoBuildRawEvents::AddDetector(RawEventBuilderDetector selDet) @@ -1841,4 +1912,49 @@ void CbmAlgoBuildRawEvents::UpdateWidestTimeWinRange() } } +void CbmAlgoBuildRawEvents::SwitchBmonStation(int id, bool on) +{ + if (id < 0 || id >= (int) fUseBmonMap.size()) { + LOG(warning) << "CbmAlgoBuildRawEvents::SwitchBmonStation: Bmon station id outside range. Skip."; + return; + } + LOG(info) << "CbmAlgoBuildRawEvents::SwitchBmonStation: Bmon" << id << " station switched " << (on ? "ON" : "OFF") + << " for trigger."; + fUseBmonMap[id] = on; +} + +bool CbmAlgoBuildRawEvents::filterBmon(int32_t add) +{ + // skip any filtering if not explicitly requested by user. + if (!fUseBmonMap.size()) return true; + + // consistency check on the Bmon detector + if (CbmTofAddress::GetSmType(add) != 5) { + LOG(warning) << "CbmAlgoBuildRawEvents::filterBmon: Bmon digi with wrong address [GetSmType() != 5]. Skip."; + return false; + } + size_t mod = (size_t) CbmTofAddress::GetChannelSide(add); + // select Bmon detector + if (!fUseBmonMap[mod]) { + LOG(debug2) << "CbmAlgoBuildRawEvents::filterBmon : reject seed from Bmon" << mod; + return false; + } + return true; +} + +int32_t CbmAlgoBuildRawEvents::getNofFilteredBmonDigis(CbmEvent* event) +{ + // skip any filtering if not explicitly requested by user. + if (!fUseBmonMap.size()) return event->GetNofData(ECbmDataType::kBmonDigi); + + int32_t ndigi(0); + for (size_t idigi = 0; idigi < event->GetNofData(ECbmDataType::kBmonDigi); ++idigi) { + uint idx = event->GetIndex(ECbmDataType::kBmonDigi, idigi); + const CbmBmonDigi* pDigi = GetDigi<CbmBmonDigi>(idx); + if (!filterBmon(pDigi->GetAddress())) continue; + ndigi++; + } + return ndigi; +} + ClassImp(CbmAlgoBuildRawEvents) diff --git a/reco/eventbuilder/digis/CbmAlgoBuildRawEvents.h b/reco/eventbuilder/digis/CbmAlgoBuildRawEvents.h index 8f49b27b93ab768e6259ffffbfac9766ab883f6b..bf474c867a1cb3932dc73362255932f1a0a0482b 100644 --- a/reco/eventbuilder/digis/CbmAlgoBuildRawEvents.h +++ b/reco/eventbuilder/digis/CbmAlgoBuildRawEvents.h @@ -1,6 +1,6 @@ -/* Copyright (C) 2020-2021 Facility for Antiproton and Ion Research in Europe, Darmstadt +/* Copyright (C) 2020-2024 Facility for Antiproton and Ion Research in Europe, Darmstadt SPDX-License-Identifier: GPL-3.0-only - Authors: Pierre-Alain Loizeau [committer], Dominik Smith */ + Authors: Pierre-Alain Loizeau [committer], Dominik Smith, Alexandru Bercuci*/ #ifndef CBMALGOBUILDRAWEVENTS_H #define CBMALGOBUILDRAWEVENTS_H @@ -40,7 +40,7 @@ class TProfile; class TNamed; class TStopwatch; class TCanvas; -class TFolder; +class TDirectoryFile; enum class EOverlapModeRaw { @@ -153,7 +153,7 @@ public: void AddDetector(ECbmModuleId selDet, ECbmDataType dataTypeIn, std::string sNameIn, UInt_t uTriggerMinDigisIn = 0, Int_t iTriggerMaxDigisIn = -1, Double_t fdTimeWinBegIn = -100, Double_t fdTimeWinEndIn = 100); - void SetReferenceDetector(RawEventBuilderDetector refDetIn); + void SetReferenceDetector(RawEventBuilderDetector refDetIn, std::vector<bool> select = {}); void AddDetector(RawEventBuilderDetector selDet); void RemoveDetector(RawEventBuilderDetector selDet); @@ -162,7 +162,6 @@ public: void SetTriggerMinLayersNumber(ECbmModuleId selDet, UInt_t uVal); void SetTriggerWindow(ECbmModuleId selDet, Double_t dWinBeg, Double_t dWinEnd); void SetHistogramMaxDigiNb(ECbmModuleId selDet, Double_t dDigiNbMax); - void SetTsParameters(Double_t dTsStartTime, Double_t dTsLength, Double_t dTsOverLength) { fdTsStartTime = dTsStartTime; @@ -225,7 +224,7 @@ public: } // Output folder for histograms - TFolder* GetOutFolder() { return outFolder; } + TDirectoryFile* GetOutFolder() { return outFolder; } /// Data output access std::vector<CbmEvent*>& GetEventVector() { return fEventVector; } @@ -257,11 +256,19 @@ private: void UpdateTimeWinBoundariesExtrema(); void UpdateWidestTimeWinRange(); - void SetBmonEventTime(CbmEvent* event); + void SwitchBmonStation(int id, bool on = true); + bool SetBmonEventTime(CbmEvent* event); void CheckBmonInUse(); - TFolder* outFolder; // oputput folder to store histograms + /** \brief Filter Bmon stations. Hack added for the mCBM2024 data (AB) + * \param[in] add address of the Bmon digi + * \return true if selected + * \sa fuUseBmonMap, SelectBmonStations(), getNofFilteredDigis() */ + bool filterBmon(int32_t add); + int32_t getNofFilteredBmonDigis(CbmEvent* ev); + + TDirectoryFile* outFolder; // oputput folder to store histograms /// Constants static constexpr Double_t kdDefaultTimeWinBeg = -100.0; @@ -274,6 +281,8 @@ private: Bool_t fbUseMuchBeamtimeDigi = kTRUE; //! Switch between MUCH digi classes Bool_t fbGetTimings = kFALSE; //! Measure CPU time using stopwatch Bool_t fbUseTsMetaData = kTRUE; //! Read Ts Parameters from input tree + std::vector<bool> fUseBmonMap = {}; //! bit map for Bmon trigger. Defined by user + /// Event building mode and detectors selection EOverlapModeRaw fOverMode {EOverlapModeRaw::AllowOverlap}; @@ -372,7 +381,7 @@ private: Double_t fdPrevEvtTime = 0.; //! Save previous time information Double_t fdPrevEvtEndTime = 0.; //! Save previous event last digi time information - ClassDefNV(CbmAlgoBuildRawEvents, 1); + ClassDefNV(CbmAlgoBuildRawEvents, 2); }; #endif // CBMALGOBUILDRAWEVENTS_H diff --git a/reco/eventbuilder/digis/CbmTaskBuildRawEvents.h b/reco/eventbuilder/digis/CbmTaskBuildRawEvents.h index 00d6d79a2cef6bc419efef8ed68e5ed80cb10bdd..7b5ab4214fac5d9cf256a47ede680d3464a00816 100644 --- a/reco/eventbuilder/digis/CbmTaskBuildRawEvents.h +++ b/reco/eventbuilder/digis/CbmTaskBuildRawEvents.h @@ -75,9 +75,9 @@ public: fbFillHistos = bFlag; if (nullptr != fpAlgo) fpAlgo->SetFillHistos(fbFillHistos); } - void SetReferenceDetector(RawEventBuilderDetector refDet) + void SetReferenceDetector(RawEventBuilderDetector refDet, std::vector<bool> select = {}) { - if (nullptr != fpAlgo) fpAlgo->SetReferenceDetector(refDet); + if (nullptr != fpAlgo) fpAlgo->SetReferenceDetector(refDet, select); } void AddDetector(RawEventBuilderDetector selDet) { diff --git a/reco/qa/CMakeLists.txt b/reco/qa/CMakeLists.txt index f31759495be590b7ca18051c896642ecba9ff413..8dc5d62e6ef29ce756bcc3db179010735c90c315 100644 --- a/reco/qa/CMakeLists.txt +++ b/reco/qa/CMakeLists.txt @@ -13,7 +13,7 @@ set(SRCS set(LIBRARY_NAME CbmRecoQa) set(LINKDEF RecoQaLinkDef.h) set(PUBLIC_DEPENDENCIES - #Algo + CbmSimSteer CbmBase CbmData FairRoot::Base diff --git a/reco/qa/CbmRecoQaTask.cxx b/reco/qa/CbmRecoQaTask.cxx index 259210dc0bc8d04b1caff856e418143974fb52bb..17c82881d75aaf27ca2bdbe7b30645b50703b555 100644 --- a/reco/qa/CbmRecoQaTask.cxx +++ b/reco/qa/CbmRecoQaTask.cxx @@ -5,21 +5,92 @@ // CBM headers #include "CbmRecoQaTask.h" +#include "../../core/detectors/rich/utils/CbmRichUtil.h" +#include "CbmDefs.h" +#include "CbmEvent.h" +#include "CbmFsdHit.h" #include "CbmGlobalTrack.h" +#include "CbmMvdHit.h" +#include "CbmPsdHit.h" +#include "CbmRichHit.h" +#include "CbmSetup.h" +#include "CbmStsAddress.h" +#include "CbmStsHit.h" #include "CbmTimeSlice.h" #include "CbmTofAddress.h" +#include "CbmTofHit.h" #include "CbmTrdAddress.h" +#include "CbmTrdHit.h" // FAIR headers -#include "FairRootManager.h" -#include "FairSink.h" +#include <FairRootManager.h> +#include <FairSink.h> // ROOT headers -#include "TClonesArray.h" -#include "TH2D.h" +#include <TClonesArray.h> +#include <TGeoManager.h> +#include <TGeoNode.h> +#include <TH2D.h> using namespace std; +std::bitset<kRecoQaNConfigs> CbmRecoQaTask::fuRecoConfig = {}; + //_____________________________________________________________________ CbmRecoQaTask::CbmRecoQaTask() : FairTask("RecoQA", 0) {} +//_____________________________________________________________________ +CbmRecoQaTask::Detector* CbmRecoQaTask::AddDetector(ECbmModuleId id) +{ + /* Interface to the user. Check that the det defined in the outside world fulfills the quality criteria. + */ + switch (id) { + case ECbmModuleId::kMvd: + case ECbmModuleId::kSts: + case ECbmModuleId::kMuch: + case ECbmModuleId::kRich: + case ECbmModuleId::kTrd: + case ECbmModuleId::kTrd2d: + case ECbmModuleId::kTof: + case ECbmModuleId::kFsd: + case ECbmModuleId::kPsd: + if (GetDetector(id)) { + LOG(warn) << GetName() << "::AddDetector : det " << ToString(id) + << " already registered. Using \"CbmRecoQaTask::GetDetector(ECbmModuleId).\""; + return GetDetector(id); + } + LOG(debug) << GetName() << "::AddDetector(" << ToString(id) << ")."; + fDetQa.emplace(id, id); + break; + default: LOG(warn) << GetName() << "::AddDetector : unsupported det " << ToString(id); return nullptr; + } + + return &fDetQa[id]; +} + +//_____________________________________________________________________ +CbmRecoQaTask::Detector* CbmRecoQaTask::GetDetector(ECbmModuleId id) +{ + if (fDetQa.find(id) == fDetQa.end()) return nullptr; + return &fDetQa[id]; +} + +//_____________________________________________________________________ +const CbmTrack* CbmRecoQaTask::GetTrack(ECbmModuleId did, int id) const +{ + if (fTracks.find(did) == fTracks.end()) { + LOG(warning) << GetName() << " missing tracks for " << ToString(did); + return nullptr; + } + if (id < 0) { + LOG(warning) << GetName() << " negative trk idx for " << ToString(did); + return nullptr; + } + const CbmTrack* trk = (const CbmTrack*) (fTracks.at(did))->At(id); + if (!trk) { + LOG(debug1) << GetName() << " missing trk_" << id << " for " << ToString(did); + return nullptr; + } + return trk; +} + //_____________________________________________________________________ InitStatus CbmRecoQaTask::Init() { @@ -34,301 +105,388 @@ InitStatus CbmRecoQaTask::Init() return kERROR; } - fTracks = static_cast<TClonesArray*>(ioman->GetObject("GlobalTrack")); - if (!fTracks) { - LOG(fatal) << GetName() << "::Init: Global track array not found!"; - return kERROR; - } + fGTracks = static_cast<TClonesArray*>(ioman->GetObject("GlobalTrack")); + if (!fGTracks) + LOG(warn) << GetName() << "::Init: Global track array not found!"; + else + fuRecoConfig.set(kRecoTracks); - fTimeSlice = static_cast<CbmTimeSlice*>(ioman->GetObject("TimeSlice.")); - if (!fTimeSlice) { - LOG(warn) << GetName() << "::Init: No time slice object. Checking for events"; - fEvents = static_cast<TClonesArray*>(ioman->GetObject("CbmEvent")); - if (!fEvents) LOG(warn) << GetName() << "::Init: No event found. Some results will be missing."; - } + fEvents = static_cast<TClonesArray*>(ioman->GetObject("CbmEvent")); + if (!fEvents) + LOG(warn) << GetName() << "::Init: No event found. Some results will be missing."; + else + fuRecoConfig.set(kRecoEvents); fTrackMatches = static_cast<TClonesArray*>(ioman->GetObject("GlobalTrackMatch")); if (!fTrackMatches) { LOG(warn) << GetName() << "::Init: MC info for Global track not available !"; } - LOG(info) << GetName() << "::Init: Registered projections " << fProjView.size(); + LOG(info) << GetName() << "::Init: Registered projections " << fProjs.size(); - int itrkLy(0), iprjLy(0); - TFolder *modDir(nullptr), *smDir(nullptr); - fOutFolder.Clear(); switch (fSetupClass) { case kMcbm22: LOG(info) << GetName() << "::Init: Setup config for \"mCBM 2022\"."; - // STS U0 - station 0 - modDir = fOutFolder.AddFolder("STS", "STS reziduals to CA"); - fModView[itrkLy].push_back(ModuleView()); - fModView[itrkLy][0].hdXx.first = 10; - fModView[itrkLy][0].hdXx.second = - new TH2D(Form("hxx%d", itrkLy), Form("STS U0 x-dx; X_{STS U0} (cm); #Delta X (mm)"), 160, -8, 8, 400, -2, 2); - modDir->Add(fModView[itrkLy][0].hdXx.second); - fModView[itrkLy][0].hdYy.first = 10; - fModView[itrkLy][0].hdYy.second = new TH2D( - Form("hyy%d", itrkLy), Form("STS U0 y-dy; Y_{STS U0} (cm); #Delta Y (mm)"), 160, -8, 8, 350, -3.5, 3.5); - modDir->Add(fModView[itrkLy][0].hdYy.second); - fModView[itrkLy][0].hdT.first = 1; - fModView[itrkLy][0].hdT.second = - new TH2D(Form("ht%d", itrkLy), Form("STS U0 x-dt; X_{STS U0} (cm); #Delta T (ns)"), 160, -8, 8, 15, -60, 60); - modDir->Add(fModView[itrkLy][0].hdT.second); - fModView[itrkLy][0].hpullXphi = - new TH2D(Form("hpullx%d", itrkLy), Form("STS U0 pullx-phi; dx/dz_{trk}; pull X"), 160, -0.8, 0.8, 100, -5, 5); - modDir->Add(fModView[itrkLy][0].hpullXphi); - fModView[itrkLy][0].hpullYtht = - new TH2D(Form("hpully%d", itrkLy), Form("STS U0 pully-tht; dy/dz_{trk}; pull Y"), 160, -0.8, 0.8, 100, -5, 5); - modDir->Add(fModView[itrkLy][0].hpullYtht); - itrkLy++; - // STS U1 - station 1 - fModView[itrkLy].push_back(ModuleView()); - fModView[itrkLy][0].hdXx.first = 10; - fModView[itrkLy][0].hdXx.second = - new TH2D(Form("hxx%d", itrkLy), Form("STS U1 x-dx; X_{STS U1} (cm); #Delta X (mm)"), 200, -10, 10, 400, -2, 2); - modDir->Add(fModView[itrkLy][0].hdXx.second); - fModView[itrkLy][0].hdYy.first = 10; - fModView[itrkLy][0].hdYy.second = new TH2D( - Form("hyy%d", itrkLy), Form("STS U1 y-dy; Y_{STS U1} (cm); #Delta Y (mm)"), 200, -10, 10, 350, -3.5, 3.5); - modDir->Add(fModView[itrkLy][0].hdYy.second); - fModView[itrkLy][0].hdT.first = 1; - fModView[itrkLy][0].hdT.second = - new TH2D(Form("ht%d", itrkLy), Form("STS U1 x-dt; X_{STS U1} (cm); #Delta T (ns)"), 200, -10, 10, 15, -60, 60); - modDir->Add(fModView[itrkLy][0].hdT.second); - fModView[itrkLy][0].hpullXphi = - new TH2D(Form("hpullx%d", itrkLy), Form("STS U1 pullx-phi; dx/dz_{trk}; pull X"), 160, -0.8, 0.8, 100, -5, 5); - modDir->Add(fModView[itrkLy][0].hpullXphi); - fModView[itrkLy][0].hpullYtht = - new TH2D(Form("hpully%d", itrkLy), Form("STS U1 pully-tht; dy/dz_{trk}; pull Y"), 160, -0.8, 0.8, 100, -5, 5); - modDir->Add(fModView[itrkLy][0].hpullYtht); - itrkLy++; - - // =============================================================================== - modDir = fOutFolder.AddFolder("TRD", "TRD reziduals to CA"); - // TRD 2D - station 2 - fModView[itrkLy].push_back(ModuleView()); - fModView[itrkLy][0].hdXx.first = 10; - fModView[itrkLy][0].hdXx.second = - new TH2D(Form("hxx%d", itrkLy), Form("TRD2D x-dx; X_{TRD2D} (cm); #Delta X (mm)"), 500, -25, 25, 240, -6, 6); - modDir->Add(fModView[itrkLy][0].hdXx.second); - fModView[itrkLy][0].hdYy.first = 1; - fModView[itrkLy][0].hdYy.second = - new TH2D(Form("hyy%d", itrkLy), Form("TRD2D y-dy; Y_{TRD2D} (cm); #Delta Y (cm)"), 300, -30, 30, 400, -2, 2); - modDir->Add(fModView[itrkLy][0].hdYy.second); - fModView[itrkLy][0].hdT.first = 1; - fModView[itrkLy][0].hdT.second = - new TH2D(Form("ht%d", itrkLy), Form("TRD2D x-dt; X_{TRD2D} (cm); #Delta T (ns)"), 500, -25, 25, 25, -100, 100); - modDir->Add(fModView[itrkLy][0].hdT.second); - fModView[itrkLy][0].hpullXphi = - new TH2D(Form("hpullx%d", itrkLy), Form("TRD2D pullx-phi; dx/dz_{trk}; pull X"), 160, -0.8, 0.8, 100, -5, 5); - modDir->Add(fModView[itrkLy][0].hpullXphi); - fModView[itrkLy][0].hpullYtht = - new TH2D(Form("hpully%d", itrkLy), Form("TRD2D pully-tht; dy/dz_{trk}; pull Y"), 160, -0.8, 0.8, 100, -5, 5); - modDir->Add(fModView[itrkLy][0].hpullYtht); - itrkLy++; - // TRD 1Dx - station 3 - fModView[itrkLy].push_back(ModuleView()); - fModView[itrkLy][0].hdXx.first = 10; - fModView[itrkLy][0].hdXx.second = new TH2D( - Form("hxx%d", itrkLy), Form("TRD1Dx x-dx; X_{TRD1Dx} (cm); #Delta X (mm)"), 450, -45, 45, 200, -10, 10); - modDir->Add(fModView[itrkLy][0].hdXx.second); - fModView[itrkLy][0].hdYy.first = 1.; - fModView[itrkLy][0].hdYy.second = - new TH2D(Form("hyy%d", itrkLy), Form("TRD1Dx y-dy; Y_{TRD1Dx} (cm); #Delta Y (cm)"), 12, -45, 45, 400, -20, 20); - modDir->Add(fModView[itrkLy][0].hdYy.second); - fModView[itrkLy][0].hdT.first = 1; - fModView[itrkLy][0].hdT.second = new TH2D( - Form("ht%d", itrkLy), Form("TRD1Dx x-dt; X_{TRD1Dx} (cm); #Delta T (ns)"), 450, -45, 45, 25, -100, 100); - modDir->Add(fModView[itrkLy][0].hdT.second); - fModView[itrkLy][0].hpullXphi = - new TH2D(Form("hpullx%d", itrkLy), Form("TRD1Dx pullx-phi; dx/dz_{trk}; pull X"), 100, -0.5, 0.5, 100, -5, 5); - modDir->Add(fModView[itrkLy][0].hpullXphi); - fModView[itrkLy][0].hpullYtht = - new TH2D(Form("hpully%d", itrkLy), Form("TRD1Dx pully-tht; dy/dz_{trk}; pull Y"), 100, -0.5, 0.5, 100, -5, 5); - modDir->Add(fModView[itrkLy][0].hpullYtht); - itrkLy++; - // TRD 1Dy - station 4 - fModView[itrkLy].push_back(ModuleView()); - fModView[itrkLy][0].hdXx.first = 1; - fModView[itrkLy][0].hdXx.second = - new TH2D(Form("hxx%d", itrkLy), Form("TRD1Dy x-dx; X_{TRD1Dy} (cm); #Delta X (cm)"), 12, -45, 45, 400, -20, 20); - modDir->Add(fModView[itrkLy][0].hdXx.second); - fModView[itrkLy][0].hdYy.first = 10.; - fModView[itrkLy][0].hdYy.second = new TH2D( - Form("hyy%d", itrkLy), Form("TRD1Dy y-dy; Y_{TRD1Dy} (cm); #Delta Y (mm)"), 500, -50, 50, 400, -20, 20); - modDir->Add(fModView[itrkLy][0].hdYy.second); - fModView[itrkLy][0].hdT.first = 1; - fModView[itrkLy][0].hdT.second = new TH2D( - Form("ht%d", itrkLy), Form("TRD1Dy y-dt; Y_{TRD1Dy} (cm); #Delta T (ns)"), 500, -50, 50, 25, -100, 100); - modDir->Add(fModView[itrkLy][0].hdT.second); - fModView[itrkLy][0].hpullXphi = - new TH2D(Form("hpullx%d", itrkLy), Form("TRD1Dy pullx-phi; dx/dz_{trk}; pull X"), 100, -0.5, 0.5, 100, -5, 5); - modDir->Add(fModView[itrkLy][0].hpullXphi); - fModView[itrkLy][0].hpullYtht = - new TH2D(Form("hpully%d", itrkLy), Form("TRD1Dy pully-tht; dy/dz_{trk}; pull Y"), 100, -0.5, 0.5, 100, -5, 5); - modDir->Add(fModView[itrkLy][0].hpullYtht); - itrkLy++; - - // =============================================================================== - // ToF Sm0 & Sm3 (Typ0) - station 5 - modDir = fOutFolder.AddFolder("ToF", "ToF reziduals to CA"); - smDir = modDir->AddFolder("SM0_0", "ToF reziduals to CA for Sm0 and Sm3 type 0"); - for (int irpc(0); irpc < 5; irpc++) { - fModView[itrkLy].push_back(ModuleView()); - ModuleView* cdet = &fModView[itrkLy][irpc]; - cdet->hdXx.first = 1; - cdet->hdXx.second = - new TH2D(Form("hxx%d%d", itrkLy, irpc), Form("ToF Sm0/0 Rpc%d x-dx; X_{ToF} (cm); #Delta X (cm)", irpc), 900, - -25, 65, 60, -3, 3); - smDir->Add(cdet->hdXx.second); - cdet->hdYy.first = 1; - cdet->hdYy.second = - new TH2D(Form("hyy%d%d", itrkLy, irpc), Form("ToF Sm0/0 Rpc%d y-dy; Y_{ToF} (cm); #Delta Y (cm)", irpc), 160, - -80, 80, 60, -3, 3); - smDir->Add(cdet->hdYy.second); - cdet->hdT.first = 1.; - cdet->hdT.second = - new TH2D(Form("ht%d%d", itrkLy, irpc), Form("ToF Sm0/0 Rpc%d x-dt; X_{ToF} (cm); #Delta T (ns)", irpc), 900, - -25, 65, 70, -20, 50); - smDir->Add(cdet->hdT.second); - cdet->hpullXphi = - new TH2D(Form("hpullx%d%d", itrkLy, irpc), Form("ToF Sm0/0 Rpc%d pullx-phi; dx/dz_{ToF}; pull X", irpc), 160, - -0.3, 0.5, 100, -5, 5); - smDir->Add(cdet->hpullXphi); - cdet->hpullYtht = - new TH2D(Form("hpully%d%d", itrkLy, irpc), Form("ToF Sm0/0 Rpc%d pully-tht; dy/dz_{ToF}; pull Y", irpc), 180, - -0.45, 0.45, 100, -5, 5); - smDir->Add(cdet->hpullYtht); - } - itrkLy++; - // ToF Sm1 (Typ0) - station 6 - smDir = modDir->AddFolder("SM1_0", "ToF reziduals to CA for Sm1 type 0"); - for (int irpc(0); irpc < 5; irpc++) { - fModView[itrkLy].push_back(ModuleView()); - ModuleView* cdet = &fModView[itrkLy][irpc]; - cdet->hdXx.first = 1; - cdet->hdXx.second = - new TH2D(Form("hxx%d%d", itrkLy, irpc), Form("ToF Sm1/0 Rpc%d x-dx; X_{ToF} (cm); #Delta X (cm)", irpc), 500, - -25, 25, 60, -3, 3); - smDir->Add(cdet->hdXx.second); - cdet->hdYy.first = 1; - cdet->hdYy.second = - new TH2D(Form("hyy%d%d", itrkLy, irpc), Form("ToF Sm1/0 Rpc%d y-dy; Y_{ToF} (cm); #Delta Y (cm)", irpc), 160, - -80, 80, 60, -3, 3); - smDir->Add(cdet->hdYy.second); - cdet->hdT.first = 1.; - cdet->hdT.second = - new TH2D(Form("ht%d%d", itrkLy, irpc), Form("ToF Sm1/0 Rpc%d x-dt; X_{ToF} (cm); #Delta T (ns)", irpc), 500, - -25, 25, 70, -20, 50); - smDir->Add(cdet->hdT.second); - cdet->hpullXphi = - new TH2D(Form("hpullx%d%d", itrkLy, irpc), Form("ToF Sm1/0 Rpc%d pullx-phi; dx/dz_{ToF}; pull X", irpc), 120, - -0.3, 0.3, 100, -5, 5); - smDir->Add(cdet->hpullXphi); - cdet->hpullYtht = - new TH2D(Form("hpully%d%d", itrkLy, irpc), Form("ToF Sm1/0 Rpc%d pully-tht; dy/dz_{ToF}; pull Y", irpc), 180, - -0.45, 0.45, 100, -5, 5); - smDir->Add(cdet->hpullYtht); - } - itrkLy++; - // ToF Sm0 (Typ2) - station 7 - smDir = modDir->AddFolder("SM0_2", "ToF reziduals to CA for Sm0 type 2"); - for (int irpc(0); irpc < 5; irpc++) { - fModView[itrkLy].push_back(ModuleView()); - ModuleView* cdet = &fModView[itrkLy][irpc]; - cdet->hdXx.first = 1; - cdet->hdXx.second = - new TH2D(Form("hxx%d%d", itrkLy, irpc), Form("ToF Sm0/2 Rpc%d x-dx; X_{ToF} (cm); #Delta X (cm)", irpc), 500, - -50, 50, 60, -3, 3); - smDir->Add(cdet->hdXx.second); - cdet->hdYy.first = 1; - cdet->hdYy.second = - new TH2D(Form("hyy%d%d", itrkLy, irpc), Form("ToF Sm0/2 Rpc%d y-dy; Y_{ToF} (cm); #Delta Y (cm)", irpc), 160, - -80, 80, 60, -3, 3); - smDir->Add(cdet->hdYy.second); - cdet->hdT.first = 1.; - cdet->hdT.second = - new TH2D(Form("ht%d%d", itrkLy, irpc), Form("ToF Sm0/2 Rpc%d x-dt; X_{ToF} (cm); #Delta T (ps)", irpc), 500, - -50, 50, 100, -500, 500); - smDir->Add(cdet->hdT.second); - cdet->hpullXphi = - new TH2D(Form("hpullx%d%d", itrkLy, irpc), Form("ToF Sm0/2 Rpc%d pullx-phi; dx/dz_{ToF}; pull X", irpc), 120, - -0.3, 0.3, 100, -5, 5); - smDir->Add(cdet->hpullXphi); - cdet->hpullYtht = - new TH2D(Form("hpully%d%d", itrkLy, irpc), Form("ToF Sm0/2 Rpc%d pully-tht; dy/dz_{ToF}; pull Y", irpc), 180, - -0.45, 0.45, 100, -5, 5); - smDir->Add(cdet->hpullYtht); - } - itrkLy++; - // ToF Sm2 (Typ0) - station 8 - smDir = modDir->AddFolder("SM2_0", "ToF reziduals to CA for Sm2 type 0"); - for (int irpc(0); irpc < 5; irpc++) { - fModView[itrkLy].push_back(ModuleView()); - ModuleView* cdet = &fModView[itrkLy][irpc]; - cdet->hdXx.first = 1; - cdet->hdXx.second = - new TH2D(Form("hxx%d%d", itrkLy, irpc), Form("ToF Sm2/0 Rpc%d x-dx; X_{ToF} (cm); #Delta X (cm)", irpc), 600, - -30, 30, 60, -3, 3); - smDir->Add(cdet->hdXx.second); - cdet->hdYy.first = 1; - cdet->hdYy.second = - new TH2D(Form("hyy%d%d", itrkLy, irpc), Form("ToF Sm2/0 Rpc%d y-dy; Y_{ToF} (cm); #Delta Y (cm)", irpc), 160, - -80, 80, 60, -3, 3); - smDir->Add(cdet->hdYy.second); - cdet->hdT.first = 1.; - cdet->hdT.second = - new TH2D(Form("ht%d%d", itrkLy, irpc), Form("ToF Sm2/0 Rpc%d x-dt; X_{ToF} (cm); #Delta T (ps)", irpc), 600, - -30, 30, 100, -500, 500); - smDir->Add(cdet->hdT.second); - cdet->hpullXphi = - new TH2D(Form("hpullx%d%d", itrkLy, irpc), Form("ToF Sm2/0 Rpc%d pullx-phi; dx/dz_{ToF}; pull X", irpc), 120, - -0.3, 0.3, 100, -5, 5); - smDir->Add(cdet->hpullXphi); - cdet->hpullYtht = - new TH2D(Form("hpully%d%d", itrkLy, irpc), Form("ToF Sm2/0 Rpc%d pully-tht; dy/dz_{ToF}; pull Y", irpc), 180, - -0.45, 0.45, 100, -5, 5); - smDir->Add(cdet->hpullYtht); - } - itrkLy++; - - // =============================================================================== - // TRG - upstream projections - modDir = fOutFolder.AddFolder("Target", "Target tomography with CA"); - iprjLy = itrkLy; - for (auto zprj : fProjView) { - LOG(debug) << GetName() << "::Init: Project trks @ " << zprj.first; - fModView[iprjLy].push_back(ModuleView()); - fModView[iprjLy][0].hdXx.first = 1; - fModView[iprjLy][0].hdXx.second = - new TH2D(Form("hxy%d", iprjLy - itrkLy), Form("Project @ z = %+5.2f; X_{trk} (cm); Y_{trk} (cm)", zprj.first), - 700, -25, 10, 100, -5, 5); - modDir->Add(fModView[iprjLy][0].hdXx.second); - fModView[iprjLy][0].hdYy.first = 1; - fModView[iprjLy][0].hdYy.second = - new TH2D(Form("hxt%d", iprjLy), Form("Project @ z = %+5.2f; X_{trk} (cm); T_{trk} - T_{ev} (ns)", zprj.first), - 700, -25, 10, 350, -15.5, 5.5); - modDir->Add(fModView[iprjLy][0].hdYy.second); - iprjLy++; - } + InitMcbm22(); + break; + case kMcbm24: + LOG(info) << GetName() << "::Init: Setup config for \"mCBM 2024\". "; + InitMcbm24(); break; - case kMcbm24: LOG(info) << GetName() << "::Init: Setup config for \"mCBM 2024\". Not implemented."; break; case kDefault: LOG(info) << GetName() << "::Init: Setup config for \"DEFAULT\". Not implemented."; break; } + fOutFolder.Clear(); + for (auto& detp : fDetQa) { // SYSTEM LOOP + auto& det = detp.second; + + fHits[det.id] = static_cast<TClonesArray*>(ioman->GetObject(det.hit.name.data())); + if (!fHits[det.id]) { + LOG(warn) << GetName() << "::Init: Hit array for " << ToString(det.id) << " not found!"; + continue; + } + + if (fGTracks && det.trk.id != ECbmDataType::kUnknown) { + fTracks[det.id] = static_cast<TClonesArray*>(ioman->GetObject(det.trk.name.data())); + if (!fTracks[det.id]) LOG(warn) << GetName() << "::Init: Track array for " << ToString(det.id) << " not found!"; + } + if (!det.Init(&fOutFolder)) continue; + } + + // TDirectoryFile* trkDir = (TDirectoryFile*)fOutFolder.mkdir("track", "CA QA"); + // for (auto& trkly : fTrkView) { + // for (auto& view : trkly.second) view.Register(trkDir); + // } + + TDirectoryFile* trgDir = (TDirectoryFile*) fOutFolder.mkdir("target", "Target tomography with CA"); + for (auto& prj : fProjs) + prj.second.Register(trgDir); + return kSUCCESS; } +/// Hit classification on system and view +template<class Hit> +bool CbmRecoQaTask::Detector::View::HasAddress(const CbmHit* h, double&, double&) const +{ + LOG(error) << "Unprocessed hit in view " << name; + cout << h->ToString(); + + return false; +} +// STS specialization +template<> +bool CbmRecoQaTask::Detector::View::HasAddress<CbmStsHit>(const CbmHit* h, double& x, double& y) const +{ + int32_t a = h->GetAddress(); + uint32_t sel[] = {CbmStsAddress::GetElementId(a, EStsElementLevel::kStsUnit), + CbmStsAddress::GetElementId(a, EStsElementLevel::kStsLadder), + CbmStsAddress::GetElementId(a, EStsElementLevel::kStsModule)}; + uint idx(0); + for (auto ii : fSelector) { + if (uint(ii) != sel[idx]) break; + idx++; + } + if (idx != fSelector.size()) + return false; + else + LOG(debug4) << "Accept Sts hit for " << sel[0] << " " << sel[1] << " " << sel[2]; + + const CbmStsHit* h0 = dynamic_cast<const CbmStsHit*>(h); + if (!h0) { + LOG(error) << "Failed loading STS hit in view " << name; + return false; + } + x = h0->GetX(); + y = h0->GetY(); + return true; +} +// Rich specialization +template<> +bool CbmRecoQaTask::Detector::View::HasAddress<CbmRichHit>(const CbmHit* h, double& x, double& y) const +{ + int16_t uId = CbmRichUtil::GetDirichId(h->GetAddress()); + // TODO implement at RichUtil level + int8_t modId = (uId >> 8) & 0xF; + if (modId >= fSelector[0]) return false; + + const CbmRichHit* h0 = dynamic_cast<const CbmRichHit*>(h); + if (!h0) { + LOG(error) << "Failed loading RICH hit in view " << name; + return false; + } + x = h0->GetX(); + y = h0->GetY(); + return true; +} +// TRD specialization +template<> +bool CbmRecoQaTask::Detector::View::HasAddress<CbmTrdHit>(const CbmHit* h, double& x, double& y) const +{ + int16_t uId = CbmTrdAddress::GetModuleAddress(h->GetAddress()); + if (uId != fSelector[0]) + return false; + else + LOG(debug4) << "Accept Trd hit for " << uId; + + + const CbmTrdHit* h0 = dynamic_cast<const CbmTrdHit*>(h); + if (!h0) { + LOG(error) << "Failed loading TRD hit in view " << name; + return false; + } + x = h0->GetX(); + y = h0->GetY(); + return true; +} +// ToF specialization +template<> +bool CbmRecoQaTask::Detector::View::HasAddress<CbmTofHit>(const CbmHit* h, double& x, double& y) const +{ + int32_t a = h->GetAddress(); + int32_t sel[] = {CbmTofAddress::GetSmId(a), CbmTofAddress::GetSmType(a), CbmTofAddress::GetRpcId(a)}; + uint idx(0); + for (auto ii : fSelector) { + if (ii != sel[idx]) break; + idx++; + } + if (idx != fSelector.size()) + return false; + else + LOG(debug4) << "Accept Tof hit for " << sel[0] << " " << sel[1] << " " << sel[2]; + + const CbmTofHit* h0 = dynamic_cast<const CbmTofHit*>(h); + if (!h0) { + LOG(error) << "Failed loading ToF hit in view " << name; + return false; + } + x = h0->GetX(); + y = h0->GetY(); + return true; +} +template<class Hit> +bool CbmRecoQaTask::Detector::View::Load(const CbmHit* h, const CbmEvent* ev) +{ + double x(0), y(0); + if (!HasAddress<Hit>(h, x, y)) return false; + + //printf("View[%s] z(%d)[%f]\n", name.data(), (int)h->GetType(), h->GetZ()); + int scale(0); + TH2* hh(nullptr); + if (ev) { + if (fProjection.find(eViewProjection::kChdT) != fProjection.end()) { + scale = get<0>(fProjection[eViewProjection::kChdT]); + hh = get<2>(fProjection[eViewProjection::kChdT]); + hh->Fill(x, scale * (h->GetTime() - ev->GetStartTime())); + } + if (fProjection.find(eViewProjection::kXYh) != fProjection.end()) { + hh = get<2>(fProjection[eViewProjection::kXYh]); + hh->Fill(x, y); + } + } + if (fProjection.find(eViewProjection::kXYs) != fProjection.end()) { + hh = get<2>(fProjection[eViewProjection::kXYs]); + hh->Fill(x, y); + } + return true; +} + +bool CbmRecoQaTask::Detector::View::Load(const CbmKfTrackFitter::FitNode* n) +{ + double dx = n->fMxy.X()[0] - n->fTrack.X()[0], dy = n->fMxy.Y()[0] - n->fTrack.Y()[0], + dt = n->fMt.T()[0] - n->fTrack.Time()[0], + pullx = dx / sqrt(n->fMxy.Dx2()[0] + n->fTrack.GetCovariance(0, 0)[0]), + pully = dy / sqrt(n->fMxy.Dy2()[0] + n->fTrack.GetCovariance(1, 1)[0]); + // pullt = dt / sqrt(n->fMt.Dt2()[0] + n->fTrack.GetCovariance(5, 5)[0]); + + for (auto& projection : fProjection) { + int scale = get<0>(projection.second); + TH2* hh = get<2>(projection.second); + if (!hh) continue; + + switch (projection.first) { + case eViewProjection::kXYa: hh->Fill(n->fMxy.X()[0], n->fMxy.Y()[0]); break; + case eViewProjection::kXYp: hh->Fill(n->fTrack.X()[0], n->fTrack.Y()[0]); break; + case eViewProjection::kXdX: hh->Fill(n->fMxy.X()[0], scale * dx); break; + case eViewProjection::kYdY: hh->Fill(n->fMxy.Y()[0], scale * dy); break; + case eViewProjection::kWdT: hh->Fill(n->fMxy.X()[0], scale * dt); break; + case eViewProjection::kXpX: hh->Fill(n->fMxy.X()[0], pullx); break; + case eViewProjection::kYpY: hh->Fill(n->fMxy.Y()[0], pully); break; + default: break; + } + } + return true; +} + //_____________________________________________________________________ void CbmRecoQaTask::Exec(Option_t*) { - LOG(debug) << GetName() << "::Exec : Evs[" << (fEvents ? fEvents->GetEntriesFast() : 0) << "] Trks[" - << fTracks->GetEntriesFast() << "]"; - int itrack(0), nnodes(0); - for (auto trackObj : *fTracks) { - //printf("GlobalTrack %d\n", itrack); + LOG(info) << GetName() << "::Exec : Evs[" << (fEvents ? fEvents->GetEntriesFast() : 0) << "] Trks[" + << (fGTracks ? fGTracks->GetEntriesFast() : 0) << "]"; + + int iev(0), itrack(0), nnodes(0); + if (fEvents) { + for (auto evObj : *fEvents) { // EVENT LOOP + auto ev = dynamic_cast<CbmEvent*>(evObj); + // track QA filtering + if (!FilterEvent(ev)) continue; + + for (auto detp : fDetQa) { // SYSTEM LOOP + auto det = detp.second; + // check SYSTEM @ hit level + int nh = max(int(0), int(ev->GetNofData(det.hit.id))); + + if (!fHits[det.id]) { + LOG(error) << GetName() << "::Exec() : Hits for " << ToString(det.id) << " not available. Skip."; + continue; + } + for (int ih(0); ih < nh; ih++) { // HIT LOOP + const int jh = ev->GetIndex(det.hit.id, ih); + const CbmHit* hit = dynamic_cast<CbmHit*>(fHits[det.id]->At(jh)); + // printf("%s hit_%2d dt=%f time_event=%f time_hit=%f\n", ToString(det.id).data(), ih, ev->GetStartTime() - hit->GetTime(), ev->GetStartTime(), hit->GetTime()); + + bool ret(false); + for (auto view : det.fViews) { // VIEW LOOP + switch (det.id) { + case ECbmModuleId::kMvd: ret = view.Load<CbmMvdHit>(hit, ev); break; + case ECbmModuleId::kSts: ret = view.Load<CbmStsHit>(hit, ev); break; + case ECbmModuleId::kMuch: ret = view.Load<CbmMuchPixelHit>(hit, ev); break; + case ECbmModuleId::kRich: ret = view.Load<CbmRichHit>(hit, ev); break; + case ECbmModuleId::kTrd: ret = view.Load<CbmTrdHit>(hit, ev); break; + case ECbmModuleId::kTrd2d: ret = view.Load<CbmTrdHit>(hit, ev); break; + case ECbmModuleId::kTof: ret = view.Load<CbmTofHit>(hit, ev); break; + case ECbmModuleId::kFsd: ret = view.Load<CbmFsdHit>(hit, ev); break; + case ECbmModuleId::kPsd: ret = view.Load<CbmPsdHit>(hit, ev); break; + default: LOG(fatal) << GetName() << "::Exec : unsupported det " << ToString(det.id); break; + } + if (ret) break; + } // END VIEW LOOP + } // END HIT LOOP + } // END SYSTEM LOOP + + if (!fGTracks) continue; + + int ntrk = max(int(0), int(ev->GetNofData(ECbmDataType::kGlobalTrack))); + for (int itrk(0); itrk < ntrk; itrk++) { // TRACK LOOP + auto trackObj = (CbmGlobalTrack*) (*fGTracks)[ev->GetIndex(ECbmDataType::kGlobalTrack, itrk)]; + + // track QA filtering + if (!FilterTrack(trackObj)) continue; + + auto track = dynamic_cast<const CbmGlobalTrack*>(trackObj); + CbmKfTrackFitter::Track trkKf; + if (!fFitter.CreateGlobalTrack(trkKf, *track)) { + LOG(fatal) << GetName() << "::Exec: can not create the track for the fit! "; + break; + } + trkKf.fMsQp0 = 1. / 0.5; + trkKf.fIsMsQp0Set = true; + + // minimalistic QA tool for tracks used for target projection + int nhit[(size_t) ECbmModuleId::kLastModule] = {0}; + for (auto& n : trkKf.fNodes) { + // check if hit is well defined + if (n.fHitSystemId == ECbmModuleId::kNotExist) continue; + // check if detector is registered + if (fDetQa.find(n.fHitSystemId) == fDetQa.end()) continue; + + auto det = fDetQa[n.fHitSystemId]; + // det.Print(); + auto view = det.FindView(n.fMxy.X()[0], n.fMxy.Y()[0], n.fZ); + if (!view) { + LOG(debug) << GetName() << "::Exec: view for tracking layer " << ToString(det.id) << " not defined."; + continue; + } + + n.fIsTimeSet = false; + n.fIsXySet = false; + trkKf.MakeConsistent(); + fFitter.FitTrack(trkKf); + view->Load(&n); + nhit[(int) n.fHitSystemId]++; + n.fIsTimeSet = true; + n.fIsXySet = true; + } + + // Fit track for intermediate projections + int iprj(0); + if (!nnodes) nnodes = (int) trkKf.fNodes.size(); + for (auto zprj : fProjs) { + CbmKfTrackFitter::FitNode n = CbmKfTrackFitter::FitNode(); + n.fZ = zprj.first; + n.fIsXySet = true; + n.fReference1 = iprj++; + trkKf.fNodes.push_back(n); + } + trkKf.MakeConsistent(); + fFitter.FitTrack(trkKf); + for (auto& n : trkKf.fNodes) { + if (n.fReference1 < 0) continue; + if (fProjs.find(n.fReference1 + nnodes) == fProjs.end()) { + LOG(debug) << GetName() << "::Exec: view for tracking layer " << n.fReference1 + nnodes << " not defined."; + continue; + } + + // View* mod = &fProjs[n.fReference1 + nnodes][0]; + // mod->Load(&n); + // + // if (mod->hdXx.second) + // mod->hdXx.second->Fill(mod->hdXx.first * n.fTrack.X()[0], mod->hdXx.first * n.fTrack.Y()[0]); + // if (mod->hdYy.second) mod->hdYy.second->Fill(mod->hdYy.first * n.fTrack.X()[0], n.fTrack.Time()[0]); + } + itrack++; + } // END TRACK LOOP + iev++; + } // END EVENT LOOP + + LOG(info) << GetName() << "::Exec : Evs(%)[" << 1.e2 * iev / fEvents->GetEntriesFast() << "] Trks(%)[" + << (fGTracks ? 1.e3 * itrack / fGTracks->GetEntriesFast() : 0) << "]"; + return; // END EbyE QA + } + + // FULL TS LOOP + for (auto detp : fDetQa) { // SYSTEM LOOP + auto det = detp.second; + // check SYSTEM @ hit level + if (!fHits[det.id]) { + LOG(error) << GetName() << "::Exec() : Hits for " << ToString(det.id) << " not available. Skip."; + continue; + } + int nh = fHits[det.id]->GetEntriesFast(); + + for (int ih(0); ih < nh; ih++) { // HIT LOOP + const CbmHit* hit = dynamic_cast<CbmHit*>(fHits[det.id]->At(ih)); + // printf("%s hit_%2d dt=%f time_event=%f time_hit=%f\n", ToString(det.id).data(), ih, ev->GetStartTime() - hit->GetTime(), ev->GetStartTime(), hit->GetTime()); + + bool ret(false); + for (auto view : det.fViews) { // VIEW LOOP + switch (det.id) { + case ECbmModuleId::kMvd: ret = view.Load<CbmMvdHit>(hit); break; + case ECbmModuleId::kSts: ret = view.Load<CbmStsHit>(hit); break; + case ECbmModuleId::kMuch: ret = view.Load<CbmMuchPixelHit>(hit); break; + case ECbmModuleId::kRich: ret = view.Load<CbmRichHit>(hit); break; + case ECbmModuleId::kTrd: ret = view.Load<CbmTrdHit>(hit); break; + case ECbmModuleId::kTrd2d: ret = view.Load<CbmTrdHit>(hit); break; + case ECbmModuleId::kTof: ret = view.Load<CbmTofHit>(hit); break; + case ECbmModuleId::kFsd: ret = view.Load<CbmFsdHit>(hit); break; + case ECbmModuleId::kPsd: ret = view.Load<CbmPsdHit>(hit); break; + default: LOG(fatal) << GetName() << "::Exec : unsupported det " << ToString(det.id); break; + } + if (ret) break; + } // END VIEW LOOP + } // END HIT LOOP + } // END SYSTEM LOOP + if (!fGTracks) { + LOG(info) << GetName() << "::Exec : TS local reco only."; + return; // END TS QA (no tracking) + } + + for (auto trackObj : *fGTracks) { // TRACK LOOP auto track = dynamic_cast<const CbmGlobalTrack*>(trackObj); + + // track QA filtering + if (!FilterTrack(track)) continue; + CbmKfTrackFitter::Track trkKf; if (!fFitter.CreateGlobalTrack(trkKf, *track)) { LOG(fatal) << GetName() << "::Exec: can not create the track for the fit! "; @@ -341,66 +499,32 @@ void CbmRecoQaTask::Exec(Option_t*) // minimalistic QA tool for tracks used for target projection int nhit[(size_t) ECbmModuleId::kLastModule] = {0}; for (auto& n : trkKf.fNodes) { + // check if hit is well defined if (n.fHitSystemId == ECbmModuleId::kNotExist) continue; + // check if detector is registered + if (fDetQa.find(n.fHitSystemId) == fDetQa.end()) continue; + + auto det = fDetQa[n.fHitSystemId]; + // det.Print(); + auto view = det.FindView(n.fMxy.X()[0], n.fMxy.Y()[0], n.fZ); + if (!view) { + LOG(debug) << GetName() << "::Exec: view for tracking layer " << ToString(det.id) << " not defined."; + continue; + } + n.fIsTimeSet = false; n.fIsXySet = false; trkKf.MakeConsistent(); fFitter.FitTrack(trkKf); - double dx = n.fMxy.X()[0] - n.fTrack.X()[0], dy = n.fMxy.Y()[0] - n.fTrack.Y()[0], - dt = n.fMt.T()[0] - n.fTrack.Time()[0], - pullx = dx / sqrt(n.fMxy.Dx2()[0] + n.fTrack.GetCovariance(0, 0)[0]), - pully = dy / sqrt(n.fMxy.Dy2()[0] + n.fTrack.GetCovariance(1, 1)[0]); - // pullt = dt / sqrt(n.fMt.Dt2()[0] + n.fTrack.GetCovariance(5, 5)[0]); - - // add granularity for specific systems - int modId = 0; - switch (n.fHitSystemId) { - case ECbmModuleId::kTof: - modId = CbmTofAddress::GetRpcId(n.fHitAddress); - nhit[(int) n.fHitSystemId]++; - break; - default: nhit[(int) n.fHitSystemId]++; break; - } - - // check that we have correctly created all views - if (fModView.find(n.fMaterialLayer) == fModView.end()) { - LOG(debug) << GetName() << "::Exec: view for tracking layer " << n.fMaterialLayer << " not defined."; - continue; - } - if (fModView[n.fMaterialLayer].size() <= (size_t) modId) { - LOG(debug) << GetName() << "::Exec: view for tracking layer " << n.fMaterialLayer << " @ " << modId - << " not defined."; - continue; - } - ModuleView* mod = &fModView[n.fMaterialLayer][modId]; - if (!mod) { - LOG(warn) << GetName() << "::Exec: can not access view for tracking layer " << n.fMaterialLayer << " @ " - << modId; - continue; - } - if (mod->hdXx.second) mod->hdXx.second->Fill(n.fMxy.X()[0], mod->hdXx.first * dx); - if (mod->hdYy.second) mod->hdYy.second->Fill(n.fMxy.Y()[0], mod->hdYy.first * dy); - if (mod->hdT.second) { - if (n.fHitSystemId == ECbmModuleId::kTrd - && CbmTrdAddress::GetModuleAddress(n.fHitAddress) - == 37) { // TODO mark generically the low resolution coordinate of TRD - mod->hdT.second->Fill(n.fMxy.Y()[0], mod->hdT.first * dt); - } - else - mod->hdT.second->Fill(n.fMxy.X()[0], mod->hdT.first * dt); - } - if (mod->hpullXphi) mod->hpullXphi->Fill(n.fTrack.Tx()[0], pullx); - if (mod->hpullYtht) mod->hpullYtht->Fill(n.fTrack.Ty()[0], pully); + view->Load(&n); + nhit[(int) n.fHitSystemId]++; n.fIsTimeSet = true; n.fIsXySet = true; } - // track QA filtering - if (!FilterTrack(nhit)) continue; - // Fit track with all hits ON for vx projection int iprj(0); - for (auto zprj : fProjView) { + for (auto zprj : fProjs) { CbmKfTrackFitter::FitNode n = CbmKfTrackFitter::FitNode(); n.fZ = zprj.first; n.fIsXySet = true; @@ -411,49 +535,1041 @@ void CbmRecoQaTask::Exec(Option_t*) fFitter.FitTrack(trkKf); for (auto& n : trkKf.fNodes) { if (n.fReference1 < 0) continue; - if (fModView.find(n.fReference1 + nnodes) == fModView.end()) { + if (fProjs.find(n.fReference1 + nnodes) == fProjs.end()) { LOG(debug) << GetName() << "::Exec: view for tracking layer " << n.fReference1 + nnodes << " not defined."; continue; } - ModuleView* mod = &fModView[n.fReference1 + nnodes][0]; - if (mod->hdXx.second) - mod->hdXx.second->Fill(mod->hdXx.first * n.fTrack.X()[0], mod->hdXx.first * n.fTrack.Y()[0]); - if (mod->hdYy.second) mod->hdYy.second->Fill(mod->hdYy.first * n.fTrack.X()[0], n.fTrack.Time()[0]); + // View* mod = &fProjs[n.fReference1 + nnodes][0]; + // mod->Load(&n); + // if (mod->hdXx.second) + // mod->hdXx.second->Fill(mod->hdXx.first * n.fTrack.X()[0], mod->hdXx.first * n.fTrack.Y()[0]); + // if (mod->hdYy.second) mod->hdYy.second->Fill(mod->hdYy.first * n.fTrack.X()[0], n.fTrack.Time()[0]); } itrack++; - } + } // END TRACK LOOP + LOG(info) << GetName() << "::Exec : Trks(%)[" << (fGTracks ? 1.e3 * itrack / fGTracks->GetEntriesFast() : 0) << "]"; + + return; // END TS QA (tracking) } //_____________________________________________________________________ void CbmRecoQaTask::SetProjections(std::vector<double> vzpj) { - fProjView.clear(); + fProjs.clear(); for (auto zprj : vzpj) { - fProjView[zprj] = new TH2D(Form("hxx"), Form("; X (cm); Y (cm)"), 450, -25, 20, 450, -25, 20); + // fProjView[zprj] = new TH2D(Form("hxx"), Form("; X (cm); Y (cm)"), 450, -25, 20, 450, -25, 20); + fProjs.emplace(zprj, Detector::View(Form("z%.2f", zprj), "", {})); } } //_____________________________________________________________________ -bool CbmRecoQaTask::FilterTrack(int* ptr) +void CbmRecoQaTask::Finish() { - bool ret = false; - switch (fSetupClass) { - case kMcbm22: { - int* nhit = ptr; - if (nhit[int(ECbmModuleId::kSts)] == 2 && nhit[int(ECbmModuleId::kTrd2d)] && nhit[int(ECbmModuleId::kTof)]) - ret = true; + FairSink* sink = FairRootManager::Instance()->GetSink(); + sink->WriteObject(&fOutFolder, nullptr); +} + +//_____________________________________________________________________ +bool CbmRecoQaTask::FilterEvent(const CbmEvent* ptr) +{ + for (auto evCut : fFilterEv) { + if (!evCut.Accept(ptr, this)) return false; + } + return true; +} + +//_____________________________________________________________________ +bool CbmRecoQaTask::FilterTrack(const CbmGlobalTrack* ptr) +{ + for (auto trkCut : fFilterTrk) { + if (!trkCut.Accept(ptr, this)) return false; + } + return true; +} + +//_____________________________________________________________________ +void CbmRecoQaTask::InitMcbm22() +{ + CbmSetup* setup = CbmSetup::Instance(); + if (!setup) { + LOG(fatal) << GetName() << "::InitMcbm22() : Missing setup definition."; + return; + } + + TString dtag; + Detector::View* v(nullptr); + if (setup->IsActive(ECbmModuleId::kSts)) { + dtag = "v22f_mcbm"; + Detector* sts = AddDetector(ECbmModuleId::kSts); + // U0 L0 M0 + v = sts->AddView( + "U0L0M0", + Form("/cave_1/sts_%s_0/Station01_1/Ladder09_1/HalfLadder09d_2/HalfLadder09d_Module03_1/Sensor03_1", dtag.Data()), + {0, 0, 0}); + v->SetProjection(eViewProjection::kXdX, 1, "mm"); + v->SetProjection(eViewProjection::kYdY, 4, "mm"); + v = sts->AddView( + "U0L0M1", + Form("/cave_1/sts_%s_0/Station01_1/Ladder09_1/HalfLadder09d_2/HalfLadder09d_Module03_2/Sensor03_1", dtag.Data()), + {0, 0, 1}); + v->SetProjection(eViewProjection::kXdX, 1, "mm"); + v->SetProjection(eViewProjection::kYdY, 4, "mm"); + // U0 L1 + v = sts->AddView( + "U0L1M0", + Form("/cave_1/sts_%s_0/Station01_1/Ladder09_2/HalfLadder09d_2/HalfLadder09d_Module03_1/Sensor03_1", dtag.Data()), + {0, 1, 0}); + v->SetProjection(eViewProjection::kXdX, 1, "mm"); + v->SetProjection(eViewProjection::kYdY, 4, "mm"); + v = sts->AddView( + "U0L1M1", + Form("/cave_1/sts_%s_0/Station01_1/Ladder09_2/HalfLadder09d_2/HalfLadder09d_Module03_2/Sensor03_1", dtag.Data()), + {0, 1, 1}); + v->SetProjection(eViewProjection::kXdX, 1, "mm"); + v->SetProjection(eViewProjection::kYdY, 4, "mm"); + // U1 L0 + v = sts->AddView( + "U1L0M0", + Form("/cave_1/sts_%s_0/Station02_2/Ladder10_1/HalfLadder10d_2/HalfLadder10d_Module03_1/Sensor03_1", dtag.Data()), + {1, 0, 0}); + v->SetProjection(eViewProjection::kXdX, 0.75, "mm"); + v->SetProjection(eViewProjection::kYdY, 3, "mm"); + v = sts->AddView( + "U1L0M1", + Form("/cave_1/sts_%s_0/Station02_2/Ladder10_1/HalfLadder10d_2/HalfLadder10d_Module04_2/Sensor04_1", dtag.Data()), + {1, 0, 1}); + v->SetProjection(eViewProjection::kXdX, 0.75, "mm"); + v->SetProjection(eViewProjection::kYdY, 3, "mm"); + // U1 L1 + v = sts->AddView( + "U1L1M0", + Form("/cave_1/sts_%s_0/Station02_2/Ladder12_2/HalfLadder12d_2/HalfLadder12d_Module03_1/Sensor03_1", dtag.Data()), + {1, 1, 0}); + v->SetProjection(eViewProjection::kXdX, 0.75, "mm"); + v->SetProjection(eViewProjection::kYdY, 3, "mm"); + v = sts->AddView( + "U1L1M1", + Form("/cave_1/sts_%s_0/Station02_2/Ladder12_2/HalfLadder12d_2/HalfLadder12d_Module04_2/Sensor04_1", dtag.Data()), + {1, 1, 1}); + v->SetProjection(eViewProjection::kXdX, 0.75, "mm"); + v->SetProjection(eViewProjection::kYdY, 3, "mm"); + // U1 L2 + v = sts->AddView( + "U1L2M0", + Form("/cave_1/sts_%s_0/Station02_2/Ladder11_3/HalfLadder11d_2/HalfLadder11d_Module03_1/Sensor03_1", dtag.Data()), + {1, 2, 0}); + v->SetProjection(eViewProjection::kXdX, 0.75, "mm"); + v->SetProjection(eViewProjection::kYdY, 3, "mm"); + v = sts->AddView( + "U1L2M1", + Form("/cave_1/sts_%s_0/Station02_2/Ladder11_3/HalfLadder11d_2/HalfLadder11d_Module03_2/Sensor03_1", dtag.Data()), + {1, 2, 1}); + v->SetProjection(eViewProjection::kXdX, 0.75, "mm"); + v->SetProjection(eViewProjection::kYdY, 3, "mm"); + v = sts->AddView( + "U1L2M2", + Form("/cave_1/sts_%s_0/Station02_2/Ladder11_3/HalfLadder11d_2/HalfLadder11d_Module03_3/Sensor03_1", dtag.Data()), + {1, 2, 2}); + v->SetProjection(eViewProjection::kXdX, 0.75, "mm"); + v->SetProjection(eViewProjection::kYdY, 3, "mm"); + } + if (setup->IsActive(ECbmModuleId::kTrd)) { + dtag = "v22h_mcbm"; + Detector* trd = AddDetector(ECbmModuleId::kTrd2d); + // Trd2D + v = trd->AddView("2D", Form("/cave_1/trd_%s_0/layer01_20101/module9_101001001/gas_0", dtag.Data()), {5}); + v->SetProjection(eViewProjection::kChdT, 400, "ns"); + v->SetProjection(eViewProjection::kXdX, 10, "mm"); + v->SetProjection(eViewProjection::kYdY, 20, "mm"); + // Trd1Dx + trd = AddDetector(ECbmModuleId::kTrd); + v = trd->AddView("1Dx", Form("/cave_1/trd_%s_0/layer02_10202/module8_101002001", dtag.Data()), {21}); + v->SetProjection(eViewProjection::kChdT, 400, "ns"); + v->SetProjection(eViewProjection::kXdX, 1.5, "cm"); + // Trd1Dy + v = trd->AddView("1Dy", Form("/cave_1/trd_%s_0/layer03_11303/module8_101303001", dtag.Data()), {37}); + v->SetProjection(eViewProjection::kChdT, 400, "ns"); + } + if (setup->IsActive(ECbmModuleId::kTof)) { + dtag = "v21k_mcbm"; + Detector* tof = AddDetector(ECbmModuleId::kTof); + tof->hit.name = "TofCalHit"; + vector<int> tofSelect(3); + // add type 0 + tofSelect[1] = 0; // ToF type + for (int ism(0); ism < 4; ism++) { + tofSelect[0] = ism; + for (int irpc(0); irpc < 5; irpc++) { + tofSelect[2] = irpc; + v = tof->AddView(Form("Sm%dRpc%d", tofSelect[0], tofSelect[2]), + Form("/cave_1/tof_%s_0/tof_%sStand_1/module_%d_%d/gas_box_0/counter_%d", dtag.Data(), + dtag.Data(), tofSelect[1], tofSelect[0], tofSelect[2]), + tofSelect); + v->SetProjection(eViewProjection::kChdT, 15, "ns"); + } + } + // add type 2 + tofSelect[1] = 2; // ToF type + tofSelect[0] = 0; // Tof SM id + for (int irpc(0); irpc < 5; irpc++) { + tofSelect[2] = irpc; + tof->AddView(Form("Sm_2%dRpc%d", tofSelect[0], tofSelect[2]), + Form("/cave_1/tof_%s_0/tof_%sStand_1/module_%d_%d/gas_box_0/counter_%d", dtag.Data(), dtag.Data(), + tofSelect[1], tofSelect[0], tofSelect[2]), + tofSelect); + } + } + + // =============================================================================== + // TRG - upstream projections + // int iprjLy = 0; + // for (auto prj : fProjs) { + // LOG(debug) << GetName() << "::Init: Project trks @ " << prj.first; + // prj.second.name = Form("Z=%+4.1f", prj.first); + // prj.second.hdXx.first = 1; + // prj.second.hdXx.second = + // new TH2D(Form("Hxy%d", iprjLy), Form("Project @ z = %+5.2f; X_{trk} (cm); Y_{trk} (cm)", prj.first), + // 700, -25, 10, 100, -5, 5); + // prj.second.hdT.first = 1; + // prj.second.hdT.second = + // new TH2D(Form("Hxt%d", iprjLy), Form("Project @ z = %+5.2f; X_{trk} (cm); T_{trk} - T_{ev} (ns)", prj.first), + // 700, -25, 10, 350, -15.5, 5.5); + // iprjLy++; + // } +} + +//_____________________________________________________________________ +void CbmRecoQaTask::InitMcbm24() +{ + CbmSetup* setup = CbmSetup::Instance(); + if (!setup) { + LOG(fatal) << GetName() << "::InitMcbm24() : Missing setup definition."; + return; + } + TString dtag; + Detector::View* v(nullptr); + if (setup->IsActive(ECbmModuleId::kSts)) { + // setup->GetGeoTag(ECbmModuleId::kSts, dtag); + // LOG(debug) << GetName() << "::InitMcbm24() : found " << dtag; + dtag = "v24c_mcbm"; + Detector* sts = AddDetector(ECbmModuleId::kSts); + // U0 L0 M0 + v = sts->AddView( + "U0L0M0", + Form("/cave_1/sts_%s_0/Station01_1/Ladder13_1/HalfLadder13u_1/HalfLadder13u_Module03_1/Sensor03_1", dtag.Data()), + {0, 0, 0}); + v->SetProjection(eViewProjection::kYdY, 5, "mm"); + v->SetProjection(eViewProjection::kXdX, 1, "mm"); + // U1 L0 M0 + v = sts->AddView( + "U1L0M0", + Form("/cave_1/sts_%s_0/Station02_2/Ladder09_1/HalfLadder09d_2/HalfLadder09d_Module03_1/Sensor03_1", dtag.Data()), + {1, 0, 0}); + v->SetProjection(eViewProjection::kYdY, 5, "mm"); + v->SetProjection(eViewProjection::kXdX, 1, "mm"); + v = sts->AddView( + "U1L0M1", + Form("/cave_1/sts_%s_0/Station02_2/Ladder09_1/HalfLadder09d_2/HalfLadder09d_Module03_2/Sensor03_1", dtag.Data()), + {1, 0, 1}); + v->SetProjection(eViewProjection::kYdY, 5, "mm"); + v->SetProjection(eViewProjection::kXdX, 1, "mm"); + // U1 L1 + v = sts->AddView( + "U1L1M0", + Form("/cave_1/sts_%s_0/Station02_2/Ladder09_2/HalfLadder09d_2/HalfLadder09d_Module03_1/Sensor03_1", dtag.Data()), + {1, 1, 0}); + v->SetProjection(eViewProjection::kYdY, 5, "mm"); + v->SetProjection(eViewProjection::kXdX, 1, "mm"); + v = sts->AddView( + "U1L1M1", + Form("/cave_1/sts_%s_0/Station02_2/Ladder09_2/HalfLadder09d_2/HalfLadder09d_Module03_2/Sensor03_1", dtag.Data()), + {1, 1, 1}); + v->SetProjection(eViewProjection::kYdY, 5, "mm"); + v->SetProjection(eViewProjection::kXdX, 1, "mm"); + // U2 L0 + v = sts->AddView( + "U2L0M0", + Form("/cave_1/sts_%s_0/Station03_3/Ladder10_1/HalfLadder10d_2/HalfLadder10d_Module03_1/Sensor03_1", dtag.Data()), + {2, 0, 0}); + v->SetProjection(eViewProjection::kYdY, 5, "mm"); + v->SetProjection(eViewProjection::kXdX, 1, "mm"); + v = sts->AddView( + "U2L0M1", + Form("/cave_1/sts_%s_0/Station03_3/Ladder10_1/HalfLadder10d_2/HalfLadder10d_Module04_2/Sensor04_1", dtag.Data()), + {2, 0, 1}); + v->SetProjection(eViewProjection::kYdY, 5, "mm"); + v->SetProjection(eViewProjection::kXdX, 1, "mm"); + // U2 L1 + v = sts->AddView( + "U2L1M0", + Form("/cave_1/sts_%s_0/Station03_3/Ladder12_2/HalfLadder12d_2/HalfLadder12d_Module03_1/Sensor03_1", dtag.Data()), + {2, 1, 0}); + v->SetProjection(eViewProjection::kYdY, 5, "mm"); + v->SetProjection(eViewProjection::kXdX, 1, "mm"); + v = sts->AddView( + "U2L1M1", + Form("/cave_1/sts_%s_0/Station03_3/Ladder12_2/HalfLadder12d_2/HalfLadder12d_Module04_2/Sensor04_1", dtag.Data()), + {2, 1, 1}); + v->SetProjection(eViewProjection::kYdY, 5, "mm"); + v->SetProjection(eViewProjection::kXdX, 1, "mm"); + // U2 L2 + v = sts->AddView( + "U2L2M0", + Form("/cave_1/sts_%s_0/Station03_3/Ladder11_3/HalfLadder11d_2/HalfLadder11d_Module03_1/Sensor03_1", dtag.Data()), + {2, 2, 0}); + v->SetProjection(eViewProjection::kYdY, 5, "mm"); + v->SetProjection(eViewProjection::kXdX, 1, "mm"); + v = sts->AddView( + "U2L2M1", + Form("/cave_1/sts_%s_0/Station03_3/Ladder11_3/HalfLadder11d_2/HalfLadder11d_Module03_2/Sensor03_1", dtag.Data()), + {2, 2, 1}); + v = sts->AddView( + "U2L2M2", + Form("/cave_1/sts_%s_0/Station03_3/Ladder11_3/HalfLadder11d_2/HalfLadder11d_Module03_3/Sensor03_1", dtag.Data()), + {2, 2, 2}); + v->SetProjection(eViewProjection::kYdY, 5, "mm"); + v->SetProjection(eViewProjection::kXdX, 1, "mm"); + } + if (setup->IsActive(ECbmModuleId::kTrd)) { + // setup->GetGeoTag(ECbmModuleId::kTrd, dtag); + // LOG(debug) << GetName() << "::InitMcbm24() : found " << dtag; + dtag = "v24e_mcbm"; + Detector* trd = AddDetector(ECbmModuleId::kTrd2d); + // Trd2D + v = trd->AddView("2D", Form("/cave_1/trd_%s_0/layer01_20101/module9_101001001/gas_0", dtag.Data()), {5}); + v->SetProjection(eViewProjection::kChdT, 300, "ns"); + // Trd1Dx + trd = AddDetector(ECbmModuleId::kTrd); + v = trd->AddView("1Dx", Form("/cave_1/trd_%s_0/layer02_10202/module5_101002001", dtag.Data()), {21}); + v->SetProjection(eViewProjection::kChdT, 300, "ns"); + v->SetProjection(eViewProjection::kXdX, 7, "cm"); + // Trd1Dy + v = trd->AddView("1Dy", Form("/cave_1/trd_%s_0/layer03_11303/module5_101103001", dtag.Data()), {37}); + v->SetProjection(eViewProjection::kChdT, 300, "ns"); + v->SetProjection(eViewProjection::kXdX, 7, "cm"); + } + if (setup->IsActive(ECbmModuleId::kTof)) { + // setup->GetGeoTag(ECbmModuleId::kTof, dtag); + // LOG(debug) << GetName() << "::InitMcbm24() : found " << dtag; + dtag = "v24d_mcbm"; + Detector* tof = AddDetector(ECbmModuleId::kTof); + vector<int> tofSelect(3); + // add type 0 + for (int ism(0); ism < 6; ism++) { + tofSelect[0] = ism; + for (int irpc(0); irpc < 5; irpc++) { + tofSelect[2] = irpc; + v = tof->AddView(Form("Sm%dRpc%d", ism, irpc), + Form("/cave_1/tof_%s_0/tof_%sStand_1/module_%d_%d/gas_box_0/counter_%d", dtag.Data(), + dtag.Data(), tofSelect[1], tofSelect[0], tofSelect[2]), + tofSelect); + v->SetProjection(eViewProjection::kXdX, 7, "cm"); + v->SetProjection(eViewProjection::kYdY, 7, "cm"); + } + } + // add type 6 (Buch) + tofSelect[0] = 0; + tofSelect[1] = 6; + for (int irpc(0); irpc < 2; irpc++) { + tofSelect[2] = irpc; + tof->AddView(Form("BuchRpc%d", irpc), + Form("/cave_1/tof_%s_0/tof_%sStand_1/module_%d_%d/gas_box_0/counter_%d", dtag.Data(), dtag.Data(), + tofSelect[1], tofSelect[0], tofSelect[2]), + tofSelect); + } + // add type 9 + tofSelect[1] = 9; + for (int ism(0); ism < 2; ism++) { + tofSelect[0] = ism; + for (int irpc(0); irpc < 2; irpc++) { + tofSelect[2] = irpc; + tof->AddView(Form("Test%dRpc%d", ism, irpc), + Form("/cave_1/tof_%s_0/tof_%sStand_1/module_%d_%d/gas_box_0/counter_%d", dtag.Data(), dtag.Data(), + tofSelect[1], tofSelect[0], tofSelect[2]), + tofSelect); + } + } + // add type 2 + tofSelect[1] = 2; + for (int ism(0); ism < 2; ism++) { + tofSelect[0] = ism; + for (int irpc(0); irpc < 5; irpc++) { + tofSelect[2] = irpc; + tof->AddView(Form("Sm2%dRpc%d", ism, irpc), + Form("/cave_1/tof_%s_0/tof_%sStand_1/module_%d_%d/gas_box_0/counter_%d", dtag.Data(), dtag.Data(), + tofSelect[1], tofSelect[0], tofSelect[2]), + tofSelect); + } + } + } + if (setup->IsActive(ECbmModuleId::kRich)) { + // setup->GetGeoTag(ECbmModuleId::kRich, dtag); + // LOG(debug) << GetName() << "::InitMcbm24() : found " << dtag; + dtag = "v24a_mcbm"; + Detector* rich = AddDetector(ECbmModuleId::kRich); + // Aerogel 1 + rich->AddView("Aerogel", Form("/cave_1/rich_%s_0/box_1/Gas_1", dtag.Data()), {4}); + } +} + +//========= DETECTOR ====================== +CbmRecoQaTask::Detector::Detector(ECbmModuleId did) +{ + id = did; + switch (id) { + case ECbmModuleId::kMvd: new (&hit) Data(ECbmDataType::kMvdHit, "MvdHit"); break; + case ECbmModuleId::kSts: + new (&hit) Data(ECbmDataType::kStsHit, "StsHit"); + new (&trk) Data(ECbmDataType::kStsTrack, "StsTrack"); + break; + case ECbmModuleId::kMuch: new (&hit) Data(ECbmDataType::kMuchPixelHit, "MuchHit"); break; + case ECbmModuleId::kRich: new (&hit) Data(ECbmDataType::kRichHit, "RichHit"); break; + case ECbmModuleId::kTrd: + case ECbmModuleId::kTrd2d: + new (&hit) Data(ECbmDataType::kTrdHit, "TrdHit"); + new (&trk) Data(ECbmDataType::kTrdTrack, "TrdTrack"); + break; + case ECbmModuleId::kTof: + new (&hit) Data(ECbmDataType::kTofHit, "TofHit"); + new (&trk) Data(ECbmDataType::kTofTrack, "TofTrack"); break; + case ECbmModuleId::kFsd: new (&hit) Data(ECbmDataType::kFsdHit, "FsdHit"); break; + case ECbmModuleId::kPsd: new (&hit) Data(ECbmDataType::kPsdHit, "PsdHit"); break; + default: + LOG(warn) << "QA unsupported for Detector=" << ToString(did); + id = ECbmModuleId::kNotExist; + break; + } +} + +//+++++++++++++++++++++ Detector ++++++++++++++++++++++++++++++++ +//_________________________________________________________________ +CbmRecoQaTask::Detector::View* CbmRecoQaTask::Detector::AddView(const char* n, const char* p, std::vector<int> set) +{ + View* v(nullptr); + fViews.emplace_back(n, p, set); + v = &fViews.back(); + v->AddProjection(CbmRecoQaTask::eViewProjection::kXYs); + + v->AddProjection(CbmRecoQaTask::eViewProjection::kChdT); + v->AddProjection(CbmRecoQaTask::eViewProjection::kXYh); + + v->AddProjection(CbmRecoQaTask::eViewProjection::kXYa); + v->AddProjection(CbmRecoQaTask::eViewProjection::kXYp); + v->AddProjection(CbmRecoQaTask::eViewProjection::kXdX); + v->AddProjection(CbmRecoQaTask::eViewProjection::kYdY); + v->AddProjection(CbmRecoQaTask::eViewProjection::kWdT); + v->AddProjection(CbmRecoQaTask::eViewProjection::kXpX); + v->AddProjection(CbmRecoQaTask::eViewProjection::kYpY); + + return v; +} + +CbmRecoQaTask::Detector::View* CbmRecoQaTask::Detector::GetView(const char* n) +{ + for (auto& view : fViews) + if (view.name.compare(n) == 0) return &view; + + return nullptr; +} + +CbmRecoQaTask::Detector::View* CbmRecoQaTask::Detector::FindView(double x, double y, double z) +{ + for (auto& v : fViews) { + // printf("Looking for p[%f %f %f] in V[%s-%s] @ %f %f %f (%f %f %f)\n", x, y, z, ToString(id).data(), v.name.data(), v.pos[0], v.pos[1], v.pos[2], v.size[0], v.size[1], v.size[2]); + if (abs(v.pos[0] - x) > 0.5 * v.size[0]) continue; + if (abs(v.pos[1] - y) > 0.5 * v.size[1]) continue; + if (abs(v.pos[2] - z) > 0.5 * v.size[2]) continue; + return &v; + } + + return nullptr; +} + +bool CbmRecoQaTask::Detector::Init(TDirectoryFile* fOut) +{ + /* Query the geometry and trigger detector views init + */ + if (!gGeoManager) { + LOG(fatal) << "CbmRecoQaTask::Detector::Init() " << ToString(id) << " missing geometry."; + return false; + } + LOG(debug) << "CbmRecoQaTask::Detector::Init() : " << ToString(id); + + TDirectoryFile* modDir = + (TDirectoryFile*) fOut->mkdir(ToString(id).data(), Form("Reco QA for %s", ToString(id).data())); + bool ret(true); + for (auto& view : fViews) { + bool vret = view.Init(ToString(id).data()); + view.Register(modDir); + ret = ret && vret; + } + return ret; +} + +void CbmRecoQaTask::Detector::Print() const +{ + stringstream s; + s << "D[" << ToString(id) << "] views[" << fViews.size() << "]\n"; + for (auto v : fViews) + s << v.ToString(); + cout << s.str(); +} + +//+++++++++++++++++++++ Detector::View ++++++++++++++++++++++++++++++++ +//_______________________________________________________________________ +bool CbmRecoQaTask::Detector::View::AddProjection(eViewProjection prj, float range, const char* unit) +{ + if (fProjection.find(prj) != fProjection.end()) { + LOG(warn) << "Projection " << ToString(prj) << " already registered"; + return false; + } + int scale(1); + if (strcmp(unit, "mm") == 0) + scale = 10; + else if (strcmp(unit, "um") == 0) + scale = 10000; + else if (strcmp(unit, "ps") == 0) + scale = 1000; + else if (strcmp(unit, "eV") == 0) + scale = 1000; + else if (strcmp(unit, "cm") == 0) + scale = 1; + else if (strcmp(unit, "ns") == 0) + scale = 1; + else if (strcmp(unit, "keV") == 0) + scale = 1; + else if (strcmp(unit, "a.u.") == 0) + scale = 1; + else + LOG(warn) << "Projection units " << unit << " not registered. Natural units will be used."; + + fProjection[prj] = make_tuple(scale, range, nullptr); + return true; +} + +bool CbmRecoQaTask::Detector::View::SetProjection(eViewProjection prj, float range, const char* unit) +{ + if (fProjection.find(prj) == fProjection.end()) { + LOG(warn) << "Projection " << ToString(prj) + << " not initialized. Calling \"CbmRecoQaTask::Detector::View::AddProjection()\""; + return AddProjection(prj, range, unit); + } + int scale(1); + if (strcmp(unit, "mm") == 0) + scale = 10; + else if (strcmp(unit, "um") == 0) + scale = 10000; + else if (strcmp(unit, "ps") == 0) + scale = 1000; + else if (strcmp(unit, "eV") == 0) + scale = 1000; + else if (strcmp(unit, "cm") == 0) + scale = 1; + else if (strcmp(unit, "ns") == 0) + scale = 1; + else if (strcmp(unit, "keV") == 0) + scale = 1; + else if (strcmp(unit, "a.u.") == 0) + scale = 1; + else + LOG(warn) << "Projection units " << unit << " not registered. Natural units will be used."; + + get<0>(fProjection[prj]) = scale; + get<1>(fProjection[prj]) = range; + return true; +} + +bool CbmRecoQaTask::Detector::View::Init(const char* dname) +{ + if (!gGeoManager->cd(path.data())) return false; + TGeoHMatrix* m = gGeoManager->GetCurrentMatrix(); + const double* tr(m->GetTranslation()); + TGeoVolume* v = gGeoManager->GetCurrentVolume(); + TGeoShape* bb = v->GetShape(); + double w_lo, w_hi; + for (int i(0); i < 3; i++) { // loop over the spatial dimensions + size[i] = bb->GetAxisRange(i + 1, w_lo, w_hi); + pos[i] = 0.5 * (w_lo + w_hi) + tr[i]; + } + + LOG(info) << "CbmRecoQaTask::Detector(" << dname << ")::View(" << name << ")::Init() : size [" << size[0] << " x " + << size[1] << " x " << size[2] << "]."; + + // TODO short-hand for XY display resolution + int dscale = 10; + if (strcmp(dname, "Tof") == 0 || strcmp(dname, "Rich") == 0) dscale = 1; + + int nbinsx, nbinsy; + string unit; + for (auto& projection : fProjection) { + int scale = get<0>(projection.second); + float yrange = get<1>(projection.second); + char xy_id = 0; + double xlo = pos[0] - 0.5 * size[0], xhi = pos[0] + 0.5 * size[0], ylo = pos[1] - 0.5 * size[1], + yhi = pos[1] + 0.5 * size[1]; + switch (projection.first) { + case eViewProjection::kXdX: + nbinsx = 10 * ceil(size[0]); // mm binning + unit = makeYrange(scale, yrange); + nbinsy = 200; //* ceil(yrange); + get<2>(projection.second) = new TH2D(Form("hxx_%s%s", dname, name.data()), + Form("X resolution %s [%s]; X_{%s-%s} (cm); #Delta X (%s)", name.data(), + dname, dname, name.data(), unit.data()), + nbinsx, xlo, xhi, nbinsy, -yrange, yrange); + break; + + case eViewProjection::kYdY: + nbinsx = 10 * ceil(size[1]); // mm binning + unit = makeYrange(scale, yrange); + nbinsy = 200; //* ceil(yrange); + get<2>(projection.second) = new TH2D(Form("hyy_%s%s", dname, name.data()), + Form("Y resolution %s [%s]; Y_{%s-%s} (cm); #Delta Y (%s)", name.data(), + dname, dname, name.data(), unit.data()), + nbinsx, ylo, yhi, nbinsy, -yrange, yrange); + break; + + case eViewProjection::kXpX: + nbinsx = 10 * ceil(size[0]); // mm binning + if (yrange < 0) { + LOG(debug) << "ProjectionP[" << name << "] using default range."; + yrange = 5; // +- 5 sigma range + } + nbinsy = 200; //* ceil(yrange); + get<2>(projection.second) = + new TH2D(Form("hpx_%s%s", dname, name.data()), + Form("X pulls %s [%s]; X_{%s-%s} (cm); pull(X)", name.data(), dname, dname, name.data()), nbinsx, + xlo, xhi, nbinsy, -yrange, yrange); + break; + + case eViewProjection::kYpY: + nbinsx = 10 * ceil(size[1]); // mm binning + if (yrange < 0) { + LOG(debug) << "ProjectionP[" << name << "] using default range."; + yrange = 5; // +- 5 sigma range + } + nbinsy = 200; //* ceil(yrange); + get<2>(projection.second) = + new TH2D(Form("hpy_%s%s", dname, name.data()), + Form("Y pulls %s [%s]; Y_{%s-%s} (cm); pull(Y)", name.data(), dname, dname, name.data()), nbinsx, + ylo, yhi, nbinsy, -yrange, yrange); + break; + + case eViewProjection::kWdT: + nbinsx = 10 * ceil(size[0]); // mm binning + unit = makeTrange(scale, yrange); + nbinsy = 2 * ceil(yrange); + get<2>(projection.second) = new TH2D(Form("hxt_%s%s", dname, name.data()), + Form("Hit_Trk %s [%s]; X_{%s-%s} (cm); #Delta time_{TRK} (%s)", + name.data(), dname, dname, name.data(), unit.data()), + nbinsx, xlo, xhi, nbinsy, -yrange, yrange); + break; + + case eViewProjection::kChdT: + nbinsx = dscale * ceil(size[0]); // mm binning + unit = makeTrange(scale, yrange); + nbinsy = 10 * ceil(yrange); + get<2>(projection.second) = new TH2D(Form("hct_%s%s", dname, name.data()), + Form("Hit_Event %s [%s]; X_{%s-%s} (cm); #Delta time_{EV} (%s)", + name.data(), dname, dname, name.data(), unit.data()), + nbinsx, xlo, xhi, nbinsy, -yrange, yrange); + break; + + case eViewProjection::kXYa: + xy_id = 'a'; + // fall through + case eViewProjection::kXYs: + if (!xy_id) xy_id = 's'; + // fall through + case eViewProjection::kXYh: + if (!xy_id) xy_id = 'h'; + nbinsx = dscale * ceil(size[0]); // mm binning + nbinsy = dscale * ceil(size[1]); + get<2>(projection.second) = + new TH2D(Form("hxy%c_%s%s", xy_id, dname, name.data()), + Form("Hit_{%s} %s [%s]; X_{%s-%s} (cm); Y_{%s-%s} (cm)", (xy_id == 'h' ? "reco" : "attach"), + name.data(), dname, dname, name.data(), dname, name.data()), + nbinsx, xlo, xhi, nbinsy, ylo, yhi); + break; + case eViewProjection::kXYp: + nbinsx = dscale * ceil(size[0] * 2.); // mm binning + nbinsy = dscale * ceil(size[1] * 2.); + xlo = pos[0] - size[0]; + xhi = pos[0] + size[0]; + ylo = pos[1] - size[1]; + yhi = pos[1] + size[1]; + get<2>(projection.second) = new TH2D(Form("hxyp_%s%s", dname, name.data()), + Form("Trk_{proj.} %s [%s]; X_{%s-%s} (cm); Y_{%s-%s} (cm)", name.data(), + dname, dname, name.data(), dname, name.data()), + nbinsx, xlo, xhi, nbinsy, ylo, yhi); + break; + } + } + return true; +} + +string CbmRecoQaTask::Detector::View::ToString() const +{ + stringstream s; + s << "V[" << name << "] path[" << path << "] @ [" << pos[0] << ", " << pos[1] << ", " << pos[2] << "] size[" + << size[0] << ", " << size[1] << ", " << size[2] << "] projections[" << fProjection.size() << "] sel["; + for (auto ii : fSelector) + s << ii << " "; + s << "]\n"; + return s.str(); +} + +uint CbmRecoQaTask::Detector::View::Register(TDirectoryFile* fOut) +{ + uint n(0); + TDirectoryFile* lDir = (TDirectoryFile*) fOut->mkdir(name.data(), Form("QA for vol[%s]", path.data())); + TDirectoryFile* sDir = + (!CbmRecoQaTask::fuRecoConfig[kRecoEvents] ? (TDirectoryFile*) lDir->mkdir("TS", "TimeSlice QA") : nullptr); + TDirectoryFile* eDir = + (CbmRecoQaTask::fuRecoConfig[kRecoEvents] ? (TDirectoryFile*) lDir->mkdir("event", "Local Reco QA") : nullptr); + TDirectoryFile* tDir = + (CbmRecoQaTask::fuRecoConfig[kRecoTracks] ? (TDirectoryFile*) lDir->mkdir("track", "CA QA") : nullptr); + LOG(debug) << "CbmRecoQaTask::Detector::View[" << name << "]::Register() : " + << "\n\t level \"TS \" [" << (sDir ? "ON" : "OFF") << "]" + << "\n\t level \"EVT\" [" << (eDir ? "ON" : "OFF") << "]" + << "\n\t level \"TRK\" [" << (tDir ? "ON" : "OFF") << "]"; + + for (auto& projection : fProjection) { + TH2* hh = get<2>(projection.second); + if (!hh) continue; + switch (projection.first) { + case eViewProjection::kXYa: + case eViewProjection::kXYp: + case eViewProjection::kXdX: + case eViewProjection::kYdY: + case eViewProjection::kWdT: + case eViewProjection::kXpX: + case eViewProjection::kYpY: + if (tDir) tDir->Add(hh); + break; + case eViewProjection::kChdT: + case eViewProjection::kXYh: + if (eDir) eDir->Add(hh); + break; + case eViewProjection::kXYs: + if (sDir) sDir->Add(hh); + break; } - case kMcbm24: break; - case kDefault: break; + n++; } + LOG(debug) << "CbmRecoQaTask::Detector::View[" << name << "]::Register() : " << n << " projections for " + << fOut->GetName(); + return n; +} + +string CbmRecoQaTask::Detector::View::ToString(eViewProjection prj) +{ + string s; + switch (prj) { + case eViewProjection::kXYa: s = "x-y (attach)"; break; + case eViewProjection::kXYp: s = "x-y (track)"; break; + case eViewProjection::kXdX: s = "dx-x"; break; + case eViewProjection::kYdY: s = "dy-y"; break; + case eViewProjection::kXpX: s = "pull(x)-x"; break; + case eViewProjection::kYpY: s = "pull(y)-y"; break; + case eViewProjection::kWdT: s = "dt(trk)-w"; break; + case eViewProjection::kChdT: s = "dt(ev)-w"; break; + case eViewProjection::kXYh: s = "x-y (hit)"; break; + case eViewProjection::kXYs: s = "x-y (TS)"; break; + default: LOG(error) << "Detector::View::ToString() : Unknown projection " << int(prj); break; + } + return s; +} + +string CbmRecoQaTask::Detector::View::makeYrange(const int scale, float& yrange) +{ + bool kDefaultRange = false; + string unit = "cm"; + if (yrange < 0) { + LOG(debug) << "ProjectionY[" << name << "] using default range."; + kDefaultRange = true; + yrange = 3; // +- 6 cm default range + } + if (scale == 10) { // mm resolution + unit = "mm"; + if (kDefaultRange) yrange = 10; // +- 20 mm default range + } + else if (scale == 10000) { // micron resolution + unit = "#mu m"; + if (kDefaultRange) yrange = 150; // +- 300 um default range + } + return unit; +} + +string CbmRecoQaTask::Detector::View::makeTrange(const int scale, float& yrange) +{ + bool kDefaultRange = false; + string unit = "ns"; + if (yrange < 0) { + LOG(debug) << "ProjectionT[" << name << "] using default range."; + kDefaultRange = true; + yrange = 40; // +- 80 ns default range + } + if (scale == 1000) { // ps resolution + unit = "ps"; + if (kDefaultRange) yrange = 300; // +- 600 ps default range + } + return unit; +} + +CbmRecoQaTask::EventFilter* CbmRecoQaTask::AddEventFilter(CbmRecoQaTask::EventFilter::eEventCut type) +{ + for (auto cut : fFilterEv) { + if (cut.fType == type) { + LOG(warning) << GetName() << "::AddEventFilter event filter : " << cut.ToString() << " already on the list."; + return nullptr; + } + } + fFilterEv.emplace_back(type); + return &fFilterEv.back(); +} + +CbmRecoQaTask::TrackFilter* CbmRecoQaTask::AddTrackFilter(CbmRecoQaTask::TrackFilter::eTrackCut type) +{ + for (auto cut : fFilterTrk) { + if (cut.fType == type) { + LOG(warning) << GetName() << "::AddTrackFilter track filter : " << cut.ToString() << " already on the list."; + return nullptr; + } + } + fFilterTrk.emplace_back(type); + return &fFilterTrk.back(); +} + +//+++++++++++++++++++++ EventFilter ++++++++++++++++++++++++++++++++ +//____________________________________________________________________ +bool CbmRecoQaTask::EventFilter::Accept(const CbmEvent* ptr, const CbmRecoQaTask* /* lnk*/) +{ + stringstream ss; + bool ret(true); + size_t val(0); + switch (fType) { + case eEventCut::kMultTrk: + val = ptr->GetNofData(ECbmDataType::kGlobalTrack); + if (fMinTrack > 0 && val < size_t(fMinTrack)) { + ss << "NofTrack[" << val << "] < min[" << fMinTrack << "]."; + ret = false; + break; + } + if (ret && fMaxTrack > 0 && val > size_t(fMaxTrack)) { + ss << "NofTrack[" << val << "] > max[" << fMaxTrack << "]."; + ret = false; + } + break; + case eEventCut::kMultHit: + val = ptr->GetNofData(ECbmDataType::kStsHit); + if (fMultHit[0] > 0 && val > size_t(fMultHit[0])) { + ss << "Sts hits [" << val << "] > max[" << fMultHit[0] << "]."; + ret = false; + break; + } + val = ptr->GetNofData(ECbmDataType::kTrdHit); + if (fMultHit[1] > 0 && val > size_t(fMultHit[1])) { + ss << "Trd hits [" << val << "] > max[" << fMultHit[1] << "]."; + ret = false; + break; + } + val = ptr->GetNofData(ECbmDataType::kTofHit); + if (fMultHit[2] > 0 && val > size_t(fMultHit[2])) { + ss << "Tof hits [" << val << "] > max[" << fMultHit[2] << "]."; + ret = false; + } + break; + default: break; + } + if (!ret) LOG(debug2) << "Event reject for : " << ss.str(); return ret; } +bool CbmRecoQaTask::EventFilter::SetFilter(std::vector<float> cuts) +{ + switch (fType) { + case eEventCut::kMultTrk: + if (cuts.size() < 2 || cuts[1] < cuts[0]) { + LOG(warning) << "Improper definition for event filter :\n\t" << ToString() << endl; + HelpMess(); + return false; + } + fMinTrack = int(cuts[0]); + fMaxTrack = int(cuts[1]); + break; + case eEventCut::kMultHit: + if (cuts.size() < 3) { + LOG(warning) << "Improper definition for event filter :\n\t" << ToString() << endl; + HelpMess(); + return false; + } + for (int i(0); i < int(CbmRecoQaTask::EventFilter::eEventDef::kNofDetHit); i++) + fMultHit[i] = int(cuts[i]); + break; + case eEventCut::kTrigger: break; + case eEventCut::kVertex: break; + default: break; + } + return true; +} +std::string CbmRecoQaTask::EventFilter::ToString() const +{ + stringstream ss; + switch (fType) { + case eEventCut::kMultTrk: ss << "kMultTrk : \"cut on track multiplicity"; break; + case eEventCut::kMultHit: ss << "kMultHit : \"cut on hit multiplicity"; break; + case eEventCut::kTrigger: ss << "kTrigger : \"cut on trigger conditions"; break; + case eEventCut::kVertex: ss << "kVertex : \"cut on vertex definition"; break; + default: break; + } + return ss.str(); +} +void CbmRecoQaTask::EventFilter::HelpMess() const +{ + LOG(info) << "CbmRecoQaTask::EventFilter : Usage"; + switch (fType) { + case eEventCut::kMultTrk: + LOG(info) << ToString(); + LOG(info) << "\tDepends one two values : min and max of the no of global tracks / event."; + LOG(info) << "\tValue should follow the relation max >= min."; + break; + case eEventCut::kMultHit: + LOG(info) << ToString(); + LOG(info) << "\tDepends one three values : total hits in the following systems (in this order) : STS TRD TOF."; + LOG(info) << "\tNegative values are interpreted as no-cut."; + break; + default: + LOG(info) << ToString(); + LOG(info) << "\tNo user info."; + break; + } +} +//+++++++++++++++++++++ TrackFilter ++++++++++++++++++++++++++++++++ +//____________________________________________________________________ +bool CbmRecoQaTask::TrackFilter::Accept(const CbmGlobalTrack* ptr, const CbmRecoQaTask* lnk) +{ + bool ret(true); + stringstream ss; + int idx(-1); + const CbmTrack* trk(nullptr); + switch (fType) { + case eTrackCut::kSts: + if (fNSts <= 0 && !fStsHits.size()) break; + if ((idx = ptr->GetStsTrackIndex()) < 0) { + ss << "Sts trk index missing"; + ret = false; + break; + } + if (!(trk = lnk->GetTrack(ECbmModuleId::kSts, idx))) { + ss << "Sts trk nullptr"; + ret = false; + break; + } + // cut on the total no of STS hits/trk + if (trk->GetNofHits() < fNSts) { + ss << "Sts hits/trk [" << trk->GetNofHits() << "] < min[" << fNSts << "]."; + ret = false; + break; + } + // cut on the distribution of STS hits/trk/station + for (auto stsStation : fStsHits) { + if (!stsStation) continue; + // check hit in this particular station + } + break; + case eTrackCut::kTrd: + if (fNTrd <= 0) break; + if ((idx = ptr->GetTrdTrackIndex()) < 0) { + ss << "Trd trk index missing"; + ret = false; + break; + } + if (!(trk = lnk->GetTrack(ECbmModuleId::kTrd, idx))) { + ss << "Trd trk nullptr"; + ret = false; + break; + } + // cut on the total no of TRD hits/trk + if (trk->GetNofHits() < fNTrd) { + ss << "Trd` hits/trk [" << trk->GetNofHits() << "] < min[" << fNTrd << "]."; + ret = false; + break; + } + break; + case eTrackCut::kTof: + if (fNTof <= 0) break; + if ((idx = ptr->GetTofTrackIndex()) < 0) { + ss << "Tof trk index missing"; + ret = false; + break; + } + if (!(trk = lnk->GetTrack(ECbmModuleId::kTof, idx))) { + ss << "Tof trk nullptr"; + ret = false; + break; + } + // cut on the total no of ToF hits/trk + if (trk->GetNofHits() < fNTof) { + ss << "Tof` hits/trk [" << trk->GetNofHits() << "] < min[" << fNTof << "]."; + ret = false; + break; + } + break; + default: break; + } -//_____________________________________________________________________ -void CbmRecoQaTask::Finish() + if (!ret) LOG(debug2) << "Track reject for : " << ss.str(); + return ret; +} +bool CbmRecoQaTask::TrackFilter::SetFilter(std::vector<float> cuts) { - FairSink* sink = FairRootManager::Instance()->GetSink(); - sink->WriteObject(&fOutFolder, nullptr); + switch (fType) { + case eTrackCut::kSts: + if (cuts.size() < 1) { + LOG(warning) << "Improper definition for track filter :\n\t" << ToString() << endl; + //HelpMess(); + return false; + } + fNSts = int(cuts[0]); + break; + case eTrackCut::kTrd: + if (cuts.size() < 1) { + LOG(warning) << "Improper definition for track filter :\n\t" << ToString() << endl; + //HelpMess(); + return false; + } + fNTrd = int(cuts[0]); + break; + case eTrackCut::kTof: + if (cuts.size() < 1) { + LOG(warning) << "Improper definition for track filter :\n\t" << ToString() << endl; + //HelpMess(); + return false; + } + fNTof = int(cuts[0]); + break; + default: break; + } + return true; +} +std::string CbmRecoQaTask::TrackFilter::ToString() const +{ + stringstream ss; + switch (fType) { + case eTrackCut::kSts: ss << "kSts : \"cut on no of STS hits / track\""; break; + case eTrackCut::kMuch: ss << "kMuch : \"cut on no of Much hits / track\""; break; + case eTrackCut::kRich: ss << "kRich : \"cut on no of Rich hits / track\""; break; + case eTrackCut::kTrd: ss << "kTrd : \"cut on no of TRD hits / track\""; break; + case eTrackCut::kTof: ss << "kTof : \"cut on no of Tof hits / track\""; break; + default: break; + } + return ss.str(); } +/* clang-format off */ +ClassImp(CbmRecoQaTask) +ClassImp(CbmRecoQaTask::Detector) +ClassImp(CbmRecoQaTask::Detector::View) +ClassImp(CbmRecoQaTask::TrackFilter) +ClassImp(CbmRecoQaTask::EventFilter) + /* clang-format on */ diff --git a/reco/qa/CbmRecoQaTask.h b/reco/qa/CbmRecoQaTask.h index 44dca4e5d08b3c6959cb9e3de45e1d81aa2747cc..2f219191cea9137862edb379716d0a8924bdfdf6 100644 --- a/reco/qa/CbmRecoQaTask.h +++ b/reco/qa/CbmRecoQaTask.h @@ -6,66 +6,244 @@ #define CBMRECOQATASK_H 1 #include "CbmKfTrackFitter.h" -// #include "CbmQaHist.h" +#include "CbmTrack.h" -#include "FairTask.h" -#include "TFolder.h" +#include <FairTask.h> +#include <TDirectoryFile.h> + +#include <bitset> #include <map> #include <vector> +#define kRecoQaNConfigs 8 + +class CbmEvent; +class CbmHit; class CbmTimeSlice; class TClonesArray; +class TH2; class TH2D; class CbmRecoQaTask : public FairTask { public: - enum Setup + enum eRecoConfig + { + kRecoEvents = 0, /// has events reconstructed (CbmEvent branch) + kRecoTracks, /// has tracks reconstructed (GlobalTrack branch) + kStsHits, /// has STS hits (StsHit branch) + kTrdHits, /// has TRD` hits (TrdHit branch) + kTofHits, /// has ToF hits (TofHit branch) + kRichHits, /// has Rich hits (RichHit branch) + kMuchHits, /// has Much hits (MuchHit branch) + }; + enum eSetup { kMcbm22 = 0, kMcbm24, kDefault }; + enum class eViewProjection : int + { + kXYa = 0, /// X-Y hit coorelation in track filtered data + kXYp, /// X-Y track projections + kXdX, /// X to TRK residuals as function of local X in view + kYdY, /// Y to TRK residuals as function of local Y in view + kWdT, /// Time to TRK residuals as function of local high resolution coordinate in view + kXpX, /// X to TRK pulls as function of local X in view + kYpY, /// Y to TRK pulls as function of local Y in view + kChdT, /// Time to EV residuals as function of coordinate in view + kXYh, /// X-Y hit coorelation in local view + kXYs /// X-Y hit coorelation in time slice + }; + struct Detector { + struct Data { + Data() = default; + Data(ECbmDataType i, const char* n) : id(i), name(n) { ; } + ECbmDataType id = ECbmDataType::kUnknown; + std::string name = "nn"; + }; + struct View { + friend struct Detector; + friend class CbmRecoQaTask; + + View() = default; + View(const char* n, const char* p, std::vector<int> set) : name(n), path(p), fSelector(set) { ; } + virtual ~View() = default; + bool SetProjection(eViewProjection prj, float range, const char* unit); + template<class Hit> + bool HasAddress(const CbmHit* h, double& x, double& y) const; + template<class Hit> + bool Load(const CbmHit* h, const CbmEvent* ev = nullptr); + bool Load(const CbmKfTrackFitter::FitNode* n); + std::string ToString() const; + static std::string ToString(eViewProjection prj); + + std::string name = ""; /// name describing the module + std::string path = ""; /// path to the geo volume describing the module + double size[3] = {0.}; /// detection element geometrical dx dy dz dimmensions + double pos[3] = {0.}; /// detection element center x0 y0 z0 + std::vector<int> fSelector = {}; /// defining subset of the address set for this view + std::map<eViewProjection, std::tuple<int, float, TH2*>> fProjection = + {}; /// map of projections indexed by their type. Each projection contains also the relative scale [int] wrt to default units (ns, cm, keV) and the range [float]. + protected: + bool AddProjection(eViewProjection prj, float range = -1, const char* unit = "cm"); + /** \brief convert geo address into pointer to geometry. + * By the time of the call the geometry has to be available in memory. + * Failing to identify the named physical node will rezult in error */ + bool Init(const char* dname); + /** \brief build directory structure for all projections of current view.*/ + uint Register(TDirectoryFile* f); + /** helper functions to estimate the representation (y) axis + * \param[in] scale read-only unit defining parameter + * \param[in] range read-write full range on the ordinate + * \return units for the ordinate and the range value + */ + std::string makeTrange(const int scale, float& range); + std::string makeYrange(const int scale, float& range); + + ClassDef(CbmRecoQaTask::Detector::View, 1); // A QA significant correlation + }; + Detector(ECbmModuleId did = ECbmModuleId::kNotExist); + virtual ~Detector() = default; + View* AddView(const char* n, const char* p, std::vector<int> set); + View* GetView(const char* n); + View* FindView(double x, double y, double z); + /** \brief Check geometry and trigger Init() for all registered views. Build main directory outut for the current detector. + * Failing to identify the geometry will rezult in fatal error. + * \return true If ALL the subsequent calls to Init result in a true */ + bool Init(TDirectoryFile* f); + void Print() const; + + ECbmModuleId id; + Data hit; + Data trk; + std::vector<View> fViews = {}; + + ClassDef(CbmRecoQaTask::Detector, 1); // QA representation of a detector unit + }; + + struct TrackFilter { + enum class eTrackCut : int + { + kSts = 0, /// cut on no of STS hits / track + kMuch, /// cut on no of Much hits / track + kRich, /// cut on no of Rich hits / track + kTrd, /// cut on no of TRD hits / track + kTof, /// cut on no of Tof hits / track + kNone /// no cut + }; + TrackFilter(eTrackCut typ = eTrackCut::kNone) : fType(typ) { ; } + virtual ~TrackFilter() = default; + bool Accept(const CbmGlobalTrack* ptr, const CbmRecoQaTask* lnk); + bool SetFilter(std::vector<float> cuts); + std::string ToString() const; + + eTrackCut fType = eTrackCut::kNone; + + private: + // STS definition of track + int fNSts = -1; + std::vector<bool> fStsHits = {}; + // TRD definition of track + int fNTrd = -1; + // ToF definition of track + int fNTof = -1; + ClassDef(CbmRecoQaTask::TrackFilter, 1); // Track cut implementation + }; + + struct EventFilter { + enum class eEventCut : int + { + kMultTrk = 0, /// cut on track multiplicity + kMultHit, /// cut on hit multiplicity + kTrigger, /// cut on trigger conditions + kVertex, /// cut on vertex definition + kNone /// no cut + }; + enum class eEventDef : int + { + kNofDetHit = 3 /// no of detectors considered for the hit cut [STS TRD ToF] + }; + EventFilter(eEventCut typ = eEventCut::kNone) : fType(typ) { ; } + virtual ~EventFilter() = default; + bool Accept(const CbmEvent* ptr, const CbmRecoQaTask* lnk); + bool SetFilter(std::vector<float> cuts); + std::string ToString() const; + + eEventCut fType = eEventCut::kNone; + + private: + // track multiplicity cut definition + int fMinTrack = 0; + int fMaxTrack = 0; + // hit multiplicity cut definition + int fMultHit[(int) eEventDef::kNofDetHit] = {0}; /// max no of hits/ev for the systems [STS TRD ToF] + + /** \brief Helper function : display usage message for each filter case*/ + void HelpMess() const; + + ClassDef(CbmRecoQaTask::EventFilter, 1); // Event cut implementation + }; public: CbmRecoQaTask(); virtual ~CbmRecoQaTask() { ; } - + /** Copy the qa test defined for detector det from the steering macro to the current class */ + virtual Detector* AddDetector(ECbmModuleId did); + virtual EventFilter* AddEventFilter(EventFilter::eEventCut cut); + virtual TrackFilter* AddTrackFilter(TrackFilter::eTrackCut cut); + virtual Detector* GetDetector(ECbmModuleId did); + /** \brief Retrieve detector specific track by index. + * \param[in] did system Identifier + * \param[in] id track id in the TClonesArray + * \return pointer to track or nullptr if track/system not available + */ + virtual const CbmTrack* GetTrack(ECbmModuleId did, int id) const; + /** \brief Perform initialization of data sources and projections */ virtual InitStatus Init(); /** \brief Executed task **/ virtual void Exec(Option_t* option); - /** \brief Filter tracks for further use (e.g. track projections) - * \param[in] ptr information on which to filter (e.g. nhits from detectors) - * \return true if track accepted - */ - virtual bool FilterTrack(int* ptr); virtual void Finish(); /** \brief Define the set of extra z positions where the track should be projected in the x-y plane */ void SetProjections(std::vector<double> vzpj); - void SetSetupClass(CbmRecoQaTask::Setup setup) { fSetupClass = setup; } + void SetSetupClass(CbmRecoQaTask::eSetup setup) { fSetupClass = setup; } + + protected: + static std::bitset<kRecoQaNConfigs> fuRecoConfig; private: CbmRecoQaTask(const CbmRecoQaTask&); CbmRecoQaTask& operator=(const CbmRecoQaTask&); - struct ModuleView { - std::pair<float, TH2D*> hdXx = std::make_pair(1, nullptr); - std::pair<float, TH2D*> hdYy = std::make_pair(1, nullptr); - std::pair<float, TH2D*> hdT = std::make_pair(1, nullptr); - TH2D* hpullXphi = nullptr; - TH2D* hpullYtht = nullptr; - }; + /** \brief Filter events for QA use (e.g. event multiplicity) + * \param[in] ptr cbm event + * \return true if event accepted + */ + virtual bool FilterEvent(const CbmEvent* ptr); + /** \brief Filter tracks for further use (e.g. track projections) + * \param[in] ptr global track + * \return true if track accepted + */ + virtual bool FilterTrack(const CbmGlobalTrack* ptr); + void InitMcbm22(); + void InitMcbm24(); + CbmKfTrackFitter fFitter; - TClonesArray* fTracks = nullptr; //! reconstructed global tracks / event + TClonesArray* fGTracks = nullptr; //! reconstructed global tracks / event + std::map<ECbmModuleId, TClonesArray*> fTracks = {}; //! reconstructed global tracks / event TClonesArray* fTrackMatches = nullptr; //! MC info for the global tracks TClonesArray* fEvents = nullptr; //! reconstructed events CbmTimeSlice* fTimeSlice = nullptr; //! Time slice info - // - TFolder fOutFolder = {"RecoQA", "CA track driven reco QA"}; //! - Setup fSetupClass = Setup::kMcbm22; - std::map<int, std::vector<ModuleView>> fModView = {}; //! - std::map<double, TH2D*> fProjView = {}; //! + std::map<ECbmModuleId, TClonesArray*> fHits = {}; //! reconstructed hits + std::map<ECbmModuleId, Detector> fDetQa = {}; + std::vector<EventFilter> fFilterEv = {}; + std::vector<TrackFilter> fFilterTrk = {}; + + TDirectoryFile fOutFolder = {"RecoQA", "CA track driven reco QA"}; //! + eSetup fSetupClass = eSetup::kMcbm24; + std::map<double, Detector::View> fProjs = {}; //! ClassDef(CbmRecoQaTask, 1); // Reconstruction QA analyzed from CA perspective }; diff --git a/reco/qa/RecoQaLinkDef.h b/reco/qa/RecoQaLinkDef.h index ecbf6054cf0f27e7c3f030e6bf13845e335dd5b6..f4e30615242b36ac0c72d130db7179e8f68d37ae 100644 --- a/reco/qa/RecoQaLinkDef.h +++ b/reco/qa/RecoQaLinkDef.h @@ -13,5 +13,9 @@ #pragma link C++ class CbmRecoQa + ; #pragma link C++ class CbmTrackingTrdQa + ; #pragma link C++ class CbmRecoQaTask + ; +#pragma link C++ class CbmRecoQaTask::Detector + ; +#pragma link C++ class CbmRecoQaTask::Detector::View + ; +#pragma link C++ class CbmRecoQaTask::EventFilter + ; +#pragma link C++ class CbmRecoQaTask::TrackFilter + ; #endif