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