From 8834e89060cca75a53bc29367d828a0e064424ce Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Mon, 21 Jul 2025 17:11:34 +0200 Subject: [PATCH 01/12] add OpenFileWithNullptrCheck to HelperFunctions --- infra/HelperFunctions.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/infra/HelperFunctions.hpp b/infra/HelperFunctions.hpp index 800c5b71..c97778b4 100644 --- a/infra/HelperFunctions.hpp +++ b/infra/HelperFunctions.hpp @@ -103,6 +103,14 @@ inline std::vector MergeVectors(const std::vector& vec1, const std::vector return MergeVectors(vec1, MergeVectors(vec2, args...)); } +inline TFile* OpenFileWithNullptrCheck(const std::string& fileName, const std::string& option = "read") { + TFile* file = TFile::Open(fileName.c_str(), option.c_str()); + if (file == nullptr) { + throw std::runtime_error("HelperFunctions::OpenFileWithNullptrCheck() - file " + fileName + " is missing"); + } + return file; +} + template inline T* GetObjectWithNullptrCheck(TFile* fileIn, const std::string& objectName) { T* ptr = fileIn->Get(objectName.c_str()); From dfa815435bd5c28253c6139488dbbde57052f807 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Tue, 22 Jul 2025 16:30:20 +0200 Subject: [PATCH 02/12] HelperFunctions: add MergeHistograms, MkDirIfNotExists, CD --- infra/HelperFunctions.hpp | 54 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/infra/HelperFunctions.hpp b/infra/HelperFunctions.hpp index c97778b4..7a110489 100644 --- a/infra/HelperFunctions.hpp +++ b/infra/HelperFunctions.hpp @@ -4,6 +4,7 @@ #include "SimpleCut.hpp" #include +#include #include #include @@ -120,5 +121,58 @@ inline T* GetObjectWithNullptrCheck(TFile* fileIn, const std::string& objectName return ptr; } +inline void CheckHistogramsForXaxisIdentity(const TH1* h1, const TH1* h2) { + if(h1->GetNbinsX() != h2->GetNbinsX()) { + throw std::runtime_error("HelperFunctions::CheckHistogramsForXaxisIdentity(): nBinsX do not match for " + static_cast(h1->GetName()) + " and " + h2->GetName()); + } + const int nBins = h1->GetNbinsX(); + for(int iBin=1; iBin<=nBins; iBin++) { + if(std::abs(h1->GetBinCenter(iBin) - h2->GetBinCenter(iBin)) > 1e-6) { + throw std::runtime_error("HelperFunctions::CheckHistogramsForXaxisIdentity(): bins do not coincide for " + static_cast(h1->GetName()) + " and " + h2->GetName()); + } + } +} + +inline TH1* MergeHistograms(const std::vector& histos) { + for(const auto& h : histos) { + CheckHistogramsForXaxisIdentity(h, histos.at(0)); + } + + TH1* hResult = dynamic_cast(histos.at(0)->Clone("hMerged")); + hResult->Sumw2(); + hResult->SetDirectory(nullptr); + for(size_t iH=1, nHs=histos.size(); iHAdd(histos.at(iH)); + } + hResult->Sumw2(false); + + return hResult; +} + +inline TH1* MergeHistograms(TFile* fileIn, const std::vector& histoNames) { + std::vector histos; + for(const auto& hN : histoNames) { + histos.emplace_back(GetObjectWithNullptrCheck(fileIn, hN)); + } + TH1* hResult = MergeHistograms(histos); + + return hResult; +} + +template +inline TDirectory* MkDirIfNotExists(T* fileOrDirectory, const std::string& name) { + if (fileOrDirectory == nullptr) throw std::runtime_error("HelperFunctions::MkDirIfNotExists(): file or directory ptr is null"); + TDirectory* result = fileOrDirectory->GetDirectory(name.c_str()); + if (result == nullptr) fileOrDirectory->mkdir(name.c_str()); + result = fileOrDirectory->GetDirectory(name.c_str()); + return result; +} + +template +inline void CD(T* fileOrDirectory, const std::string& name) { + auto destination = MkDirIfNotExists(fileOrDirectory, name); + destination->cd(); +} + }// namespace HelperFunctions #endif// ANALYSISTREE_INFRA_HELPER_FUNCTIONS_HPP From 0a97d9c162c68a7576370fb9f257ad377b1e4e7d Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Tue, 22 Jul 2025 16:33:05 +0200 Subject: [PATCH 03/12] SimpleCut: clang-tidy, decouple from HelperFunctions --- infra/SimpleCut.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/infra/SimpleCut.cpp b/infra/SimpleCut.cpp index ff3c979e..5547fac3 100644 --- a/infra/SimpleCut.cpp +++ b/infra/SimpleCut.cpp @@ -3,8 +3,6 @@ Authors: Viktor Klochkov, Ilya Selyuzhenkov */ #include "SimpleCut.hpp" -#include "HelperFunctions.hpp" - #include namespace AnalysisTree { @@ -30,19 +28,19 @@ bool operator==(const SimpleCut& that, const SimpleCut& other) { } SimpleCut RangeCut(const std::string& variable_name, double lo, double hi, const std::string& title) { - return SimpleCut(Variable::FromString(variable_name), lo, hi, title); + return {Variable::FromString(variable_name), lo, hi, title}; } SimpleCut EqualsCut(const std::string& variable_name, int value, const std::string& title) { - return SimpleCut(Variable::FromString(variable_name), value, title); + return {Variable::FromString(variable_name), value, title}; } SimpleCut RangeCut(const Variable& var, double lo, double hi, const std::string& title) { - return SimpleCut(var, lo, hi, title); + return {var, lo, hi, title}; } SimpleCut EqualsCut(const Variable& var, int value, const std::string& title) { - return SimpleCut(var, value, title); + return {var, value, title}; } SimpleCut OpenCut(const std::string& branchName, const std::string& title) { @@ -53,7 +51,7 @@ SimpleCut::SimpleCut(const Variable& var, int value, std::string title) : title_ vars_.emplace_back(var); lambda_ = [value](std::vector& vars) { return vars[0] <= value + SmallNumber && vars[0] >= value - SmallNumber; }; FillBranchNames(); - const std::string stringForHash = var.GetName() + HelperFunctions::ToStringWithPrecision(value, 6) + title_; + const std::string stringForHash = var.GetName() + std::to_string(value) + title_; std::hash hasher; hash_ = hasher(stringForHash); } @@ -62,7 +60,7 @@ SimpleCut::SimpleCut(const Variable& var, double min, double max, std::string ti vars_.emplace_back(var); lambda_ = [max, min](std::vector& vars) { return vars[0] <= max && vars[0] >= min; }; FillBranchNames(); - const std::string stringForHash = var.GetName() + HelperFunctions::ToStringWithPrecision(min, 6) + HelperFunctions::ToStringWithPrecision(max, 6) + title_; + const std::string stringForHash = var.GetName() + std::to_string(min) + std::to_string(max) + title_; std::hash hasher; hash_ = hasher(stringForHash); } @@ -80,8 +78,8 @@ bool SimpleCut::Apply(std::vector& bch, std::vector brch_vec{a_ptr, b_ptr}; std::vector id_vec{a_id, b_id}; bool result = Apply(brch_vec, id_vec); From 7b4153d726631cdd33d7b18feae34dd89ed7d754 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Thu, 31 Jul 2025 11:14:31 +0200 Subject: [PATCH 04/12] update ClassDef version of Track and Particle due to changes introduced in https://github.com/HeavyIonAnalysis/AnalysisTree/pull/132 --- core/Particle.hpp | 2 +- core/Track.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/Particle.hpp b/core/Particle.hpp index ec00a2b9..00049dc5 100644 --- a/core/Particle.hpp +++ b/core/Particle.hpp @@ -102,7 +102,7 @@ class Particle : public Track { PdgCode_t pid_{0}; bool is_allowed_set_charge_and_mass_explicitly_{false};//! - ClassDefOverride(Particle, 2); + ClassDefOverride(Particle, 3); }; }// namespace AnalysisTree diff --git a/core/Track.hpp b/core/Track.hpp index 9063e548..e715e87f 100644 --- a/core/Track.hpp +++ b/core/Track.hpp @@ -164,7 +164,7 @@ class Track : public Container { Floating_t pz_{UndefValueFloat};///< z-component of track's momentum Integer_t charge_{-1000}; - ClassDefOverride(Track, 2); + ClassDefOverride(Track, 3); }; }// namespace AnalysisTree From aeb0367a376df28cf7748309e050a76c469b8480 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Thu, 31 Jul 2025 12:16:05 +0200 Subject: [PATCH 05/12] add language specification for bash commands in ReadMe --- README.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index e08e3537..c2585ecc 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Information about all fields in all branches is stored in Configuration object. ROOT6 is needed for installation. Follow CERN ROOT [instructions](https://root.cern/install/) to install it. Version compiled with c++17 flag is preferred, otherwise CMAKE_CXX_STANDARD flag needs to be explicitly specified (see below). - +```bash git clone https://github.com/HeavyIonAnalysis/AnalysisTree.git cd AnalysisTree mkdir build install @@ -50,14 +50,14 @@ Version compiled with c++17 flag is preferred, otherwise CMAKE_CXX_STANDARD flag source path-to-root-installation/bin/thisroot.sh cmake -DCMAKE_INSTALL_PREFIX=../install ../ make -j install - +``` *path-to-root-installation* must be replaced with your actual location of Root install directory. ### List of CMake options: To apply the flag use -D{Name}={value}, for example, if you want to compile using c++11: - +```bash cmake -DCMAKE_CXX_STANDARD=11 ../ - +``` | Name | Default value | Possible values | | ------------- | ------------- | ---------- | | CMAKE_BUILD_TYPE | RELEASE | RELEASE/DEBUG | @@ -70,16 +70,16 @@ To apply the flag use -D{Name}={value}, for example, if you want to compile usin ### Setting AnalysisTree environment Whatever you are going to do with AnalysisTree - read the file, perform analysis based on information stored in it or create your own file, first of all you need to set up environment variables. It can be done in a single command: - +```bash source path-to-analysis_tree-installation/bin/AnalysisTreeConfig.sh - +``` ### Reading files from ROOT session An example of AnalysisTree ROOT file can be downloaded by this [link](https://sf.gsi.de/f/3ba5a9e3ff5248edba2c/?dl=1) Open a ROOT-file - +```bash root -l 1.analysistree.root - +``` Check its content .ls @@ -98,9 +98,9 @@ and, finally, AnalysisTree::DataHeader object named *DataHeader* containing info #### Reading the configuration In order to know the structure of the tree, perform following command: - +```c++ Configuration->Print() - +``` An output will contain plenty of branches and matchings between them. Let us look at one of them: @@ -114,7 +114,7 @@ Negative ids belong to default fields of branches while positive ids and 0 - to Middle column contains string name of the field, and right column - a description of it. #### Digesting the tree content - +```c++ Configuration->GetBranchConfig("SimParticles").GetType() // to know to which type (Hit, Track, Module, Particle or EventHeader belongs SimParticles branch) @@ -149,27 +149,27 @@ Middle column contains string name of the field, and right column - a descriptio // drawing a histogram with user-defined binning and ranges. rTree->Draw("TMath::Log(TMath::Abs(SimParticles.channels_.GetPx()))") - // drawing a distribution of derived quantites calculated by formula - + // drawing a distribution of derived quantities calculated by formula +``` Moreover, for default fields which are explicitly present in Container (i.e. px is OK, but not pt, which is not stored but calculated on fly) there is a possibility to draw them using TTree::Draw syntax: - +```c++ rTree->Draw("SimParticles.px_") rTree->Draw("TMath::Log(TMath::Abs(SimParticles.px_))") rTree->Draw("TMath::Log(TMath::Abs(SimParticles.px_)) * TMath::Cos(SimParticles.py_)") - +``` Also you can open a ROOT interactive session and create an AnalysisTree::Chain: - +```c++ AnalysisTree::Chain t("1.analysistree.root", "rTree") // Chain constructor with a single file // or AnalysisTree::Chain t({"filelist.txt"}, {"rTree"}) // Chain constructor with a file list - +``` and then build any fields including user-defined and implicitly present fields (such as phi or pt): - +```c++ t.Draw("SimParticles.px") t.Draw("SimParticles.pid") t.Draw("VtxTracks.chi2") // 2D histograms, cuts, drawing options and math formulas mentioned above are also available - +``` ### Reading file with a macro Building of distributions in interactive mode is a good approach only if the commands are simple, and the number of events to be analized is not so big. From 9aea348c7c360d1f5758dc04e7673be97111d77b Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Thu, 31 Jul 2025 19:46:38 +0200 Subject: [PATCH 06/12] extend HelperFunctions --- infra/HelperFunctions.hpp | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/infra/HelperFunctions.hpp b/infra/HelperFunctions.hpp index 7a110489..62533966 100644 --- a/infra/HelperFunctions.hpp +++ b/infra/HelperFunctions.hpp @@ -122,36 +122,43 @@ inline T* GetObjectWithNullptrCheck(TFile* fileIn, const std::string& objectName } inline void CheckHistogramsForXaxisIdentity(const TH1* h1, const TH1* h2) { - if(h1->GetNbinsX() != h2->GetNbinsX()) { + if (h1->GetNbinsX() != h2->GetNbinsX()) { throw std::runtime_error("HelperFunctions::CheckHistogramsForXaxisIdentity(): nBinsX do not match for " + static_cast(h1->GetName()) + " and " + h2->GetName()); } const int nBins = h1->GetNbinsX(); - for(int iBin=1; iBin<=nBins; iBin++) { - if(std::abs(h1->GetBinCenter(iBin) - h2->GetBinCenter(iBin)) > 1e-6) { + for (int iBin = 1; iBin <= nBins; iBin++) { + if (std::abs(h1->GetBinCenter(iBin) - h2->GetBinCenter(iBin)) > 1e-6) { throw std::runtime_error("HelperFunctions::CheckHistogramsForXaxisIdentity(): bins do not coincide for " + static_cast(h1->GetName()) + " and " + h2->GetName()); } } } +inline void Sumw2IfNotYet(TH1* histo, bool value = true) { + const bool isSumw2Already = histo->GetSumw2N() > 0; + if (isSumw2Already != value) histo->Sumw2(value); +} + inline TH1* MergeHistograms(const std::vector& histos) { - for(const auto& h : histos) { + for (const auto& h : histos) { CheckHistogramsForXaxisIdentity(h, histos.at(0)); } + const bool isSumw2 = histos.at(0)->GetSumw2N() > 0; + TH1* hResult = dynamic_cast(histos.at(0)->Clone("hMerged")); - hResult->Sumw2(); + Sumw2IfNotYet(hResult); hResult->SetDirectory(nullptr); - for(size_t iH=1, nHs=histos.size(); iHAdd(histos.at(iH)); } - hResult->Sumw2(false); + Sumw2IfNotYet(hResult, isSumw2); return hResult; } inline TH1* MergeHistograms(TFile* fileIn, const std::vector& histoNames) { std::vector histos; - for(const auto& hN : histoNames) { + for (const auto& hN : histoNames) { histos.emplace_back(GetObjectWithNullptrCheck(fileIn, hN)); } TH1* hResult = MergeHistograms(histos); @@ -174,5 +181,13 @@ inline void CD(T* fileOrDirectory, const std::string& name) { destination->cd(); } +inline double InterpolateTH1SuppressWarning(const TH1* h, double value) { + double result; + if (value <= h->GetBinLowEdge(1) || value >= h->GetBinLowEdge(h->GetNbinsX() + 1)) result = 0.; + else + result = h->Interpolate(value); + return result; +} + }// namespace HelperFunctions #endif// ANALYSISTREE_INFRA_HELPER_FUNCTIONS_HPP From 4bbf64ab7c7d3466b4c3f788f458b441c034a859 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Tue, 28 Oct 2025 13:43:59 +0100 Subject: [PATCH 07/12] get rid of compiler warnings --- core/BranchConfig.cpp | 8 ++++---- core/Configuration.cpp | 4 ---- core/Configuration.test.cpp | 2 -- infra/AnalysisEntry.cpp | 4 ++-- infra/Branch.cpp | 6 ++++++ infra/GenericContainerFiller.cpp | 14 +++++++------- infra/HelperFunctions.hpp | 2 +- infra/SimpleCut.cpp | 4 ++-- infra/SimpleCut.hpp | 4 ++-- infra/Variable.cpp | 2 +- 10 files changed, 25 insertions(+), 25 deletions(-) diff --git a/core/BranchConfig.cpp b/core/BranchConfig.cpp index b044f1b3..85eca5de 100644 --- a/core/BranchConfig.cpp +++ b/core/BranchConfig.cpp @@ -14,7 +14,7 @@ void BranchConfig::GenerateId() { id_ = id_hasher(name_); } -BranchConfig::BranchConfig(std::string name, DetType type, std::string title) : name_(std::move(name)), type_(type), title_(std::move(title)) { +BranchConfig::BranchConfig(std::string name, DetType type, std::string title) : name_(std::move(name)), title_(std::move(title)), type_(type) { GenerateId(); if (type_ == DetType::kTrack) { @@ -156,12 +156,12 @@ void VectorConfig::Print() const { std::vector result; std::vector newlinepositions{-1}; int it{0}; - while (it < std::string::npos) { + while (it < static_cast(std::string::npos)) { it = input.find("\n", it + 1); newlinepositions.emplace_back(it); } newlinepositions.back() = input.size(); - for (int ip = 0; ip < newlinepositions.size() - 1; ++ip) { + for (int ip = 0; ip < static_cast(newlinepositions.size()) - 1; ++ip) { result.emplace_back(input.substr(newlinepositions.at(ip) + 1, newlinepositions.at(ip + 1) - newlinepositions.at(ip) - 1)); } return result; @@ -174,7 +174,7 @@ void VectorConfig::Print() const { } else { auto est = SplitString(entry.second.title_); print_row({{std::to_string(entry.second.id_), 10}, {entry.first, name_strlen}, {est.at(0), 50}}); - for (int iest = 1; iest < est.size(); ++iest) { + for (int iest = 1; iest < static_cast(est.size()); ++iest) { print_row({{"", 10}, {"", name_strlen}, {est.at(iest), 50}}); } } diff --git a/core/Configuration.cpp b/core/Configuration.cpp index e8fc0ffc..2d381e2a 100644 --- a/core/Configuration.cpp +++ b/core/Configuration.cpp @@ -19,14 +19,12 @@ namespace AnalysisTree { void Configuration::Streamer(TBuffer& rb) { if (rb.IsReading()) { - bool read_ok = false; UInt_t rs = 0, rc = 0; auto version_from_file = rb.ReadVersion(&rs, &rc, Configuration::Class()); if (version_from_file == Class()->GetClassVersion()) { Configuration::Class()->ReadBuffer(rb, this, version_from_file, rs, rc); // populate the transient field this->matches_index_ = MakeMatchingIndex(matches_); - read_ok = true; } else if (version_from_file == 3) { // below structure description for version 3 of this class Warning(__func__, "Reading AnalysisTree::Configuration of version %d in compatibility mode. " @@ -40,14 +38,12 @@ void Configuration::Streamer(TBuffer& rb) { this->matches_ = MakeMatchConfigsFromIndex(conf_v3.matches_); // populate the transient field this->matches_index_ = conf_v3.matches_; - read_ok = true; } else { Warning(__func__, "Current version of AnalysisTree::Configuration (%d) " "is different from the version from file (%d) and no rule to read this version was implemented. " "Contact developers if dedicated Streamer implementation is needed for this version.", Configuration::Class()->GetClassVersion(), version_from_file); - read_ok = false; } } else { diff --git a/core/Configuration.test.cpp b/core/Configuration.test.cpp index 189affdd..a972997e 100644 --- a/core/Configuration.test.cpp +++ b/core/Configuration.test.cpp @@ -31,8 +31,6 @@ TEST(Configuration, Basics) { EXPECT_EQ(config.GetNumberOfBranches(), 1); // EXPECT_EQ(config.GetLastId(), 0); - const auto& br1 = config.GetBranchConfig("RecTrack"); - // EXPECT_EQ(br1.GetId(), 0); } TEST(Configuration, Match) { diff --git a/infra/AnalysisEntry.cpp b/infra/AnalysisEntry.cpp index e784132a..f964c02d 100644 --- a/infra/AnalysisEntry.cpp +++ b/infra/AnalysisEntry.cpp @@ -32,7 +32,7 @@ bool AnalysisEntry::ApplyCutOnBranches(std::vector& br, std::vect std::vector id_vec; bch_vec.reserve(br.size()); id_vec.reserve(br.size()); - for (int i = 0; i < br.size(); i++) { + for (int i = 0; i < static_cast(br.size()); i++) { BranchChannel* bchptr = new BranchChannel(br.at(i), ch.at(i)); if (cuts.at(i) != nullptr) { if (!cuts.at(i)->Apply(*bchptr)) { @@ -71,7 +71,7 @@ double AnalysisEntry::FillVariable(const Variable& var, std::vector id_vec; bch_vec.reserve(br.size()); id_vec.reserve(br.size()); - for (int i = 0; i < br.size(); i++) { + for (int i = 0; i < static_cast(br.size()); i++) { BranchChannel* bchptr = new BranchChannel(br.at(i), id.at(i)); bch_vec.emplace_back(bchptr); id_vec.emplace_back(br.at(i)->GetId()); diff --git a/infra/Branch.cpp b/infra/Branch.cpp index c7b68db0..ff920f4e 100644 --- a/infra/Branch.cpp +++ b/infra/Branch.cpp @@ -169,6 +169,12 @@ void Branch::CopyContentsRaw(Branch* other) { *ANALYSISTREE_UTILS_GET(data_) = *ANALYSISTREE_UTILS_GET(other->data_); break; } + case DetType::kGeneric: { + *ANALYSISTREE_UTILS_GET(data_) = *ANALYSISTREE_UTILS_GET(other->data_); + break; + } + default: + throw std::runtime_error("Branch::CopyContentsRaw(): unexpected branch type of 'this'"); } } diff --git a/infra/GenericContainerFiller.cpp b/infra/GenericContainerFiller.cpp index 49818ce5..d2517a3a 100644 --- a/infra/GenericContainerFiller.cpp +++ b/infra/GenericContainerFiller.cpp @@ -55,7 +55,7 @@ void GenericContainerFiller::Init() { config_.AddBranchConfig(branchConfig); - for (int iV = 0; iV < branch_values_.size(); iV++) { + for (int iV = 0; iV < static_cast(branch_values_.size()); iV++) { SetAddressFICS(branch_map_.at(iV).name_, branch_map_.at(iV), branch_values_.at(iV)); } @@ -95,8 +95,8 @@ void GenericContainerFiller::Finish() { void GenericContainerFiller::Run(int nEntries) { Init(); - const size_t nTreeEntries = tree_in_->GetEntries(); - const size_t nRunEntries = (nEntries < 0 || nEntries > nTreeEntries) ? nTreeEntries : nEntries; + const int nTreeEntries = tree_in_->GetEntries(); + const int nRunEntries = (nEntries < 0 || nEntries > nTreeEntries) ? nTreeEntries : nEntries; int previousTriggerVar{-799}; for (int iEntry = 0; iEntry < nRunEntries; iEntry++) { @@ -108,8 +108,8 @@ void GenericContainerFiller::Run(int nEntries) { } int GenericContainerFiller::DetermineFieldIdByName(const std::vector& iMap, const std::string& name) { - auto distance = std::distance(iMap.begin(), std::find_if(iMap.begin(), iMap.end(), [&name](const IndexMap& p) { return p.name_ == name; })); - if (distance == iMap.size()) throw std::runtime_error("DetermineFieldIdByName(): name " + name + " is missing"); + const auto distance = static_cast(std::distance(iMap.begin(), std::find_if(iMap.begin(), iMap.end(), [&name](const IndexMap& p) { return p.name_ == name; }))); + if (distance == static_cast(iMap.size())) throw std::runtime_error("DetermineFieldIdByName(): name " + name + " is missing"); return distance; } @@ -126,7 +126,7 @@ void GenericContainerFiller::SetAddressFICS(const std::string& branchName, const } void GenericContainerFiller::SetFieldsFICS(const std::vector& imap, Container& container, const std::vector& ficc) { - for (int iV = 0; iV < ficc.size(); iV++) { + for (int iV = 0; iV < static_cast(ficc.size()); iV++) { if (imap.at(iV).field_type_ == "TLeafF") container.SetField(ficc.at(iV).float_, imap.at(iV).index_); else if (imap.at(iV).field_type_ == "TLeafI") container.SetField(ficc.at(iV).int_, imap.at(iV).index_); @@ -137,4 +137,4 @@ void GenericContainerFiller::SetFieldsFICS(const std::vector& imap, Co else throw std::runtime_error("GenericContainerFiller::SetFieldsFICS(): unsupported filed type " + imap.at(iV).field_type_); } -} \ No newline at end of file +} diff --git a/infra/HelperFunctions.hpp b/infra/HelperFunctions.hpp index 62533966..0bb21ca6 100644 --- a/infra/HelperFunctions.hpp +++ b/infra/HelperFunctions.hpp @@ -61,7 +61,7 @@ inline std::vector CreateRangeCuts(const std::vector sliceCuts; - for (int iRange = 0; iRange < ranges.size() - 1; iRange++) { + for (int iRange = 0; iRange < static_cast(ranges.size()) - 1; iRange++) { const std::string cutName = cutNamePrefix + ToStringWithPrecision(ranges.at(iRange), precision) + "_" + ToStringWithPrecision(ranges.at(iRange + 1), precision); sliceCuts.emplace_back(AnalysisTree::RangeCut(branchFieldName, ranges.at(iRange), ranges.at(iRange + 1), cutName)); } diff --git a/infra/SimpleCut.cpp b/infra/SimpleCut.cpp index 5547fac3..71006704 100644 --- a/infra/SimpleCut.cpp +++ b/infra/SimpleCut.cpp @@ -43,8 +43,8 @@ SimpleCut EqualsCut(const Variable& var, int value, const std::string& title) { return {var, value, title}; } -SimpleCut OpenCut(const std::string& branchName, const std::string& title) { - return SimpleCut({branchName + ".ones"}, [](const std::vector& par) { return true; }); +SimpleCut OpenCut(const std::string& branchName) { + return SimpleCut({branchName + ".ones"}, [](const std::vector&) { return true; }); } SimpleCut::SimpleCut(const Variable& var, int value, std::string title) : title_(std::move(title)) { diff --git a/infra/SimpleCut.hpp b/infra/SimpleCut.hpp index 9b00481b..533beddd 100644 --- a/infra/SimpleCut.hpp +++ b/infra/SimpleCut.hpp @@ -89,7 +89,7 @@ class SimpleCut { * is iterated and an iteration with no-cut is needed) * @param branchName name of the branch, which is present in other cuts */ - friend SimpleCut OpenCut(const std::string& branchName, const std::string& title); + friend SimpleCut OpenCut(const std::string& branchName); /** * @brief Evaluates cut @@ -139,7 +139,7 @@ SimpleCut RangeCut(const std::string& variable_name, double lo, double hi, const SimpleCut EqualsCut(const std::string& variable_name, int value, const std::string& title = ""); SimpleCut RangeCut(const Variable& var, double lo, double hi, const std::string& title = ""); SimpleCut EqualsCut(const Variable& var, int value, const std::string& title = ""); -SimpleCut OpenCut(const std::string& branchName, const std::string& title = "alwaysTrue"); +SimpleCut OpenCut(const std::string& branchName); }// namespace AnalysisTree #endif//ANALYSISTREE_SIMPLECUT_H diff --git a/infra/Variable.cpp b/infra/Variable.cpp index df32559a..e32577f3 100644 --- a/infra/Variable.cpp +++ b/infra/Variable.cpp @@ -79,7 +79,7 @@ double Variable::GetValue(std::vector& bch, std::vector(bch.size()); i++) { if (field.GetBranchId() == id.at(i)) { vars_.emplace_back(bch.at(i)->Value(field)); success = true; From 78ccacb29552f953983249a21bbf2d4aeecfda34 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Tue, 28 Oct 2025 13:45:53 +0100 Subject: [PATCH 08/12] apply clang-format --- core/Configuration.test.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/core/Configuration.test.cpp b/core/Configuration.test.cpp index a972997e..629b702b 100644 --- a/core/Configuration.test.cpp +++ b/core/Configuration.test.cpp @@ -30,7 +30,6 @@ TEST(Configuration, Basics) { EXPECT_EQ(config.GetNumberOfBranches(), 1); // EXPECT_EQ(config.GetLastId(), 0); - } TEST(Configuration, Match) { From a991a0b08ce3a90e38587f55afd28306ff6ff34d Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Tue, 28 Oct 2025 15:02:06 +0100 Subject: [PATCH 09/12] get rid of compiler warning and apply clang-format --- examples/example.cpp | 7 +++---- infra/BranchChannel.cpp | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/example.cpp b/examples/example.cpp index db6b92b2..913e6093 100644 --- a/examples/example.cpp +++ b/examples/example.cpp @@ -1,8 +1,8 @@ /* Copyright (C) 2019-2021 GSI, Universität Tübingen SPDX-License-Identifier: GPL-3.0-only Authors: Viktor Klochkov, Ilya Selyuzhenkov */ -#include #include +#include using namespace AnalysisTree; @@ -23,7 +23,7 @@ int main(int argc, char* argv[]) { return 0; } -void example(const std::string& filename, const std::string& treename){ +void example(const std::string& filename, const std::string& treename) { auto* chain = new Chain(filename, treename); chain->InitPointersToBranches({"VtxTracks", "SimParticles"}); @@ -34,13 +34,12 @@ void example(const std::string& filename, const std::string& treename){ config->Print(); auto rec_particles = chain->GetBranchObject("VtxTracks"); - auto rec2sim_particles = chain->GetMatching("VtxTracks", "SimParticles"); auto rec_pT = rec_particles.GetField("pT"); for (long i_event = 0; i_event < 10; ++i_event) { chain->GetEntry(i_event); - for(size_t i=0; i Date: Thu, 6 Nov 2025 21:07:22 +0100 Subject: [PATCH 10/12] foresee weight==1 when filling, deprecate IfEmptyVariableConvertToOnes --- infra/AnalysisEntry.cpp | 10 +++++++--- infra/AnalysisEntry.hpp | 2 +- infra/Variable.hpp | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/infra/AnalysisEntry.cpp b/infra/AnalysisEntry.cpp index f964c02d..05520133 100644 --- a/infra/AnalysisEntry.cpp +++ b/infra/AnalysisEntry.cpp @@ -83,6 +83,10 @@ double AnalysisEntry::FillVariable(const Variable& var, std::vector& br, std::vector& id) { + return var.GetNumberOfBranches() > 0 ? FillVariable(var, br, id) : 1.; +} + double AnalysisEntry::FillVariable(const Variable& var, const Branch& br1, int ch1, const Branch& br2, int ch2) { Branch* br1_ptr = new Branch(std::move(br1)); Branch* br2_ptr = new Branch(std::move(br2)); @@ -132,7 +136,7 @@ void AnalysisEntry::FillFromEveHeaders() { i_var++; }//variables values_.emplace_back(temp_vars); - weights_.emplace_back(FillVariable(var4weight_, br_vec, id_vec)); + weights_.emplace_back(FillWeight(var4weight_, br_vec, id_vec)); } /** @@ -168,7 +172,7 @@ void AnalysisEntry::FillFromOneChannalizedBranch() { i_var++; }//variables values_.emplace_back(temp_vars); - weights_.emplace_back(FillVariable(var4weight_, br_vec, id_vec)); + weights_.emplace_back(FillWeight(var4weight_, br_vec, id_vec)); }// channels } @@ -211,7 +215,7 @@ void AnalysisEntry::FillFromTwoChannalizedBranches() { i_var++; }//variables values_.emplace_back(temp_vars); - weights_.emplace_back(FillVariable(var4weight_, br_vec, id_vec)); + weights_.emplace_back(FillWeight(var4weight_, br_vec, id_vec)); }// channels } diff --git a/infra/AnalysisEntry.hpp b/infra/AnalysisEntry.hpp index 19d08265..97c8ac20 100644 --- a/infra/AnalysisEntry.hpp +++ b/infra/AnalysisEntry.hpp @@ -29,7 +29,6 @@ class AnalysisEntry { explicit AnalysisEntry(std::vector vars, Cuts* cuts = nullptr, Variable vars4weight = {}) : vars_(std::move(vars)), var4weight_(std::move(vars4weight)), cuts_(cuts) { - var4weight_.IfEmptyVariableConvertToOnes(vars_.at(0)); FillBranchNames(); }; @@ -62,6 +61,7 @@ class AnalysisEntry { ANALYSISTREE_ATTR_NODISCARD bool ApplyCutOnBranches(std::vector& br, std::vector& cuts, std::vector& ch) const; [[deprecated]] ANALYSISTREE_ATTR_NODISCARD bool ApplyCutOnBranches(const Branch& br1, Cuts* cuts1, int ch1, const Branch& br2, Cuts* cuts2, int ch2) const; static double FillVariable(const Variable& var, std::vector& br, std::vector& id); + static double FillWeight(const Variable& var, std::vector& br, std::vector& id); [[deprecated]] static double FillVariable(const Variable& var, const Branch& br1, int ch1, const Branch& br2, int ch2); std::vector vars_{}; diff --git a/infra/Variable.hpp b/infra/Variable.hpp index e3e2acdc..06d794ad 100644 --- a/infra/Variable.hpp +++ b/infra/Variable.hpp @@ -82,7 +82,7 @@ class Variable { void Print() const; - void IfEmptyVariableConvertToOnes(const Variable& var); + ANALYSISTREE_ATTR_DEPRECATED() void IfEmptyVariableConvertToOnes(const Variable& var); protected: std::string name_; From 83fc3b233fbd513a50a3bf5519dd09fb99bd9208 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Tue, 13 Jan 2026 22:47:11 +0100 Subject: [PATCH 11/12] HelperFunctions::MergeHistograms(): foresee empty when applying sumw2 --- infra/HelperFunctions.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/infra/HelperFunctions.hpp b/infra/HelperFunctions.hpp index 0bb21ca6..c91be29d 100644 --- a/infra/HelperFunctions.hpp +++ b/infra/HelperFunctions.hpp @@ -139,17 +139,17 @@ inline void Sumw2IfNotYet(TH1* histo, bool value = true) { } inline TH1* MergeHistograms(const std::vector& histos) { - for (const auto& h : histos) { + bool isSumw2{false}; + for(const auto& h : histos) { CheckHistogramsForXaxisIdentity(h, histos.at(0)); + isSumw2 |= h->GetSumw2N() > 0; } - const bool isSumw2 = histos.at(0)->GetSumw2N() > 0; - TH1* hResult = dynamic_cast(histos.at(0)->Clone("hMerged")); Sumw2IfNotYet(hResult); hResult->SetDirectory(nullptr); - for (size_t iH = 1, nHs = histos.size(); iH < nHs; ++iH) { - hResult->Add(histos.at(iH)); + for(const auto& h : histos) { + hResult->Add(h); } Sumw2IfNotYet(hResult, isSumw2); From eafeffda3de8582fa98e32d2024f88992efe36e8 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Mon, 19 Jan 2026 15:31:19 +0100 Subject: [PATCH 12/12] bugfix 83fc3b2: do not merge the 0-th histogram twice --- infra/HelperFunctions.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/infra/HelperFunctions.hpp b/infra/HelperFunctions.hpp index c91be29d..d5a514aa 100644 --- a/infra/HelperFunctions.hpp +++ b/infra/HelperFunctions.hpp @@ -148,8 +148,8 @@ inline TH1* MergeHistograms(const std::vector& histos) { TH1* hResult = dynamic_cast(histos.at(0)->Clone("hMerged")); Sumw2IfNotYet(hResult); hResult->SetDirectory(nullptr); - for(const auto& h : histos) { - hResult->Add(h); + for(size_t iH = 1, nHs = histos.size(); iH < nHs; ++iH) { + hResult->Add(histos.at(iH)); } Sumw2IfNotYet(hResult, isSumw2);