ATLAS Offline Software
Loading...
Searching...
No Matches
FPGATrackSimOutputHeaderTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
8
9FPGATrackSimOutputHeaderTool::FPGATrackSimOutputHeaderTool(std::string const & algname, std::string const & name, IInterface const * ifc) :
10 AthAlgTool(algname,name,ifc) {}
11
12
13// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
14StatusCode FPGATrackSimOutputHeaderTool::openFile(std::string const & path) const
15{
16 // close old file (I don't think we delete the pointer. Does ROOT handle that?)
17 if (m_infile && m_infile->IsOpen()) m_infile->Close();
18
19 // open new file
20 ATH_MSG_DEBUG ("Opening file " << path.c_str() << " in " << m_rwoption.value() << " mode.");
21 m_infile = TFile::Open(path.c_str(), m_rwoption.value().c_str());
22
23 if (!m_infile) {
24 ATH_MSG_FATAL("Could not open input file: " << path);
25 return StatusCode::FAILURE;
26 }
27
28 if (m_rwoption.value() == std::string("READ")) {
29 // get the tree
30 m_EventTree = (TTree*) m_infile->Get(m_treeName.value().c_str());
31 if (!m_EventTree || m_EventTree->GetEntries() == -1) {
32 ATH_MSG_FATAL ("Input file: " << m_inpath.value() << " has no entries");
33 return StatusCode::FAILURE;
34 }
35
36 ATH_MSG_INFO ("Input file: " << path << " has " << m_EventTree->GetEntries() << " event entries.");
37 }
38
39 m_infile->cd();
40 m_event = 0; // in file
41 m_totevent = 0; // total counter
42 return StatusCode::SUCCESS;
43}
44
45// Since now the list of branches to read gets configured by algorithms, we can't do this in initialize().
46// We could use properties to pass the branch names to this tool, but the algorithms would need to know those
47// names too, so it may make more sense to store them as properties on individual algorithms.
48
49// Also... the properties would have to be a vector because we can have an arbitrary number of input and output headers.
50// Perhaps we don't actually *need* an arbitrary number of input and output headers but I think it's best to allow for it.
51
53
54 // Don't do anything
55 if (m_rwoption.value() != std::string("READ")) {
56 ATH_MSG_FATAL("Called configureReadBranches() when ROOT file was not opened in READ mode.");
57 return StatusCode::FAILURE;
58 }
59
60 // In read mode, we want to make sure the configured branches are actually available.
61 // Configuration is via a function call (to allow different algorithms to set up different numbers of branches).
62 for (unsigned i = 0; i < m_branchNameIns.size(); i++) {
63 std::string branchName = m_branchNameIns.at(i);
64 if (!m_EventTree->GetListOfBranches()->FindObject(branchName.c_str())) {
65 ATH_MSG_FATAL("Configured input branch: " << branchName << " not found!");
66 return StatusCode::FAILURE;
67 }
68 TBranch *branchIn = m_EventTree->GetBranch(branchName.c_str());
69 branchIn->SetAddress(&(m_eventInputHeaders.at(i)));
70 m_EventTree->SetBranchStatus(branchName.c_str(), 1);
71 }
72
73 // Do the same thing for the output branches. In fact we could maybe combine these loops by making a function.
74 for (unsigned i = 0; i < m_branchNameOuts.size(); i++) {
75 std::string branchName = m_branchNameOuts.at(i);
76 if (!m_EventTree->GetListOfBranches()->FindObject(branchName.c_str())) {
77 ATH_MSG_FATAL("Configured output branch: " << branchName << " not found!");
78 return StatusCode::FAILURE;
79 }
80 TBranch *branchIn = m_EventTree->GetBranch(branchName.c_str());
81 branchIn->SetAddress(&(m_eventOutputHeaders.at(i)));
82 m_EventTree->SetBranchStatus(branchName.c_str(), 1);
83 }
84
85 return StatusCode::SUCCESS;
86}
87
88// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
90{
91 // Dump the configuration to make sure it propagated through right
92 const std::vector<Gaudi::Details::PropertyBase*> props = this->getProperties();
93 for( Gaudi::Details::PropertyBase* prop : props ) {
94 if (prop->ownerTypeName()==this->type()) {
95 ATH_MSG_DEBUG("Property:\t" << prop->name() << "\t : \t" << prop->toString());
96 }
97 }
98
99 ATH_CHECK(m_tHistSvc.retrieve());
100
101 if( m_rwoption.value()!=std::string("HEADER"))
102 {
103 if (m_inpath.value().empty())
104 {
105 ATH_MSG_ERROR("Empty input file list");
106 return StatusCode::FAILURE;
107 }
108 ATH_CHECK(openFile(m_inpath.value().front()));
109 }
110
111 if (m_rwoption.value() == std::string("READ")) {
112 ATH_MSG_DEBUG ("Initialized in READ MODE");
113 } else if (m_rwoption.value()==std::string("RECREATE") || m_rwoption.value()==std::string("HEADER")) {
114
115 // branches are NO LONGER created here, the user needs to do this.
116 m_EventTree = new TTree(m_treeName.value().c_str(), "data");
117
118 // For HEADER-- use THistSvc explicitly to set things up.
119 if (m_rwoption.value() == std::string("HEADER")) {
120 ATH_CHECK(m_tHistSvc->regTree(Form("/FPGATRACKSIMOUTPUT/%s", m_treeName.value().c_str()), m_EventTree));
121 }
122
123 } else {
124 ATH_MSG_ERROR ("RWstatus = " << m_rwoption.value() << " is not allowed!");
125 return StatusCode::FAILURE;
126 }
127
128 m_event = 0; // in file
129 m_totevent = 0; // total counter
130 return StatusCode::SUCCESS;
131}
132
133// Create a new input or output branch and return a pointer to the header object so code can write to it.
134// These functions work for both reading and writing.
136 m_eventInputHeaders.push_back(new FPGATrackSimLogicalEventInputHeader());
137 FPGATrackSimLogicalEventInputHeader* inputHeader = m_eventInputHeaders.at(m_eventInputHeaders.size() - 1);
138 m_branchNameIns.push_back(branchName);
139 if (write) {
140 m_EventTree->Branch(branchName.c_str(), "FPGATrackSimLogicalEventInputHeader", inputHeader);
141 }
142 return inputHeader;
143}
144
146 m_eventOutputHeaders.push_back(new FPGATrackSimLogicalEventOutputHeader());
147 FPGATrackSimLogicalEventOutputHeader* outputHeader = m_eventOutputHeaders.at(m_eventOutputHeaders.size() - 1);
148 m_branchNameOuts.push_back(branchName);
149 if (write) {
150 m_EventTree->Branch(branchName.c_str(), "FPGATrackSimLogicalEventOutputHeader", outputHeader);
151 }
152 return outputHeader;
153}
154
155// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
157{
158 ATH_MSG_INFO ("finalize: closing files");
159
160 if (m_rwoption.value() == std::string("RECREATE")) {
161 ATH_MSG_INFO ("Contains " << m_EventTree->GetEntries() << " entries, over " << m_event << " events run");
162 // close the output files, but check that it exists (for athenaMP)
163 m_infile->Write();
164 }
165
166 if (m_rwoption.value() != std::string("HEADER")) {
167 m_infile->Close();
168 }
169
170 // deleting pointers
171 for (auto* header : m_eventInputHeaders) delete header;
172 for (auto* header : m_eventOutputHeaders) delete header;
173
174 return StatusCode::SUCCESS;
175}
176
177// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
178// This version of writeData assumes that the header objects were created using addInputBranch and addOutputBranch
179// and so don't need to be passed back to the tool.
181
182 if (m_rwoption.value() == std::string("READ")) {
183 ATH_MSG_WARNING ("Asked to write file in READ mode");
184 return StatusCode::SUCCESS;
185 }
186
187 ATH_MSG_DEBUG ("Writing data in TTree, event cnt=" << m_event << " limit=" << m_eventLimit << " activated" << m_activated);
188
189 // Interpret -1 as no limit.
190 if ((m_event < static_cast<unsigned>(m_eventLimit) || m_eventLimit < 0) &&
192
193 {
194 std::lock_guard<std::mutex> lock(m_writeMutex);
195 m_EventTree->Fill(); // Protected ROOT operation
196 }
197
198 m_event++;
199 m_totevent++;
200 m_activated = false;
201
202 for (unsigned i = 0; i < m_eventInputHeaders.size(); i++) {
203 ATH_MSG_DEBUG("Wrote event " << m_event << " in input header (" << m_branchNameIns.at(i) << ") event " << m_eventInputHeaders.at(i)->event());
204 }
205 for (unsigned i = 0; i < m_eventOutputHeaders.size(); i++) {
206 ATH_MSG_DEBUG("Wrote event " << m_event << " in output header (" << m_branchNameOuts.at(i) << ")");
207 ATH_MSG_DEBUG("n.roads_1st = " << m_eventOutputHeaders.at(i)->nFPGATrackSimRoads_1st());
208 ATH_MSG_DEBUG("n.roads_2nd = " << m_eventOutputHeaders.at(i)->nFPGATrackSimRoads_2nd());
209 ATH_MSG_DEBUG("n.tracks_1st = " << m_eventOutputHeaders.at(i)->nFPGATrackSimTracks_1st());
210 ATH_MSG_DEBUG("n.tracks_2nd = " << m_eventOutputHeaders.at(i)->nFPGATrackSimTracks_2nd());
211 }
212 }
213
214 // Reset any input headers that we wrote out (with debugging prints).
215 for (unsigned i = 0; i < m_eventInputHeaders.size(); i++) {
216 m_eventInputHeaders.at(i)->reset();
217 }
218
219 // Reset any output headers that we wrote out (With debugging prints).
220 for (unsigned i = 0; i < m_eventOutputHeaders.size(); i++) {
221 m_eventOutputHeaders.at(i)->reset();
222 }
223
224 // Only return FAILURe if there were no input AND output headers (i.e. something is misconfigured).
225 if (m_eventInputHeaders.size() == 0 and m_eventOutputHeaders.size() == 0) {
226 ATH_MSG_ERROR("Tried to fill output ROOT file with no configured input or output headers.");
227 return StatusCode::FAILURE;
228 }
229
230 return StatusCode::SUCCESS;
231}
232
233// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
234// Since the branches are now created using the same set of functions the user already has a pointer to the object.
235// So in this function we just need to reset those objects, test last, and... call GetEntry I think.
236StatusCode FPGATrackSimOutputHeaderTool::readData(bool &last) const
237{
238 if (m_rwoption.value() != std::string("READ")) {
239 ATH_MSG_WARNING ("Asked to read file that is not in READ mode");
240 return StatusCode::SUCCESS;
241 }
242
243 for (auto* header : m_eventInputHeaders) {
244 header->reset();
245 }
246
247 for (auto* header : m_eventOutputHeaders) {
248 header->reset();
249 }
250
251 ATH_MSG_DEBUG ("Asked Event " << m_event << " in this file; current total is " << m_totevent);
252 last = false;
253 if (m_event >= static_cast<unsigned>(m_EventTree->GetEntries())) {
254 std::lock_guard<std::mutex> lock(m_writeMutex);
255 if (m_event >= static_cast<unsigned>(m_EventTree->GetEntries())) {
256 unsigned current_file = m_file++;
257 if (current_file < m_inpath.value().size()) {
258 ATH_CHECK(openFile(m_inpath.value().at(current_file)));
259 // If opening a new file we need to update the branch addresses.
261 }
262 else {
263 last = true;
264 return StatusCode::SUCCESS;
265 }
266 }
267 }
268
269 // Protect ROOT TTree reads with mutex
270 {
271 std::lock_guard<std::mutex> lock(m_writeMutex);
272 // Read the objects. I removed some of the debug messages here, they could be readded.
273 for (const std::string& branchName : m_branchNameIns) {
274 int statIn = m_EventTree->GetBranch(branchName.c_str())->GetEntry(m_event);
275 if (statIn <= 0) ATH_MSG_WARNING("Error in reading from branch " << branchName);
276 }
277
278 for (const std::string& branchName : m_branchNameOuts) {
279 int statOut = m_EventTree->GetBranch(branchName.c_str())->GetEntry(m_event);
280 if (statOut <= 0) ATH_MSG_WARNING("Error in reading from branch " << branchName);
281 }
282 }
283
284 // increase counters
285 m_event++;
286 m_totevent++;
287
288 return StatusCode::SUCCESS;
289}
290
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
This class reads/write FPGATrackSim output data from/to a ROOT file Designed to be not thread-safe.
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
StatusCode openFile(std::string const &path) const
FPGATrackSimLogicalEventOutputHeader * addOutputBranch(const std::string &branchName, bool write=true)
std::vector< std::string > m_branchNameIns
Gaudi::Property< std::string > m_treeName
Gaudi::Property< std::string > m_rwoption
std::vector< std::string > m_branchNameOuts
virtual StatusCode initialize() override
FPGATrackSimOutputHeaderTool(const std::string &, const std::string &, const IInterface *)
Gaudi::Property< std::vector< std::string > > m_inpath
FPGATrackSimLogicalEventInputHeader * addInputBranch(const std::string &branchName, bool write=true)