diff --git a/core/AnalysisTreeCoreLinkDef.h b/core/AnalysisTreeCoreLinkDef.h index 87d4f4c7..e658095d 100644 --- a/core/AnalysisTreeCoreLinkDef.h +++ b/core/AnalysisTreeCoreLinkDef.h @@ -40,6 +40,7 @@ #pragma link C++ typedef AnalysisTree::ModuleDetector; #pragma link C++ typedef AnalysisTree::HitDetector; #pragma link C++ typedef AnalysisTree::ModulePositions; +#pragma link C++ typedef AnalysisTree::GenericDetector; #pragma link C++ defined_in "Constants.h"; diff --git a/core/Constants.hpp b/core/Constants.hpp index 916e4275..6af3fa4b 100644 --- a/core/Constants.hpp +++ b/core/Constants.hpp @@ -49,7 +49,8 @@ enum class DetType : ShortInt_t { kModule, kTrack, kEventHeader, - kParticle + kParticle, + kGeneric }; enum class Types : ShortInt_t { diff --git a/examples/AnalysisTreeUserLinkDef.h b/examples/AnalysisTreeUserLinkDef.h index fda60a60..759171bf 100644 --- a/examples/AnalysisTreeUserLinkDef.h +++ b/examples/AnalysisTreeUserLinkDef.h @@ -4,7 +4,7 @@ #pragma link off all functions; #pragma link C++ nestedclasses; -//#pragma link C++ class UserTaskRead++; -#pragma link C++ class UserTaskWrite++; +#pragma link C++ class UserTaskRead+; +#pragma link C++ class UserTaskWrite+; #endif diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 65e011a3..d04d3744 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -14,7 +14,7 @@ message(STATUS "CMAKE_PROJECT_NAME ${CMAKE_PROJECT_NAME}") string(REPLACE ".cpp" ".hpp" HEADERS "${SOURCES}") include_directories(${CMAKE_SOURCE_DIR}/core ${CMAKE_SOURCE_DIR}/infra ${CMAKE_CURRENT_SOURCE_DIR} $<$:${Boost_INCLUDE_DIRS}>) -add_library(AnalysisTreeUser SHARED ${SOURCES} G__AnalysisTreeUser.cxx) +add_library(AnalysisTreeUser SHARED ${SOURCES}) target_compile_definitions(AnalysisTreeUser PUBLIC $<$:ANALYSISTREE_BOOST_FOUND>) @@ -23,6 +23,7 @@ ROOT_GENERATE_DICTIONARY(G__AnalysisTreeUser ${HEADERS} OPTIONS -I${CMAKE_BINARY_DIR}/include $<$:-DANALYSISTREE_BOOST_FOUND> + MODULE AnalysisTreeUser ) target_link_libraries(AnalysisTreeUser PUBLIC diff --git a/examples/UserTaskRead.hpp b/examples/UserTaskRead.hpp index 653128ee..5d42c1d3 100644 --- a/examples/UserTaskRead.hpp +++ b/examples/UserTaskRead.hpp @@ -1,7 +1,7 @@ #ifndef ANALYSISTREE_EXAMPLES_USERTASKREAD_HPP_ #define ANALYSISTREE_EXAMPLES_USERTASKREAD_HPP_ -#include +#include class UserTaskRead : public AnalysisTree::Task { diff --git a/examples/UserTaskWrite.hpp b/examples/UserTaskWrite.hpp index 3163cb2d..16af7f08 100644 --- a/examples/UserTaskWrite.hpp +++ b/examples/UserTaskWrite.hpp @@ -1,9 +1,9 @@ #ifndef ANALYSISTREE_EXAMPLES_USERTASKWRITE_HPP_ #define ANALYSISTREE_EXAMPLES_USERTASKWRITE_HPP_ -#include #include -#include +#include +#include class UserTaskWrite : public AnalysisTree::Task { diff --git a/examples/example.cpp b/examples/example.cpp index b690bdf3..db6b92b2 100644 --- a/examples/example.cpp +++ b/examples/example.cpp @@ -33,7 +33,7 @@ void example(const std::string& filename, const std::string& treename){ data_header->Print(); config->Print(); - auto rec_particles = chain->GetBranch("VtxTracks"); + auto rec_particles = chain->GetBranchObject("VtxTracks"); auto rec2sim_particles = chain->GetMatching("VtxTracks", "SimParticles"); auto rec_pT = rec_particles.GetField("pT"); diff --git a/infra/Branch.cpp b/infra/Branch.cpp index 46c5512d..cc2fc8fa 100644 --- a/infra/Branch.cpp +++ b/infra/Branch.cpp @@ -41,6 +41,10 @@ void Branch::InitDataPtr() { data_ = temp; break; } + case DetType::kGeneric: { + data_ = new GenericDetector(config_.GetId()); + break; + } default: throw std::runtime_error("Branch type is not known!"); } } diff --git a/infra/CMakeLists.txt b/infra/CMakeLists.txt index 9b6f23c7..9d84a270 100644 --- a/infra/CMakeLists.txt +++ b/infra/CMakeLists.txt @@ -13,6 +13,7 @@ set(SOURCES Branch.cpp BranchChannel.cpp AnalysisEntry.cpp + GenericContainerFiller.cpp ) @@ -22,7 +23,7 @@ string(REPLACE ".cpp" ".hpp" HEADERS "${SOURCES}") list(APPEND HEADERS "VariantMagic.hpp" "ToyMC.hpp" "Utils.hpp" "BranchHashHelper.hpp" "HelperFunctions.hpp") include_directories(${CMAKE_SOURCE_DIR}/core ${CMAKE_CURRENT_SOURCE_DIR} $<$:${Boost_INCLUDE_DIRS}>) -add_library(AnalysisTreeInfra SHARED ${SOURCES} G__AnalysisTreeInfra.cxx) +add_library(AnalysisTreeInfra SHARED ${SOURCES}) target_compile_definitions(AnalysisTreeInfra PUBLIC $<$:ANALYSISTREE_BOOST_FOUND>) @@ -31,6 +32,7 @@ ROOT_GENERATE_DICTIONARY(G__AnalysisTreeInfra ${HEADERS} OPTIONS -I${CMAKE_BINARY_DIR}/include $<$:-DANALYSISTREE_BOOST_FOUND> + MODULE AnalysisTreeInfra ) target_link_libraries(AnalysisTreeInfra PUBLIC diff --git a/infra/Chain.cpp b/infra/Chain.cpp index cac31914..d31dfd16 100644 --- a/infra/Chain.cpp +++ b/infra/Chain.cpp @@ -88,6 +88,10 @@ void Chain::InitPointersToBranches(std::set names) { branch_ptr = new ModuleDetector; break; } + case DetType::kGeneric: { + branch_ptr = new GenericDetector; + break; + } } branches_.emplace(branch, branch_ptr); } diff --git a/infra/GenericContainerFiller.cpp b/infra/GenericContainerFiller.cpp new file mode 100644 index 00000000..e51881ca --- /dev/null +++ b/infra/GenericContainerFiller.cpp @@ -0,0 +1,125 @@ +// +// Created by oleksii on 09.04.25. +// + +#include "GenericContainerFiller.hpp" + +using namespace AnalysisTree; + +GenericContainerFiller::GenericContainerFiller(std::string fileInName, std::string treeInName) : file_in_name_(std::move(fileInName)), + tree_in_name_(std::move(treeInName)) {} + +void GenericContainerFiller::Init() { + file_in_ = TFile::Open(file_in_name_.c_str(), "read"); + if (file_in_ == nullptr) throw std::runtime_error("GenericContainerFiller::Run(): file_in_ == nullptr"); + + tree_in_ = file_in_->Get(tree_in_name_.c_str()); + if (tree_in_ == nullptr) throw std::runtime_error("GenericContainerFiller::Run(): tree_in_ == nullptr"); + + if (!fields_to_ignore_.empty() && !fields_to_preserve_.empty()) throw std::runtime_error("GenericContainerFiller::Run(): !fields_to_ignore_.empty() && !fields_to_preserve_.empty()"); + + BranchConfig branchConfig(branch_out_name_, DetType::kGeneric); + + auto lol = tree_in_->GetListOfLeaves(); + const int nLeaves = lol->GetEntries(); + for (int iLeave = 0; iLeave < nLeaves; iLeave++) { + auto leave = lol->At(iLeave); + const std::string fieldName = leave->GetName(); + const std::string fieldType = leave->ClassName(); + if (!fields_to_ignore_.empty() && (std::find(fields_to_ignore_.begin(), fields_to_ignore_.end(), fieldName) != fields_to_ignore_.end())) continue; + if (!fields_to_preserve_.empty() && (std::find(fields_to_preserve_.begin(), fields_to_preserve_.end(), fieldName) == fields_to_preserve_.end())) continue; + if (fieldType == "TLeafF") { + branchConfig.AddField(fieldName); + } else if (fieldType == "TLeafI" || fieldType == "TLeafB" || fieldType == "TLeafS") { + branchConfig.AddField(fieldName); + } + branch_map_.emplace_back((IndexMap){fieldName, fieldType, branchConfig.GetFieldId(fieldName)}); + } + branch_values_.resize(branch_map_.size()); + + config_.AddBranchConfig(branchConfig); + + for (int iV = 0; iV < branch_values_.size(); iV++) { + TBranch* branch = tree_in_->GetBranch(branch_map_.at(iV).name_.c_str()); + SetAddressFICS(branch, branch_map_.at(iV), branch_values_.at(iV)); + } + + generic_detector_ = new GenericDetector(branchConfig.GetId()); + + file_out_ = TFile::Open(file_out_name_.c_str(), "recreate"); + tree_out_ = new TTree(tree_out_name_.c_str(), "Analysis Tree"); + tree_out_->SetAutoSave(0); + tree_out_->Branch((branchConfig.GetName() + ".").c_str(), "AnalysisTree::GenericDetector", &generic_detector_); + + entry_switch_trigger_id_ = entry_switch_trigger_var_name_.empty() ? -999 : DetermineFieldIdByName(branch_map_, entry_switch_trigger_var_name_); +} + +int GenericContainerFiller::Exec(int iEntry, int previousTriggerVar) { + tree_in_->GetEntry(iEntry); + const int currentTriggerVar = entry_switch_trigger_id_ >= 0 ? branch_values_.at(entry_switch_trigger_id_).get() : previousTriggerVar; + auto isNewATEntry = [&]() { return iEntry == 0 || (currentTriggerVar != previousTriggerVar) || (n_channels_per_entry_ >= 0 && iEntry % n_channels_per_entry_ == 0); }; + + if (isNewATEntry()) { + if (iEntry != 0) tree_out_->Fill(); + generic_detector_->ClearChannels(); + } + auto& channel = generic_detector_->AddChannel(config_.GetBranchConfig(generic_detector_->GetId())); + SetFieldsFICS(branch_map_, channel, branch_values_); + + return currentTriggerVar; +} + +void GenericContainerFiller::Finish() { + file_out_->cd(); + config_.Write("Configuration"); + tree_out_->Write(); + file_out_->Close(); + file_in_->Close(); +} + +void GenericContainerFiller::Run(int nEntries) { + Init(); + + const size_t nTreeEntries = tree_in_->GetEntries(); + const size_t nRunEntries = (nEntries < 0 || nEntries > nTreeEntries) ? nTreeEntries : nEntries; + + int previousTriggerVar{-799}; + for (int iEntry = 0; iEntry < nRunEntries; iEntry++) { + previousTriggerVar = Exec(iEntry, previousTriggerVar); + }// iEntry + tree_out_->Fill(); + + Finish(); +} + +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"); + return distance; +} + +void GenericContainerFiller::SetAddressFICS(TBranch* branch, const IndexMap& imap, FICS& ficc) { + if (imap.field_type_ == "TLeafF") branch->SetAddress(&ficc.float_); + else if (imap.field_type_ == "TLeafI") + branch->SetAddress(&ficc.int_); + else if (imap.field_type_ == "TLeafB") + branch->SetAddress(&ficc.char_); + else if (imap.field_type_ == "TLeafS") + branch->SetAddress(&ficc.short_); + else + throw std::runtime_error("GenericContainerFiller::SetAddressFICS(): unsupported filed type " + imap.field_type_); +} + +void GenericContainerFiller::SetFieldsFICS(const std::vector& imap, Container& container, const std::vector& ficc) { + for (int iV = 0; iV < 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_); + else if (imap.at(iV).field_type_ == "TLeafB") + container.SetField(static_cast(ficc.at(iV).char_), imap.at(iV).index_); + else if (imap.at(iV).field_type_ == "TLeafS") + container.SetField(static_cast(ficc.at(iV).short_), imap.at(iV).index_); + 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/GenericContainerFiller.hpp b/infra/GenericContainerFiller.hpp new file mode 100644 index 00000000..b7a5bbda --- /dev/null +++ b/infra/GenericContainerFiller.hpp @@ -0,0 +1,100 @@ +// +// Created by oleksii on 09.04.25. +// + +#ifndef ANALYSISTREE_GENERICCONTAINERFILLER_HPP +#define ANALYSISTREE_GENERICCONTAINERFILLER_HPP + +#include "Configuration.hpp" +#include "Container.hpp" +#include "Detector.hpp" + +#include +#include + +#include +#include + +struct IndexMap { + std::string name_; + std::string field_type_; + short index_; +}; + +struct FICS {// FICS stands for float, int, char, short + float float_{-199.f}; + int int_{-199}; + char char_{static_cast(-199)}; + short short_{static_cast(-199)}; + + float get() { + if (std::fabs(float_ + 199.f) > 1e-4) return float_; + if (int_ != -199) return static_cast(int_); + if (char_ != static_cast(-199)) return static_cast(char_); + if (short_ != static_cast(-199)) return static_cast(short_); + throw std::runtime_error("GenericContainerFiller, FICS::get(): none of values initialized"); + } +}; + +namespace AnalysisTree { + +class GenericContainerFiller { + public: + GenericContainerFiller() = delete; + explicit GenericContainerFiller(std::string fileInName, std::string treeInName = "pTree"); + virtual ~GenericContainerFiller() = default; + + void SetOutputFileName(const std::string& name) { file_out_name_ = name; } + void SetOutputTreeName(const std::string& name) { tree_out_name_ = name; } + void SetOutputBranchName(const std::string& name) { branch_out_name_ = name; } + + void SetFieldsToIgnore(const std::vector& fields) { fields_to_ignore_ = fields; } + void SetFieldsToPreserve(const std::vector& fields) { fields_to_preserve_ = fields; } + + void SetEntrySwitchTriggerVarName(const std::string& name) { entry_switch_trigger_var_name_ = name; } + + void SetNChannelsPerEntry(int n) { n_channels_per_entry_ = n; } + + void Run(int nEntries = -1); + + protected: + void Init(); + int Exec(int iEntry, int previousTriggerVar); + void Finish(); + + static int DetermineFieldIdByName(const std::vector& iMap, const std::string& name); + static void SetAddressFICS(TBranch* branch, const IndexMap& imap, FICS& ficc); + static void SetFieldsFICS(const std::vector& imap, AnalysisTree::Container& container, const std::vector& ficc); + + std::string file_in_name_; + std::string tree_in_name_; + + std::string file_out_name_{"AnalysisTree.root"}; + std::string tree_out_name_{"aTree"}; + std::string branch_out_name_{"PlainBranch"}; + + TFile* file_in_{nullptr}; + TTree* tree_in_{nullptr}; + TFile* file_out_{nullptr}; + TTree* tree_out_{nullptr}; + + AnalysisTree::Configuration config_; + AnalysisTree::GenericDetector* generic_detector_{nullptr}; + std::vector branch_map_; + std::vector branch_values_; + + // variable, change of value of which triggers switch to a new AT event + std::string entry_switch_trigger_var_name_{""}; + + int entry_switch_trigger_id_{-1}; + + // if entry_switch_trigger_var_name_ is not empty, this field does not matter + // if entry_switch_trigger_var_name_ is empty, sets how many AT channels + // will constitute a single AT entry (event) + int n_channels_per_entry_{-1}; + + std::vector fields_to_ignore_{}; + std::vector fields_to_preserve_{}; +}; +}// namespace AnalysisTree +#endif//ANALYSISTREE_GENERICCONTAINERFILLER_HPP diff --git a/infra/HelperFunctions.hpp b/infra/HelperFunctions.hpp index 50a300c7..6b6caaff 100644 --- a/infra/HelperFunctions.hpp +++ b/infra/HelperFunctions.hpp @@ -33,7 +33,7 @@ inline std::string ToStringWithSignificantFigures(const T a_value, const int n) inline std::vector CreateRangeCuts(const std::vector& ranges, const std::string& cutNamePrefix, const std::string& branchFieldName, int precision = 2) { std::vector sliceCuts; for (int iRange = 0; iRange < ranges.size() - 1; iRange++) { - const std::string cutName = cutNamePrefix + ToStringWithPrecision(ranges.at(iRange), 2) + "_" + ToStringWithPrecision(ranges.at(iRange + 1), precision); + 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)); } @@ -50,5 +50,13 @@ inline std::vector CreateEqualCuts(const std::vectorGetDataRaw(), branch->GetConfig()); break; } + case DetType::kGeneric: { + AddBranch(branch->GetDataRaw(), branch->GetConfig()); + break; + } } } @@ -126,9 +130,6 @@ class TaskManager { configuration_->GetBranchConfig(br2).GetId()); configuration_->AddMatch(match); - // if (write_mode_ == eBranchWriteMode::kCreateNewTree) { - // chain_->GetConfiguration()->AddMatch(match); - // } out_tree_->Branch((configuration_->GetMatchName(br1, br2) + ".").c_str(), &match); } diff --git a/infra/Utils.hpp b/infra/Utils.hpp index 046a4414..e0e8e67b 100644 --- a/infra/Utils.hpp +++ b/infra/Utils.hpp @@ -32,9 +32,10 @@ class Particle; class Module; class Hit; class EventHeader; +class Container; -using BranchPointer = ANALYSISTREE_UTILS_VARIANT; -using ChannelPointer = ANALYSISTREE_UTILS_VARIANT; +using BranchPointer = ANALYSISTREE_UTILS_VARIANT; +using ChannelPointer = ANALYSISTREE_UTILS_VARIANT; namespace Utils {