diff --git a/macro/qa/run_recoQa.C b/macro/qa/run_recoQa.C new file mode 100644 index 0000000000000000000000000000000000000000..709753cc8116fe89800d1c260032f13de2b36f09 --- /dev/null +++ b/macro/qa/run_recoQa.C @@ -0,0 +1,209 @@ +/* Copyright (C) 2024 Hulubei National Institute of Physics and Nuclear Engineering - Horia Hulubei, Bucharest + SPDX-License-Identifier: GPL-3.0-only + Authors: Alexandru Bercuci [committer] */ + +// -------------------------------------------------------------------------- +// +// Macro for simulation & reconstruction QA +// +// The following naming conventions are assumed: +// Raw data file: [dataset].event.raw.root +// Transport file: [dataset].tra.root +// Parameter file: [dataset].par.root +// Reconstruction file: [dataset].rec.root +// +// S. Gorbunov 28/09/2020 +// +// -------------------------------------------------------------------------- + +// Includes needed for IDE +#if !defined(__CLING__) +#include "CbmDefs.h" +#include "CbmMCDataManager.h" +#include "CbmMuchTransportQa.h" +#include "CbmQaManager.h" +#include "CbmSetup.h" + +#include <FairFileSource.h> +#include <FairMonitor.h> +#include <FairParAsciiFileIo.h> +#include <FairParRootFileIo.h> +#include <FairRootFileSink.h> +#include <FairRunAna.h> +#include <FairRuntimeDb.h> +#include <FairSystemInfo.h> + +#include <TStopwatch.h> +#endif + +void run_recoQa(Int_t nEvents = -1, TString dataset = "2391_node8_0_0000", + TString setupName = "mcbm_beam_2022_05_23_nickel", Bool_t bUseMC = kFALSE) +{ + + // ======================================================================== + // Adjust this part according to your requirements + + // ----- Logger settings ---------------------------------------------- + FairLogger::GetLogger()->SetLogScreenLevel("DEBUG"); + FairLogger::GetLogger()->SetLogVerbosityLevel("LOW"); + // ------------------------------------------------------------------------ + + // ----- Environment -------------------------------------------------- + int verbose = 6; // verbose level + TString myName = "recoQA"; // this macro's name for screen output + TString srcDir = gSystem->Getenv("VMCWORKDIR"); // top source directory + // ------------------------------------------------------------------------ + + // ----- In- and output file names ------------------------------------ + 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"; + + // ------------------------------------------------------------------------ + + // ----- Load the geometry setup ------------------------------------- + std::cout << '\n'; + + CbmSetup* setup = CbmSetup::Instance(); + setup->LoadSetup(setupName); + + // In general, the following parts need not be touched + // ======================================================================== + + // ----- Timer -------------------------------------------------------- + TStopwatch timer; + timer.Start(); + // ------------------------------------------------------------------------ + + // ---- Debug option ------------------------------------------------- + gDebug = 0; + // ------------------------------------------------------------------------ + + // ----- FairRunAna --------------------------------------------------- + FairFileSource* inputSource = new FairFileSource(recFile); + if (bUseMC) { + inputSource->AddFriend(traFile); + } + //inputSource->AddFriend(rawFile); + + FairRunAna* run = new FairRunAna(); + run->SetSource(inputSource); + run->SetGenerateRunInfo(kFALSE); + run->SetGeomFile(geoFile); + + FairRootFileSink* sink = new FairRootFileSink(sinkFile); + run->SetSink(sink); + + TString monitorFile{sinkFile}; + monitorFile.ReplaceAll("rqa", "rqa.moni"); + FairMonitor::GetMonitor()->EnableMonitor(kTRUE, monitorFile); + // ------------------------------------------------------------------------ + + // ----- MCDataManager (legacy mode) ----------------------------------- + if (bUseMC) { + std::cout << "-I- " << myName << ": Adding MC manager and MC to reco matching tasks\n"; + + auto* mcManager = new CbmMCDataManager("MCDataManager", 1); + mcManager->AddFile(traFile); + run->AddTask(mcManager); + + auto* matchRecoToMC = new CbmMatchRecoToMC(); + // NOTE: Matching is suppressed, if there are hit and cluster matches already in the tree. If there + // are no hit matches, they are produced on this stage. + matchRecoToMC->SuppressHitReMatching(); + run->AddTask(matchRecoToMC); + } + // ------------------------------------------------------------------------ + + // ----- Tracking detector interface -------------------------------------- + run->AddTask(new CbmTrackingDetectorInterfaceInit()); + // ------------------------------------------------------------------------ + + + // ------------------------------------------------------------------------ + + // TODO: read tracking parameters from the file like CaOutputQa does + //TODO: instead of initializing the tracker + //TString caParFile = recFile; + //caParFile.ReplaceAll(".root", ".L1Parameters.dat"); + //auto* pCaOutputQa = new cbm::ca::OutputQa(verbose, bUseMC); + //pCaOutputQa->ReadParameters(caParFile.Data()); + + // L1 CA track finder setup + auto l1 = new CbmL1("CA"); + l1->SetMcbmMode(); + + // User configuration example for CA: + //l1->SetConfigUser(srcDir + "/macro/L1/configs/ca_params_user_example.yaml"); + run->AddTask(l1); + + // ----- Reco QA -------------------------------------------- + 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}); + run->AddTask(recoQa); + run->SetGenerateRunInfo(kFALSE); + + // ------------------------------------------------------------------------ + //----- Load Parameters -------------------------------------------------- + std::cout << std::endl << std::endl; + std::cout << "-I- " << myName << ": Set runtime DB" << std::endl; + FairRuntimeDb* rtdb = run->GetRuntimeDb(); + FairParRootFileIo* parIo1 = new FairParRootFileIo(); + parIo1->open(parFile.Data(), "in"); + rtdb->setFirstInput(parIo1); + + // ------------------------------------------------------------------------ + // ----- 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, nEvents); + // ------------------------------------------------------------------------ + + // ----- Finish ------------------------------------------------------- + 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 " << sinkFile << std::endl; + std::cout << "Parameter file is " << parFile << std::endl; + std::cout << "Real time " << rtime << " s, CPU time " << ctime << " s" << std::endl; + std::cout << std::endl; + std::cout << " Test passed" << std::endl; + std::cout << " All ok " << 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(); + // ------------------------------------------------------------------------ +} diff --git a/reco/qa/CMakeLists.txt b/reco/qa/CMakeLists.txt index 136abb007695c24efdbc9a2d1faf215712835a11..85ce9991cef57402c931747c7bffa8fbd8d89fa6 100644 --- a/reco/qa/CMakeLists.txt +++ b/reco/qa/CMakeLists.txt @@ -4,9 +4,9 @@ set(INCLUDE_DIRECTORIES set(SRCS - CbmRecoQaTask.cxx CbmRecoQa.cxx CbmTrackingTrdQa.cxx + CbmRecoQaTask.cxx ) set(LIBRARY_NAME CbmRecoQa) diff --git a/reco/qa/CbmRecoQaTask.cxx b/reco/qa/CbmRecoQaTask.cxx index 26bb61d2ee985c5c83d2181587a2970bc78af247..3388c58dc07bb1e93f49cfe55b5c8dda5b6f63b4 100644 --- a/reco/qa/CbmRecoQaTask.cxx +++ b/reco/qa/CbmRecoQaTask.cxx @@ -3,23 +3,22 @@ Authors: Alexandru Bercuci [committer] */ // CBM headers -#include "CbmGlobalTrack.h" #include "CbmRecoQaTask.h" + +#include "CbmGlobalTrack.h" +#include "CbmTimeSlice.h" +#include "CbmTofAddress.h" +#include "CbmTrdAddress.h" // FAIR headers #include "FairRootManager.h" +#include "FairSink.h" // ROOT headers #include "TClonesArray.h" -//#include "TObject.h" +#include "TH2D.h" +using namespace std; //_____________________________________________________________________ -CbmRecoQaTask::CbmRecoQaTask() : FairTask("RecoQA", 0) -{ -} - - -//_____________________________________________________________________ -CbmRecoQaTask::~CbmRecoQaTask() -{} +CbmRecoQaTask::CbmRecoQaTask() : FairTask("RecoQA", 0) {} //_____________________________________________________________________ InitStatus CbmRecoQaTask::Init() @@ -31,19 +30,273 @@ InitStatus CbmRecoQaTask::Init() FairRootManager* ioman = FairRootManager::Instance(); if (!ioman) { - LOG(error) << "CbmRecoQaTask::Init :: RootManager not instantiated!"; + LOG(fatal) << GetName() << "::Init :: RootManager not instantiated!"; return kERROR; } - fGlobalTracks = static_cast<TClonesArray*>(ioman->GetObject("GlobalTrack")); - if (!fGlobalTracks) { - LOG(error) << "CbmRecoQaTask::Init: Global track array not found!"; + fTracks = static_cast<TClonesArray*>(ioman->GetObject("GlobalTrack")); + if (!fTracks) { + LOG(fatal) << GetName() << "::Init: Global track array not found!"; return kERROR; } - fGlobalTrackMatches = static_cast<TClonesArray*>(ioman->GetObject("GlobalTrackMatch")); - if (!fGlobalTrackMatches) { - LOG(warn) << "CbmRecoQaTask::Init: MC info for Global track not available !"; + 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."; + } + + 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(); + for (auto zprj : fProjView) + LOG(debug) << GetName() << "::Init: Project trks @ " << zprj.first; + + int itrkLy(0); + TFolder *modDir(nullptr), *smDir(nullptr); + fOutFolder.Clear(); + switch (fSetupClass) { + case kMcbm22: + LOG(info) << GetName() << "::Init: Setup config for \"mCBM 2022\"."; + modDir = fOutFolder.AddFolder("STS", "STS reziduals to CA"); + // STS U0 - station 0 + 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++; + // =============================================================================== + modDir = fOutFolder.AddFolder("ToF", "ToF reziduals to CA"); + // ToF Sm0 & Sm3 (Typ0) - station 5 + 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); + } + 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; } return kSUCCESS; @@ -52,60 +305,99 @@ InitStatus CbmRecoQaTask::Init() //_____________________________________________________________________ void CbmRecoQaTask::Exec(Option_t*) { - for (int iTr = 0; iTr < fGlobalTracks->GetEntriesFast(); iTr++) { -// if (static_cast<int>(fTracks.size()) >= fMaxNtracks) { -// break; -// } - const CbmGlobalTrack* globalTrack = dynamic_cast<const CbmGlobalTrack*>(fGlobalTracks->At(iTr)); - if (!globalTrack) { - LOG(fatal) << "RecoQA: null pointer to the global track!"; + LOG(debug) << GetName() << "::Exec : Evs[" << (fEvents ? fEvents->GetEntriesFast() : 0) << "] Trks[" + << fTracks->GetEntriesFast() << "]"; + int itrack(0); + for (auto trackObj : *fTracks) { + //printf("GlobalTrack %d\n", itrack); + 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; } - CbmKfTrackFitter::Track trk; - if (!fFitter.CreateGlobalTrack(trk, *globalTrack)) { - LOG(fatal) << "RecoQA: can not create the global track for the fit! "; - break; - } - trk.fNodes.insert(trk.fNodes.begin(), CbmKfTrackFitter::FitNode()); - trk.fMsQp0 = 1. / 0.5; - trk.fIsMsQp0Set = true; - - // try first fit with all hits ON - trk.MakeConsistent(); - fFitter.FitTrack(trk); - CbmKfTrackFitter::FitNode &node = trk.fNodes.front(); - printf("val @ vx %f fit %f\n", node.fMxy.X()[0], node.fTrack.X()[0]); - - - for (auto& n : trk.fNodes) { + trkKf.fMsQp0 = 1. / 0.5; + trkKf.fIsMsQp0Set = true; + + for (auto& n : trkKf.fNodes) { + if (n.fHitSystemId == ECbmModuleId::kNotExist) continue; + //printf(" %d z[%6.2f]\n", n.fMaterialLayer, n.fZ); + //printf(" D[%d] hit[%d %d] Flags[%c %c %c %c]\n", + // (int)n.fHitSystemId, n.fHitAddress, n.fHitIndex, + // (n.fIsXySet ? 'y' : 'n'), (n.fIsTimeSet ? 'y' : 'n'), (n.fIsFitted ? 'y' : 'n'), (n.fIsRadThickSet ? 'y' : 'n')); + //printf(" hit x[%+6.2f] y[%+6.2f] t[%f]\n", (double)n.fMxy.X()[0], (double)n.fMxy.Y()[0], (double)n.fMt.T()[0]); + n.fIsTimeSet = false; n.fIsXySet = false; - trk.MakeConsistent(); - fFitter.FitTrack(trk); - double dx = n.fMxy.X()[0] - n.fTrack.X()[0], - dy = n.fMxy.Y()[0] - n.fTrack.Y()[0], + 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]); + 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]); + //printf(" res dx[%+6.4f] dy[%+6.4f] dt[%+6.4f]\n pull x[%+6.4f] y[%+6.4f] t[%+6.4f]\n", dx, dy, dt, pullx, pully, pullt); + + // add granularity for specific systems + int modId = 0; + if (n.fHitSystemId == ECbmModuleId::kTof) modId = CbmTofAddress::GetRpcId(n.fHitAddress); + + // check that we have correctly created all views + if (fModView.find(n.fMaterialLayer) == fModView.end()) continue; + if (fModView[n.fMaterialLayer].size() <= (size_t)modId) continue; + ModuleView* mod = &fModView[n.fMaterialLayer][modId]; + if (!mod) { + LOG(warn) << GetName() << "::Exec: can not access mod view for " << 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); + n.fIsTimeSet = true; + n.fIsXySet = true; } -// //if (t.fNstsHits < 1) continue; -// //if (t.fNtrdHits < 2) continue; -// if (t.fNstsHits + t.fNmuchHits + t.fNtrd1dHits + t.fNtrd2dHits + t.fNtofHits < fNtrackingStations - 1) continue; -// //if (t.fNtrdHits < 3) continue; -// if (t.fNstsHits < 2) continue; -// if (t.fNtofHits < 2) continue; -// - fFitter.FitTrack(trk); - fTracks.push_back(trk); + // Fit track with all hits ON for vx projection + int iprj(0); + for (auto zprj : fProjView) { + 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; + //printf(" prj[%d] z[%+6.4f] x[%+6.4f] y[%+6.4f] t[%+6.4f]\n", n.fReference1, n.fZ, (double)n.fTrack.X()[0], (double)n.fTrack.Y()[0], (double)n.fTrack.Time()[0]); + } + itrack++; } } //_____________________________________________________________________ -void CbmRecoQaTask::FinishEvent() +void CbmRecoQaTask::SetProjections(std::vector<double> vzpj) { + fProjView.clear(); + for (auto zprj : vzpj) { + fProjView[zprj] = new TH2D(Form("hxx"), Form("; X (cm); Y (cm)"), 450, -25, 20, 450, -25, 20); + } } //_____________________________________________________________________ -void CbmRecoQaTask::FinishTask() +void CbmRecoQaTask::Finish() { + FairSink* sink = FairRootManager::Instance()->GetSink(); + sink->WriteObject(&fOutFolder, nullptr); } diff --git a/reco/qa/CbmRecoQaTask.h b/reco/qa/CbmRecoQaTask.h index 80fa7dbc6247a567ba4eab04e4ef9f507bbe8b7e..156088158fc38da5371fe2c4017b688caf6cf121 100644 --- a/reco/qa/CbmRecoQaTask.h +++ b/reco/qa/CbmRecoQaTask.h @@ -5,34 +5,64 @@ #ifndef CBMRECOQATASK_H #define CBMRECOQATASK_H 1 +#include "CbmKfTrackFitter.h" +// #include "CbmQaHist.h" + #include "FairTask.h" +#include "TFolder.h" -#include "CbmKfTrackFitter.h" +#include <map> #include <vector> +class CbmTimeSlice; class TClonesArray; +class TH2D; class CbmRecoQaTask : public FairTask { -public: + public: + enum Setup + { + kMcbm22 = 0, + kMcbm24, + kDefault + }; + + public: CbmRecoQaTask(); - ~CbmRecoQaTask(); + virtual ~CbmRecoQaTask() { ; } virtual InitStatus Init(); /** \brief Executed task **/ virtual void Exec(Option_t* option); - virtual void FinishEvent(); - virtual void FinishTask(); - -private: + 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; } + + 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; + }; CbmKfTrackFitter fFitter; - TClonesArray* fGlobalTracks = nullptr; //! reconstructed global tracks / event - TClonesArray* fGlobalTrackMatches = nullptr; //! MC info for the global tracks + TClonesArray* fTracks = nullptr; //! 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::vector<CbmKfTrackFitter::Track> fTracks; - ClassDef(CbmRecoQaTask, 1); + ClassDef(CbmRecoQaTask, 1); // Reconstruction QA analyzed from CA perspective }; #endif // CBMRECOQATASK_H diff --git a/reco/qa/RecoQaLinkDef.h b/reco/qa/RecoQaLinkDef.h index 12944fe046571192684836df6e8eaeb88ef1511b..ecbf6054cf0f27e7c3f030e6bf13845e335dd5b6 100644 --- a/reco/qa/RecoQaLinkDef.h +++ b/reco/qa/RecoQaLinkDef.h @@ -10,8 +10,8 @@ #pragma link off all functions; -#pragma link C++ class CbmRecoQaTask + ; #pragma link C++ class CbmRecoQa + ; #pragma link C++ class CbmTrackingTrdQa + ; +#pragma link C++ class CbmRecoQaTask + ; #endif