JAPAn
Just Another Parity Analyzer
Loading...
Searching...
No Matches
QwRootFile.h
Go to the documentation of this file.
1/*!
2 * \file QwRootFile.h
3 * \brief ROOT file and tree management wrapper classes
4 */
5
6#pragma once
7
8// System headers
9#include <algorithm>
10#include <cctype>
11#include <cstdint>
12#include <sstream>
13#include <stdexcept>
14#include <string>
15#include <typeindex>
16#include <unordered_map>
17#include <vector>
18#include <unistd.h>
19using std::type_info;
21// ROOT headers
22#include "TFile.h"
23#include "TTree.h"
24#include "TPRegexp.h"
25#include "TSystem.h"
26#include "TString.h"
27
28// RNTuple headers (modern ROOT namespace) - only if supported
29#ifdef HAS_RNTUPLE_SUPPORT
30#include "ROOT/RNTuple.hxx"
31#include "ROOT/RNTupleModel.hxx"
32#include "ROOT/RField.hxx"
33#include "ROOT/RNTupleWriter.hxx"
34#endif
35
36// Qweak headers
37#include "QwOptions.h"
38#include "TMapFile.h"
39
40// If one defines more than this number of words in the full ntuple,
41// the results are going to get very very crazy.
42#define BRANCH_VECTOR_MAX_SIZE 25000
43
44/**
45 * \class QwRootTreeBranchVector
46 * \ingroup QwAnalysis
47 * \brief A helper class to manage a vector of branch entries for ROOT trees
48 *
49 * This class provides functionality to manage a collection of branch entries,
50 * including their names, types, offsets, and sizes. It supports adding new entries,
51 * accessing entries by index or name, and generating leaf lists for ROOT trees.
52 */
54public:
55 struct Entry {
56 std::string name;
57 std::size_t offset;
58 std::size_t size;
59 char type;
60 };
61
62 using size_type = std::size_t;
63
65
66 void reserve(size_type count) {
67 m_entries.reserve(count);
68 m_buffer.reserve(sizeof(double)*count);
69 }
70
72 m_entries.shrink_to_fit();
73 m_buffer.shrink_to_fit();
74 }
75
76 void clear() {
77 m_entries.clear();
78 m_buffer.clear();
79 }
80
81 size_type size() const noexcept { return m_entries.size(); }
82 bool empty() const noexcept { return m_entries.empty(); }
83
84 template <typename T = uint8_t>
85 const T& operator[](size_type index) const {
86 return value<T>(index);
87 }
88
89 template <typename T = uint8_t>
91 return value<T>(index);
92 }
93
94 template <typename T>
95 T& value(size_type index) {
96 auto& entry = m_entries.at(index);
97 return *reinterpret_cast<T*>(m_buffer.data() + entry.offset);
98 }
99
100 template <typename T>
101 const T& value(size_type index) const {
102 const auto& entry = m_entries.at(index);
103 return *reinterpret_cast<const T*>(m_buffer.data() + entry.offset);
104 }
105
106 // Explicit SetValue overloads with type checking to prevent automatic conversions
107 // (presence of multiple overloads ensures a compilation error if the types do not match)
108 void SetValue(size_type index, Double_t val) {
109 const auto& entry = m_entries.at(index);
110 if (entry.type != 'D') {
111 throw std::invalid_argument("Type mismatch: entry type '" + std::string(1, entry.type) + "' cannot store double value '" + entry.name + "'");
112 }
113 this->value<Double_t>(index) = val;
114 }
115
116 void SetValue(size_type index, Float_t val) {
117 const auto& entry = m_entries.at(index);
118 if (entry.type != 'F') {
119 throw std::invalid_argument("Type mismatch: entry type '" + std::string(1, entry.type) + "' cannot store float value '" + entry.name + "'");
120 }
121 this->value<Float_t>(index) = val;
122 }
123
124 void SetValue(size_type index, Int_t val) {
125 const auto& entry = m_entries.at(index);
126 if (entry.type != 'I') {
127 throw std::invalid_argument("Type mismatch: entry type '" + std::string(1, entry.type) + "' cannot store int value '" + entry.name + "'");
128 }
129 this->value<Int_t>(index) = val;
130 }
131
132 void SetValue(size_type index, Long64_t val) {
133 const auto& entry = m_entries.at(index);
134 if (entry.type != 'L') {
135 throw std::invalid_argument("Type mismatch: entry type '" + std::string(1, entry.type) + "' cannot store long long value '" + entry.name + "'");
136 }
137 this->value<Long64_t>(index) = val;
138 }
139
140 void SetValue(size_type index, Short_t val) {
141 const auto& entry = m_entries.at(index);
142 if (entry.type != 'S') {
143 throw std::invalid_argument("Type mismatch: entry type '" + std::string(1, entry.type) + "' cannot store short value '" + entry.name + "'");
144 }
145 this->value<Short_t>(index) = val;
146 }
147
148 // Unsigned type overloads
149 void SetValue(size_type index, UShort_t val) {
150 const auto& entry = m_entries.at(index);
151 if (entry.type != 's') {
152 throw std::invalid_argument("Type mismatch: entry type '" + std::string(1, entry.type) + "' cannot store short value '" + entry.name + "'");
153 }
154 this->value<UShort_t>(index) = val;
155 }
156
157 void SetValue(size_type index, UInt_t val) {
158 const auto& entry = m_entries.at(index);
159 if (entry.type != 'i') {
160 throw std::invalid_argument("Type mismatch: entry type '" + std::string(1, entry.type) + "' cannot store unsigned int value '" + entry.name + "'");
161 }
162 this->value<UInt_t>(index) = val;
163 }
164
165 void SetValue(size_type index, ULong64_t val) {
166 const auto& entry = m_entries.at(index);
167 if (entry.type != 'l') {
168 throw std::invalid_argument("Type mismatch: entry type '" + std::string(1, entry.type) + "' cannot store long long value '" + entry.name + "'");
169 }
170 this->value<ULong64_t>(index) = val;
171 }
172
173 void* data() noexcept { return m_buffer.data(); }
174 const void* data() const noexcept { return m_buffer.data(); }
175 size_type data_size() const noexcept { return m_buffer.size(); }
176
177 template <typename T>
178 T& back() {
179 if (m_entries.empty()) {
180 throw std::out_of_range("QwRootTreeBranchVector::back() called on empty container");
181 }
182 const auto& last_entry = m_entries.back();
183 return *reinterpret_cast<T*>(m_buffer.data() + last_entry.offset);
184 }
185
186 template <typename T>
187 const T& back() const {
188 if (m_entries.empty()) {
189 throw std::out_of_range("QwRootTreeBranchVector::back() called on empty container");
190 }
191 const auto& last_entry = m_entries.back();
192 return *reinterpret_cast<const T*>(m_buffer.data() + last_entry.offset);
193 }
194
195 void push_back(const std::string& name, const char type = 'D') {
196 const std::size_t entry_size = GetTypeSize(type);
197 const std::size_t offset = AlignOffset(m_buffer.size());
198
199 if (offset > m_buffer.capacity()) {
200 throw std::out_of_range("QwRootTreeBranchVector::push_back() requires buffer resize beyond reserved capacity");
201 }
202 if (offset > m_buffer.size()) {
203 m_buffer.resize(offset, 0u);
204 }
205
206 Entry entry{name, offset, entry_size, type};
207 m_entries.push_back(entry);
208
209 const std::size_t required = offset + entry_size;
210 if (required > m_buffer.capacity()) {
211 throw std::out_of_range("QwRootTreeBranchVector::push_back() requires buffer resize beyond reserved capacity");
212 }
213 if (required > m_buffer.size()) {
214 m_buffer.resize(required, 0u);
215 }
216 }
217
218 // Overload for TString (ROOT's string class)
219 void push_back(const TString& name, const char type = 'D') {
220 push_back(std::string(name.Data()), type);
221 }
222
223 // Overload for const char* (string literals)
224 void push_back(const char* name, const char type = 'D') {
225 push_back(std::string(name), type);
226 }
227
228 std::string LeafList(size_type start_index = 0) const {
229 static const std::string separator = ":";
230 std::ostringstream stream;
231 bool first = true;
232 for (size_type index = start_index; index < m_entries.size(); ++index) {
233 const auto& entry = m_entries[index];
234 if (!first) {
235 stream << separator;
236 }
237 stream << entry.name << "/" << entry.type;
238 first = false;
239 }
240 return stream.str();
241 }
242
243 std::string Dump(size_type start_index = 0, size_type end_index = 0) const {
244 std::ostringstream stream;
245 stream << "QwRootTreeBranchVector: " << m_entries.size() << " entries, "
246 << m_buffer.size() << " bytes\n";
247 size_t end_offset = (end_index == 0 || end_index > m_entries.size()) ?
248 m_buffer.size()
249 : m_entries[end_index - 1].offset + m_entries[end_index - 1].size;
250 stream << "QwRootTreeBranchVector: buffer at 0x" << std::hex << (void*) &m_buffer[0] << '\n';
251 stream << "QwRootTreeBranchVector: entries at 0x" << std::hex << (void*) &m_entries[0] << '\n';
252 for (size_t offset = m_entries[start_index].offset; offset < end_offset; offset += 4) {
253 stream << std::dec
254 << " [" << offset << "] "
255 << std::hex
256 << " offset=0x" << offset
257 << " (0x" << std::setw(4) << std::setfill('0')
258 << offset - m_entries[start_index].offset << ")"
259 << " buff=";
260 // Little-endian
261 for (std::size_t byte = 0; byte < 4; ++byte) {
262 stream << std::hex << std::setw(2) << std::setfill('0')
263 << static_cast<unsigned int>(m_buffer[offset + byte])
264 << " ";
265 }
266 stream << '\n';
267 }
268 end_index = (end_index == 0 || end_index > m_entries.size()) ?
269 m_entries.size()
270 : end_index;
271 for (size_type index = start_index; index < end_index; ++index) {
272 const auto& entry = m_entries[index];
273 stream << std::dec
274 << " [" << index << "] "
275 << std::hex
276 << " offset=0x" << entry.offset
277 << " (0x" << std::setw(4) << std::setfill('0')
278 << entry.offset - m_entries[start_index].offset << ")"
279 << " size=0x" << entry.size
280 << " buff=0x";
281 // Little-endian
282 for (std::size_t byte = GetTypeSize(entry.type); byte > 0; --byte) {
283 stream << std::hex << std::setw(2) << std::setfill('0')
284 << static_cast<unsigned int>((m_buffer.data() + entry.offset)[byte - 1]);
285 }
286 stream << std::dec
287 << " name=" << entry.name << "/" << entry.type
288 << " value=" << FormatValue(entry, index);
289 stream << '\n';
290 }
291 return stream.str();
292 }
293
294private:
295 static std::size_t GetTypeSize(char type) {
296 switch (type) {
297 case 'D':
298 return sizeof(double);
299 case 'F':
300 return sizeof(float);
301 case 'L':
302 return sizeof(long long);
303 case 'l':
304 return sizeof(unsigned long long);
305 case 'I':
306 return sizeof(int);
307 case 'i':
308 return sizeof(unsigned int);
309 case 'S':
310 return sizeof(short);
311 case 's':
312 return sizeof(unsigned short);
313 default:
314 throw std::invalid_argument("Unsupported branch type code: " + std::string(1, type));
315 }
316 }
317
318 static std::size_t AlignOffset(std::size_t offset) {
319 const std::size_t alignment = 4u;
320 return (offset + (alignment - 1u)) & ~(alignment - 1u);
321 }
322
323 std::vector<Entry> m_entries;
324 std::vector<std::uint8_t> m_buffer;
325
326 std::string FormatValue(const Entry& entry, size_type index) const {
327 switch (entry.type) {
328 case 'D':
329 return FormatNumeric(value<double>(index));
330 case 'F':
331 return FormatNumeric(value<float>(index));
332 case 'L':
333 return FormatNumeric(value<long long>(index));
334 case 'l':
336 case 'I':
337 return FormatNumeric(value<int>(index));
338 case 'i':
339 return FormatNumeric(value<unsigned int>(index));
340 case 'S':
341 return FormatNumeric(value<short>(index));
342 case 's':
344 default:
345 return "<unknown>";
346 }
347 }
348
349 template <typename T>
350 static std::string FormatNumeric(T input) {
351 std::ostringstream stream;
352 stream << input;
353 return stream.str();
354 }
355};
356
357/**
358 * \class QwRootTree
359 * \ingroup QwAnalysis
360 * \brief Wrapper class for ROOT tree management with vector-based data storage
361 *
362 * Provides functionality to write to ROOT trees using vectors of doubles,
363 * with support for branch construction, event filtering, and tree sharing.
364 * Handles both new tree creation and attachment to existing trees, enabling
365 * multiple subsystems to contribute data to a single ROOT tree.
366 */
368
369 public:
370
371 /// Constructor with name, and description
372 QwRootTree(const std::string& name, const std::string& desc, const std::string& prefix = "")
373 : fName(name),fDesc(desc),fPrefix(prefix),fType("type undefined"),
375 // Construct tree
377 }
378
379 /// Constructor with existing tree
380 QwRootTree(const QwRootTree* tree, const std::string& prefix = "")
381 : fName(tree->GetName()),fDesc(tree->GetDesc()),fPrefix(prefix),fType("type undefined"),
383 QwMessage << "Existing tree: " << tree->GetName() << ", " << tree->GetDesc() << QwLog::endl;
384 fTree = tree->fTree;
385 }
386
387 /// Constructor with name, description, and object
388 template < class T >
389 QwRootTree(const std::string& name, const std::string& desc, T& object, const std::string& prefix = "")
390 : fName(name),fDesc(desc),fPrefix(prefix),fType("type undefined"),
392 // Construct tree
394
395 // Construct branch
397
398 // Construct branches and vector
400 }
401
402 /// Constructor with existing tree, and object
403 template < class T >
404 QwRootTree(const QwRootTree* tree, T& object, const std::string& prefix = "")
405 : fName(tree->GetName()),fDesc(tree->GetDesc()),fPrefix(prefix),fType("type undefined"),
407 QwMessage << "Existing tree: " << tree->GetName() << ", " << tree->GetDesc() << QwLog::endl;
408 fTree = tree->fTree;
409
410 // Construct branches and vector
412 }
413
414 /// Destructor
415 virtual ~QwRootTree() { }
416
417
418 private:
419
420 static const TString kUnitsName;
421 static Double_t kUnitsValue[];
422
423 /// Construct the tree
425 QwMessage << "New tree: " << fName << ", " << fDesc << QwLog::endl;
426
427 fTree = new TTree(fName.c_str(), fDesc.c_str());
428
429 // Ensure tree is in the current directory
430 if (gDirectory) {
431 fTree->SetDirectory(gDirectory);
432
433 } else {
434
435 }
436 }
437
439 std::string name = "units";
440 fTree->Branch(name.c_str(), &kUnitsValue, kUnitsName);
441 }
442
443 /// Construct index from this tree to another tree
445 std::string name = "previous_entry_in_" + to->fName;
446 fTree->Branch(name.c_str(), &(to->fCurrentEvent));
447 }
448
449 /// Construct the branches and vector for generic objects
450 template < class T >
451 void ConstructBranchAndVector(T& object) {
452 // Reserve space for the branch vector
454 // Associate branches with vector
455 TString prefix = Form("%s",fPrefix.c_str());
456 object.ConstructBranchAndVector(fTree, prefix, fVector);
457
458 // Store the type of object
459 fType = typeid(object).name();
460
461 // Check memory reservation
462 if (fVector.size() > BRANCH_VECTOR_MAX_SIZE) {
463 QwError << "The branch vector is too large: " << fVector.size() << " leaves! "
464 << "The maximum size is " << BRANCH_VECTOR_MAX_SIZE << "."
465 << QwLog::endl;
466 exit(-1);
467 }
468 }
469
470
471 public:
472
473 /// Fill the branches for generic objects
474 template < class T >
475 void FillTreeBranches(const T& object) {
476 if (typeid(object).name() == fType) {
477 // Fill the branch vector
478 object.FillTreeVector(fVector);
479 } else {
480 QwError << "Attempting to fill tree vector for type " << fType << " with "
481 << "object of type " << typeid(object).name() << QwLog::endl;
482 exit(-1);
483 }
484 }
485
486 Long64_t AutoSave(Option_t *option){
487 return fTree->AutoSave(option);
488 }
489
490 /// Fill the tree
491 Int_t Fill() {
493
494 // Tree prescaling
495 if (fNumEventsCycle > 0) {
498 return 0;
499 }
500
501 // Fill the tree
502 Int_t retval = fTree->Fill();
503 // Check for errors
504 if (retval < 0) {
505 QwError << "Writing tree failed! Check disk space or quota." << QwLog::endl;
506 exit(retval);
507 }
508 return retval;
509 }
510
511
512 /// Print the tree name and description
513 void Print() const {
514 QwMessage << GetName() << ", " << GetType();
515 if (fPrefix != "")
516 QwMessage << " (prefix " << GetPrefix() << ")";
518 }
519
520 /// Get the tree pointer for low level operations
521 TTree* GetTree() const { return fTree; };
522
523
524 friend class QwRootFile;
525
526 private:
527
528 /// Tree pointer
529 TTree* fTree;
530 /// Vector of leaves
532
533
534 /// Name, description
535 const std::string fName;
536 const std::string fDesc;
537 const std::string fPrefix;
538
539 /// Get the name of the tree
540 const std::string& GetName() const { return fName; };
541 /// Get the description of the tree
542 const std::string& GetDesc() const { return fDesc; };
543 /// Get the description of the tree
544 const std::string& GetPrefix() const { return fPrefix; };
545
546
547 /// Object type
548 std::string fType;
549
550 /// Get the object type
551 std::string GetType() const { return fType; };
552
553
554 /// Tree prescaling parameters
559
560 /// Set tree prescaling parameters
561 void SetPrescaling(UInt_t num_to_save, UInt_t num_to_skip) {
562 fNumEventsToSave = num_to_save;
563 fNumEventsToSkip = num_to_skip;
565 }
566
567
568 /// Maximum tree size, autoflush and autosave
569 Long64_t fMaxTreeSize;
570 Long64_t fAutoFlush;
571 Long64_t fAutoSave;
573
574 /// Set maximum tree size
575 void SetMaxTreeSize(Long64_t maxsize = 1900000000) {
576 fMaxTreeSize = maxsize;
577 if (fTree) fTree->SetMaxTreeSize(maxsize);
578 }
579
580 /// Set autoflush size
581 void SetAutoFlush(Long64_t autoflush = 30000000) {
582 fAutoFlush = autoflush;
583 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,26,00)
584 if (fTree) fTree->SetAutoFlush(autoflush);
585 #endif
586 }
587
588 /// Set autosave size
589 void SetAutoSave(Long64_t autosave = 300000000) {
590 fAutoSave = autosave;
591 if (fTree) fTree->SetAutoSave(autosave);
592 }
593
594 /// Set basket size
595 void SetBasketSize(Int_t basketsize = 16000) {
596 fBasketSize = basketsize;
597 if (fTree) fTree->SetBasketSize("*",basketsize);
598 }
599
600 //Set circular buffer size for the memory resident tree
601 void SetCircular(Long64_t buff = 100000) {
602 if (fTree) fTree->SetCircular(buff);
603 }
604};
605
606#ifdef HAS_RNTUPLE_SUPPORT
607/**
608 * \class QwRootNTuple
609 * \ingroup QwAnalysis
610 * \brief A wrapper class for a ROOT RNTuple
611 *
612 * This class provides the functionality to write to ROOT RNTuples using a vector
613 * of doubles, similar to QwRootTree but using the newer RNTuple format.
614 */
615class QwRootNTuple {
616
617 public:
618
619 /// Constructor with name and description
620 QwRootNTuple(const std::string& name, const std::string& desc, const std::string& prefix = "")
621 : fName(name), fDesc(desc), fPrefix(prefix), fType("type undefined"),
622 fCurrentEvent(0), fNumEventsCycle(0), fNumEventsToSave(0), fNumEventsToSkip(0) {
623 // Create RNTuple model
624 fModel = ROOT::RNTupleModel::Create();
625 }
626
627 /// Constructor with name, description, and object
628 template < class T >
629 QwRootNTuple(const std::string& name, const std::string& desc, T& object, const std::string& prefix = "")
630 : fName(name), fDesc(desc), fPrefix(prefix), fType("type undefined"),
631 fCurrentEvent(0), fNumEventsCycle(0), fNumEventsToSave(0), fNumEventsToSkip(0) {
632 // Create RNTuple model
633 fModel = ROOT::RNTupleModel::Create();
634
635 // Construct fields and vector
636 ConstructFieldsAndVector(object);
637 }
638
639 /// Destructor
640 virtual ~QwRootNTuple() {
641 Close();
642 }
643
644 /// Close and finalize the RNTuple writer
645 void Close() {
646 if (fWriter) {
647 // Explicitly commit any remaining data and close the writer
648 // This ensures all data is written to the file before destruction
649 fWriter.reset(); // This calls the destructor which should finalize the RNTuple
650 }
651 }
652
653 private:
654
655 /// Construct the fields and vector for generic objects
656 template < class T >
657 void ConstructFieldsAndVector(T& object) {
658 // Reserve space for the field vector
659 fVector.reserve(BRANCH_VECTOR_MAX_SIZE);
660
661 // Associate fields with vector - now using shared field pointers
662 TString prefix = Form("%s", fPrefix.c_str());
663 object.ConstructNTupleAndVector(fModel, prefix, fVector, fFieldPtrs);
664
665 // Store the type of object
666 fType = typeid(object).name();
667
668 // Check memory reservation
669 if (fVector.size() > BRANCH_VECTOR_MAX_SIZE) {
670 QwError << "The field vector is too large: " << fVector.size() << " fields! "
671 << "The maximum size is " << BRANCH_VECTOR_MAX_SIZE << "."
672 << QwLog::endl;
673 exit(-1);
674 }
675
676 // Shrink memory reservation
677 fVector.shrink_to_fit();
678 }
679
680 public:
681
682 /// Initialize the RNTuple writer with a file
683 void InitializeWriter(TFile* file) {
684 if (!fModel) {
685 QwError << "RNTuple model not created for " << fName << QwLog::endl;
686 return;
687 }
688
689 // Before creating the writer, ensure all fields are added to the model
690 if (fVector.empty()) {
691 QwError << "No fields defined in RNTuple model for " << fName << QwLog::endl;
692 return;
693 }
694
695 try {
696 // Create the writer with the model (transfers ownership)
697 // Use Append to add RNTuple to existing TFile
698 fWriter = ROOT::RNTupleWriter::Append(std::move(fModel), fName, *file);
699
700 QwMessage << "Created RNTuple '" << fName << "' in file " << file->GetName() << QwLog::endl;
701
702 } catch (const std::exception& e) {
703 QwError << "Failed to create RNTuple writer for '" << fName << "': " << e.what() << QwLog::endl;
704 }
705 }
706
707 /// Fill the fields for generic objects
708 template < class T >
709 void FillNTupleFields(const T& object) {
710 if (typeid(object).name() == fType) {
711 // Fill the field vector
712 object.FillNTupleVector(fVector);
713
714 // Use the shared field pointers which remain valid
715 if (fWriter) {
716 for (size_t i = 0; i < fVector.size() && i < fFieldPtrs.size(); ++i) {
717 if (fFieldPtrs[i]) {
718 *(fFieldPtrs[i]) = fVector[i];
719 }
720 }
721
722 // CRITICAL: Actually commit the data to the RNTuple
723 fWriter->Fill();
724
725 // Update event counter
726 fCurrentEvent++;
727 // RNTuple prescaling
728 if (fNumEventsCycle > 0) {
729 fCurrentEvent %= fNumEventsCycle;
730 }
731 } else {
732 QwError << "RNTuple writer not initialized for " << fName << QwLog::endl;
733 }
734 } else {
735 QwError << "Attempting to fill RNTuple vector for type " << fType << " with "
736 << "object of type " << typeid(object).name() << QwLog::endl;
737 exit(-1);
738 }
739 }
740
741 /// Fill the RNTuple (called by FillTree wrapper methods)
742 void Fill() {
743 // This method is now called indirectly - the actual filling happens in FillNTupleFields
744 // Just here for compatibility with the tree interface
745 }
746
747 /// Get the name of the RNTuple
748 const std::string& GetName() const { return fName; }
749 /// Get the description of the RNTuple
750 const std::string& GetDesc() const { return fDesc; }
751 /// Get the prefix of the RNTuple
752 const std::string& GetPrefix() const { return fPrefix; }
753 /// Get the object type
754 std::string GetType() const { return fType; }
755
756 /// Set prescaling parameters
757 void SetPrescaling(UInt_t num_to_save, UInt_t num_to_skip) {
758 fNumEventsToSave = num_to_save;
759 fNumEventsToSkip = num_to_skip;
760 fNumEventsCycle = fNumEventsToSave + fNumEventsToSkip;
761 }
762
763 /// Print the RNTuple name and description
764 void Print() const {
765 QwMessage << GetName() << ", " << GetType();
766 if (fPrefix != "")
767 QwMessage << " (prefix " << GetPrefix() << ")";
769 }
770
771 private:
772
773 /// RNTuple model and writer
774 std::unique_ptr<ROOT::RNTupleModel> fModel;
775 std::unique_ptr<ROOT::RNTupleWriter> fWriter;
776
777 /// Vector of values and shared field pointers (for RNTuple)
778 std::vector<Double_t> fVector;
779 std::vector<std::shared_ptr<Double_t>> fFieldPtrs;
780
781 /// Name, description, prefix
782 const std::string fName;
783 const std::string fDesc;
784 const std::string fPrefix;
785
786 /// Object type
787 std::string fType;
788
789 /// RNTuple prescaling parameters
790 UInt_t fCurrentEvent;
791 UInt_t fNumEventsCycle;
792 UInt_t fNumEventsToSave;
793 UInt_t fNumEventsToSkip;
794
795 friend class QwRootFile;
796};
797#endif // HAS_RNTUPLE_SUPPORT
798
799/**
800 * \class QwRootFile
801 * \ingroup QwAnalysis
802 * \brief A wrapper class for a ROOT file or memory mapped file
803 *
804 * This class functions as a wrapper around a ROOT TFile or a TMapFile. The
805 * common inheritance of both is only TObject, so there is a lot that we have
806 * to wrap (rather than inherit). Theoretically you could have both a TFile
807 * and a TMapFile represented by an object of this class at the same time, but
808 * that is untested.
809 *
810 * The functionality of writing to the file is done by templated functions.
811 * The objects that are passed to these functions have to provide the following
812 * functions:
813 * <ul>
814 * <li>ConstructHistograms, FillHistograms
815 * <li>ConstructBranchAndVector, FillTreeVector
816 * </ul>
817 *
818 * The class keeps track of the registered tree names, and the types of objects
819 * that have branches constructed in those trees (via QwRootTree). In most
820 * cases it should be possible to just call FillTreeBranches with only the object,
821 * although in rare cases this could be ambiguous.
822 *
823 * The proper way to register a tree is by either calling ConstructTreeBranches
824 * of NewTree first. Then FillTreeBranches will fill the vector, and FillTree
825 * will actually fill the tree. FillTree should be called only once.
826 */
828
829 public:
830
831 /// \brief Constructor with run label
832 QwRootFile(const TString& run_label);
833 /// \brief Destructor
834 virtual ~QwRootFile();
835
836
837 /// \brief Define the configuration options
838 static void DefineOptions(QwOptions &options);
839 /// \brief Process the configuration options
840 void ProcessOptions(QwOptions &options);
841 /// \brief Set default ROOT files dir
842 static void SetDefaultRootFileDir(const std::string& dir) {
844 }
845 /// \brief Set default ROOT file stem
846 static void SetDefaultRootFileStem(const std::string& stem) {
848 }
849
850
851 /// Is the ROOT file active?
852 Bool_t IsRootFile() const { return (fRootFile); };
853 /// Is the map file active?
854 Bool_t IsMapFile() const { return (fMapFile); };
855
856 /// \brief Construct indices from one tree to another tree
857 void ConstructIndices(const std::string& from, const std::string& to, bool reverse = true);
858
859 /// \brief Construct the tree branches of a generic object
860 template < class T >
861 void ConstructTreeBranches(const std::string& name, const std::string& desc, T& object, const std::string& prefix = "");
862 /// \brief Fill the tree branches of a generic object by tree name
863 template < class T >
864 void FillTreeBranches(const std::string& name, const T& object);
865 /// \brief Fill the tree branches of a generic object by type only
866 template < class T >
867 void FillTreeBranches(const T& object);
868
869#ifdef HAS_RNTUPLE_SUPPORT
870 /// \brief Construct the RNTuple fields of a generic object
871 template < class T >
872 void ConstructNTupleFields(const std::string& name, const std::string& desc, T& object, const std::string& prefix = "");
873 /// \brief Fill the RNTuple fields of a generic object by name
874 template < class T >
875 void FillNTupleFields(const std::string& name, const T& object);
876 /// \brief Fill the RNTuple fields of a generic object by type only
877 template < class T >
878 void FillNTupleFields(const T& object);
879#endif // HAS_RNTUPLE_SUPPORT
880
881
882 template < class T >
883 Int_t WriteParamFileList(const TString& name, T& object);
884
885
886 /// \brief Construct the histograms of a generic object
887 template < class T >
888 void ConstructObjects(const std::string& name, T& object);
889
890 /// \brief Construct the histograms of a generic object
891 template < class T >
892 void ConstructHistograms(const std::string& name, T& object);
893 /// Fill histograms of the subsystem array
894 template < class T >
895 void FillHistograms(T& object) {
896 // Update regularly
897 static Int_t update_count = 0;
898 update_count++;
899 if ((fUpdateInterval > 0) && ( update_count % fUpdateInterval == 0)) Update();
900
901 // Debug directory registration
902 std::string type = typeid(object).name();
903 bool hasDir = HasDirByType(object);
904
905 if (! hasDir) return;
906 // Fill histograms
907 object.FillHistograms();
908 }
909
910
911 /// Create a new tree with name and description
912 void NewTree(const std::string& name, const std::string& desc) {
913 if (IsTreeDisabled(name)) return;
914 this->cd();
915 QwRootTree *tree = 0;
916 if (! HasTreeByName(name)) {
917 tree = new QwRootTree(name,desc);
918 } else {
919 tree = new QwRootTree(fTreeByName[name].front());
920 }
921 fTreeByName[name].push_back(tree);
922 }
923
924#ifdef HAS_RNTUPLE_SUPPORT
925 /// Create a new RNTuple with name and description
926 void NewNTuple(const std::string& name, const std::string& desc) {
927 if (IsTreeDisabled(name) || !fEnableRNTuples) return;
928 QwRootNTuple *ntuple = 0;
929 if (! HasNTupleByName(name)) {
930 ntuple = new QwRootNTuple(name, desc);
931 // Initialize the writer with our file
932 ntuple->InitializeWriter(fRootFile);
933 } else {
934 // For simplicity, don't support copying existing RNTuples yet
935 QwError << "Cannot create duplicate RNTuple: " << name << QwLog::endl;
936 return;
937 }
938 fNTupleByName[name].push_back(ntuple);
939 }
940#endif // HAS_RNTUPLE_SUPPORT
941
942 /// Get the tree with name
943 TTree* GetTree(const std::string& name) {
944 if (! HasTreeByName(name)) return 0;
945 else return fTreeByName[name].front()->GetTree();
946 }
947
948 /// Fill the tree with name
949 Int_t FillTree(const std::string& name) {
950 if (! HasTreeByName(name)) return 0;
951 else return fTreeByName[name].front()->Fill();
952 }
953
954 /// Fill all registered trees
955 Int_t FillTrees() {
956 // Loop over all registered tree names
957 Int_t retval = 0;
958 std::map< const std::string, std::vector<QwRootTree*> >::iterator iter;
959 for (iter = fTreeByName.begin(); iter != fTreeByName.end(); iter++) {
960 retval += iter->second.front()->Fill();
961 }
962 return retval;
963 }
964
965#ifdef HAS_RNTUPLE_SUPPORT
966 /// Fill the RNTuple with name
967 void FillNTuple(const std::string& name) {
968 if (HasNTupleByName(name)) {
969 fNTupleByName[name].front()->Fill();
970 }
971 }
972#endif // HAS_RNTUPLE_SUPPORT
973
974#ifdef HAS_RNTUPLE_SUPPORT
975 /// Fill all registered RNTuples
976 void FillNTuples() {
977 // Loop over all registered RNTuple names
978 std::map< const std::string, std::vector<QwRootNTuple*> >::iterator iter;
979 for (iter = fNTupleByName.begin(); iter != fNTupleByName.end(); iter++) {
980 iter->second.front()->Fill();
981 }
982 }
983#endif // HAS_RNTUPLE_SUPPORT
984
985 /// Print registered trees
986 void PrintTrees() const {
987 QwMessage << "Trees: " << QwLog::endl;
988 // Loop over all registered tree names
989 std::map< const std::string, std::vector<QwRootTree*> >::const_iterator iter;
990 for (iter = fTreeByName.begin(); iter != fTreeByName.end(); iter++) {
991 QwMessage << iter->first << ": " << iter->second.size()
992 << " objects registered" << QwLog::endl;
993 // Loop over all registered objects for this tree
994 std::vector<QwRootTree*>::const_iterator tree;
995 for (tree = iter->second.begin(); tree != iter->second.end(); tree++) {
996 (*tree)->Print();
997 }
998 }
999 }
1000 /// Print registered histogram directories
1001 void PrintDirs() const {
1002 QwMessage << "Dirs: " << QwLog::endl;
1003 // Loop ove rall registered directories
1004 std::map< const std::string, TDirectory* >::const_iterator iter;
1005 for (iter = fDirsByName.begin(); iter != fDirsByName.end(); iter++) {
1006 QwMessage << iter->first << QwLog::endl;
1007 }
1008 }
1009
1010
1011 /// Write any object to the ROOT file (only valid for TFile)
1012 template < class T >
1013 Int_t WriteObject(const T* obj, const char* name, Option_t* option = "", Int_t bufsize = 0) {
1014 Int_t retval = 0;
1015 // TMapFile has no support for WriteObject
1016 if (fRootFile) retval = fRootFile->WriteObject(obj,name,option,bufsize);
1017 return retval;
1018 }
1019
1020
1021 // Wrapped functionality
1022 void Update() {
1023 if (fMapFile) {
1024 QwMessage << "TMapFile memory resident size: "
1025 << ((int*)fMapFile->GetBreakval() - (int*)fMapFile->GetBaseAddr()) *
1026 4 / sizeof(int32_t) / 1024 / 1024 << " MiB"
1027 << QwLog::endl;
1028 fMapFile->Update();
1029 }else{
1030 // this option will allow for reading the tree during write
1031 Long64_t nBytes(0);
1032 for (auto iter = fTreeByName.begin(); iter != fTreeByName.end(); iter++)
1033 nBytes += iter->second.front()->AutoSave("SaveSelf");
1034
1035 QwMessage << "TFile saved: "
1036 << nBytes/1000000 << "MB (inaccurate number)" //FIXME this calculation is inaccurate
1037 << QwLog::endl;
1038 }
1039 }
1040 void Print() { if (fMapFile) fMapFile->Print(); if (fRootFile) fRootFile->Print(); }
1041 void ls() { if (fMapFile) fMapFile->ls(); if (fRootFile) fRootFile->ls(); }
1042 void Map() { if (fRootFile) fRootFile->Map(); }
1043 void Close() {
1044
1045 // Check if we should make the file permanent - restore original logic
1047
1048
1049#ifdef HAS_RNTUPLE_SUPPORT
1050 // Close all RNTuples before closing the file
1051 for (auto& pair : fNTupleByName) {
1052 for (auto& ntuple : pair.second) {
1053 if (ntuple) ntuple->Close();
1054 }
1055 }
1056#endif // HAS_RNTUPLE_SUPPORT
1057
1058 // CRITICAL FIX: Explicitly write all trees before closing!
1059 if (fRootFile) {
1060
1061 for (auto iter = fTreeByName.begin(); iter != fTreeByName.end(); iter++) {
1062 if (!iter->second.empty() && iter->second.front()) {
1063 TTree* tree = iter->second.front()->GetTree();
1064 if (tree && tree->GetEntries() > 0) {
1065
1066 tree->Write();
1067 }
1068 }
1069 }
1070 }
1071
1072 // Close the file and handle renaming
1073 if (fRootFile) {
1074 TString rootfilename = fRootFile->GetName();
1075
1076 fRootFile->Close();
1077
1078 }
1079
1080 if (fMapFile) fMapFile->Close();
1081
1082
1083 }
1084
1085 // Wrapped functionality
1086 Bool_t cd(const char* path = 0) {
1087 Bool_t status = kTRUE;
1088 if (fMapFile) status &= fMapFile->cd(path);
1089 if (fRootFile) status &= fRootFile->cd(path);
1090 return status;
1091 }
1092
1093 // Wrapped functionality
1094 TDirectory* mkdir(const char* name, const char* title = "") {
1095 // TMapFile has no support for mkdir
1096 if (fRootFile) return fRootFile->mkdir(name, title);
1097 else return 0;
1098 }
1099
1100 // Wrapped functionality
1101 Int_t Write(const char* name = 0, Int_t option = 0, Int_t bufsize = 0) {
1102 Int_t retval = 0;
1103 // TMapFile has no support for Write
1104 if (fRootFile) retval = fRootFile->Write(name, option, bufsize);
1105 return retval;
1106 }
1107
1108
1109 private:
1110
1111 /// Private default constructor
1113
1114
1115 /// ROOT file
1117
1118 /// ROOT files dir
1120 /// Default ROOT files dir
1121 static std::string fDefaultRootFileDir;
1122
1123 /// ROOT file stem
1125 /// Default ROOT file stem
1126 static std::string fDefaultRootFileStem;
1127
1128 /// While the file is open, give it a temporary filename. Perhaps
1129 /// change to a permanent name when closing the file.
1133
1134 /// Search for non-empty trees or histograms in the file
1135 Bool_t HasAnyFilled(void);
1136 Bool_t HasAnyFilled(TDirectory* d);
1137
1138 /// Map file
1139 TMapFile* fMapFile;
1147
1148
1149
1150 private:
1151
1152 /// List of excluded trees
1153 std::vector< TPRegexp > fDisabledTrees;
1154 std::vector< TPRegexp > fDisabledHistos;
1155
1156 /// Add regexp to list of disabled trees names
1157 void DisableTree(const TString& regexp) {
1158 fDisabledTrees.push_back(regexp);
1159 }
1160 /// Does this tree name match a disabled tree name?
1161 bool IsTreeDisabled(const std::string& name) {
1162 for (size_t i = 0; i < fDisabledTrees.size(); i++)
1163 if (fDisabledTrees.at(i).Match(name)) return true;
1164 return false;
1165 }
1166 /// Add regexp to list of disabled histogram directories
1167 void DisableHisto(const TString& regexp) {
1168 fDisabledHistos.push_back(regexp);
1169 }
1170 /// Does this histogram directory match a disabled histogram directory?
1171 bool IsHistoDisabled(const std::string& name) {
1172 for (size_t i = 0; i < fDisabledHistos.size(); i++)
1173 if (fDisabledHistos.at(i).Match(name)) return true;
1174 return false;
1175 }
1176
1177
1178 private:
1179
1180 /// Tree names, addresses, and types
1181 std::map< const std::string, std::vector<QwRootTree*> > fTreeByName;
1182 std::map< const void* , std::vector<QwRootTree*> > fTreeByAddr;
1183 std::map< const std::type_index , std::vector<QwRootTree*> > fTreeByType;
1184 // ... Are type_index objects really unique? Let's hope so.
1185
1186#ifdef HAS_RNTUPLE_SUPPORT
1187 /// RNTuple names, addresses, and types
1188 std::map< const std::string, std::vector<QwRootNTuple*> > fNTupleByName;
1189 std::map< const void* , std::vector<QwRootNTuple*> > fNTupleByAddr;
1190 std::map< const std::type_index , std::vector<QwRootNTuple*> > fNTupleByType;
1191
1192 /// RNTuple support flag
1193 Bool_t fEnableRNTuples;
1194#endif // HAS_RNTUPLE_SUPPORT
1195
1196 /// Is a tree registered for this name
1197 bool HasTreeByName(const std::string& name) {
1198 if (fTreeByName.count(name) == 0) return false;
1199 else return true;
1200 }
1201 /// Is a tree registered for this type
1202 template < class T >
1203 bool HasTreeByType(const T& object) {
1204 const std::type_index type = typeid(object);
1205 if (fTreeByType.count(type) == 0) return false;
1206 else return true;
1207 }
1208 /// Is a tree registered for this object
1209 template < class T >
1210 bool HasTreeByAddr(const T& object) {
1211 const void* addr = static_cast<const void*>(&object);
1212 if (fTreeByAddr.count(addr) == 0) return false;
1213 else return true;
1214 }
1215
1216#ifdef HAS_RNTUPLE_SUPPORT
1217 /// Is an RNTuple registered for this name
1218 bool HasNTupleByName(const std::string& name) {
1219 if (fNTupleByName.count(name) == 0) return false;
1220 else return true;
1221 }
1222 /// Is an RNTuple registered for this type
1223 template < class T >
1224 bool HasNTupleByType(const T& object) {
1225 const std::type_index type = typeid(object);
1226 if (fNTupleByType.count(type) == 0) return false;
1227 else return true;
1228 }
1229 /// Is an RNTuple registered for this object
1230 template < class T >
1231 bool HasNTupleByAddr(const T& object) {
1232 const void* addr = static_cast<const void*>(&object);
1233 if (fNTupleByAddr.count(addr) == 0) return false;
1234 else return true;
1235 }
1236#endif // HAS_RNTUPLE_SUPPORT
1237
1238 /// Directories
1239 std::map< const std::string, TDirectory* > fDirsByName;
1240 std::map< const std::string, std::vector<std::string> > fDirsByType;
1241
1242 /// Is a tree registered for this name
1243 bool HasDirByName(const std::string& name) {
1244 if (fDirsByName.count(name) == 0) return false;
1245 else return true;
1246 }
1247 /// Is a directory registered for this type
1248 template < class T >
1249 bool HasDirByType(const T& object) {
1250 std::string type = typeid(object).name();
1251 if (fDirsByType.count(type) == 0) return false;
1252 else return true;
1253 }
1254
1255
1256 private:
1257
1258 /// Prescaling of events written to tree
1265
1266 /// Maximum tree size
1267 static const Long64_t kMaxTreeSize;
1268 static const Int_t kMaxMapFileSize;
1269};
1270
1271/**
1272 * Construct the indices from one tree to another tree, and optionally in reverse as well.
1273 * @param from Name of tree where index will be created
1274 * @param to Name of tree to which index will point
1275 * @param reverse Flag to create indices in both direction
1276 */
1277inline void QwRootFile::ConstructIndices(const std::string& from, const std::string& to, bool reverse)
1278{
1279 // Return if we do not want this tree information
1280 if (IsTreeDisabled(from)) return;
1281 if (IsTreeDisabled(to)) return;
1282
1283 // If the trees are defined
1284 if (fTreeByName.count(from) > 0 && fTreeByName.count(to) > 0) {
1285
1286 // Construct index from the first tree to the second tree
1287 fTreeByName[from].front()->ConstructIndexTo(fTreeByName[to].front());
1288
1289 // Construct index from the second tree back to the first tree
1290 if (reverse)
1291 fTreeByName[to].front()->ConstructIndexTo(fTreeByName[from].front());
1292 }
1293}
1294
1295/**
1296 * Construct the tree branches of a generic object
1297 * @param name Name for tree
1298 * @param desc Description for tree
1299 * @param object Subsystem array
1300 * @param prefix Prefix for the tree
1301 */
1302template < class T >
1304 const std::string& name,
1305 const std::string& desc,
1306 T& object,
1307 const std::string& prefix)
1308{
1309 // Return if we do not want this tree information
1310 if (IsTreeDisabled(name)) return;
1311
1312 // Pointer to new tree
1313 QwRootTree* tree = 0;
1314
1315 // If the tree does not exist yet, create it
1316 if (fTreeByName.count(name) == 0) {
1317
1318 // Go to top level directory
1319
1320 this->cd();
1321
1322 // New tree with name, description, object, prefix
1323 tree = new QwRootTree(name, desc, object, prefix);
1324
1325 // Settings only relevant for new trees
1326 if (name == "evt")
1328 else if (name == "mul")
1330
1331 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,26,00)
1332 tree->SetAutoFlush(fAutoFlush);
1333 #endif
1334 tree->SetAutoSave(fAutoSave);
1337
1338 if (fCircularBufferSize > 0)
1340
1341 } else {
1342
1343 // New tree based on existing tree
1344 tree = new QwRootTree(fTreeByName[name].front(), object, prefix);
1345 }
1346
1347 // Add the branches to the list of trees by name, object, type
1348 const void* addr = static_cast<const void*>(&object);
1349 const std::type_index type = typeid(object);
1350 fTreeByName[name].push_back(tree);
1351 fTreeByAddr[addr].push_back(tree);
1352 fTreeByType[type].push_back(tree);
1353}
1354
1355
1356/**
1357 * Fill the tree branches of a generic object by name
1358 * @param name Name for tree
1359 * @param object Subsystem array
1360 */
1361template < class T >
1363 const std::string& name,
1364 const T& object)
1365{
1366 // If this name has no registered trees
1367 if (! HasTreeByName(name)) return;
1368 // If this type has no registered trees
1369 if (! HasTreeByType(object)) return;
1370
1371 // Get the address of the object
1372 const void* addr = static_cast<const void*>(&object);
1373
1374 // Fill the trees with the correct address
1375 for (size_t tree = 0; tree < fTreeByAddr[addr].size(); tree++) {
1376 if (fTreeByAddr[addr].at(tree)->GetName() == name) {
1377 fTreeByAddr[addr].at(tree)->FillTreeBranches(object);
1378 }
1379 }
1380}
1381
1382
1383/**
1384 * Fill the tree branches of a generic object by type only
1385 * @param object Subsystem array
1386 */
1387template < class T >
1389 const T& object)
1390{
1391 // If this address has no registered trees
1392 if (! HasTreeByAddr(object)) return;
1393
1394 // Get the address of the object
1395 const void* addr = static_cast<const void*>(&object);
1396
1397 // Fill the trees with the correct address
1398 for (size_t tree = 0; tree < fTreeByAddr[addr].size(); tree++) {
1399 fTreeByAddr[addr].at(tree)->FillTreeBranches(object);
1400 }
1401}
1402
1403
1404#ifdef HAS_RNTUPLE_SUPPORT
1405/**
1406 * Construct the RNTuple fields of a generic object
1407 * @param name Name for RNTuple
1408 * @param desc Description for RNTuple
1409 * @param object Subsystem array
1410 * @param prefix Prefix for the RNTuple
1411 */
1412template < class T >
1413void QwRootFile::ConstructNTupleFields(
1414 const std::string& name,
1415 const std::string& desc,
1416 T& object,
1417 const std::string& prefix)
1418{
1419 // Return if RNTuples are disabled
1420 if (!fEnableRNTuples) return;
1421
1422 // Pointer to new RNTuple
1423 QwRootNTuple* ntuple = 0;
1424
1425 // If the RNTuple does not exist yet, create it
1426 if (fNTupleByName.count(name) == 0) {
1427
1428 // New RNTuple with name, description, object, prefix
1429 ntuple = new QwRootNTuple(name, desc, object, prefix);
1430
1431 // Initialize the writer with our file
1432 ntuple->InitializeWriter(fRootFile);
1433
1434 // Settings only relevant for new RNTuples
1435 if (name == "evt")
1436 ntuple->SetPrescaling(fNumMpsEventsToSave, fNumMpsEventsToSkip);
1437 else if (name == "mul")
1438 ntuple->SetPrescaling(fNumHelEventsToSave, fNumHelEventsToSkip);
1439
1440 } else {
1441
1442 // For simplicity, don't support multiple RNTuples with same name yet
1443 QwError << "Cannot create duplicate RNTuple: " << name << QwLog::endl;
1444 return;
1445 }
1446
1447 // Add the fields to the list of RNTuples by name, object, type
1448 const void* addr = static_cast<const void*>(&object);
1449 const std::type_index type = typeid(object);
1450 fNTupleByName[name].push_back(ntuple);
1451 fNTupleByAddr[addr].push_back(ntuple);
1452 fNTupleByType[type].push_back(ntuple);
1453}
1454
1455
1456/**
1457 * Fill the RNTuple fields of a generic object by name
1458 * @param name Name for RNTuple
1459 * @param object Subsystem array
1460 */
1461template < class T >
1462void QwRootFile::FillNTupleFields(
1463 const std::string& name,
1464 const T& object)
1465{
1466 // If this name has no registered RNTuples
1467 if (! HasNTupleByName(name)) return;
1468 // If this type has no registered RNTuples
1469 if (! HasNTupleByType(object)) return;
1470
1471 // Get the address of the object
1472 const void* addr = static_cast<const void*>(&object);
1473
1474 // Fill the RNTuples with the correct address
1475 for (size_t ntuple = 0; ntuple < fNTupleByAddr[addr].size(); ntuple++) {
1476 if (fNTupleByAddr[addr].at(ntuple)->GetName() == name) {
1477 fNTupleByAddr[addr].at(ntuple)->FillNTupleFields(object);
1478 }
1479 }
1480}
1481
1482
1483/**
1484 * Fill the RNTuple fields of a generic object by type only
1485 * @param object Subsystem array
1486 */
1487template < class T >
1488void QwRootFile::FillNTupleFields(
1489 const T& object)
1490{
1491 // If this address has no registered RNTuples
1492 if (! HasNTupleByAddr(object)) return;
1493
1494 // Get the address of the object
1495 const void* addr = static_cast<const void*>(&object);
1496
1497 // Fill the RNTuples with the correct address
1498 for (size_t ntuple = 0; ntuple < fNTupleByAddr[addr].size(); ntuple++) {
1499 fNTupleByAddr[addr].at(ntuple)->FillNTupleFields(object);
1500 }
1501}
1502#endif // HAS_RNTUPLE_SUPPORT
1503
1504
1505/**
1506 * Construct the objects directory of a generic object
1507 * @param name Name for objects directory
1508 * @param object Subsystem array
1509 */
1510template < class T >
1511void QwRootFile::ConstructObjects(const std::string& name, T& object)
1512{
1513 // Create the objects in a directory
1514 if (fRootFile) {
1515 std::string type = typeid(object).name();
1516 fDirsByName[name] =
1517 fRootFile->GetDirectory(("/" + name).c_str()) ?
1518 fRootFile->GetDirectory(("/" + name).c_str()) :
1519 fRootFile->GetDirectory("/")->mkdir(name.c_str());
1520 fDirsByType[type].push_back(name);
1521 object.ConstructObjects(fDirsByName[name]);
1522 }
1523
1524 // No support for directories in a map file
1525 if (fMapFile) {
1526 QwMessage << "QwRootFile::ConstructObjects::detectors address "
1527 << &object
1528 << " and its name " << name
1529 << QwLog::endl;
1530
1531 std::string type = typeid(object).name();
1532 fDirsByName[name] = fMapFile->GetDirectory()->mkdir(name.c_str());
1533 fDirsByType[type].push_back(name);
1534 object.ConstructObjects();
1535 }
1536}
1537
1538
1539/**
1540 * Construct the histogram of a generic object
1541 * @param name Name for histogram directory
1542 * @param object Subsystem array
1543 */
1544template < class T >
1545void QwRootFile::ConstructHistograms(const std::string& name, T& object)
1546{
1547 // Return if we do not want this histogram information
1548 if (IsHistoDisabled(name)) return;
1549
1550 // Create the histograms in a directory
1551 if (fRootFile) {
1552 std::string type = typeid(object).name();
1553 fDirsByName[name] =
1554 fRootFile->GetDirectory(("/" + name).c_str()) ?
1555 fRootFile->GetDirectory(("/" + name).c_str()) :
1556 fRootFile->GetDirectory("/")->mkdir(name.c_str());
1557 fDirsByType[type].push_back(name);
1558
1559 object.ConstructHistograms(fDirsByName[name]);
1560 }
1561
1562 // No support for directories in a map file
1563 if (fMapFile) {
1564 QwMessage << "QwRootFile::ConstructHistograms::detectors address "
1565 << &object
1566 << " and its name " << name
1567 << QwLog::endl;
1568
1569 std::string type = typeid(object).name();
1570 fDirsByName[name] = fMapFile->GetDirectory()->mkdir(name.c_str());
1571 fDirsByType[type].push_back(name);
1572 //object.ConstructHistograms(fDirsByName[name]);
1573 object.ConstructHistograms();
1574 }
1575}
1576
1577
1578template < class T >
1579Int_t QwRootFile::WriteParamFileList(const TString &name, T& object)
1580{
1581 Int_t retval = 0;
1582 if (fRootFile) {
1583 TList *param_list = (TList*) fRootFile->FindObjectAny(name);
1584 if (not param_list) {
1585 retval = fRootFile->WriteObject(object.GetParamFileNameList(name), name);
1586 }
1587 }
1588 return retval;
1589}
An options class which parses command line, config file and environment.
#define QwError
Predefined log drain for errors.
Definition QwLog.h:39
#define QwMessage
Predefined log drain for regular messages.
Definition QwLog.h:49
#define BRANCH_VECTOR_MAX_SIZE
Definition QwRootFile.h:42
unsigned long long ULong64_t
Definition QwBlinder.h:41
static std::ostream & endl(std::ostream &)
End of the line.
Definition QwLog.cc:297
Command-line and configuration file options processor.
Definition QwOptions.h:141
A helper class to manage a vector of branch entries for ROOT trees.
Definition QwRootFile.h:53
const void * data() const noexcept
Definition QwRootFile.h:174
void SetValue(size_type index, Long64_t val)
Definition QwRootFile.h:132
void push_back(const char *name, const char type='D')
Definition QwRootFile.h:224
void reserve(size_type count)
Definition QwRootFile.h:66
std::size_t size_type
Definition QwRootFile.h:62
size_type size() const noexcept
Definition QwRootFile.h:81
void SetValue(size_type index, Int_t val)
Definition QwRootFile.h:124
T & value(size_type index)
Definition QwRootFile.h:95
static std::string FormatNumeric(T input)
Definition QwRootFile.h:350
std::vector< Entry > m_entries
Definition QwRootFile.h:323
std::string LeafList(size_type start_index=0) const
Definition QwRootFile.h:228
QwRootTreeBranchVector()=default
T & operator[](size_type index)
Definition QwRootFile.h:90
void SetValue(size_type index, Short_t val)
Definition QwRootFile.h:140
std::string FormatValue(const Entry &entry, size_type index) const
Definition QwRootFile.h:326
bool empty() const noexcept
Definition QwRootFile.h:82
void SetValue(size_type index, ULong64_t val)
Definition QwRootFile.h:165
void SetValue(size_type index, UInt_t val)
Definition QwRootFile.h:157
size_type data_size() const noexcept
Definition QwRootFile.h:175
std::vector< std::uint8_t > m_buffer
Definition QwRootFile.h:324
const T & operator[](size_type index) const
Definition QwRootFile.h:85
static std::size_t GetTypeSize(char type)
Definition QwRootFile.h:295
void push_back(const std::string &name, const char type='D')
Definition QwRootFile.h:195
std::string Dump(size_type start_index=0, size_type end_index=0) const
Definition QwRootFile.h:243
static std::size_t AlignOffset(std::size_t offset)
Definition QwRootFile.h:318
void SetValue(size_type index, Float_t val)
Definition QwRootFile.h:116
void SetValue(size_type index, UShort_t val)
Definition QwRootFile.h:149
void SetValue(size_type index, Double_t val)
Definition QwRootFile.h:108
const T & value(size_type index) const
Definition QwRootFile.h:101
void * data() noexcept
Definition QwRootFile.h:173
const T & back() const
Definition QwRootFile.h:187
void push_back(const TString &name, const char type='D')
Definition QwRootFile.h:219
Wrapper class for ROOT tree management with vector-based data storage.
Definition QwRootFile.h:367
QwRootTree(const std::string &name, const std::string &desc, T &object, const std::string &prefix="")
Constructor with name, description, and object.
Definition QwRootFile.h:389
Long64_t AutoSave(Option_t *option)
Definition QwRootFile.h:486
Int_t Fill()
Fill the tree.
Definition QwRootFile.h:491
void ConstructNewTree()
Construct the tree.
Definition QwRootFile.h:424
UInt_t fCurrentEvent
Tree prescaling parameters.
Definition QwRootFile.h:555
virtual ~QwRootTree()
Destructor.
Definition QwRootFile.h:415
const std::string fPrefix
Definition QwRootFile.h:537
UInt_t fNumEventsToSave
Definition QwRootFile.h:557
void SetAutoFlush(Long64_t autoflush=30000000)
Set autoflush size.
Definition QwRootFile.h:581
UInt_t fNumEventsToSkip
Definition QwRootFile.h:558
void Print() const
Print the tree name and description.
Definition QwRootFile.h:513
Long64_t fAutoFlush
Definition QwRootFile.h:570
Long64_t fMaxTreeSize
Maximum tree size, autoflush and autosave.
Definition QwRootFile.h:569
const std::string fName
Name, description.
Definition QwRootFile.h:535
std::string fType
Object type.
Definition QwRootFile.h:548
static const TString kUnitsName
Definition QwRootFile.h:420
void ConstructUnitsBranch()
Definition QwRootFile.h:438
void SetCircular(Long64_t buff=100000)
Definition QwRootFile.h:601
void SetMaxTreeSize(Long64_t maxsize=1900000000)
Set maximum tree size.
Definition QwRootFile.h:575
UInt_t fNumEventsCycle
Definition QwRootFile.h:556
QwRootTree(const std::string &name, const std::string &desc, const std::string &prefix="")
Constructor with name, and description.
Definition QwRootFile.h:372
void SetAutoSave(Long64_t autosave=300000000)
Set autosave size.
Definition QwRootFile.h:589
const std::string & GetPrefix() const
Get the description of the tree.
Definition QwRootFile.h:544
QwRootTreeBranchVector fVector
Vector of leaves.
Definition QwRootFile.h:531
void ConstructBranchAndVector(T &object)
Construct the branches and vector for generic objects.
Definition QwRootFile.h:451
Int_t fBasketSize
Definition QwRootFile.h:572
static Double_t kUnitsValue[]
Definition QwRootFile.h:20
TTree * GetTree() const
Get the tree pointer for low level operations.
Definition QwRootFile.h:521
void ConstructIndexTo(QwRootTree *to)
Construct index from this tree to another tree.
Definition QwRootFile.h:444
const std::string & GetDesc() const
Get the description of the tree.
Definition QwRootFile.h:542
TTree * fTree
Tree pointer.
Definition QwRootFile.h:529
friend class QwRootFile
Definition QwRootFile.h:524
void SetBasketSize(Int_t basketsize=16000)
Set basket size.
Definition QwRootFile.h:595
const std::string fDesc
Definition QwRootFile.h:536
void FillTreeBranches(const T &object)
Fill the branches for generic objects.
Definition QwRootFile.h:475
QwRootTree(const QwRootTree *tree, T &object, const std::string &prefix="")
Constructor with existing tree, and object.
Definition QwRootFile.h:404
QwRootTree(const QwRootTree *tree, const std::string &prefix="")
Constructor with existing tree.
Definition QwRootFile.h:380
const std::string & GetName() const
Get the name of the tree.
Definition QwRootFile.h:540
Long64_t fAutoSave
Definition QwRootFile.h:571
void SetPrescaling(UInt_t num_to_save, UInt_t num_to_skip)
Set tree prescaling parameters.
Definition QwRootFile.h:561
std::string GetType() const
Get the object type.
Definition QwRootFile.h:551
Bool_t IsRootFile() const
Is the ROOT file active?
Definition QwRootFile.h:852
bool HasTreeByType(const T &object)
Is a tree registered for this type.
std::vector< TPRegexp > fDisabledTrees
List of excluded trees.
std::map< const std::string, std::vector< std::string > > fDirsByType
Int_t fBasketSize
void NewTree(const std::string &name, const std::string &desc)
Create a new tree with name and description.
Definition QwRootFile.h:912
TString fRootFileStem
ROOT file stem.
void Print()
Int_t FillTree(const std::string &name)
Fill the tree with name.
Definition QwRootFile.h:949
TFile * fRootFile
ROOT file.
Bool_t IsMapFile() const
Is the map file active?
Definition QwRootFile.h:854
bool HasDirByType(const T &object)
Is a directory registered for this type.
virtual ~QwRootFile()
Destructor.
TString fRootFileDir
ROOT files dir.
void DisableTree(const TString &regexp)
Add regexp to list of disabled trees names.
Int_t fCompressionAlgorithm
Bool_t cd(const char *path=0)
Bool_t HasAnyFilled(void)
Search for non-empty trees or histograms in the file.
Int_t Write(const char *name=0, Int_t option=0, Int_t bufsize=0)
void PrintDirs() const
Print registered histogram directories.
static std::string fDefaultRootFileDir
Default ROOT files dir.
void PrintTrees() const
Print registered trees.
Definition QwRootFile.h:986
static const Int_t kMaxMapFileSize
Int_t WriteObject(const T *obj, const char *name, Option_t *option="", Int_t bufsize=0)
Write any object to the ROOT file (only valid for TFile)
std::map< const std::string, TDirectory * > fDirsByName
Directories.
void ProcessOptions(QwOptions &options)
Process the configuration options.
QwRootFile(const TString &run_label)
Constructor with run label.
Definition QwRootFile.cc:25
UInt_t fNumHelEventsToSkip
bool IsHistoDisabled(const std::string &name)
Does this histogram directory match a disabled histogram directory?
Int_t fAutoSave
std::map< const std::string, std::vector< QwRootTree * > > fTreeByName
Tree names, addresses, and types.
TDirectory * mkdir(const char *name, const char *title="")
Int_t fCompressionLevel
void Close()
void DisableHisto(const TString &regexp)
Add regexp to list of disabled histogram directories.
void Update()
static void SetDefaultRootFileStem(const std::string &stem)
Set default ROOT file stem.
Definition QwRootFile.h:846
static void SetDefaultRootFileDir(const std::string &dir)
Set default ROOT files dir.
Definition QwRootFile.h:842
void ConstructTreeBranches(const std::string &name, const std::string &desc, T &object, const std::string &prefix="")
Construct the tree branches of a generic object.
Bool_t fUseTemporaryFile
UInt_t fNumMpsEventsToSave
static std::string fDefaultRootFileStem
Default ROOT file stem.
void FillHistograms(T &object)
Fill histograms of the subsystem array.
Definition QwRootFile.h:895
TString fPermanentName
bool IsTreeDisabled(const std::string &name)
Does this tree name match a disabled tree name?
Int_t FillTrees()
Fill all registered trees.
Definition QwRootFile.h:955
std::map< const std::type_index, std::vector< QwRootTree * > > fTreeByType
static void DefineOptions(QwOptions &options)
Define the configuration options.
UInt_t fNumHelEventsToSave
TTree * GetTree(const std::string &name)
Get the tree with name.
Definition QwRootFile.h:943
bool HasTreeByAddr(const T &object)
Is a tree registered for this object.
Int_t fAutoFlush
TMapFile * fMapFile
Map file.
bool HasDirByName(const std::string &name)
Is a tree registered for this name.
Int_t fUpdateInterval
void FillTreeBranches(const std::string &name, const T &object)
Fill the tree branches of a generic object by tree name.
Int_t WriteParamFileList(const TString &name, T &object)
QwRootFile()
Private default constructor.
void ConstructHistograms(const std::string &name, T &object)
Construct the histograms of a generic object.
UInt_t fCircularBufferSize
std::map< const void *, std::vector< QwRootTree * > > fTreeByAddr
void ConstructObjects(const std::string &name, T &object)
Construct the histograms of a generic object.
static const Long64_t kMaxTreeSize
Maximum tree size.
Bool_t fMakePermanent
std::vector< TPRegexp > fDisabledHistos
UInt_t fNumMpsEventsToSkip
Prescaling of events written to tree.
void ConstructIndices(const std::string &from, const std::string &to, bool reverse=true)
Construct indices from one tree to another tree.
UInt_t fCurrentEvent
bool HasTreeByName(const std::string &name)
Is a tree registered for this name.
Bool_t fEnableMapFile