18#include <FairEventHeader.h>
19#include <FairFileHeader.h>
20#include <FairRootManager.h>
22#include <TBranchElement.h>
23#include <TClonesArray.h>
26#include <fmt/chrono.h>
33 constexpr auto DEFAULT_TITLE =
"InputRootFile";
35 template <
typename ContainerType,
typename DataType>
36 auto Vector2TContainer(std::vector<DataType>& vec) -> std::unique_ptr<ContainerType>
38 using RawType = std::remove_reference_t<std::remove_pointer_t<DataType>>;
39 static_assert(std::is_base_of_v<TObject, RawType>);
40 auto list = std::make_unique<ContainerType>();
41 for (
auto& iter : vec)
43 if constexpr (std::is_pointer_v<DataType>)
55 template <
typename StringType = std::
string>
56 auto GetBranchList(TFile* rootFile, std::string_view listName) -> std::vector<StringType>
58 auto branchList = std::vector<StringType>{};
59 if (
auto* list =
dynamic_cast<TList*
>(rootFile->Get(listName.data())); list !=
nullptr)
61 for (
const auto& str : TRangeDynCast<TObjString>(list))
63 branchList.emplace_back(str->GetString().Data());
69 fmt::format(
"No branch list named {0} in input file {1}", listName, rootFile->GetName()));
74 template <
typename UnaryFunc>
75 void loop_through_branch_elements(TFile* root_file, std::string_view tree_name, UnaryFunc&& action)
77 auto* tree = root_file->Get<TTree>(tree_name.data());
78 auto* branches = tree->GetListOfBranches();
80 fmt::format(
"Get {} branches from the tree file {}", branches->GetEntries(), root_file->GetName()));
81 for (
auto* branch_obj : TRangeDynCast<TObject>(branches))
83 auto* branch =
dynamic_cast<TBranchElement*
>(branch_obj);
84 if (branch ==
nullptr)
92 template <
typename UnaryFunc>
93 void loop_through_branches(TFile* root_file, std::string_view tree_name, UnaryFunc&& action)
95 auto* tree = root_file->Get<TTree>(tree_name.data());
96 auto* branches = tree->GetListOfBranches();
98 fmt::format(
"Get {} branches from the tree file {}", branches->GetEntries(), root_file->GetName()));
99 for (
auto* branch_obj : TRangeDynCast<TObject>(branches))
101 auto* branch =
dynamic_cast<TBranch*
>(branch_obj);
102 if (branch ==
nullptr)
110 template <
typename StringType = std::
string>
111 auto GetBranchListFromTree(TFile* root_file, std::string_view tree_name) -> std::vector<StringType>
113 auto branch_name_list = std::vector<StringType>{};
114 loop_through_branch_elements(root_file,
116 [&branch_name_list](
auto* branch)
117 { branch_name_list.emplace_back(branch->GetName()); });
118 return branch_name_list;
121 auto get_tca_data_class(TBranchElement* branch) -> std::string
123 TClonesArray* buffer =
nullptr;
124 branch->SetAddress(&buffer);
126 branch->SetAddress(
nullptr);
127 if (buffer !=
nullptr)
129 auto class_name = std::string{ buffer->GetClass()->GetName() };
131 fmt::format(
"Determine the class name {:?} of the branch {:?}", class_name, branch->GetName()));
134 R3BLOG(warn, fmt::format(
"Cannot determine the class name of the branch {:?}", branch->GetName()));
135 return std::string{
"TObject" };
138 void add_branches_to_folder(TFolder* folder, TFile* root_file, std::string_view tree_name)
140 loop_through_branch_elements(root_file,
142 [folder](
auto* branch)
144 auto class_name = std::string_view{ branch->GetClassName() };
145 if (class_name ==
"TClonesArray")
147 const auto data_class = get_tca_data_class(branch);
148 auto tca_obj = std::make_unique<TClonesArray>(data_class.data());
149 tca_obj->SetName(branch->GetName());
150 folder->Add(tca_obj.release());
157 auto HasBranchList(TFile* rootFile,
const std::vector<std::string>& branchList) ->
bool
159 auto const newBranchList = GetBranchList(rootFile,
"BranchList");
160 auto view1 = std::vector<std::string_view>(branchList.begin(), branchList.end());
161 auto view2 = std::vector<std::string_view>(newBranchList.begin(), newBranchList.end());
163 std::sort(view1.begin(), view1.end());
164 std::sort(view2.begin(), view2.end());
165 return view1 == view2;
168 template <
typename ContainerType>
169 auto GetDataFromAnyFolder(TFile* rootFile,
const ContainerType& folderNames) -> std::optional<TKey*>
171 for (
auto const& name : folderNames)
173 R3BLOG(debug,
"looking for " + name);
174 auto* dataFolder =
dynamic_cast<TKey*
>(rootFile->FindKey(name.c_str()));
175 if (dataFolder !=
nullptr)
177 R3BLOG(debug, name +
" has been found!");
184 auto Get_TChain_FromFairRM(FairRootManager* rootMan) -> TChain*
186 auto const chainTitle =
"/" + std::string{ FairRootManager::GetFolderName() };
187 auto inChain = std::make_unique<TChain>(FairRootManager::GetTreeName(), chainTitle.c_str());
188 R3BLOG(debug,
"Chain created");
189 LOG(info) <<
"chain name: " << FairRootManager::GetTreeName();
190 rootMan->SetInChain(inChain.release());
191 return FairRootManager::Instance()->GetInChain();
199 throw R3B::logic_error(fmt::format(
"Refresh rate {} must be a positive floating point value", rate));
202 refresh_rate_ = rate;
203 refresh_period_ = std::chrono::milliseconds(
static_cast<int>(1000. / rate));
212 if (max_event_num_ == 0)
216 const auto now_t = std::chrono::steady_clock::now();
217 const auto time_spent = std::chrono::ceil<std::chrono::milliseconds>(now_t - previous_t_);
218 if (time_spent > refresh_period_)
220 const auto processed_events = event_num - previous_event_num_;
221 const auto events_per_millisecond =
222 static_cast<double>(processed_events) /
static_cast<double>(time_spent.count());
223 Print(event_num, events_per_millisecond);
226 previous_event_num_ = event_num;
230void R3BEventProgressPrinter::Print(uint64_t event_num,
double speed_per_ms)
232 if (speed_per_ms <= 0.)
236 const auto event_num_str =
237 fmt::format(fg(fmt::terminal_color::bright_green) | fmt::emphasis::bold,
"{:^5d}k", event_num / 1000);
238 const auto speed_str = fmt::format(fg(fmt::color::white),
"{:^6.1F}k/s", speed_per_ms);
239 const auto progress_str = fmt::format(fg(fmt::terminal_color::bright_yellow) | fmt::emphasis::bold,
241 100. *
static_cast<double>(event_num) /
static_cast<double>(max_event_num_));
242 const auto time_left_ms =
243 std::chrono::milliseconds{ (max_event_num_ - event_num) /
static_cast<int>(std::ceil(speed_per_ms)) };
244 fmt::print(
"Events processed: {0} ({1}) Progress: {2}% (time left: {3:%H h %M m %S s}) Run ID: {4}\r",
248 std::chrono::ceil<std::chrono::seconds>(time_left_ms),
250 std::cout << std::flush;
255 auto const msg = fmt::format(
"Adding {} to file source\n", fileName);
257 if (fileNames_.empty())
259 Intitialize(fileName, is_tree_file);
260 register_branch_name();
262 if (!ValidateFile(fileName, is_tree_file))
266 fileNames_.emplace_back(std::move(fileName));
270void R3BInputRootFiles::register_branch_name()
273 for (
auto const& branchName : branchList_)
275 FairRootManager::Instance()->AddBranchToList(branchName.c_str());
281 if (rootChain_ !=
nullptr)
286 for (
auto const& filename : fileNames_)
288 rootChain_->AddFile(filename.c_str(), TTree::kMaxEntries, treeName_.c_str());
298 if (validMainFolders_.empty())
305 auto listOfFolders = Vector2TContainer<TObjArray>(validMainFolders_);
306 R3BLOG(debug, fmt::format(
"Set {} main folder(s) to FairRootManager.", listOfFolders->GetEntries()));
307 rootMan->SetListOfFolders(listOfFolders.release());
308 rootMan->SetTimeBasedBranchNameList(Vector2TContainer<TList>(timeBasedBranchList_).release());
313auto R3BInputRootFiles::ExtractMainFolder(TFile* rootFile) -> std::optional<TKey*>
315 auto const folderNames =
316 std::array<std::string, 4>{ FairRootManager::GetFolderName(),
"r3broot",
"cbmout",
"cbmroot" };
318 return GetDataFromAnyFolder(rootFile, folderNames);
321auto R3BInputRootFiles::ValidateFile(
const std::string& filename,
bool is_tree_file) ->
bool
329 auto folder = std::make_unique<TFolder>(
"r3broot",
"r3broot");
330 add_branches_to_folder(folder.get(), rootFile.get(), treeName_);
331 validRootFiles_.push_back(std::move(rootFile));
332 validMainFolders_.push_back(folder.release());
337 auto folderKey = ExtractMainFolder(rootFile.get());
338 auto res1 = folderKey.has_value();
339 auto res2 = HasBranchList(rootFile.get(), branchList_);
342 if (!folderName_.empty() && (folderKey.value()->GetName() != folderName_))
344 R3BLOG(warn,
"Different folder name!");
348 validRootFiles_.push_back(std::move(rootFile));
349 validMainFolders_.push_back((folderKey.value())->ReadObject<TFolder>());
356 R3BLOG(warn,
"folder has no key");
360 R3BLOG(warn,
"HasBranchList is false!");
363 return res1 and res2;
366auto R3BInputRootFiles::ExtractRunId(TFile* rootFile) -> std::optional<uint>
369 auto* header = rootFile->Get<FairFileHeader>(fileHeader_.c_str());
370 if (header ==
nullptr)
374 auto runID = header->GetRunId();
378void R3BInputRootFiles::Intitialize(std::string_view filename,
bool is_tree_file)
384 branchList_ = GetBranchListFromTree(file.get(), treeName_);
388 if (
const auto runID = ExtractRunId(file.get()); runID.has_value() && runID.value() != 0)
390 auto const msg = fmt::format(R
"(Successfully extract RunID "{}" from root file "{}")", runID.value(), filename);
392 initial_RunID_ = runID.value();
396 auto const msg = fmt::format(
"Failed to extract RunID from root file \"{}\"", filename);
400 if (
auto folderKey = ExtractMainFolder(file.get()); folderKey.has_value())
402 folderName_ = folderKey.value()->GetName();
406 throw R3B::logic_error(fmt::format(
"Cannot find main folder from the root file {}!", filename));
409 branchList_ = GetBranchList(file.get(),
"BranchList");
411 if (timeBasedBranchList_ = GetBranchList<TObjString>(file.get(),
"TimeBasedBranchList");
412 timeBasedBranchList_.empty())
414 LOG(warn) <<
"No time based branch list in input file";
424 auto chain = std::make_unique<TChain>(friendFiles.
GetTitle().c_str(), friendFiles.
GetFolderName().c_str());
426 rootChain_->AddFriend(chain.release());
431 if (rootChain_ ==
nullptr)
435 return rootChain_->GetEntries();
440 LOG(debug) <<
"Creating a new R3BFileSource!";
441 inputDataFiles_.SetTitle(title);
442 inputDataFiles_.SetFileHeaderName(
"FileHeader");
443 for (
auto& name : fileNames)
454 :
R3BFileSource2(std::vector<std::string>{ std::move(file) }, title)
470 if (
auto const res = inputDataFiles_.AddFileName(std::move(file_name), is_tree_file); res.has_value())
472 if (not dataFileNames_.empty())
478 "Root file {0} is incompatible with the first root file {1}", res.value(), dataFileNames_.front()));
482 R3BLOG(error, fmt::format(
"Failed to add the first root file {:?}", file_name));
485 dataFileNames_.emplace_back(file_name);
490 for (
auto& file_name : file_names)
492 AddFile(std::move(file_name), is_tree_file);
498 for (
auto& file_name : file_names)
500 AddFriend(std::move(file_name), is_tree_file);
508 auto friendGroup = std::find_if(inputFriendFiles_.begin(),
509 inputFriendFiles_.end(),
510 [&rootfile](
const auto& friends)
511 { return HasBranchList(rootfile.get(), friends.GetBranchListRef()); });
512 if (friendGroup == inputFriendFiles_.end())
516 inputFriendFiles_.push_back(std::move(newFriendGroup));
517 friendGroup = --inputFriendFiles_.end();
518 friendGroup->SetTitle(fmt::format(
"FriendTree_{}", inputFriendFiles_.size()));
520 auto res = friendGroup->AddFileName(file_name, is_tree_file);
524 fmt::format(
"Friend file {0} is incompatible with the first friend file {1}",
526 friendGroup->GetBaseFileName()));
531 friendFileNames_.emplace_back(std::move(file_name));
537 if (inputDataFiles_.is_empty())
542 inputDataFiles_.RegisterTo(FairRootManager::Instance());
544 for (
auto& friendGroup : inputFriendFiles_)
546 inputDataFiles_.SetFriend(friendGroup);
549 event_progress_.SetMaxEventNum(inputDataFiles_.GetEntries());
550 event_progress_.SetRunID(inputDataFiles_.GetInitialRunID());
557 if (evtHeader ==
nullptr)
561 evtHeader_ = evtHeader;
564 auto const init_runID = inputDataFiles_.GetInitialRunID();
571 if (init_runID != GetRunId())
575 fmt::format(
"runID {} being set is different from the runID {} in the data file!", GetRunId(), init_runID));
577 SetRunId(init_runID);
578 evtHeader->SetRunId(init_runID);
583 event_end_ = (EvtEnd <= 0) ? inputDataFiles_.GetEntries() : EvtEnd;
584 R3BLOG(info, fmt::format(
"Setting printing event max to {}", event_end_));
585 event_progress_.SetMaxEventNum(event_end_);
591 auto const currentEventID = evtHeader_->GetMCEntryNumber();
597 auto const read_bytes = inputDataFiles_.GetChain()->FindBranch(BrName)->GetEntry(entryID);
600 LOG(warn) << fmt::format(
"Failed to read the data of the event {0} from the branch {1}", entryID, BrName);
606 auto* chain = inputDataFiles_.GetChain();
607 if (fair::Logger::GetConsoleSeverity() == fair::Severity::info)
609 event_progress_.ShowProgress(eventID);
612 auto read_bytes = chain->GetEntry(eventID);
615 LOG(warn) << fmt::format(
"Failed to read the data of the event {0} from the source", eventID);
623 auto* chain = inputDataFiles_.GetChain();
624 chain->SetBranchStatus(BrName,
true);
625 chain->SetBranchAddress(BrName, obj);
631 auto* chain = inputDataFiles_.GetChain();
632 if (chain !=
nullptr)
634 return ActivateObjectAnyImpl(chain, obj, info, BrName);
#define R3BLOG(severity, x)
void SetRefreshRate_Hz(float rate)
void ShowProgress(uint64_t event_num)
Int_t ReadEvent(UInt_t eventID=0) override
Bool_t ActivateObject(TObject **obj, const char *BrName) override
void ReadBranchEvent(const char *BrName) override
void AddFriend(std::string, bool is_tree_file=false)
Int_t CheckMaxEventNo(Int_t EvtEnd=0) override
Bool_t ActivateObjectAny(void **obj, const std::type_info &info, const char *BrName) override
void AddFile(std::string file_name, bool is_tree_file=false)
void FillEventHeader(FairEventHeader *evtHeader) override
auto make_rootfile(Args &&... args)