ATLAS Offline Software
OutputStreamData.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 
7 
8 
9 //
10 // includes
11 //
12 
14 
16 #include <RootCoreUtils/Assert.h>
18 #include <TH1.h>
19 #include <TTree.h>
20 #include <tuple>//for std::ignore
21 
22 //
23 // method implementations
24 //
25 
26 namespace EL
27 {
28  namespace Detail
29  {
30  namespace
31  {
33  class DirectoryReset {
34  public:
36  DirectoryReset() : m_dir( *gDirectory ) {}
38  ~DirectoryReset() { m_dir.cd(); }
39  private:
41  TDirectory& m_dir;
42  };
43 
44 
45 
46  struct MyWriter : public SH::DiskWriter
47  {
50 
51  public:
52  std::unique_ptr<TFile> m_file;
53 
54  explicit MyWriter (std::unique_ptr<TFile> val_file)
55  : m_file (std::move (val_file))
56  {
57  if (m_file == nullptr)
58  throw std::runtime_error ("encountered null pointer for output file");
59  m_path = m_file->GetName();
60  }
61 
62  ~MyWriter ()
63  {
64  if (m_file != 0)
65  close();
66  }
67  //cppcheck-suppress returnByReference
68  std::string getPath () const
69  {
70  return m_path;
71  }
72 
73  TFile *getFile ()
74  {
75  RCU_REQUIRE2_SOFT (m_file != 0, "file already closed");
76  return m_file.get();
77  }
78 
79  void doClose ()
80  {
81  RCU_REQUIRE2_SOFT (m_file != 0, "file already closed");
82  m_file->Write ();
83  m_file->Close ();
84  m_file = 0;
85  }
87  private:
88  std::string m_path;
89  };
90 
91 
92 
94  std::unique_ptr<TFile> checkedOpenFile (const std::string& path, const std::string& mode)
95  {
96  std::unique_ptr<TFile> result (TFile::Open (path.c_str(), mode.c_str()));
97  if (result == nullptr)
98  throw std::runtime_error ("failed to open file " + path + " with mode " + mode);
99  return result;
100  }
101  }
102 
103 
104 
106  testInvariant () const
107  {
108  RCU_INVARIANT (this != nullptr);
109  RCU_INVARIANT (m_writer != nullptr);
110  }
111 
112 
113 
115  OutputStreamData (const std::string& val_fileName, const std::string& mode)
116  : OutputStreamData (checkedOpenFile (val_fileName, mode))
117  {
118  // no invariant used
119  }
120 
121 
122 
124  OutputStreamData (std::unique_ptr<TFile> file)
125  : OutputStreamData (std::make_unique<MyWriter> (std::move (file)))
126  {
127  // no invariant used
128  }
129 
130 
131 
133  OutputStreamData (std::unique_ptr<SH::DiskWriter> val_writer)
134  : m_writer (std::move (val_writer))
135  {
136  RCU_NEW_INVARIANT (this);
137  }
138 
139 
140 
141  const std::string& OutputStreamData ::
142  mainStreamName () const noexcept
143  {
144  RCU_READ_INVARIANT (this);
145  return m_mainStreamName;
146  }
147 
148 
149 
151  setMainStreamName (const std::string& val_mainStreamName)
152  {
153  RCU_CHANGE_INVARIANT (this);
154  if (!m_mainStreamName.empty())
155  throw std::runtime_error ("main stream name already set");
156  m_mainStreamName = val_mainStreamName;
157  }
158 
159 
160 
162  file () const noexcept
163  {
164  RCU_READ_INVARIANT (this);
165  TFile *result = m_writer->file();
166  RCU_PROVIDE (result != nullptr);
167  return result;
168  }
169 
170 
171 
173  close ()
174  {
175  RCU_CHANGE_INVARIANT (this);
176  saveOutput ();
177  m_writer->close ();
178  }
179 
180 
181 
183  finalFileName () const
184  {
185  RCU_READ_INVARIANT (this);
186  return m_writer->path ();
187  }
188 
189 
190 
192  saveOutput ()
193  {
194  RCU_CHANGE_INVARIANT (this);
195  TFile *const file {m_writer->file()};
196  RCU_ASSERT (file != nullptr);
197  for (std::unique_ptr<TObject>& object : m_output)
198  {
199  std::string name = object->GetName();
200  TDirectory *dir = makeDirectoryFor (name);
201  if (dir != file)
202  {
203  TNamed *named = dynamic_cast<TNamed*>(object.get());
204  if (named)
205  named->SetName (name.c_str());
206  }
207 
208  if (!RCU::SetDirectory (object.get(), dir))
209  {
210  dir->WriteObject (object.get(), name.c_str());
211  }
212  //release object which was consumed by SetDirectory or WriteObject
213  //placate cppcheck using std::ignore
214  std::ignore = object.release();
215  }
216  m_outputHistMap.clear ();
217  m_outputTreeMap.clear ();
218  m_output.clear ();
219  }
220 
221 
222 
224  addOutput (std::unique_ptr<TObject> outputObject)
225  {
226  RCU_CHANGE_INVARIANT (this);
227 
228  TTree *const tree = dynamic_cast<TTree*> (outputObject.get());
229  if (tree)
230  {
231  std::string name = tree->GetName();
232  std::string treeName = tree->GetName();
233 
234  TDirectory *dir = makeDirectoryFor (treeName);
235 
236  // if we are in a sub-directory we need to rename the tree
237  if (name != treeName)
238  tree->SetName (treeName.c_str());
239 
240  // pass ownership of the tree to the directory
241  tree->SetDirectory (dir);
242  outputObject.release();
243 
245 
246 
247  } else
248  {
249  TH1 *const hist = dynamic_cast<TH1*> (outputObject.get());
250 
251  m_outputHistMap[outputObject->GetName()] = outputObject.get();
252  m_output.emplace_back (std::move (outputObject));
253  if (hist)
254  hist->SetDirectory (nullptr);
255  }
256  }
257 
258 
259 
261  addClone (const TObject& prototypeObject)
262  {
263  // no invariant used
264 
265  // Do not change the user's "current directory" during any of the
266  // following...
267  DirectoryReset dirReset;
268 
269  // Make a clone of the object, and make sure we are already in
270  // the right directory if needed
271  std::string name = prototypeObject.GetName();
272  TDirectory *dir = makeDirectoryFor (name);
273  dir->cd();
274 
275  std::unique_ptr<TObject> clone {prototypeObject.Clone()};
276 
277  // Hold on to the pointer of the tree in our internal cache.
278  addOutput (std::move (clone));
279  }
280 
281 
282 
284  makeDirectoryFor (std::string& name)
285  {
286  RCU_CHANGE_INVARIANT (this);
287 
288  TDirectory *result = file();
289  std::string::size_type split = name.rfind ("/");
290  if (split == std::string::npos)
291  {
292  return result;
293  } else
294  {
295  const std::string dirname = name.substr (0, split);
296  name = name.substr (split + 1);
297  TDirectory *subdir = dynamic_cast<TDirectory*>(result->Get (dirname.c_str()));
298  if (!subdir)
299  {
300  result->mkdir (dirname.c_str());
301  subdir = dynamic_cast<TDirectory*>(result->Get (dirname.c_str()));
302  RCU_ASSERT (subdir != nullptr);
303  }
304  result = subdir;
305  RCU_ASSERT (result != nullptr);
306  return result;
307  }
308  }
309 
310 
311 
313  getOutputHist (const std::string& name) const noexcept
314  {
315  RCU_READ_INVARIANT (this);
316 
317  auto iter = m_outputHistMap.find (name);
318  return iter != m_outputHistMap.end() ? iter->second : nullptr;
319  }
320 
321 
322 
324  getOutputTree (const std::string& name) const noexcept
325  {
326  RCU_READ_INVARIANT (this);
327 
328  auto iter = m_outputTreeMap.find (name);
329  return iter != m_outputTreeMap.end() ? iter->second : nullptr;
330  }
331  }
332 }
EL::Detail::OutputStreamData::addOutput
void addOutput(std::unique_ptr< TObject > outputObject)
add the given output object to this stream
Definition: OutputStreamData.cxx:224
EL::Detail::OutputStreamData::m_mainStreamName
std::string m_mainStreamName
the name of the main stream
Definition: OutputStreamData.h:176
EL::Detail::OutputStreamData
all data needed to manage a given output stream
Definition: OutputStreamData.h:30
EL::Detail::OutputStreamData::file
TFile * file() const noexcept
the file we are writing to
Definition: OutputStreamData.cxx:162
createLinkingScheme.iter
iter
Definition: createLinkingScheme.py:62
EL::Detail::OutputStreamData::m_output
std::vector< std::unique_ptr< TObject > > m_output
the list of objects to write out at the end of job
Definition: OutputStreamData.h:184
EL::Detail::OutputStreamData::getOutputHist
TObject * getOutputHist(const std::string &name) const noexcept
get the output histogram with the given name, or nullptr if there is no histogam with such a name
Definition: OutputStreamData.cxx:313
m_dir
TDirectory & m_dir
The directory we need to return to.
Definition: OutputStreamData.cxx:41
get_generator_info.result
result
Definition: get_generator_info.py:21
athena.path
path
python interpreter configuration --------------------------------------—
Definition: athena.py:128
EL::Detail::OutputStreamData::getOutputTree
TTree * getOutputTree(const std::string &name) const noexcept
get the output tree with the given name, or nullptr if there is no tree with such a name
Definition: OutputStreamData.cxx:324
RootUtils.h
make_unique
std::unique_ptr< T > make_unique(Args &&... args)
Definition: SkimmingToolEXOT5.cxx:23
plotmaker.hist
hist
Definition: plotmaker.py:148
EL::Detail::OutputStreamData::addClone
void addClone(const TObject &prototypeObject)
add a clone of the given object to the output
Definition: OutputStreamData.cxx:261
tree
TChain * tree
Definition: tile_monitor.h:30
dirname
std::string dirname(std::string name)
Definition: utils.cxx:200
EL::Detail::OutputStreamData::mainStreamName
const std::string & mainStreamName() const noexcept
the name of the main stream
Definition: OutputStreamData.cxx:142
EL::Detail::OutputStreamData::close
void close()
close this file
Definition: OutputStreamData.cxx:173
EL::Detail::OutputStreamData::setMainStreamName
void setMainStreamName(const std::string &val_mainStreamName)
Definition: OutputStreamData.cxx:151
EL::Detail::OutputStreamData::m_writer
std::unique_ptr< SH::DiskWriter > m_writer
the writer we use
Definition: OutputStreamData.h:180
Assert.h
const
bool const RAWDATA *ch2 const
Definition: LArRodBlockPhysicsV0.cxx:560
python.Utilities.clone
clone
Definition: Utilities.py:134
m_file
std::unique_ptr< TFile > m_file
description: this is a custom writer for the old-school drivers that don't use an actual writer
Definition: OutputStreamData.cxx:52
DiTauMassTools::ignore
void ignore(T &&)
Definition: PhysicsAnalysis/TauID/DiTauMassTools/DiTauMassTools/HelperFunctions.h:58
RCU_PROVIDE
#define RCU_PROVIDE(x)
Definition: Assert.h:215
EL::Detail::OutputStreamData::m_outputTreeMap
std::unordered_map< std::string, TTree * > m_outputTreeMap
the output tree map
Definition: OutputStreamData.h:192
OutputStreamData.h
EL::Detail::OutputStreamData::finalFileName
std::string finalFileName() const
the final path of the file created
Definition: OutputStreamData.cxx:183
ParseInputs.gDirectory
gDirectory
Definition: Final2012/ParseInputs.py:133
m_path
std::string m_path
the path being used
Definition: OutputStreamData.cxx:88
file
TFile * file
Definition: tile_monitor.h:29
dumpFileToPlots.treeName
string treeName
Definition: dumpFileToPlots.py:19
EL
This module defines the arguments passed from the BATCH driver to the BATCH worker.
Definition: AsgComponentFactories.h:16
Preparation.mode
mode
Definition: Preparation.py:107
SH::DiskWriter
an interface that manages writing a single output file
Definition: DiskWriter.h:29
EL::Detail::OutputStreamData::testInvariant
void testInvariant() const
test the invariant of this object
Definition: OutputStreamData.cxx:106
RCU_INVARIANT
#define RCU_INVARIANT(x)
Definition: Assert.h:201
beamspotman.dir
string dir
Definition: beamspotman.py:619
StatusCode.h
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
xAOD::DiTauJetParameters::Detail
Detail
Definition: DiTauDefs.h:38
RCU::SetDirectory
bool SetDirectory(TObject *object, TDirectory *directory)
effects: set the directory this object is associated with returns: whether the object type actively k...
Definition: RootUtils.cxx:28
EL::Detail::OutputStreamData::makeDirectoryFor
TDirectory * makeDirectoryFor(std::string &name)
make the directory for the object of the given name
Definition: OutputStreamData.cxx:284
RCU_REQUIRE2_SOFT
#define RCU_REQUIRE2_SOFT(x, y)
Definition: Assert.h:155
EL::Detail::OutputStreamData::m_outputHistMap
std::unordered_map< std::string, TObject * > m_outputHistMap
the output histogram map
Definition: OutputStreamData.h:188
get
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition: hcg.cxx:127
RCU_CHANGE_INVARIANT
#define RCU_CHANGE_INVARIANT(x)
Definition: Assert.h:231
EL::Detail::OutputStreamData::saveOutput
void saveOutput()
write the list of output objects to disk and clear it
Definition: OutputStreamData.cxx:192
python.LumiCalcRecover.subdir
subdir
Definition: LumiCalcRecover.py:25
RCU_ASSERT
#define RCU_ASSERT(x)
Definition: Assert.h:222
RCU_READ_INVARIANT
#define RCU_READ_INVARIANT(x)
Definition: Assert.h:229
Trk::split
@ split
Definition: LayerMaterialProperties.h:38
EL::Detail::OutputStreamData::OutputStreamData
OutputStreamData(const std::string &val_fileName, const std::string &mode)
open the given file and create an output stream for it
Definition: OutputStreamData.cxx:115
RCU_NEW_INVARIANT
#define RCU_NEW_INVARIANT(x)
Definition: Assert.h:233