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
13std::string QwRootFile::fDefaultRootFileDir = ".";
14std::string QwRootFile::fDefaultRootFileStem = "Qweak_";
15
16const Long64_t QwRootFile::kMaxTreeSize = 100000000000LL;
17const Int_t QwRootFile::kMaxMapFileSize = 0x3fffffff; // 1 GiB
18
19const TString QwRootTree::kUnitsName = "ppm/D:ppb/D:um/D:mm/D:mV_uA/D:V_uA/D";
20Double_t QwRootTree::kUnitsValue[] = { 1e-6, 1e-9, 1e-3, 1 , 1e-3, 1};
21
22/**
23 * Constructor with relative filename
24 */
25QwRootFile::QwRootFile(const TString& run_label)
27 fMapFile(0), fEnableMapFile(kFALSE),
29#ifdef HAS_RNTUPLE_SUPPORT
30 , fEnableRNTuples(kFALSE)
31#endif // HAS_RNTUPLE_SUPPORT
32{
33 // Process the configuration options
35
36#ifdef QW_ENABLE_MAPFILE
37 // Check for the memory-mapped file flag
38 if (fEnableMapFile) {
39
40 TString mapfilename = "/dev/shm/";
41
42 mapfilename += "/QwMemMapFile.map";
43
44 fMapFile = TMapFile::Create(mapfilename,"UPDATE", kMaxMapFileSize, "RealTime Producer File");
45
46 if (not fMapFile) {
47 QwError << "Memory-mapped file " << mapfilename
48 << " could not be opened!" << QwLog::endl;
49 return;
50 }
51
52 QwMessage << "================== RealTime Producer Memory Map File =================" << QwLog::endl;
53 fMapFile->Print();
54 QwMessage << "======================================================================" << QwLog::endl;
55 } else
56#endif
57 {
58
59 TString rootfilename = fRootFileDir;
60 TString hostname = gSystem -> HostName();
61
62 // Use a probably-unique temporary file name.
63 pid_t pid = getpid();
64
65 fPermanentName = rootfilename
66 + Form("/%s%s.root", fRootFileStem.Data(), run_label.Data());
68 rootfilename += Form("/%s%s.%s.%d.root",
69 fRootFileStem.Data(), run_label.Data(),
70 hostname.Data(), pid);
71 } else {
72 rootfilename = fPermanentName;
73 }
74 fRootFile = new TFile(rootfilename.Data(), "RECREATE", "myfile1");
75 if (! fRootFile) {
76 QwError << "ROOT file " << rootfilename
77 << " could not be opened!" << QwLog::endl;
78 return;
79 } else {
80 QwMessage << "Opened "<< (fUseTemporaryFile?"temporary ":"")
81 <<"rootfile " << rootfilename << QwLog::endl;
82 }
83
84 TString run_condition_name = Form("condition_%s", run_label.Data());
85 TList *run_cond_list = (TList*) fRootFile -> FindObjectAny(run_condition_name);
86 if (not run_cond_list) {
87 QwRunCondition run_condition(
88 gQwOptions.GetArgc(),
89 gQwOptions.GetArgv(),
90 run_condition_name
91 );
92
94 run_condition.Get(),
95 run_condition.GetName()
96 );
97 }
98
99 fRootFile->SetCompressionAlgorithm(fCompressionAlgorithm);
100 fRootFile->SetCompressionLevel(fCompressionLevel);
101 }
102}
103
104
105/**
106 * Destructor
107 */
109{
110 // Keep the file on disk if any trees or histograms have been filled.
111 // Also respect any other requests to keep the file around.
113
114 // Close the map file
115 if (fMapFile) {
116 fMapFile->Close();
117 // TMapFiles may not be deleted
118 fMapFile = 0;
119 }
120
121 // Close the ROOT file.
122 // Rename if permanence is requested, remove otherwise
123 if (fRootFile) {
124 TString rootfilename = fRootFile->GetName();
125
126 fRootFile->Close();
127 delete fRootFile;
128 fRootFile = 0;
129
130 int err;
131 const char* action;
133 if (fMakePermanent) {
134 action = " rename ";
135 err = rename( rootfilename.Data(), fPermanentName.Data() );
136 } else {
137 action = " remove ";
138 err = remove( rootfilename.Data() );
139 }
140 // It'd be proper to "extern int errno" and strerror() here,
141 // but that doesn't seem very C++-ish.
142 if (err) {
143 QwWarning << "Couldn't" << action << rootfilename << QwLog::endl;
144 } else {
145 QwMessage << "Was able to" << action << rootfilename << QwLog::endl;
146 QwMessage << "Root file is " << fPermanentName << QwLog::endl;
147 }
148 }
149 }
150
151 // Delete Qweak ROOT trees
152 std::map< const std::string, std::vector<QwRootTree*> >::iterator map_iter;
153 std::vector<QwRootTree*>::iterator vec_iter;
154 for (map_iter = fTreeByName.begin(); map_iter != fTreeByName.end(); map_iter++) {
155 for (vec_iter = map_iter->second.begin(); vec_iter != map_iter->second.end(); vec_iter++) {
156 delete *vec_iter;
157 }
158 }
159}
160
161/**
162 * Defines configuration options using QwOptions functionality.
163 * @param options Options object
164 */
166{
167 // Define the ROOT files directory
168 options.AddOptions("Default options")
169 ("rootfiles", po::value<std::string>()->default_value(fDefaultRootFileDir),
170 "directory of the output ROOT files");
171
172 // Define the ROOT filename stem
173 options.AddOptions("Default options")
174 ("rootfile-stem", po::value<std::string>()->default_value(fDefaultRootFileStem),
175 "stem of the output ROOT filename");
176
177 // Define the memory map option
178 options.AddOptions()
179 ("enable-mapfile", po::value<bool>()->default_bool_value(false),
180 "enable output to memory-mapped file\n(likely requires circular-buffer too)");
181 options.AddOptions()
182 ("write-temporary-rootfiles", po::value<bool>()->default_bool_value(true),
183 "When writing ROOT files, use the PID to create a temporary filename");
184
185 // Define the histogram and tree options
186 options.AddOptions("ROOT output options")
187 ("disable-tree", po::value<std::vector<std::string>>()->composing(),
188 "disable output to tree regex");
189 options.AddOptions("ROOT output options")
190 ("disable-trees", po::value<bool>()->default_bool_value(false),
191 "disable output to all trees");
192 options.AddOptions("ROOT output options")
193 ("disable-histos", po::value<bool>()->default_bool_value(false),
194 "disable output to all histograms");
195
196 // Define the helicity window versus helicity pattern options
197 options.AddOptions("ROOT output options")
198 ("disable-mps-tree", po::value<bool>()->default_bool_value(false),
199 "disable helicity window output");
200 options.AddOptions("ROOT output options")
201 ("disable-pair-tree", po::value<bool>()->default_bool_value(false),
202 "disable helicity pairs output");
203 options.AddOptions("ROOT output options")
204 ("disable-hel-tree", po::value<bool>()->default_bool_value(false),
205 "disable helicity pattern output");
206 options.AddOptions("ROOT output options")
207 ("disable-burst-tree", po::value<bool>()->default_bool_value(false),
208 "disable burst tree");
209 options.AddOptions("ROOT output options")
210 ("disable-slow-tree", po::value<bool>()->default_bool_value(false),
211 "disable slow control tree");
212
213#ifdef HAS_RNTUPLE_SUPPORT
214 // Define the RNTuple options
215 options.AddOptions("ROOT output options")
216 ("enable-rntuples", po::value<bool>()->default_bool_value(false),
217 "enable RNTuple output");
218#endif // HAS_RNTUPLE_SUPPORT
219
220 // Define the tree output prescaling options
221 options.AddOptions("ROOT output options")
222 ("num-mps-accepted-events", po::value<int>()->default_value(0),
223 "number of accepted consecutive MPS events");
224 options.AddOptions("ROOT output options")
225 ("num-mps-discarded-events", po::value<int>()->default_value(0),
226 "number of discarded consecutive MPS events");
227 options.AddOptions("ROOT output options")
228 ("num-hel-accepted-events", po::value<int>()->default_value(0),
229 "number of accepted consecutive pattern events");
230 options.AddOptions("ROOT output options")
231 ("num-hel-discarded-events", po::value<int>()->default_value(0),
232 "number of discarded consecutive pattern events");
233 options.AddOptions("ROOT output options")
234 ("mapfile-update-interval", po::value<int>()->default_value(-1),
235 "Events between a map file update");
236
237 // Define the autoflush and autosave option (default values by ROOT)
238 options.AddOptions("ROOT performance options")
239 ("autoflush", po::value<int>()->default_value(0),
240 "TTree autoflush");
241 options.AddOptions("ROOT performance options")
242 ("autosave", po::value<int>()->default_value(300000000),
243 "TTree autosave");
244 options.AddOptions("ROOT performance options")
245 ("basket-size", po::value<int>()->default_value(16000),
246 "TTree basket size");
247 options.AddOptions("ROOT performance options")
248 ("circular-buffer", po::value<int>()->default_value(0),
249 "TTree circular buffer");
250 options.AddOptions("ROOT performance options")
251 ("compression-algorithm", po::value<int>()->default_value(1),
252 "TFile compression algorithm (default = 1 ZLIB)");
253 options.AddOptions("ROOT performance options")
254 ("compression-level", po::value<int>()->default_value(1),
255 "TFile compression level (default = 1, no compression = 0)");
256}
257
258
259/**
260 * Parse the configuration options and store in class fields
261 * @param options Options object
262 */
264{
265 // Option 'rootfiles' to specify ROOT files dir
266 fRootFileDir = TString(options.GetValue<std::string>("rootfiles"));
267
268 // Option 'root-stem' to specify ROOT file stem
269 fRootFileStem = TString(options.GetValue<std::string>("rootfile-stem"));
270
271 // Option 'mapfile' to enable memory-mapped ROOT file
272 fEnableMapFile = options.GetValue<bool>("enable-mapfile");
273#ifndef QW_ENABLE_MAPFILE
274 if( fEnableMapFile ) {
276 QwWarning << "QwRootFile::ProcessOptions: "
277 << "The 'enable-mapfile' flag is not supported by the ROOT "
278 "version with which this app is built. Disabling it."
279 << QwLog::endl;
280 fEnableMapFile = false;
281 }
282#endif
283 fUseTemporaryFile = options.GetValue<bool>("write-temporary-rootfiles");
284
285#ifdef HAS_RNTUPLE_SUPPORT
286 // Option 'enable-rntuples' to enable RNTuple output
287 fEnableRNTuples = options.GetValue<bool>("enable-rntuples");
288#endif // HAS_RNTUPLE_SUPPORT
289
290 // Options 'disable-trees' and 'disable-histos' for disabling
291 // tree and histogram output
292 auto v = options.GetValueVector<std::string>("disable-tree");
293 std::for_each(v.begin(), v.end(), [&](const std::string& s){ this->DisableTree(s); });
294 if (options.GetValue<bool>("disable-trees")) DisableTree(".*");
295 if (options.GetValue<bool>("disable-histos")) DisableHisto(".*");
296
297 // Options 'disable-mps' and 'disable-hel' for disabling
298 // helicity window and helicity pattern output
299 if (options.GetValue<bool>("disable-mps-tree")) DisableTree("^evt$");
300 if (options.GetValue<bool>("disable-pair-tree")) DisableTree("^pr$");
301 if (options.GetValue<bool>("disable-hel-tree")) DisableTree("^mul$");
302 if (options.GetValue<bool>("disable-burst-tree")) DisableTree("^burst$");
303 if (options.GetValue<bool>("disable-slow-tree")) DisableTree("^slow$");
304
305 // Options 'num-accepted-events' and 'num-discarded-events' for
306 // prescaling of the tree output
307 fNumMpsEventsToSave = options.GetValue<int>("num-mps-accepted-events");
308 fNumMpsEventsToSkip = options.GetValue<int>("num-mps-discarded-events");
309 fNumHelEventsToSave = options.GetValue<int>("num-mps-accepted-events");
310 fNumHelEventsToSkip = options.GetValue<int>("num-mps-discarded-events");
311
312 // Update interval for the map file
313 fCircularBufferSize = options.GetValue<int>("circular-buffer");
314 fUpdateInterval = options.GetValue<int>("mapfile-update-interval");
315 fCompressionAlgorithm = options.GetValue<int>("compression-algorithm");
316 fCompressionLevel = options.GetValue<int>("compression-level");
317 fBasketSize = options.GetValue<int>("basket-size");
318
319 // Autoflush and autosave
320 fAutoFlush = options.GetValue<int>("autoflush");
321 if ((ROOT_VERSION_CODE < ROOT_VERSION(5,26,00)) && fAutoFlush != -30000000){
323 QwWarning << "QwRootFile::ProcessOptions: "
324 << "The 'autoflush' flag is not supported by ROOT version "
325 << ROOT_RELEASE
326 << QwLog::endl;
327 }
328 fAutoSave = options.GetValue<int>("autosave");
329 return;
330}
331
332/**
333 * Determine whether the rootfile object has any non-empty trees or
334 * histograms.
335 */
337 return this->HasAnyFilled(fRootFile);
338}
339Bool_t QwRootFile::HasAnyFilled(TDirectory* d) {
340 if (!d) {
341
342 return false;
343 }
344
345 // First check if any in-memory trees have been filled
346 for (auto& pair : fTreeByName) {
347 for (auto& tree : pair.second) {
348 if (tree && tree->GetTree()) {
349 Long64_t entries = tree->GetTree()->GetEntries();
350 if (entries > 0) {
351
352 return true;
353 }
354 }
355 }
356 }
357
358#ifdef HAS_RNTUPLE_SUPPORT
359 // Then check if any RNTuples have been filled
360 for (auto& pair : fNTupleByName) {
361 for (auto& ntuple : pair.second) {
362 if (ntuple && ntuple->fCurrentEvent > 0) {
363
364 return true;
365 }
366 }
367 }
368#endif // HAS_RNTUPLE_SUPPORT
369
370 TList* l = d->GetListOfKeys();
371
372
373 for( int i=0; i < l->GetEntries(); ++i) {
374 const char* name = l->At(i)->GetName();
375 TObject* obj = d->FindObjectAny(name);
376
377
378
379 // Objects which can't be found don't count.
380 if (!obj) {
381
382 continue;
383 }
384
385 // Lists of parameter files, map files, and job conditions don't count.
386 if ( TString(name).Contains("parameter_file") ) {
387
388 continue;
389 }
390 if ( TString(name).Contains("mapfile") ) {
391 continue;
392 }
393 if ( TString(name).Contains("_condition") ) {
394 continue;
395 }
396 // The EPICS tree doesn't count
397 if ( TString(name).Contains("slow") ) {
398 continue;
399 }
400
401 // Recursively check subdirectories.
402 if (obj->IsA()->InheritsFrom( "TDirectory" )) {
403 if (this->HasAnyFilled( (TDirectory*)obj )) return true;
404 }
405
406 if (obj->IsA()->InheritsFrom( "TTree" )) {
407 Long64_t entries = ((TTree*) obj)->GetEntries();
408 if ( entries ) return true;
409 }
410
411 if (obj->IsA()->InheritsFrom( "TH1" )) {
412 Double_t entries = ((TH1*) obj)->GetEntries();
413 if ( entries ) return true;
414 }
415 }
416 return false;
417}
#define gQwOptions
Definition QwOptions.h:31
#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
ROOT file and tree management wrapper classes.
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:420
static Double_t kUnitsValue[]
Definition QwRootFile.h:20
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 fPermanentName
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
UInt_t fNumMpsEventsToSkip
Prescaling of events written to tree.
Bool_t fEnableMapFile
Run condition and quality management.