BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
Data.cc
1/*
2Beam Delivery Simulation (BDSIM) Copyright (C) BDSIM Collaboration, 2001 - 2026.
3
4This file is part of BDSIM.
5
6BDSIM is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published
8by the Free Software Foundation version 3 of the License.
9
10BDSIM is distributed in the hope that it will be useful, but
11WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with BDSIM. If not, see <http://www.gnu.org/licenses/>.
17*/
18#include "Data.hh"
19#include "FileMapper.hh"
20#include "Header.hh"
21
22#include "Rtypes.h"
23#include "TDirectory.h"
24#include "TFile.h"
25#include "TTree.h"
26
27#include "BDSOutputROOTEventHeader.hh"
28
29#include <iostream>
30#include <map>
31#include <string>
32#include <vector>
33
34ClassImp(DataDummyClass)
35
36DataDummyClass::DataDummyClass()
37{;}
38
39DataDummyClass::~DataDummyClass()
40{;}
41
42TFile* DataDummyClass::CreateEmptyRebdsimFile(const std::string& fileName,
43 unsigned long long int nOriginalEventsIn)
44{
45 return RBDS::CreateEmptyRebdsimFile(fileName, nOriginalEventsIn);
46}
47
48TFile* DataDummyClass::CreateEmptyBdskimFile(const std::string& originalFileName,
49 const std::string& newOutputFileName)
50{
51 return RBDS::CreateEmptyBdskimFile(originalFileName, newOutputFileName);
52}
53
54std::map<std::string, TDirectory*> DataDummyClass::CreateDirectories(TFile* outputFile,
55 std::string treeName)
56{
57 return RBDS::CreateDirectories(outputFile, treeName);
58}
59
60TFile* RBDS::CreateEmptyRebdsimFile(const std::string& fileName,
61 unsigned long long int nOriginalEventsIn)
62{
63 TFile* outputFile = new TFile(fileName.c_str(), "RECREATE");
64
65 outputFile->cd();
67 headerOut->Fill(); // updates time stamp
68 headerOut->SetFileType("REBDSIM");
69 headerOut->nOriginalEvents = nOriginalEventsIn;
70
71 TTree* headerTree = new TTree("Header", "REBDSIM Header");
72 headerTree->Branch("Header.", "BDSOutputROOTEventHeader", headerOut);
73 headerTree->Fill();
74 headerTree->Write("", TObject::kOverwrite);
75
76 std::vector<std::string> expectedTrees = {"Beam.",
77 "Event.",
78 "Run.",
79 "Options.",
80 "Model."};
81 for (const auto& treeName : expectedTrees)
82 {RBDS::CreateDirectories(outputFile, treeName);}
83
84 return outputFile;
85}
86
87TFile* RBDS::CreateEmptyBdskimFile(const std::string& originalFileName,
88 const std::string& newOutputFileName)
89{
90 TFile* original = new TFile(originalFileName.c_str(), "READ");
91 if (!RBDS::IsBDSIMOutputFile(originalFileName))
92 {
93 std::cerr << originalFileName << " is not a BDSIM output file" << std::endl;
94 delete original;
95 return nullptr;
96 }
97 return CreateEmptyBdskimFile(original, newOutputFileName);
98}
99
100TFile* RBDS::CreateEmptyBdskimFile(TFile* originalFile,
101 const std::string& newOutputFileName)
102{
103 TTree* headerTree = dynamic_cast<TTree*>(originalFile->Get("Header")); // should be safe given check we've just done
104 if (!headerTree)
105 {std::cerr << "Error with header" << std::endl; return nullptr;}
106
107 auto headerLocal = new Header();
108 headerLocal->SetBranchAddress(headerTree);
109 Long64_t nEntriesHeader = headerTree->GetEntries();
110 headerTree->GetEntry(nEntriesHeader - 1); // get the last entry (2nd is more up to date if it exists)
111 // We also want to explicitly copy the skim variables that might only be known in the 2nd instance.
112 BDSOutputROOTEventHeader* headerOut = new BDSOutputROOTEventHeader(*(headerLocal->header));
113 headerOut->skimmedFile = true;
114
115 TFile* output = new TFile(newOutputFileName.c_str(), "RECREATE");
116 if (output->IsZombie())
117 {std::cerr << "Couldn't open output file " << newOutputFileName << std::endl; return nullptr;}
118 output->cd();
119 TTree* outputHeaderTree = new TTree("Header", "BDSIM Header");
120 outputHeaderTree->Branch("Header.", "BDSOutputROOTEventHeader", headerOut);
121 outputHeaderTree->Fill();
122
123 // Setup clones of other trees in the new output file
124 std::vector<std::string> treeNames = {"ParticleData", "Beam", "Options", "Model", "Run"};
125 for (const auto& tn : treeNames)
126 {
127 TTree* original = dynamic_cast<TTree*>(originalFile->Get(tn.c_str()));
128 if (!original)
129 {
130 std::cerr << "Failed to load Tree named " << tn << std::endl;
131 delete output;
132 delete originalFile;
133 return nullptr;
134 }
135 auto clone = original->CloneTree();
136 clone->AutoSave();
137 }
138
139 return output;
140}
141
142std::map<std::string, TDirectory*> RBDS::CreateDirectories(TFile* outputFile,
143 std::string treeName)
144{
145 // treeName typically has a "." at the end, deleting it here:
146 std::string cleanedName = treeName.erase(treeName.size() - 1);
147 std::string perEntryDirName = "PerEntryHistograms";
148 std::string simpleDirName = "SimpleHistograms";
149 std::string mergedDirName = "MergedHistograms";
150 // We have to pedantically check the existance of directories in the
151 // case we're overwriting a file, ROOT will segfault classically if
152 // the directory already exists ignoring the overwriting mode.
153 // Always more code to compensate for ROOT.
154 TDirectory* rebdsimDir = outputFile->GetDirectory(cleanedName.c_str());
155 if (!rebdsimDir)
156 {rebdsimDir = outputFile->mkdir(cleanedName.c_str());}
157 rebdsimDir->cd();
158
159 TDirectory* perEntryDir = rebdsimDir->GetDirectory(perEntryDirName.c_str());
160 if (!perEntryDir)
161 {rebdsimDir->mkdir(perEntryDirName.c_str());}
162
163 TDirectory* simpleDir = rebdsimDir->GetDirectory(simpleDirName.c_str());
164 if (!simpleDir)
165 {rebdsimDir->mkdir(simpleDirName.c_str());}
166
167 TDirectory* mergedDir = rebdsimDir->GetDirectory(mergedDirName.c_str());
168 if (!mergedDir)
169 {rebdsimDir->mkdir(mergedDirName.c_str());}
170
171 std::map<std::string, TDirectory*> result = {{cleanedName, rebdsimDir},
172 {perEntryDirName, perEntryDir},
173 {simpleDirName, simpleDir},
174 {mergedDirName, mergedDir}};
175 return result;
176}
Information about the software and the file.
bool skimmedFile
Whether this is a skimmed output file.
void SetFileType(const std::string &fileTypeIn)
Update the file type.
unsigned long long int nOriginalEvents
Number of original events if skimmed.
void Fill(const std::vector< std::string > &analysedFilesIn=std::vector< std::string >(), const std::vector< std::string > &combinedFilesIn=std::vector< std::string >())
A dummy class as ROOT won't seem to import namespaced functions in CLING for python.
Definition Data.hh:63
Header loader.
Definition Header.hh:33
TFile * CreateEmptyRebdsimFile(const std::string &fileName, unsigned long long int nOriginalEventsIn=1)
Create a new TFile and add a header to it. The header object is filled and written.
Definition Data.cc:60
bool IsBDSIMOutputFile(TFile *file, int *dataVersion=nullptr)
Definition FileMapper.cc:65
TFile * CreateEmptyBdskimFile(const std::string &originalFileName, const std::string &newOutputFileName)
Create a new TFile and add a header to it. The header object if filled and written.
Definition Data.cc:87
std::map< std::string, TDirectory * > CreateDirectories(TFile *outputFile, std::string treeName)
Definition Data.cc:142