diff --git a/core/qa/checker/CbmQaCheckerFileHandler.cxx b/core/qa/checker/CbmQaCheckerFileHandler.cxx index 5f935242ccad50baee55b405b2710c77edcd4905..dd799211d56a2395b822b713981acd23cd7c7908 100644 --- a/core/qa/checker/CbmQaCheckerFileHandler.cxx +++ b/core/qa/checker/CbmQaCheckerFileHandler.cxx @@ -115,7 +115,7 @@ void FileHandler::Process(Option_t* opt) // Create an instance of an object handler std::unique_ptr<ObjectHandler> pObjHandler = nullptr; - LOG(info) << "FileHandler: processing object \"" << vpObjects[0]->GetName() << '\"'; + //LOG(info) << "FileHandler: processing object \"" << vpObjects[0]->GetName() << '\"'; if (dynamic_cast<TH2*>(vpObjects[0])) { pObjHandler = std::make_unique<Hist2DHandler>(iObj, fFileID, fDatasetID); if (bCmpPointByPoint) { diff --git a/core/qa/checker/CbmQaCheckerObjectDB.cxx b/core/qa/checker/CbmQaCheckerObjectDB.cxx index abf083a8c3b1c944f608ce175030ccf316dfd57a..44f4ed3d9dce445863b693d0be135350e2146232 100644 --- a/core/qa/checker/CbmQaCheckerObjectDB.cxx +++ b/core/qa/checker/CbmQaCheckerObjectDB.cxx @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt +/* Copyright (C) 2023-2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt SPDX-License-Identifier: GPL-3.0-only Authors: Sergei Zharko [committer] */ @@ -10,6 +10,10 @@ #include "CbmQaCheckerObjectDB.h" #include "Logger.h" +#include "TDirectory.h" +#include "TFile.h" +#include "TH1.h" +#include "TString.h" #include <algorithm> #include <regex> @@ -29,24 +33,10 @@ void ObjectDB::Clear() fvObjects.clear(); fvVersionLabels.clear(); fvVersionPaths.clear(); - fvGlobalToFileObject.clear(); + fvObjectFirstGlobIndex.clear(); fvCmpResults.clear(); } -// --------------------------------------------------------------------------------------------------------------------- -// -// ObjectDB::GetObjects(int iFile) const -// { -// auto itBegin = std::upper_bound(fvGlobalToFileObject.begin(), fvGlobalToFileObject.end(), iFile, -// [](int i, const std::pair<int, int>& p) { return i <= p.first; }); -// auto itEnd = std::lower_bound(itBegin, fvGlobalToFileObject.end(), iFile, -// [](const std::pair<int, int>& p, int i) { return i >= p.first; }); -// -// int iBegin = itBegin - fvGlobalToFileObject.begin(); -// int iEnd = itEnd - fvGlobalToFileObject.begin(); -// return boost::make_iterator_range(fvObjects.begin() + iBegin, fvObjects.begin() + iEnd); -// } - // --------------------------------------------------------------------------------------------------------------------- // void ObjectDB::AddVersion(const char* label, const char* path) @@ -69,6 +59,7 @@ std::string ObjectDB::GetInputFileName(int iVersion, int iFile, int iDataset) co return res; } + // --------------------------------------------------------------------------------------------------------------------- // void ObjectDB::Init() @@ -100,8 +91,22 @@ void ObjectDB::Init() } LOG(info) << this->ToString(); + // ----- Read object list from file + for (size_t iFile = 0; iFile < fvObjects.size(); ++iFile) { + if (fvObjects[iFile].size() == 0) { + this->ReadObjectList(iFile); + } + } + + // ----- Init the object index vector + fvObjectFirstGlobIndex.clear(); + fvObjectFirstGlobIndex.resize(fvObjects.size() + 1, 0); + for (size_t iFile = 1; iFile <= fvObjects.size(); ++iFile) { + fvObjectFirstGlobIndex[iFile] = fvObjectFirstGlobIndex[iFile - 1] + fvObjects[iFile - 1].size(); + } + // ----- Reserve space for object comparison results - fvCmpResults.resize(fvVersionLabels.size() * fvObjects.size() * fvDatasets.size()); + fvCmpResults.resize(fvVersionLabels.size() * fvObjectFirstGlobIndex.back() * fvDatasets.size()); // ----- Add root path of input, if it were defined auto regexSlashes = std::regex("(/+)"); // regular expression for a sequence of consecutive slashes @@ -131,9 +136,8 @@ void ObjectDB::ReadFromYAML(const char* configName) // ----- Define file-object map if (config["files"]) { - if (fvGlobalToFileObject.size()) { + if (fvObjectFirstGlobIndex.size()) { LOG(warn) << "ObjectDB: file-object map was defined before. Redefining it from the config file " << configName; - fvGlobalToFileObject.clear(); fvFiles.clear(); fvFileLabels.clear(); fvObjects.clear(); @@ -142,22 +146,21 @@ void ObjectDB::ReadFromYAML(const char* configName) const auto& rootNode = config["files"]; // Calculate total number of objects and files - size_t nFiles = rootNode.size(); - size_t nObjects = 0; - for (const auto& fileNode : rootNode) { - nObjects += fileNode["objects"].size(); - } + size_t nFiles = rootNode.size(); fvFiles.reserve(nFiles); fvFileLabels.reserve(nFiles); - fvObjects.reserve(nObjects); - fvGlobalToFileObject.reserve(nObjects); + fvObjects.reserve(nFiles); // Fill vectors for (const auto& fileNode : rootNode) { - size_t iObj = 0; - for (const auto& objectNode : fileNode["objects"]) { - fvGlobalToFileObject.emplace_back(fvFiles.size(), iObj++); - fvObjects.push_back(objectNode.as<std::string>()); + const auto& objectsNode = fileNode["objects"]; + int nObjects = objectsNode ? objectsNode.size() : 0; + auto& objectsInFile = fvObjects.emplace_back(); + objectsInFile.reserve(nObjects); + if (nObjects > 0) { + for (const auto& objectNode : objectsNode) { + objectsInFile.push_back(objectNode.as<std::string>()); + } } fvFiles.push_back(fileNode["name"].as<std::string>()); fvFileLabels.push_back(fileNode["label"].as<std::string>()); @@ -223,6 +226,42 @@ void ObjectDB::ReadFromYAML(const char* configName) } } +// --------------------------------------------------------------------------------------------------------------------- +// +void ObjectDB::CollectObjectPaths(TDirectory* pDir, const TString& parentPath, std::set<std::string>& paths) +{ + for (auto&& pKey : *(pDir->GetListOfKeys())) { + TString sName = parentPath + pKey->GetName(); + if (gFile->Get<TH1>(sName)) { + paths.insert(sName.Data()); + } + else if (auto* pSubDir = gFile->Get<TDirectory>(sName)) { + CollectObjectPaths(pSubDir, sName + "/", paths); + } + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void ObjectDB::ReadObjectList(int iFile) +{ + // TODO: test performance, probably unordered_set will fit better + std::set<std::string> objectPaths; + LOG(info) << "Reading object list from files: ..."; + for (int iDs = 0; iDs < static_cast<int>(fvDatasets.size()); ++iDs) { + const char* fileName = this->GetInputFileName(fDefVersionID, iFile, iDs).c_str(); + LOG(info) << "- file: " << fileName; + TFile fileIn{fileName, "READONLY"}; + fileIn.cd(); + CollectObjectPaths(&fileIn, "", objectPaths); + fileIn.Close(); + } + fvObjects[iFile].clear(); + fvObjects[iFile].reserve(objectPaths.size()); + fvObjects[iFile].insert(fvObjects[iFile].begin(), objectPaths.begin(), objectPaths.end()); + LOG(info) << "Reading object list from files: done"; +} + // --------------------------------------------------------------------------------------------------------------------- // std::string ObjectDB::ToString() const diff --git a/core/qa/checker/CbmQaCheckerObjectDB.h b/core/qa/checker/CbmQaCheckerObjectDB.h index 7a0eccabc0fcd11ca72542774eca3bafeb7db721..dc73e1e4fdfea5400886bdd95f406d7dc9d37e2c 100644 --- a/core/qa/checker/CbmQaCheckerObjectDB.h +++ b/core/qa/checker/CbmQaCheckerObjectDB.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt +/* Copyright (C) 2023-2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt SPDX-License-Identifier: GPL-3.0-only Authors: Sergei Zharko [committer] */ @@ -12,10 +12,13 @@ #include "CbmQaCheckerTypedefs.h" +#include <set> #include <string> #include <utility> #include <vector> +class TString; +class TDirectory; namespace cbm::qa::checker { @@ -74,18 +77,7 @@ namespace cbm::qa::checker /// @param iFile Index of file /// @return iterator_range for ROOT objects of this file /// TODO: Understand, which type is deduced - auto GetObjects(int iFile) const - { - auto itBegin = std::upper_bound(fvGlobalToFileObject.begin(), fvGlobalToFileObject.end(), iFile, - [](int i, const std::pair<int, int>& p) { return i <= p.first; }); - auto itEnd = std::lower_bound(itBegin, fvGlobalToFileObject.end(), iFile, - [](const std::pair<int, int>& p, int i) { return i >= p.first; }); - - int iBegin = itBegin - fvGlobalToFileObject.begin(); - int iEnd = itEnd - fvGlobalToFileObject.begin(); - - return boost::make_iterator_range(fvObjects.begin() + iBegin, fvObjects.begin() + iEnd); - } + const std::vector<std::string>& GetObjects(int iFile) const { return fvObjects[iFile]; } public: /// @brief Gets comparison result @@ -96,8 +88,8 @@ namespace cbm::qa::checker /// @return Value of comparison result CmpResult_t GetCmpResult(int iDS, int iFile, int iObj, int iVer) const { - int iObjGlob = GetObjects(iFile).begin() - fvObjects.begin() + iObj; - int iRes = iVer + fvVersionLabels.size() * (iObjGlob + iDS * fvObjects.size()); + int iObjGlob = fvObjectFirstGlobIndex[iFile] + iObj; + int iRes = iVer + fvVersionLabels.size() * (iObjGlob + iDS * fvObjectFirstGlobIndex.back()); return fvCmpResults[iRes]; } @@ -157,8 +149,8 @@ namespace cbm::qa::checker /// @param value Value of comparison result void SetCmpResult(int iDS, int iFile, int iObj, int iVer, CmpResult_t value) { - int iObjGlob = GetObjects(iFile).begin() - fvObjects.begin() + iObj; - int iRes = iVer + fvVersionLabels.size() * (iObjGlob + iDS * fvObjects.size()); + int iObjGlob = fvObjectFirstGlobIndex[iFile] + iObj; + int iRes = iVer + fvVersionLabels.size() * (iObjGlob + iDS * fvObjectFirstGlobIndex.back()); fvCmpResults[iRes] = value; } @@ -174,19 +166,31 @@ namespace cbm::qa::checker void SetInputRootPath(const char* pathName) { fsInputRootPath = pathName; } private: + /// @brief Reads list of histograms from file + /// @param iFile Index of file + /// @note Accumulates all possible histograms for different datasets + void ReadObjectList(int iFile); + + /// @brief Loops over ROOT-file and collects object paths + /// @param[in] pDir Pointer on directory + /// @param[in] parentPath Parent path within file + /// @param[out] paths A set of object paths + static void CollectObjectPaths(TDirectory* pDir, const TString& parentPah, std::set<std::string>& paths); + int fDefVersionID = -1; ///< Index of default version std::string fsInputRootPath = ""; ///< Root path for input files std::string fsDefaultLabel = ""; ///< Name of default version label - std::vector<std::string> fvDatasets; ///< Container of dataset names - std::vector<std::string> fvFiles; ///< Container of file names - std::vector<std::string> fvFileLabels; ///< Container of file labels (used in output) - std::vector<std::string> fvObjects; ///< Container of object names (joint for all the files) - std::vector<std::string> fvVersionLabels; ///< Container of version labels - std::vector<std::string> fvVersionPaths; ///< Container of version paths - std::vector<std::pair<int, int>> fvGlobalToFileObject; ///< Map of global obj. index -> local file-object - std::vector<CmpResult_t> fvCmpResults; ///< Comparison results vs. dataset, object and version + std::vector<std::string> fvDatasets; ///< Container of dataset names + std::vector<std::string> fvFiles; ///< Container of file names + std::vector<char> fvbProcessWholeFile; ///< If the whole file should be processed + std::vector<int> fvObjectFirstGlobIndex; ///< First global index of object in a file + std::vector<std::string> fvFileLabels; ///< Container of file labels (used in output) + std::vector<std::vector<std::string>> fvObjects; ///< Container of object names vs file id + std::vector<std::string> fvVersionLabels; ///< Container of version labels + std::vector<std::string> fvVersionPaths; ///< Container of version paths + std::vector<CmpResult_t> fvCmpResults; ///< Comparison results vs. dataset, object and version }; } // namespace cbm::qa::checker diff --git a/macro/qa/qa_compare_ca.C b/macro/qa/qa_compare_ca.C index ddb750158a839df51c2040e3433076b142bfa2e9..04541db7dc94d654d88c9dc6972679d2dd95aef6 100644 --- a/macro/qa/qa_compare_ca.C +++ b/macro/qa/qa_compare_ca.C @@ -36,7 +36,7 @@ int qa_compare_ca( pQaChecker->SetFromYAML(configName); // Read file-object map //// ----- Run comparision routine - pQaChecker->Process("PRC"); // P - + pQaChecker->Process("PRB"); // P - //// ----- Scan results bool res = pQaChecker->Scan(); // true - objects are the same, false - objects differ