24#include <yaml-cpp/yaml.h>
33 EngineType engine,
const std::string& figExt,
bool ignoreSame)
38 fFile.reset(TFile::Open(qaFile.c_str(),
"READONLY"));
40 throw std::runtime_error(
"Cannot open input file: " + qaFile);
44 fReport = std::make_unique<Builder>(
"QA Compare Status", outDir.c_str());
45 fReport->GetHeader()->SetSubtitle(
"The CBM Collaboration");
46 fReport->GetHeader()->SetAuthor(gSystem->Getenv(
"USER"));
47 fReport->GetHeader()->SetSetup(setup.c_str());
48 fReport->SetFigureExtention(figExt.c_str());
54 std::string path =
fFile->GetName();
83 LOG(info) <<
"Processing root file: " << Path;
84 std::unique_ptr<TFile> f(TFile::Open(Path.c_str(),
"READ"));
85 if (!f || f->IsZombie()) {
86 std::cerr <<
"Cannot open file\n";
91 TIter setups(f->GetListOfKeys());
92 while (
auto* setupKey =
static_cast<TKey*
>(setups())) {
93 const std::string setupName = setupKey->GetName();
94 LOG(info) <<
"Processing setup: " << setupName;
97 auto* setupDir =
dynamic_cast<TDirectory*
>(f->GetDirectory(setupName.c_str()));
99 LOG(warn) <<
" Not a folder, skipping: " << setupName;
104 TIter fileLabels(setupDir->GetListOfKeys());
105 while (
auto* fileKey =
static_cast<TKey*
>(fileLabels())) {
106 const std::string fileLabel = fileKey->GetName();
107 LOG(info) <<
" Found file label: " << fileLabel;
109 auto* fileDir =
dynamic_cast<TDirectory*
>(setupDir->GetDirectory(fileLabel.c_str()));
111 LOG(warn) <<
" Not a folder, skipping: " << fileLabel;
116 TIter tasks(fileDir->GetListOfKeys());
117 while (
auto* taskKey =
static_cast<TKey*
>(tasks())) {
118 const std::string taskName = taskKey->GetName();
120 std::string sectionName =
"Comparison Results for " + taskName;
121 auto section = std::make_shared<Section>(taskName, sectionName);
124 LOG(info) <<
" Found task: " << taskName <<
" in " << fileLabel;
125 auto* taskDir =
dynamic_cast<TDirectory*
>(fileDir->GetDirectory(taskName.c_str()));
126 std::string currentRPath = taskName;
135 LOG(info) <<
" Creating table with " << nRows <<
" rows and " << nCols <<
" columns for task: " << taskName;
136 auto table = std::make_shared<Table>(taskName, nRows, nCols, taskName);
137 for (
size_t i = 0; i < nCols; ++i) {
139 table->SetColumnTitle(i,
"Histogram");
145 for (
size_t j = 0; j < nRows; ++j) {
153 LOG(info) <<
"Processing result for group: " <<
fObjlist[j] <<
" | Version: " <<
fVersionLabel[i - 1]
154 <<
" | Result: " << cellText;
155 table->SetCell(j, i, cellText);
164 for (
const auto& path : canvasPaths) {
165 if (
auto* canv =
dynamic_cast<TCanvas*
>(taskDir->Get(path.c_str()))) {
166 auto fig = std::make_shared<Figure>(path);
167 fig->AddPlot(
fReport->SaveCanvas(canv, path));
180 std::vector<std::string> paths;
181 if (!dir)
return paths;
183 TIter nextKey(dir->GetListOfKeys());
184 while (
auto* key =
static_cast<TKey*
>(nextKey())) {
185 const std::string keyName = key->GetName();
188 auto* obj = key->ReadObj();
189 auto* subDir =
dynamic_cast<TDirectory*
>(obj);
194 TIter subIter(subDir->GetListOfKeys());
195 while (
auto* subKey =
static_cast<TKey*
>(subIter())) {
196 auto* canvas =
dynamic_cast<TCanvas*
>(subKey->ReadObj());
198 std::string canvasPath = prefix + keyName +
"/" + subKey->GetName();
199 LOG(info) <<
"Found canvas: " << canvasPath;
200 paths.push_back(canvasPath);
204 const auto subPaths =
GetCanvasPaths(subDir, prefix + keyName +
"/");
205 paths.insert(paths.end(), subPaths.begin(), subPaths.end());
214 std::string escaped = text;
215 const std::string specialChars =
"#$%&_";
216 for (
char c : specialChars) {
217 std::string toReplace(1, c);
218 std::string replacement =
"\\" + toReplace;
220 while ((
pos = escaped.find(toReplace,
pos)) != std::string::npos) {
221 escaped.replace(
pos, toReplace.length(), replacement);
222 pos += replacement.length();
233 TIter next(dir->GetListOfKeys());
234 while (TKey* key =
static_cast<TKey*
>(next())) {
235 TObject* obj = key->ReadObj();
236 std::string name = key->GetName();
237 std::string fullPath = currentPath +
"/" + name;
240 if (obj->InheritsFrom(
"TDirectory")) {
241 auto subDir =
static_cast<TDirectory*
>(obj);
244 else if (
auto* concreteObj =
dynamic_cast<Result*
>(obj)) {
246 LOG(info) <<
"Found Result object: " << name;
247 LOG(info) <<
"full Path: " << fullPath;
248 std::string groupName;
249 std::string taskPrefix = taskName +
"/";
250 LOG(info) <<
"Task prefix: " << taskPrefix;
251 size_t pos = fullPath.find(taskPrefix);
253 if (
pos != std::string::npos) {
254 size_t start =
pos + taskPrefix.length();
255 size_t end = fullPath.rfind(
'/');
256 if (end != std::string::npos && end > start) {
257 groupName = fullPath.substr(start, end - start);
260 std::string versionLabel;
261 std::string prefix =
"result_";
262 size_t posVer = fullPath.rfind(prefix);
263 if (posVer != std::string::npos) {
264 versionLabel = fullPath.substr(posVer + prefix.length());
265 LOG(info) <<
"Extracted version label: " << versionLabel;
268 LOG(info) <<
"Group name: " << groupName;
270 fResults.at(groupName).emplace_back(res);
275 LOG(info) <<
"Added result to group: " << groupName <<
" | Total results: " <<
fResults.at(groupName).size();
283 case ECmpInference::StronglyEqual:
return "Same";
284 case ECmpInference::WeaklyEqual:
return "Consistent";
285 case ECmpInference::Different:
return "Different";
286 default:
return "Unknown";
LaTeX Beamer engine for the cbm::qa::report (header)
HTML document engine for the cbm::qa::report (source)
LaTeX Beamer engine for the cbm::qa::report (source)
Base class for the report section (header)
Base class for the report table (header)
void Process(const std::string &yamlFile)
Process the YAML results file.
std::vector< std::string > fVersionLabel
version labels for comparison
std::string fOutDir
output directory
std::string fSetup
setup tag
std::unique_ptr< TFile > fFile
input ROOT file
bool fIgnoreSame
ignore "Same" results in comparison tables
static std::vector< std::string > GetCanvasPaths(TDirectory *dir, const std::string &prefix="")
static std::string CmpInferenceToString(cbm::qa::checker::ECmpInference inf)
EngineType fEngine
chosen engine
EngineType
Supported output engines.
static std::string EscapeLatex(const std::string &text)
std::unordered_map< std::string, std::vector< cbm::qa::checker::Result > > fResults
results map
std::unique_ptr< cbm::qa::report::Builder > fReport
report builder
QaReportGenerator(const std::string &qaFile, const std::string &setup, const std::string &outDir, EngineType engine=EngineType::kLatex, const std::string &figExt="png", bool ignoreSame=false)
void Generate()
Run the complete report generation pipeline.
void GetResults(TDirectory *dir, const std::string ¤tPath, const std::string &taskName)
std::vector< std::string > fObjlist
list of objects in the file
A storable result of the QA-checker comparison routine.
Plain LaTeX document engine.
Plain LaTeX document engine.
ECmpInference
The object comparison inference.