CbmRoot
Loading...
Searching...
No Matches
CbmQaTask.cxx
Go to the documentation of this file.
1/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Sergei Zharko [committer] */
4
9
10
11#include "CbmQaTask.h"
12
13#include "FairRootFileSink.h"
14#include "FairRootManager.h"
15#include "FairRunAna.h"
16#include "TAxis.h"
17#include "TCanvas.h"
18#include "TClonesArray.h"
19#include "TF1.h"
20#include "TPad.h"
21#include "TPaveText.h"
22#include "TString.h"
23
24#include <array>
25#include <limits>
26#include <regex>
27
29
30// ---------------------------------------------------------------------------------------------------------------------
31//
32CbmQaTask::CbmQaTask(const char* name, int verbose, bool isMCUsed, ECbmRecoMode recoMode)
33 : FairTask(name, verbose)
34 , CbmQaIO(name)
35 , fbUseMC(isMCUsed)
36 , fRecoMode(recoMode)
37{
39 fStoringMode = CbmQaIO::EStoringMode::kSUBDIR; // mode of objects arrangement in the output file
40}
41
42// ---------------------------------------------------------------------------------------------------------------------
43//
44void CbmQaTask::Exec(Option_t* /*option*/)
45{
46 if (fpBrEvents) {
47 int nEvents = fpBrEvents->GetEntriesFast();
48 for (int iEvt = 0; iEvt < nEvents; ++iEvt) {
49 fpCurrentEvent = static_cast<CbmEvent*>(fpBrEvents->At(iEvt));
50 assert(fpCurrentEvent);
51 this->ExecQa();
52 fNofEvents.SetVal(fNofEvents.GetVal() + 1);
53 }
54 fpCurrentEvent = nullptr;
55 }
56 else {
57 this->ExecQa();
58 fNofEvents.SetVal(fNofEvents.GetVal() + 1);
59 }
60}
61
62// ---------------------------------------------------------------------------------------------------------------------
63//
65{
66 // Processes canvases in the end of the run
67 this->CreateSummary();
68
69 // Write the root folder to sinker
70 auto* pSink = FairRootManager::Instance()->GetSink();
71 LOG_IF(fatal, !pSink) << fName << ": output sink is undefined";
72 if (dynamic_cast<FairRootFileSink*>(pSink)) {
73 auto* pRootSink = static_cast<FairRootFileSink*>(pSink);
74 auto* pRootFile = pRootSink->GetRootFile();
75 if (!pRootFile->FindObjectAny("nEvents")) {
76 pRootFile->cd();
77 fNofEvents.Write();
78 }
79 this->WriteToFile(pRootSink->GetRootFile());
80 }
81 else {
82 LOG(warn) << fName << ": objects cannot be written into online sink (not implemented yet)";
83 }
84}
85
86// ---------------------------------------------------------------------------------------------------------------------
87//
88InitStatus CbmQaTask::Init()
89{
90 LOG_IF(info, fVerbose > 0) << fName << ": initializing task ...";
91 InitStatus res = kSUCCESS;
92
93 // ----- Clear map of the histograms (note)
94 DeInitBase();
95
96 // ----- Initialize task
97 LOG_IF(info, fVerbose > 1) << fName << ": initializing histograms";
98 res = std::max(res, this->InitQa());
99
100 // ----- Initialize event branch
102 fpBrEvents = dynamic_cast<TClonesArray*>(FairRootManager::Instance()->GetObject("CbmEvent"));
103 if (fpBrEvents) {
104 LOG_IF(info, fVerbose > 1) << fName << ": the routine will run on reconstructed events";
105 }
106 else {
107 LOG_IF(info, fVerbose > 1) << fName << ": the routine will run on timeslices, the CbmEvent branch is undefined";
109 }
110 }
111 else {
112 LOG_IF(info, fVerbose > 1) << fName << ": the routine will run on timeslices";
113 }
114
115 fNofEvents.SetVal(0);
116
117 return res;
118}
119
120// ---------------------------------------------------------------------------------------------------------------------
121//
123{
124 return Init();
125}
126
127// ---------------------------------------------------------------------------------------------------------------------
128//
130{
131 // De-initialize basic data members
132 // ...
133
134 // De-initialize particular QA-task implementation
135 DeInit();
136}
137
138
139// ---------------------------------------------------------------------------------------------------------------------
140//
141bool CbmQaTask::CheckRange(TH1* h, double meanMax, double rmsMin, double rmsMax)
142{
143 // Checks ranges for mean and standard deviation
144 // \return False, if variable exits the range
145
146 double mean = h->GetMean();
147 double meanErr = h->GetMeanError();
148
149 double rms = h->GetStdDev();
150 double rmsErr = h->GetStdDevError();
151
152 bool res = true;
153 if (h->GetEntries() >= 10) { // ask for some statistics, otherwise errors are not properly estimated
154 res = CheckRange(TString("Mean for ") + h->GetTitle(), mean, meanErr, -meanMax, meanMax) && res;
155 res = CheckRange(TString("RMS for ") + h->GetTitle(), rms, rmsErr, rmsMin, rmsMax) && res;
156 }
157 return res;
158}
159
160// ---------------------------------------------------------------------------------------------------------------------
161//
163{
164 YAML::Node tagNode = fConfigNode["check_histograms"];
165
166
167 struct HashTString {
168 std::size_t operator()(const TString& str) const { return std::hash<std::string>()(str.Data()); };
169 };
170
171 // Fill map of ROOT objects, which are going to be checked
172 std::unordered_map<TString, ObjectComparisonConfig, HashTString> mCompareList;
173 // TODO: 28.12.2023 SZh: Add a possibility to define a pack of histograms (in a similar way to check flags)
174 for (const auto& histNode : tagNode) {
175 try {
176 auto histName = fsRootFolderName + "/" + histNode["name"].as<std::string>().c_str();
178 if (const auto& subNode = histNode["point_to_point"]) {
179 entry.fPoint = subNode["use"].as<uint8_t>();
180 }
181 if (const auto& subNode = histNode["ratio"]) {
182 entry.fRatio = subNode["use"].as<uint8_t>();
183 entry.fRatioMin = subNode["min"].as<double>();
184 entry.fRatioMax = subNode["max"].as<double>();
185 }
186 if (const auto& subNode = histNode["chi2Test"]) {
187 entry.fStat = subNode["use"].as<uint8_t>();
188 entry.fChi2NdfMax = subNode["chi2_ndf_max"].as<double>();
189 }
190 if (const auto& subNode = histNode["canvas"]) {
191 entry.fCanvOpt = "";
192 if (subNode["comp"].as<bool>(false)) {
193 entry.fCanvOpt += "c";
194 }
195 if (subNode["ratio"].as<bool>(false)) {
196 entry.fCanvOpt += "r";
197 }
198 if (subNode["diff"].as<bool>(false)) {
199 entry.fCanvOpt += "d";
200 }
201 }
202 mCompareList[histName] = entry;
203 }
204 catch (const YAML::InvalidNode& exc) {
205 LOG(warn) << fName << "::CompareQaObjects(): attempt to access key which does not exist in the configuration"
206 << " file (message from YAML exception: " << exc.what() << ')';
207 }
208 }
209
210 // Process comparison
211 // Look up the objects in the object list and search for the name in the map
212
213 bool bCheckResult = true;
214 for (auto& [pObject, sPath] : (*fpvObjList)) {
215 if (pObject) {
216
217 TString objName = sPath + "/" + pObject->GetName();
218 auto configEntryIt = mCompareList.find(objName);
219 if (configEntryIt == mCompareList.end()) {
220 continue;
221 }
222 const auto& configEntry = configEntryIt->second;
223
224 // Get default object
225 auto* pObjCheck = fpBenchmarkInput->Get(objName);
226 if (!pObjCheck) {
227 LOG(warn) << fName << "::CompareQaObjects(): ROOT object " << objName << " is not found in the check file";
228 continue;
229 }
230
231 // Call the comparison function depending on the object type
232 if (dynamic_cast<TProfile*>(pObject)) {
233 bCheckResult &= CompareTwoObjects<TProfile>(pObject, pObjCheck, objName, configEntry);
234 }
235 else if (dynamic_cast<TH2*>(pObject)) {
236 bCheckResult &= CompareTwoObjects<TH2>(pObject, pObjCheck, objName, configEntry);
237 }
238 else if (dynamic_cast<TH1*>(pObject)) {
239 bCheckResult &= CompareTwoObjects<TH1>(pObject, pObjCheck, objName, configEntry);
240 }
241 }
242 }
243 return bCheckResult;
244}
245
246// ---------------------------------------------------------------------------------------------------------------------
247//
248void CbmQaTask::PutSetupNameOnPad(double xMin, double yMin, double xMax, double yMax)
249{
250 if (gPad) {
251 gPad->cd();
252 auto* paveText = new TPaveText(xMin, yMin, xMax, yMax, "NDC");
253 paveText->AddText(fsSetupName.c_str());
254 paveText->SetBorderSize(0);
255 paveText->SetTextSize(0.04);
256 paveText->SetFillStyle(0);
257 paveText->Draw("same");
258 }
259}
260
261// ---------------------------------------------------------------------------------------------------------------------
262//
264{
265 YAML::Node tagNode = fConfigNode["check_list"];
266 if (tagNode) {
267 std::vector<char> vbConfigKeyUsed;
268 std::vector<char> vbCheckKeyProcessed(fmCheckList.size(), false); // Flag to avoid checking the check entry twice
269 vbConfigKeyUsed.reserve(tagNode.size());
270 std::regex rexInt("%d");
271 // First loop: read all the entries, containing special characters ("%d")
272 for (auto it = tagNode.begin(); it != tagNode.end(); ++it) {
273 std::string configEntry = it->first.as<std::string>();
274 if (static_cast<int>(configEntry.find_last_of("%d")) != -1) {
275 vbConfigKeyUsed.push_back(true);
276 bool bCheckStatus = it->second.as<bool>(); // use-flag, stored in the configuration
277 std::regex keyRex = std::regex(std::regex_replace(configEntry, rexInt, "([0-9]+)"));
278 int iCheckEntry = 0;
279 for (auto& [checkEntry, checkFlags] : fmCheckList) {
280 if (!vbCheckKeyProcessed[iCheckEntry] && std::regex_match(checkEntry, keyRex)) {
281 vbCheckKeyProcessed[iCheckEntry] = true;
282 checkFlags.fStatus = bCheckStatus;
283 }
284 ++iCheckEntry;
285 }
286 }
287 else {
288 vbConfigKeyUsed.push_back(false);
289 }
290 }
291 // Second loop: read all other entries
292 int iConfigEntry = 0;
293 for (auto it = tagNode.begin(); it != tagNode.end(); ++it) {
294 if (!vbConfigKeyUsed[iConfigEntry]) {
295 std::string configEntry = it->first.as<std::string>();
296 auto checkListIt = fmCheckList.find(configEntry);
297 if (checkListIt != fmCheckList.end()) {
298 checkListIt->second.fStatus = it->second.as<bool>();
299 }
300 else {
301 LOG(warn) << fName << "::ReadCheckListFromConfig(): config contains unknown entry " << configEntry;
302 }
303 }
304 ++iConfigEntry;
305 }
306 }
307}
308
309// ---------------------------------------------------------------------------------------------------------------------
310//
311void CbmQaTask::StoreCheckResult(const std::string& tag, bool result, const std::string& msg)
312{
313 fmCheckList[tag] = CheckFlags{msg, result, false};
314}
ECbmRecoMode
Reconstruct the full time slice or event-by-event.
Definition CbmDefs.h:162
ClassImp(CbmQaTask)
A base class for CBM QA task logic.
Class characterising one event by a collection of links (indices) to data objects,...
Definition CbmEvent.h:34
ROOT object IO interface for QA.
Definition CbmQaIO.h:44
void WriteToFile(TFile *pOutFile) const
Writes objects into file.
Definition CbmQaIO.cxx:116
YAML::Node fConfigNode
Configuration node.
Definition CbmQaIO.h:164
std::shared_ptr< ObjList_t > fpvObjList
List of registered ROOT objects.
Definition CbmQaIO.h:162
TString fsRootFolderName
Name of root folder.
Definition CbmQaIO.h:157
@ kSUBDIR
Objects of different type will be stored in different subdirectories like histograms/ canvases/.
void SetRootFolderName(const TString &path)
Sets a common root path to the objects in the output file.
Definition CbmQaIO.h:109
EStoringMode fStoringMode
Objects storing mode.
Definition CbmQaIO.h:161
virtual void CreateSummary()
Initializes QA-task summary: canvases, tables etc.
Definition CbmQaTask.h:177
std::string fsSetupName
Name of the setup (to draw on the canvases)
Definition CbmQaTask.h:255
bool CheckRange(std::string_view name, T var, T lo, T hi) const
Checks range of variable.
Definition CbmQaTask.h:275
virtual void DeInit()
De-initialize the task.
Definition CbmQaTask.h:159
std::map< std::string, CheckFlags > fmCheckList
A QA check-list map.
Definition CbmQaTask.h:251
InitStatus Init() override final
FairTask: Task initialization in the beginning of the run.
Definition CbmQaTask.cxx:88
bool CompareQaObjects()
Process ROOT objects comparison.
void DeInitBase()
De-initializes this task.
std::shared_ptr< TFile > fpBenchmarkInput
A file with default ROOT objects used for the cross-check.
Definition CbmQaTask.h:261
virtual void ExecQa()
Method to fill histograms per event or time-slice.
Definition CbmQaTask.h:180
virtual InitStatus InitQa()
Initializes the task.
Definition CbmQaTask.h:174
void Exec(Option_t *) override final
FairTask: Defines action of the task in the event/TS.
Definition CbmQaTask.cxx:44
bool CompareTwoObjects(const TObject *pObjL, const TObject *pObjR, const TString &objName, const ObjectComparisonConfig &cfg)
Process object comparison.
Definition CbmQaTask.h:306
void StoreCheckResult(const std::string &tag, bool result, const std::string &msg="")
Stores check flag to the check-list.
CbmQaTask()=delete
Default constructor.
void ReadCheckListFromConfig()
Reads check-list from the configuration file.
TParameter< int > fNofEvents
Number of processed events.
Definition CbmQaTask.h:256
void PutSetupNameOnPad(double xMin, double yMin, double xMax, double yMax)
Puts setup title on the canvas.
TClonesArray * fpBrEvents
Pointer to CbmEvent branch.
Definition CbmQaTask.h:253
CbmEvent * fpCurrentEvent
Pointer to the current event.
Definition CbmQaTask.h:254
ECbmRecoMode fRecoMode
Reconstruction mode.
Definition CbmQaTask.h:242
void Finish() override final
FairTask: Defines action of the task in the end of run.
Definition CbmQaTask.cxx:64
InitStatus ReInit() override final
FairTask: Task reinitialization.
Data class with information on a STS local track.
Contains a check result and its activeness status of the check-list entry.
Definition CbmQaTask.h:51
Contains configuration to compare two root objects (histograms)
Definition CbmQaTask.h:59