ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4RootAnalysisManager.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4RootAnalysisManager.cc
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
10 // * *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
17 // * *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
25 //
26 
27 // Author: Ivana Hrivnacova, 18/06/2013 (ivana@ipno.in2p3.fr)
28 
29 #include "G4RootAnalysisManager.hh"
30 #include "G4RootFileManager.hh"
31 #include "G4RootNtupleManager.hh"
33 #include "G4RootPNtupleManager.hh"
34 #include "G4AnalysisVerbose.hh"
36 
37 #include "G4Threading.hh"
38 #include "G4AutoLock.hh"
39 
40 #include <iostream>
41 #include <cstdio>
42 
43 // mutex in a file scope
44 
45 namespace {
46  //Mutex to lock master manager when merging H1 histograms
47  G4Mutex mergeH1Mutex = G4MUTEX_INITIALIZER;
48  //Mutex to lock master manager when merging H1 histograms
49  G4Mutex mergeH2Mutex = G4MUTEX_INITIALIZER;
50  //Mutex to lock master manager when merging H1 histograms
51  G4Mutex mergeH3Mutex = G4MUTEX_INITIALIZER;
52  //Mutex to lock master manager when merging P1 profiles
53  G4Mutex mergeP1Mutex = G4MUTEX_INITIALIZER;
54  //Mutex to lock master manager when merging P2 profiles
55  G4Mutex mergeP2Mutex = G4MUTEX_INITIALIZER;
56 }
57 
60 
61 //_____________________________________________________________________________
63 {
64  if ( fgInstance == nullptr ) {
65  G4bool isMaster = ! G4Threading::IsWorkerThread();
66  fgInstance = new G4RootAnalysisManager(isMaster);
67  }
68 
69  return fgInstance;
70 }
71 
72 //_____________________________________________________________________________
74 {
75  return ( fgInstance != nullptr );
76 }
77 
78 //_____________________________________________________________________________
80  : G4ToolsAnalysisManager("Root", isMaster),
81  fNofNtupleFiles(0),
82  fNtupleRowWise(false),
83  fNtupleRowMode(true),
84  fNtupleMergeMode(G4NtupleMergeMode::kNone),
85  fNtupleManager(nullptr),
86  fSlaveNtupleManager(nullptr),
87  fFileManager(nullptr)
88 {
89  if ( ( isMaster && fgMasterInstance ) || ( fgInstance ) ) {
90  G4ExceptionDescription description;
91  description
92  << " "
93  << "G4RootAnalysisManager already exists."
94  << "Cannot create another instance.";
95  G4Exception("G4RootAnalysisManager::G4RootAnalysisManager()",
96  "Analysis_F001", FatalException, description);
97  }
98  if ( isMaster ) fgMasterInstance = this;
99  fgInstance = this;
100 
101  // File manager
102  fFileManager = std::make_shared<G4RootFileManager>(fState);
104  fFileManager->SetBasketSize(fgkDefaultBasketSize);
105  fFileManager->SetBasketEntries(fgkDefaultBasketEntries);
106 
107  // Do not merge ntuples by default
108  // Merging may require user code migration as analysis manager
109  // must be created both on master and workers.
110  auto mergeNtuples = false;
111  SetNtupleMergingMode(mergeNtuples, fNofNtupleFiles);
112 
113  // Create ntuple managers
115 }
116 
117 //_____________________________________________________________________________
119 {
120  if ( fState.GetIsMaster() ) fgMasterInstance = nullptr;
121  fgInstance = nullptr;
122 }
123 
124 //
125 // private methods
126 //
127 
128 //_____________________________________________________________________________
130  G4int nofNtupleFiles)
131 
132 {
133 #ifdef G4VERBOSE
134  if ( fState.GetVerboseL4() )
136  ->Message("set", "ntuple merging mode", "");
137 #endif
138 
139  auto canMerge = true;
140 
141  // Illegal situations
142  if ( mergeNtuples && ( ! G4Threading::IsMultithreadedApplication() ) ) {
143  if ( nofNtupleFiles > 0 ) {
144  G4ExceptionDescription description;
145  description
146  << " " << "Merging ntuples is not applicable in sequential application."
147  << G4endl
148  << " " << "Setting was ignored.";
149  G4Exception("G4RootAnalysisManager::SetNtupleMergingMode()",
150  "Analysis_W013", JustWarning, description);
151  }
152  canMerge = false;
153  }
154 
155  // Illegal situations
156  if ( mergeNtuples && G4Threading::IsMultithreadedApplication() &&
157  ( ! fgMasterInstance ) ) {
158  G4ExceptionDescription description;
159  description
160  << " " << "Merging ntuples requires G4AnalysisManager instance on master."
161  << G4endl
162  << " " << "Setting was ignored.";
163  G4Exception("G4RootAnalysisManager::SetNtupleMergingMode()",
164  "Analysis_W013", JustWarning, description);
165  canMerge = false;
166  }
167 
168  G4String mergingMode;
169  if ( ( ! mergeNtuples ) || ( ! canMerge ) ) {
170  fNtupleMergeMode = G4NtupleMergeMode::kNone;
171  mergingMode = "G4NtupleMergeMode::kNone";
172  }
173  else {
174  // Set the number of reduced ntuple files
175  fNofNtupleFiles = nofNtupleFiles;
176 
177  // Check the number of reduced ntuple files
178  // if ( fNofNtupleFiles < 0 || fNofNtupleFiles > nofThreads ) {
179  if ( fNofNtupleFiles < 0 ) {
180  G4ExceptionDescription description;
181  description
182  << " " << "Number of reduced files must be [0, nofThreads]."
183  << G4endl
184  << " " << "Cannot set " << nofNtupleFiles
185  // << " files when nofThreads is " << nofThreads << G4endl
186  << " files" << G4endl
187  << " " << "Ntuples will be merged in a single file.";
188  G4Exception("G4RootAnalysisManager::SetNtupleMergingMode()",
189  "Analysis_W013", JustWarning, description);
190  fNofNtupleFiles = 0;
191  }
192 
193  // if ( fNofNtupleFiles == nofThreads ) {
194  // // add warning that no merging will be applied
195  // fNtupleMergeMode = G4NtupleMergeMode::kNone;
196  // fNofNtupleFiles = 0;
197  // mergingMode = "G4NtupleMergeMode::kNone";
198  // }
199  // else {
200  // G4bool isMaster = ! G4Threading::IsWorkerThread();
201  // if ( isMaster ) {
202  // fNtupleMergeMode = G4NtupleMergeMode::kMain;
203  // mergingMode = "G4NtupleMergeMode::kMain";
204  // } else {
205  // fNtupleMergeMode = G4NtupleMergeMode::kSlave;
206  // mergingMode = "G4NtupleMergeMode::kSlave";
207  // }
208  // }
209 
210  // Forced merging mode
211  G4bool isMaster = ! G4Threading::IsWorkerThread();
212  if ( isMaster ) {
213  fNtupleMergeMode = G4NtupleMergeMode::kMain;
214  mergingMode = "G4NtupleMergeMode::kMain";
215  } else {
216  fNtupleMergeMode = G4NtupleMergeMode::kSlave;
217  mergingMode = "G4NtupleMergeMode::kSlave";
218  }
219  }
220 
221 #ifdef G4VERBOSE
222  if ( fState.GetVerboseL2() )
224  ->Message("set", "ntuple merging mode", mergingMode);
225 #endif
226 }
227 
228 //_____________________________________________________________________________
230 {
231 #ifdef G4VERBOSE
232  if ( fState.GetVerboseL4() )
233  fState.GetVerboseL4()->Message("clear", "ntuple managers", "");
234 #endif
235 
236  if ( fNtupleMergeMode != G4NtupleMergeMode::kSlave ) {
237  // Do not reset master ntuple manager
238  delete fNtupleManager;
239  fNtupleManager = nullptr;
240  // SetNtupleManager(fNtupleManager);
241  }
242 
243  delete fSlaveNtupleManager;
244  fSlaveNtupleManager = nullptr;
245 
246 #ifdef G4VERBOSE
247  if ( fState.GetVerboseL3() )
248  fState.GetVerboseL3()->Message("clear", "ntuple managers", "");
249 #endif
250 }
251 
252 //_____________________________________________________________________________
254 {
255 #ifdef G4VERBOSE
256  if ( fState.GetVerboseL4() )
257  fState.GetVerboseL4()->Message("create", "ntuple managers", "");
258 #endif
259 
260  switch ( fNtupleMergeMode )
261  {
262  case G4NtupleMergeMode::kNone:
266  break;
267 
268  case G4NtupleMergeMode::kMain: {
269  G4int nofMainManagers = fNofNtupleFiles;
270  if ( ! nofMainManagers ) nofMainManagers = 1;
271  // create one manager if merging required into the histos & profiles files
273  = new G4RootNtupleManager(fState, nofMainManagers, fNtupleRowWise, fNtupleRowMode);
276  break;
277  }
278 
279  case G4NtupleMergeMode::kSlave:
281  // The master class is used only in Get* functions
282  auto mainNtupleManager
285  = new G4RootPNtupleManager(mainNtupleManager, fState, fNtupleRowWise, fNtupleRowMode);
287  break;
288  }
289 
290 #ifdef G4VERBOSE
291  if ( fState.GetVerboseL3() )
292  fState.GetVerboseL3()->Message("create", "ntuple managers", "");
293 #endif
294 }
295 
296 //_____________________________________________________________________________
298 {
299  if ( ! fNofNtupleFiles ) return 0;
300 
301  G4int nofMainManagers = fNofNtupleFiles;
302  if ( ! nofMainManagers ) nofMainManagers = 1;
303 
304  // Debug - check G4Threading::GetNumberOfRunningWorkerThreads()
305  G4cout << "In GetNtupleFileNumber: "
307 
308  auto fileNumber = G4Threading::G4GetThreadId() % nofMainManagers;
309  return fileNumber;
310 }
311 
312 //_____________________________________________________________________________
314 {
315  auto h1Vector = fH1Manager->GetH1Vector();
316  auto hnVector = fH1Manager->GetHnVector();
317 
318  if ( ! h1Vector.size() ) return true;
319 
320  auto result = true;
321 
322  if ( ! G4Threading::IsWorkerThread() ) {
323  auto directory = fFileManager->GetHistoDirectory();
324  result = WriteT(h1Vector, hnVector, directory, "h1");
325  }
326  else {
327  // The worker manager just adds its histograms to the master
328  // This operation needs a lock
329  G4AutoLock lH1(&mergeH1Mutex);
331  lH1.unlock();
332  }
333 
334  return result;
335 }
336 
337 //_____________________________________________________________________________
339 {
340  auto h2Vector = fH2Manager->GetH2Vector();
341  auto hnVector = fH2Manager->GetHnVector();
342 
343  if ( ! h2Vector.size() ) return true;
344 
345  auto result = true;
346 
347  if ( ! G4Threading::IsWorkerThread() ) {
348  auto directory = fFileManager->GetHistoDirectory();
349  result = WriteT(h2Vector, hnVector, directory, "h2");
350  }
351  else {
352  // The worker manager just adds its histograms to the master
353  // This operation needs a lock
354  G4AutoLock lH2(&mergeH2Mutex);
356  lH2.unlock();
357  }
358 
359  return result;
360 }
361 
362 //_____________________________________________________________________________
364 {
365  auto h3Vector = fH3Manager->GetH3Vector();
366  auto hnVector = fH3Manager->GetHnVector();
367 
368  if ( ! h3Vector.size() ) return true;
369 
370  auto result = true;
371 
372  if ( ! G4Threading::IsWorkerThread() ) {
373  auto directory = fFileManager->GetHistoDirectory();
374  result = WriteT(h3Vector, hnVector, directory, "h3");
375  }
376  else {
377  // The worker manager just adds its histograms to the master
378  // This operation needs a lock
379  G4AutoLock lH3(&mergeH3Mutex);
381  lH3.unlock();
382  }
383 
384  return result;
385 }
386 
387 //_____________________________________________________________________________
389 {
390  auto p1Vector = fP1Manager->GetP1Vector();
391  auto hnVector = fP1Manager->GetHnVector();
392 
393  if ( ! p1Vector.size() ) return true;
394 
395  auto result = true;
396 
397  if ( ! G4Threading::IsWorkerThread() ) {
398  auto directory = fFileManager->GetHistoDirectory();
399  result = WriteT(p1Vector, hnVector, directory, "p1");
400  }
401  else {
402  // The worker manager just adds its histograms to the master
403  // This operation needs a lock
404  G4AutoLock lP1(&mergeP1Mutex);
406  lP1.unlock();
407  }
408 
409  return result;
410 }
411 
412 //_____________________________________________________________________________
414 {
415  auto p2Vector = fP2Manager->GetP2Vector();
416  auto hnVector = fP2Manager->GetHnVector();
417 
418  if ( ! p2Vector.size() ) return true;
419 
420  auto result = true;
421 
422  if ( ! G4Threading::IsWorkerThread() ) {
423  auto directory = fFileManager->GetHistoDirectory();
424  result = WriteT(p2Vector, hnVector, directory, "p2");
425  }
426  else {
427  // The worker manager just adds its histograms to the master
428  // This operation needs a lock
429  G4AutoLock lP2(&mergeP2Mutex);
431  lP2.unlock();
432  }
433 
434  return result;
435 }
436 
437 //_____________________________________________________________________________
439 {
440  if ( fNtupleMergeMode == G4NtupleMergeMode::kNone ) return true;
441 
442  auto finalResult = true;
443 
444  G4String ntupleType;
445  if ( fNtupleMergeMode == G4NtupleMergeMode::kMain ) ntupleType = "main ntuples";
446  if ( fNtupleMergeMode == G4NtupleMergeMode::kSlave ) ntupleType = "slave ntuples";
447 
448 #ifdef G4VERBOSE
449  if ( fState.GetVerboseL4() )
450  fState.GetVerboseL4()->Message("merge", ntupleType, "");
451 #endif
452 
453  if ( fNtupleMergeMode == G4NtupleMergeMode::kMain ) {
454  auto result = fNtupleManager->Merge();
455  finalResult = result && finalResult;
456  }
457 
458  if ( fNtupleMergeMode == G4NtupleMergeMode::kSlave ) {
459  auto result = fSlaveNtupleManager->Merge();
460  finalResult = result && finalResult;
461  }
462 
463 #ifdef G4VERBOSE
464  if ( fState.GetVerboseL1() )
465  fState.GetVerboseL1()->Message("merge", ntupleType, "");
466 #endif
467 
468  return finalResult;
469 }
470 
471 //_____________________________________________________________________________
473 {
474 // Reset histograms and ntuple
475 
476  auto finalResult = true;
477 
478  if ( fNtupleMergeMode == G4NtupleMergeMode::kNone ||
479  fNtupleMergeMode == G4NtupleMergeMode::kMain ) {
480  auto result = fNtupleManager->Reset(false);
481  finalResult = result && finalResult;
482  }
483 
484  return finalResult;
485 }
486 
487 //_____________________________________________________________________________
489 {
490 // Reset histograms and ntuple
491 
492  auto finalResult = true;
493 
494  auto result = G4ToolsAnalysisManager::Reset();
495  finalResult = finalResult && result;
496 
497  result = ResetNtuple();
498  finalResult = result && finalResult;
499 
500  return finalResult;
501 }
502 
503 //
504 // protected methods
505 //
506 
507 //_____________________________________________________________________________
509 {
510  auto finalResult = true;
511  auto result = fFileManager->SetFileName(fileName);
512  finalResult = finalResult && result;
513 
514  if ( fNtupleMergeMode == G4NtupleMergeMode::kNone ) {
515 
516 #ifdef G4VERBOSE
517  G4String name = fFileManager->GetFullFileName();
518  if ( fState.GetVerboseL4() )
519  fState.GetVerboseL4()->Message("open", "analysis file", name);
520 #endif
521 
522  result = fFileManager->OpenFile(fileName);
523  finalResult = finalResult && result;
524 
525  fNtupleManager->SetNtupleDirectory(fFileManager->GetNtupleDirectory());
526 
528 
529 #ifdef G4VERBOSE
530  if ( fState.GetVerboseL1() )
531  fState.GetVerboseL1()->Message("open", "analysis file", name, finalResult);
532 #endif
533 
534  }
535 
536  if ( fNtupleMergeMode == G4NtupleMergeMode::kMain ) {
537 
538 #ifdef G4VERBOSE
539  G4String name = fFileManager->GetFullFileName();
540  if ( fState.GetVerboseL4() )
541  fState.GetVerboseL4()->Message("open", "main analysis file", name);
542 #endif
543 
544  fFileManager->SetNofNtupleFiles(fNofNtupleFiles);
545  result = fFileManager->OpenFile(fileName);
546  finalResult = finalResult && result;
547 
549 
550 #ifdef G4VERBOSE
551  if ( fState.GetVerboseL1() )
552  fState.GetVerboseL1()->Message("open", "main analysis file", name, finalResult);
553 #endif
554  }
555 
556  if ( fNtupleMergeMode == G4NtupleMergeMode::kSlave ) {
557  G4cout << "Going to create slave ntuples from main" << G4endl;
558  // No file is open by Slave manager
560  }
561 
562  return finalResult;
563 }
564 
565 //_____________________________________________________________________________
567 {
568 
569  auto finalResult = true;
570 
571  if ( ! fgMasterInstance &&
572  ( ( ! fH1Manager->IsEmpty() ) || ( ! fH2Manager->IsEmpty() ) ||
573  ( ! fH3Manager->IsEmpty() ) || ( ! fP1Manager->IsEmpty() ) ||
574  ( ! fP2Manager->IsEmpty() ) ) ) {
575  G4ExceptionDescription description;
576  description
577  << " " << "No master G4RootAnalysisManager instance exists."
578  << G4endl
579  << " " << "Histogram/profile data will not be merged.";
580  G4Exception("G4RootAnalysisManager::Write()",
581  "Analysis_W031", JustWarning, description);
582  }
583 
584  // H1
585  auto result = WriteH1();
586  finalResult = finalResult && result;
587 
588  // H2
589  result = WriteH2();
590  finalResult = finalResult && result;
591 
592  // H3
593  result = WriteH3();
594  finalResult = finalResult && result;
595 
596  // P1
597  result = WriteP1();
598  finalResult = finalResult && result;
599 
600  // P2
601  result = WriteP2();
602  finalResult = finalResult && result;
603 
604  // Ntuples
605  result = WriteNtuple();
606  finalResult = finalResult && result;
607 
608  // File
609  if ( fNtupleMergeMode != G4NtupleMergeMode::kSlave ) {
610  result = fFileManager->WriteFile();
611  finalResult = finalResult && result;
612  }
613 
614  // Write ASCII if activated
615  if ( IsAscii() ) {
616  result = WriteAscii(fFileManager->GetFileName());
617  finalResult = finalResult && result;
618  }
619 
620  return finalResult;
621 }
622 
623 //_____________________________________________________________________________
625 {
626  auto finalResult = true;
627 
628  G4bool isNtupleManagerEmpty = fNtupleManager->IsEmpty();
629  // the ntuple decription vector is cleared on Reset()
630  // in kNoMergeAfterOpen ntuple manager mode
631 
632  auto result = true;
633  if ( reset ) {
634  result = Reset();
635  } else {
636  // ntuple must be reset
637  result = ResetNtuple();
638  }
639  if ( ! result ) {
640  G4ExceptionDescription description;
641  description << " " << "Resetting data failed";
642  G4Exception("G4RootAnalysisManager::CloseFile()",
643  "Analysis_W021", JustWarning, description);
644  }
645  finalResult = finalResult && result;
646 
647  if ( fNtupleMergeMode != G4NtupleMergeMode::kSlave ) {
648  // close file
649  fFileManager->CloseFile();
650  }
651 
652  // No files clean-up in sequential mode
653  if ( ! G4Threading::IsMultithreadedApplication() ) return finalResult;
654 
655  // Delete files if empty in MT mode
656  if ( ( fState.GetIsMaster() &&
658  fP1Manager->IsEmpty() && fP2Manager->IsEmpty() && isNtupleManagerEmpty ) ||
659  ( ( ! fState.GetIsMaster() ) && isNtupleManagerEmpty &&
660  fNtupleMergeMode == G4NtupleMergeMode::kNone ) ) {
661  result = ! std::remove(fFileManager->GetFullFileName());
662  // std::remove returns 0 when success
663  if ( ! result ) {
664  G4ExceptionDescription description;
665  description << " " << "Removing file "
666  << fFileManager->GetFullFileName() << " failed";
667  G4Exception("G4XmlAnalysisManager::CloseFile()",
668  "Analysis_W021", JustWarning, description);
669  }
670  finalResult = finalResult && result;
671 #ifdef G4VERBOSE
672  if ( fState.GetVerboseL1() )
674  ->Message("delete", "empty file", fFileManager->GetFullFileName());
675 #endif
676  }
677 
678  return finalResult;
679 }
680 
681 //
682 // public methods
683 //
684 
685 //_____________________________________________________________________________
687  G4int nofNtupleFiles)
688 
689 {
690  // Set ntuple merging mode
691  SetNtupleMergingMode(mergeNtuples, nofNtupleFiles);
692 
693  // Clear existing managers
695 
696  // Re-create managers
698 }
699 
700 //_____________________________________________________________________________
702 {
703 #ifdef G4VERBOSE
704  // Print info even when setting makes no effect
705  // (as we do not get printed the default setting in the output)
706  G4String rowWiseMode;
707  if ( rowWise ) {
708  rowWiseMode = "row-wise with extra branch";
709  }
710  else if ( rowMode ) {
711  rowWiseMode = "row-wise";
712  }
713  else {
714  rowWiseMode = "column-wise";
715  }
716 
717  if ( fState.GetVerboseL1() )
719  ->Message("set", "ntuple merging row mode", rowWiseMode);
720 #endif
721 
722  // Do nothing if the mode is not changed
723  if ( fNtupleRowWise == rowWise && fNtupleRowMode == rowMode ) return;
724 
725  fNtupleRowWise = rowWise;
726  fNtupleRowMode = rowMode;
727 
728  if ( fNtupleManager ) {
729  fNtupleManager->SetNtupleRowWise(rowWise, rowMode);
730  }
731 
732  if ( fSlaveNtupleManager ) {
733  fSlaveNtupleManager->SetNtupleRowWise(rowWise, rowMode);
734  }
735 }
736 
737 //_____________________________________________________________________________
738 void G4RootAnalysisManager::SetBasketSize(unsigned int basketSize)
739 {
740  fFileManager->SetBasketSize(basketSize);
741 }
742 
743 //_____________________________________________________________________________
744 void G4RootAnalysisManager::SetBasketEntries(unsigned int basketEntries)
745 {
746  fFileManager->SetBasketEntries(basketEntries);
747 }