JAPAn
Just Another Parity Analyzer
Loading...
Searching...
No Matches
QwRootFile.cc
Go to the documentation of this file.
1/*!
2 * \file QwRootFile.cc
3 * \brief Implementation for ROOT file and tree management wrapper classes
4 */
5
6#include "QwRootFile.h"
7#include "QwRunCondition.h"
8#include "TH1.h"
9
10#include <unistd.h>
11#include <cstdio>
12
13#include <filesystem>
14namespace fs = std::filesystem;
15
16std::string QwRootFile::fDefaultRootFileDir = ".";
17std::string QwRootFile::fDefaultRootFileStem = "Qweak_";
18
19const Long64_t QwRootFile::kMaxTreeSize = 100000000000LL;
20const Int_t QwRootFile::kMaxMapFileSize = 0x3fffffff; // 1 GiB
21
22const TString QwRootTree::kUnitsName = "ppm/D:ppb/D:um/D:mm/D:mV_uA/D:V_uA/D";
23Double_t QwRootTree::kUnitsValue[] = { 1e-6, 1e-9, 1e-3, 1 , 1e-3, 1};
24
25/**
26 * Constructor with relative filename
27 */
28QwRootFile::QwRootFile(const TString& run_label)
30 fMapFile(0), fEnableMapFile(kFALSE),
32#ifdef HAS_RNTUPLE_SUPPORT
33 , fEnableRNTuples(kFALSE)
34#endif // HAS_RNTUPLE_SUPPORT
35{
36 // Process the configuration options
38
39#ifdef QW_ENABLE_MAPFILE
40 // Check for the memory-mapped file flag
41 if (fEnableMapFile) {
42
43 // Verify the target directory exists and is writable before asking ROOT
44 // to mmap a file there. On platforms without /dev/shm (e.g. macOS) the
45 // default location is absent; give an actionable message instead of a
46 // cryptic TMapFile failure.
47 if (gSystem->AccessPathName(fMapFileDir, kWritePermission)) {
48 QwError << "Memory-mapped file directory '" << fMapFileDir
49 << "' does not exist or is not writable." << QwLog::endl;
50 QwError << "Set --mapfile-dir to a writable directory (ideally a RAM "
51 "disk). /dev/shm does not exist on macOS; a normal directory "
52 "or a hdiutil-mounted RAM disk works there." << QwLog::endl;
53 return;
54 }
55
56 TString mapfilename = fMapFileDir + "/QwMemMapFile.map";
57
58 fMapFile = TMapFile::Create(mapfilename,"UPDATE", kMaxMapFileSize, "RealTime Producer File");
59
60 if (not fMapFile) {
61 QwError << "Memory-mapped file " << mapfilename
62 << " could not be opened!" << QwLog::endl;
63 return;
64 }
65
66 QwMessage << "================== RealTime Producer Memory Map File =================" << QwLog::endl;
67 QwMessage << "Memory-mapped file: " << mapfilename << QwLog::endl;
68 fMapFile->Print();
69 QwMessage << "======================================================================" << QwLog::endl;
70 } else
71#endif
72 {
73
74 TString rootfilename = fRootFileDir;
75 TString hostname = gSystem -> HostName();
76
77 // Use a probably-unique temporary file name.
78 pid_t pid = getpid();
79
80 fPermanentName = rootfilename
81 + Form("/%s%s.root", fRootFileStem.Data(), run_label.Data());
83 rootfilename += Form("/%s%s.%s.%d.root",
84 fRootFileStem.Data(), run_label.Data(),
85 hostname.Data(), pid);
86 // Delete permanent file if it exists to prevent accumulation across segments
87 if (gSystem->AccessPathName(fPermanentName.Data()) == 0) {
88 QwVerbose << "Removing existing permanent file: " << fPermanentName << QwLog::endl;
89 gSystem->Unlink(fPermanentName.Data());
90 }
91 // CRITICAL: Also delete the temporary file if it exists!
92 // RECREATE mode doesn't properly clear files that contain RNTuples,
93 // so we must manually delete before opening
94 if (gSystem->AccessPathName(rootfilename.Data()) == 0) {
95 QwVerbose << "Removing existing temporary file before RECREATE: " << rootfilename << QwLog::endl;
96 gSystem->Unlink(rootfilename.Data());
97 }
98 } else {
99 rootfilename = fPermanentName;
100 // Delete permanent file if it exists to ensure RECREATE truly starts fresh
101 // This is especially important for RNTuple files where RECREATE doesn't properly clear
102 if (gSystem->AccessPathName(rootfilename.Data()) == 0) {
103 QwMessage << "File exists before RECREATE, deleting: " << rootfilename << QwLog::endl;
104 int unlink_result = gSystem->Unlink(rootfilename.Data());
105 if (unlink_result == 0) {
106 QwMessage << "Successfully deleted file" << QwLog::endl;
107 } else {
108 QwError << "Failed to delete file! Error code: " << unlink_result << QwLog::endl;
109 }
110 } else {
111 QwMessage << "File does not exist before RECREATE: " << rootfilename << QwLog::endl;
112 }
113 }
114 QwMessage << "Opening file with RECREATE mode: " << rootfilename << QwLog::endl;
115 QwMessage << "QwRootFile constructor called for: " << rootfilename << QwLog::endl;
116 // Use TFile::Open instead of `new TFile(...)` so the ROOT plug-in manager
117 // can dispatch remote URLs (e.g. root://host/path) to TNetXNGFile etc.
118 // The TFile(name, opt, title) constructor refuses remote paths and returns
119 // a half-built object, which then segfaults at first use.
120 fRootFile = TFile::Open(rootfilename.Data(), "RECREATE", "myfile1");
121 if (!fRootFile || fRootFile->IsZombie()) {
122 QwError << "ROOT file " << rootfilename
123 << " could not be opened!" << QwLog::endl;
124 delete fRootFile;
125 fRootFile = nullptr;
126 return;
127 } else {
128 QwMessage << "Opened "<< (fUseTemporaryFile?"temporary ":"")
129 <<"rootfile " << rootfilename << QwLog::endl;
130 }
131
132 TString run_condition_name = Form("condition_%s", run_label.Data());
133 TList *run_cond_list = (TList*) fRootFile -> FindObjectAny(run_condition_name);
134 if (not run_cond_list) {
135 QwRunCondition run_condition(
136 gQwOptions.GetArgc(),
137 gQwOptions.GetArgv(),
138 run_condition_name
139 );
140
142 run_condition.Get(),
143 run_condition.GetName()
144 );
145 }
146
147 fRootFile->SetCompressionAlgorithm(fCompressionAlgorithm);
148 fRootFile->SetCompressionLevel(fCompressionLevel);
149 }
150}
151
152
153/**
154 * Destructor
155 */
157{
158 // Keep the file on disk if any trees or histograms have been filled.
159 // Also respect any other requests to keep the file around.
161
162 // Close the map file
163 if (fMapFile) {
164 fMapFile->Close();
165 // TMapFiles may not be deleted
166 fMapFile = 0;
167 }
168
169 // Close the ROOT file.
170 // Rename if permanence is requested, remove otherwise
171 if (fRootFile) {
172 TString rootfilename = fRootFile->GetName();
173
174 fRootFile->Close();
175 delete fRootFile;
176 fRootFile = 0;
177
178 int err;
179 const char* action;
181 if (fMakePermanent) {
182 // Delete existing permanent file first to avoid accumulation
183 if (gSystem->AccessPathName(fPermanentName.Data()) == 0) {
184 remove(fPermanentName.Data());
185 }
186 action = " rename ";
187 err = rename( rootfilename.Data(), fPermanentName.Data() );
188 } else {
189 action = " remove ";
190 err = remove( rootfilename.Data() );
191 }
192 // It'd be proper to "extern int errno" and strerror() here,
193 // but that doesn't seem very C++-ish.
194 if (err) {
195 QwWarning << "Couldn't" << action << rootfilename << QwLog::endl;
196 } else {
197 QwMessage << "Was able to" << action << rootfilename << QwLog::endl;
198 QwMessage << "Root file is " << fPermanentName << QwLog::endl;
199 }
200 }
201 }
202
203 // Delete Qweak ROOT trees
204 std::map< const std::string, std::vector<QwRootTree*> >::iterator map_iter;
205 std::vector<QwRootTree*>::iterator vec_iter;
206 for (map_iter = fTreeByName.begin(); map_iter != fTreeByName.end(); map_iter++) {
207 for (vec_iter = map_iter->second.begin(); vec_iter != map_iter->second.end(); vec_iter++) {
208 delete *vec_iter;
209 }
210 }
211}
212
213/**
214 * Defines configuration options using QwOptions functionality.
215 * @param options Options object
216 */
218{
219 // Define the ROOT files directory
220 options.AddOptions("Default options")
221 ("rootfiles", po::value<std::string>()->default_value(fDefaultRootFileDir),
222 "directory of the output ROOT files");
223
224 // Define the ROOT filename stem
225 options.AddOptions("Default options")
226 ("rootfile-stem", po::value<std::string>()->default_value(fDefaultRootFileStem),
227 "stem of the output ROOT filename");
228
229 // Define the memory map option
230 options.AddOptions()
231 ("enable-mapfile", po::value<bool>()->default_bool_value(false),
232 "enable output to memory-mapped file\n(likely requires circular-buffer too)");
233 options.AddOptions()
234 ("mapfile-dir", po::value<std::string>()->default_value("/dev/shm"),
235 "directory that holds the memory-mapped file (QwMemMapFile.map). Defaults "
236 "to /dev/shm (Linux tmpfs). Set this on platforms without /dev/shm "
237 "(e.g. macOS) to a writable directory, ideally a RAM disk.");
238 options.AddOptions()
239 ("write-temporary-rootfiles", po::value<bool>()->default_bool_value(true),
240 "When writing ROOT files, use the PID to create a temporary filename");
241
242 // Define the histogram and tree options
243 options.AddOptions("ROOT output options")
244 ("disable-tree", po::value<std::vector<std::string>>()->composing(),
245 "disable output to tree regex");
246 options.AddOptions("ROOT output options")
247 ("disable-trees", po::value<bool>()->default_bool_value(false),
248 "disable output to all trees");
249 options.AddOptions("ROOT output options")
250 ("disable-histos", po::value<bool>()->default_bool_value(false),
251 "disable output to all histograms");
252
253 // Define the helicity window versus helicity pattern options
254 options.AddOptions("ROOT output options")
255 ("disable-mps-tree", po::value<bool>()->default_bool_value(false),
256 "disable helicity window output");
257 options.AddOptions("ROOT output options")
258 ("disable-pair-tree", po::value<bool>()->default_bool_value(false),
259 "disable helicity pairs output");
260 options.AddOptions("ROOT output options")
261 ("disable-hel-tree", po::value<bool>()->default_bool_value(false),
262 "disable helicity pattern output");
263 options.AddOptions("ROOT output options")
264 ("disable-burst-tree", po::value<bool>()->default_bool_value(false),
265 "disable burst tree");
266 options.AddOptions("ROOT output options")
267 ("disable-slow-tree", po::value<bool>()->default_bool_value(false),
268 "disable slow control tree");
269 options.AddOptions("ROOT output options")
270 ("disable-redundant-trees", po::value<bool>()->default_bool_value(false),
271 "disable the per-entry trees whose content is already captured by a "
272 "matching histogram directory (evt/mul/burst). Histograms, the "
273 "running-sum trees (evts/muls/bursts), the pair tree (pr) and the slow "
274 "control tree (slow) are kept.");
275
276#ifdef HAS_RNTUPLE_SUPPORT
277 // Define the RNTuple options
278 options.AddOptions("ROOT output options")
279 ("enable-rntuples", po::value<bool>()->default_bool_value(false),
280 "enable RNTuple output");
281#endif // HAS_RNTUPLE_SUPPORT
282
283 // Define the tree output prescaling options
284 options.AddOptions("ROOT output options")
285 ("num-mps-accepted-events", po::value<int>()->default_value(0),
286 "number of accepted consecutive MPS events");
287 options.AddOptions("ROOT output options")
288 ("num-mps-discarded-events", po::value<int>()->default_value(0),
289 "number of discarded consecutive MPS events");
290 options.AddOptions("ROOT output options")
291 ("num-hel-accepted-events", po::value<int>()->default_value(0),
292 "number of accepted consecutive pattern events");
293 options.AddOptions("ROOT output options")
294 ("num-hel-discarded-events", po::value<int>()->default_value(0),
295 "number of discarded consecutive pattern events");
296 options.AddOptions("ROOT output options")
297 ("mapfile-update-interval", po::value<int>()->default_value(-1),
298 "Events between a map file update");
299 options.AddOptions("ROOT output options")
300 ("fill-prescale", po::value<int>()->default_value(1),
301 "Fill trees and histograms only on every Nth processed event (physics is "
302 "still computed every event). Roughly multiplies live (mapfile) throughput "
303 "by N at the cost of fewer accumulated monitoring entries. Default 1 = "
304 "fill every event.");
305
306 // Define the autoflush and autosave option (default values by ROOT)
307 options.AddOptions("ROOT performance options")
308 ("autoflush", po::value<int>()->default_value(0),
309 "TTree autoflush");
310 options.AddOptions("ROOT performance options")
311 ("autosave", po::value<int>()->default_value(300000000),
312 "TTree autosave");
313 options.AddOptions("ROOT performance options")
314 ("basket-size", po::value<int>()->default_value(16000),
315 "TTree basket size");
316 options.AddOptions("ROOT performance options")
317 ("circular-buffer", po::value<int>()->default_value(0),
318 "TTree circular buffer");
319 options.AddOptions("ROOT performance options")
320 ("compression-algorithm", po::value<int>()->default_value(1),
321 "TFile compression algorithm (1=ZLIB, 2=LZMA, 4=LZ4, 5=ZSTD, default=1 ZLIB)");
322 options.AddOptions("ROOT performance options")
323 ("compression-level", po::value<int>()->default_value(1),
324 "TFile compression level (default = 1, no compression = 0)");
325 options.AddOptions("ROOT performance options")
326 ("rntuple-compression-algorithm", po::value<int>()->default_value(4),
327 "RNTuple compression algorithm (1=ZLIB, 2=LZMA, 4=LZ4, 5=ZSTD, default=4 LZ4)");
328 options.AddOptions("ROOT performance options")
329 ("rntuple-compression-level", po::value<int>()->default_value(0),
330 "RNTuple compression level (0-12, default=0 for maximum performance)");
331}
332
333
334/**
335 * Parse the configuration options and store in class fields
336 * @param options Options object
337 */
339{
340 // Option 'rootfiles' to specify ROOT files dir
341 fRootFileDir = TString(options.GetValue<std::string>("rootfiles"));
342 fs::path tmppath(fRootFileDir.Data());
343 if( ! fs::exists(tmppath) || ! fs::is_directory(tmppath)) {
344 QwError << "ERROR: The rootfile directory path, " << fRootFileDir
345 << ", does not exist. Exiting."
346 << QwLog::endl;
347 exit(2);
348 }
349
350 // Option 'root-stem' to specify ROOT file stem
351 fRootFileStem = TString(options.GetValue<std::string>("rootfile-stem"));
352
353 // Option 'mapfile' to enable memory-mapped ROOT file
354 fEnableMapFile = options.GetValue<bool>("enable-mapfile");
355#ifndef QW_ENABLE_MAPFILE
356 if( fEnableMapFile ) {
358 QwWarning << "QwRootFile::ProcessOptions: "
359 << "The 'enable-mapfile' flag is not supported by the ROOT "
360 "version with which this app is built. Disabling it."
361 << QwLog::endl;
362 fEnableMapFile = false;
363 }
364#endif
365 fMapFileDir = TString(options.GetValue<std::string>("mapfile-dir"));
366 while (fMapFileDir.Length() > 1 && fMapFileDir.EndsWith("/"))
367 fMapFileDir.Remove(fMapFileDir.Length() - 1);
368 fUseTemporaryFile = options.GetValue<bool>("write-temporary-rootfiles");
369
370#ifdef HAS_RNTUPLE_SUPPORT
371 // Option 'enable-rntuples' to enable RNTuple output
372 fEnableRNTuples = options.GetValue<bool>("enable-rntuples");
373 // RNTuples require a TFile (RNTupleWriter::Append takes a TDirectory&);
374 // they cannot be hosted by a TMapFile. If both flags are requested,
375 // disable RNTuples and warn loudly so the run does not crash later in
376 // QwRootNTuple::InitializeWriter with a null TFile*.
377 if (fEnableMapFile && fEnableRNTuples) {
379 QwWarning << "QwRootFile::ProcessOptions: "
380 << "RNTuple output is not supported alongside --enable-mapfile "
381 "(TMapFile is not a TDirectory). Disabling RNTuples."
382 << QwLog::endl;
383 fEnableRNTuples = false;
384 }
385#endif // HAS_RNTUPLE_SUPPORT
386
387 // Options 'disable-trees' and 'disable-histos' for disabling
388 // tree and histogram output
389 auto v = options.GetValueVector<std::string>("disable-tree");
390 std::for_each(v.begin(), v.end(), [&](const std::string& s){ this->DisableTree(s); });
391 if (options.GetValue<bool>("disable-trees")) DisableTree(".*");
392 if (options.GetValue<bool>("disable-histos")) DisableHisto(".*");
393
394 // Read --circular-buffer up front so the mapfile-mode logic below can use
395 // it (the original ProcessOptions read it further down, but we now need
396 // it during the mapfile-tree decision).
397 fCircularBufferSize = options.GetValue<int>("circular-buffer");
398
399 // TMapFile-mode tree publishing.
400 //
401 // TTrees can be published into the mapfile: TDirectoryFile::Append
402 // auto-calls TMapFile::Add() when the directory's mother is a TMapFile,
403 // so a TTree created while gDirectory == fMapFile->GetDirectory()
404 // becomes a TMapRec on its own. TMapFile::Update() then re-streams the
405 // tree (header + baskets) into the 1 GiB mmap on every interval.
406 //
407 // The hazard is that an unbounded TTree's serialized size grows
408 // monotonically and CustomReAlloc2 aborts as soon as it overruns the
409 // mmap. TTree::SetCircular(N) caps the in-memory entry count, which
410 // caps the serialized size. Require a non-zero circular buffer in
411 // mapfile mode; if the user did not pass one, force a safe default
412 // and warn loudly rather than silently dropping all trees.
414 const UInt_t kMapFileCircularDefault = 100;
416 QwWarning << "QwRootFile::ProcessOptions: "
417 << "--enable-mapfile requires a bounded TTree to avoid "
418 "overrunning the " << (kMaxMapFileSize >> 20)
419 << " MiB mmap region. "
420 "Forcing --circular-buffer=" << kMapFileCircularDefault
421 << " (pass --circular-buffer=N to override; pass "
422 "--disable-trees to suppress tree output entirely)."
423 << QwLog::endl;
424 fCircularBufferSize = kMapFileCircularDefault;
425 }
426
427#ifdef HAS_RNTUPLE_SUPPORT
428 // TTree and RNTuple writers share per-channel state (fTreeArrayIndex,
429 // fTreeArrayNumEntries, fDataToSave, b* flags). When both are active,
430 // the second Construct*AndVector() call clobbers the first writer's
431 // layout, and subsequent Fill*Vector() then walks a vector whose entry
432 // types no longer match what was pushed (e.g. SetValue throws
433 // "entry type 'D' cannot store unsigned int value 'block2'").
434 // Until per-writer layout state is added, make the two writers
435 // mutually exclusive: keep RNTuples and silence TTrees.
436 if (fEnableRNTuples) {
438 QwMessage << "QwRootFile::ProcessOptions: "
439 << "--enable-rntuples is set; disabling tree output "
440 "(channels share layout state between TTree and RNTuple "
441 "writers, so the two cannot be produced in the same run)."
442 << QwLog::endl;
443 DisableTree(".*");
444 }
445#endif // HAS_RNTUPLE_SUPPORT
446
447 // Options 'disable-mps' and 'disable-hel' for disabling
448 // helicity window and helicity pattern output
449 if (options.GetValue<bool>("disable-mps-tree")) DisableTree("^evt$");
450 if (options.GetValue<bool>("disable-pair-tree")) DisableTree("^pr$");
451 if (options.GetValue<bool>("disable-hel-tree")) DisableTree("^mul$");
452 if (options.GetValue<bool>("disable-burst-tree")) DisableTree("^burst$");
453 if (options.GetValue<bool>("disable-slow-tree")) DisableTree("^slow$");
454
455 // Option 'disable-redundant-trees' disables the per-entry trees that are
456 // fully captured by their matching histogram directories
457 // (evt->evt_histo, mul->mul_histo, burst->burst_histo). The running-sum
458 // trees (evts/muls/bursts) hold the unbinned moments, and the pair (pr)
459 // and slow (EPICS) trees have no histogram equivalent, so they are left
460 // untouched.
461 if (options.GetValue<bool>("disable-redundant-trees")) {
462 DisableTree("^evt$");
463 DisableTree("^mul$");
464 DisableTree("^burst$");
465 }
466
467 // Options 'num-accepted-events' and 'num-discarded-events' for
468 // prescaling of the tree output
469 fNumMpsEventsToSave = options.GetValue<int>("num-mps-accepted-events");
470 fNumMpsEventsToSkip = options.GetValue<int>("num-mps-discarded-events");
471 fNumHelEventsToSave = options.GetValue<int>("num-mps-accepted-events");
472 fNumHelEventsToSkip = options.GetValue<int>("num-mps-discarded-events");
473
474 // Live-output fill prescale. Filling trees and histograms is a sizeable
475 // fraction of the per-event cost, so thinning it to 1-in-N raises throughput
476 // (e.g. for live mapfile monitoring) while physics is still processed every
477 // event. The histogram side is gated in FillHistograms() via
478 // fHistoFillPrescale; the tree side reuses the existing per-tree prescale.
479 // If the user explicitly set a tree prescale we leave it untouched.
480 int fillPrescale = options.GetValue<int>("fill-prescale");
481 if (fillPrescale < 1) fillPrescale = 1;
482 fHistoFillPrescale = fillPrescale;
483 if (fillPrescale > 1) {
484 if (fNumMpsEventsToSave == 0 && fNumMpsEventsToSkip == 0) {
486 fNumMpsEventsToSkip = fillPrescale - 1;
487 }
488 if (fNumHelEventsToSave == 0 && fNumHelEventsToSkip == 0) {
490 fNumHelEventsToSkip = fillPrescale - 1;
491 }
492 }
493
494 // Update interval for the map file
495 fUpdateInterval = options.GetValue<int>("mapfile-update-interval");
496 fCompressionAlgorithm = options.GetValue<int>("compression-algorithm");
497 fCompressionLevel = options.GetValue<int>("compression-level");
498 fRNTupleCompressionAlgorithm = options.GetValue<int>("rntuple-compression-algorithm");
499 fRNTupleCompressionLevel = options.GetValue<int>("rntuple-compression-level");
500 fBasketSize = options.GetValue<int>("basket-size");
501
502 // Autoflush and autosave
503 fAutoFlush = options.GetValue<int>("autoflush");
504 if ((ROOT_VERSION_CODE < ROOT_VERSION(5,26,00)) && fAutoFlush != -30000000){
506 QwWarning << "QwRootFile::ProcessOptions: "
507 << "The 'autoflush' flag is not supported by ROOT version "
508 << ROOT_RELEASE
509 << QwLog::endl;
510 }
511 fAutoSave = options.GetValue<int>("autosave");
512 return;
513}
514
515/**
516 * Determine whether the rootfile object has any non-empty trees or
517 * histograms.
518 */
520 return this->HasAnyFilled(fRootFile);
521}
522Bool_t QwRootFile::HasAnyFilled(TDirectory* d) {
523 if (!d) {
524
525 return false;
526 }
527
528 // First check if any in-memory trees have been filled
529 for (auto& pair : fTreeByName) {
530 for (auto& tree : pair.second) {
531 if (tree && tree->GetTree()) {
532 Long64_t entries = tree->GetTree()->GetEntries();
533 if (entries > 0) {
534
535 return true;
536 }
537 }
538 }
539 }
540
541#ifdef HAS_RNTUPLE_SUPPORT
542 // Then check if any RNTuples have been filled
543 for (auto& pair : fNTupleByName) {
544 for (auto& ntuple : pair.second) {
545 if (ntuple && ntuple->fCurrentEvent > 0) {
546
547 return true;
548 }
549 }
550 }
551#endif // HAS_RNTUPLE_SUPPORT
552
553 TList* l = d->GetListOfKeys();
554
555
556 for( int i=0; i < l->GetEntries(); ++i) {
557 const char* name = l->At(i)->GetName();
558 TObject* obj = d->FindObjectAny(name);
559
560
561
562 // Objects which can't be found don't count.
563 if (!obj) {
564
565 continue;
566 }
567
568 // Lists of parameter files, map files, and job conditions don't count.
569 if ( TString(name).Contains("parameter_file") ) {
570
571 continue;
572 }
573 if ( TString(name).Contains("mapfile") ) {
574 continue;
575 }
576 if ( TString(name).Contains("_condition") ) {
577 continue;
578 }
579 // The EPICS tree doesn't count
580 if ( TString(name).Contains("slow") ) {
581 continue;
582 }
583
584 // Recursively check subdirectories.
585 if (obj->IsA()->InheritsFrom( "TDirectory" )) {
586 if (this->HasAnyFilled( (TDirectory*)obj )) return true;
587 }
588
589 if (obj->IsA()->InheritsFrom( "TTree" )) {
590 Long64_t entries = ((TTree*) obj)->GetEntries();
591 if ( entries ) return true;
592 }
593
594 if (obj->IsA()->InheritsFrom( "TH1" )) {
595 Double_t entries = ((TH1*) obj)->GetEntries();
596 if ( entries ) return true;
597 }
598 }
599 return false;
600}
#define gQwOptions
Definition QwOptions.h:31
ROOT file and tree management wrapper classes.
#define QwVerbose
Predefined log drain for verbose messages.
Definition QwLog.h:54
#define QwError
Predefined log drain for errors.
Definition QwLog.h:39
#define QwWarning
Predefined log drain for warnings.
Definition QwLog.h:44
#define QwMessage
Predefined log drain for regular messages.
Definition QwLog.h:49
Run condition management and metadata.
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
std::vector< T > GetValueVector(const std::string &key)
Get a list of templated values.
Definition QwOptions.h:249
T GetValue(const std::string &key)
Get a templated value.
Definition QwOptions.h:236
po::options_description_easy_init AddOptions(const std::string &blockname="Specialized options")
Add an option to a named block or create new block.
Definition QwOptions.h:170
static const TString kUnitsName
Definition QwRootFile.h:422
static Double_t kUnitsValue[]
Definition QwRootFile.h:23
Int_t fBasketSize
TString fRootFileStem
ROOT file stem.
TFile * fRootFile
ROOT file.
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 HasAnyFilled(void)
Search for non-empty trees or histograms in the file.
static std::string fDefaultRootFileDir
Default ROOT files dir.
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)
void ProcessOptions(QwOptions &options)
Process the configuration options.
UInt_t fNumHelEventsToSkip
Int_t fAutoSave
std::map< const std::string, std::vector< QwRootTree * > > fTreeByName
Tree names, addresses, and types.
Int_t fCompressionLevel
void DisableHisto(const TString &regexp)
Add regexp to list of disabled histogram directories.
Bool_t fUseTemporaryFile
UInt_t fNumMpsEventsToSave
static std::string fDefaultRootFileStem
Default ROOT file stem.
TString fMapFileDir
TString fPermanentName
UInt_t fHistoFillPrescale
static void DefineOptions(QwOptions &options)
Define the configuration options.
UInt_t fNumHelEventsToSave
Int_t fAutoFlush
TMapFile * fMapFile
Map file.
Int_t fUpdateInterval
QwRootFile()
Private default constructor.
UInt_t fCircularBufferSize
static const Long64_t kMaxTreeSize
Maximum tree size.
Bool_t fMakePermanent
Int_t fRNTupleCompressionLevel
UInt_t fNumMpsEventsToSkip
Prescaling of events written to tree.
Bool_t fEnableMapFile
Int_t fRNTupleCompressionAlgorithm
Run condition and quality management.