ATLAS Offline Software
Loading...
Searching...
No Matches
RootNtupleOutputMetadataTool.cxx
Go to the documentation of this file.
1
2
3/*
4 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
5*/
6
7// RootNtupleOutputMetadataTool.cxx
8// Implementation file for class Athena::RootNtupleOutputMetadataTool
9// Author Jack Cranshaw <cranshaw@anl.gov>
11
12// AthenaRootComps includes
14#include "RootBranchAddress.h"
15
16// Gaudi
17#include "GaudiKernel/IClassIDSvc.h"
18#include "GaudiKernel/IConversionSvc.h"
19#include "GaudiKernel/IOpaqueAddress.h"
20#include "GaudiKernel/IRegistry.h"
21#include "GaudiKernel/DataObject.h"
22
23// Athena
28
29#include "TString.h"
31
32// ROOT includes
33#include "TROOT.h"
34#include "TFile.h"
35#include "TTree.h"
36
37namespace Athena {
38
40 const std::string& name,
41 const IInterface* parent) :
42 base_class(type, name, parent),
43 m_imetaStore("StoreGateSvc/InputMetaDataStore", name),
44 m_ometaStore("StoreGateSvc/MetaDataStore", name),
45 m_clidSvc("ClassIDSvc", name),
46 m_metaWritten(false)
47{
48 // Properties
49 declareProperty("InputStore",
51 "Input metadata store");
52 declareProperty("OutputStore",
54 "Output metadata store");
55 declareProperty("StreamName",
56 m_tupleName = "StreamNTUP_RED",
57 "Name of the output stream tool associated with FIXME");
58 declareProperty("TupleName",
59 m_tupleName = "atlas_ntuple",
60 "Name of the output n-tuple FIXME");
61 declareProperty("OutputFile",
63 "Name of the output file FIXME");
64}
65
68
69StatusCode
71{
72 ATH_MSG_INFO("Initializing " << name());
73
74 if (!::AthAlgTool::initialize().isSuccess()) {
75 ATH_MSG_FATAL("Cannot initialize AlgTool base class.");
76 return(StatusCode::FAILURE);
77 }
78 // Get the ClassID service
79 if (!m_clidSvc.retrieve().isSuccess()) {
80 ATH_MSG_FATAL("Cannot get ClassID service via IClassIDSvc interface.");
81 return(StatusCode::FAILURE);
82 } else {
83 ATH_MSG_DEBUG("Found ClassID service.");
84 }
85 // Get the storegate services
86 if (!m_imetaStore.retrieve().isSuccess()) {
87 ATH_MSG_FATAL("Failure retrieving input metadata store.");
88 return(StatusCode::FAILURE);
89 } else {
90 ATH_MSG_DEBUG("Found input store.");
91 }
92 if (!m_ometaStore.retrieve().isSuccess()) {
93 ATH_MSG_FATAL("Failure retrieving output metadata store.");
94 return(StatusCode::FAILURE);
95 } else {
96 ATH_MSG_DEBUG("Found output store.");
97 }
98 ServiceHandle<IIncidentSvc> incSvc("IncidentSvc", this->name());
99 if (!incSvc.retrieve().isSuccess()) {
100 ATH_MSG_ERROR("Cannot get the IncidentSvc");
101 return StatusCode::FAILURE;
102 } else {
103 ATH_MSG_INFO("Retrieved IncidentSvc");
104 }
105 incSvc->addListener(this, "BeginInputFile", 50);
106 incSvc->addListener(this, "EndInputFile", 50);
107 m_treesWritten.clear();
108
109 return(StatusCode::SUCCESS);
110}
111
112StatusCode
114{
115 ATH_MSG_DEBUG("stop() for metadata write in Tool");
116 // Make sure metadata is written
117 if(writeMetadata().isFailure()) {
118 ATH_MSG_ERROR("Could not connect for metadata writing");
119 return StatusCode::RECOVERABLE;
120 }
121
122 return StatusCode::SUCCESS;
123}
124
125StatusCode
127{
128 // Release the data store service
129 if (m_imetaStore != 0) {
130 if (!m_imetaStore.release().isSuccess()) {
131 ATH_MSG_WARNING("Could not release " << m_imetaStore.type() << " store.");
132 }
133 }
134 if (m_ometaStore != 0) {
135 if (!m_ometaStore.release().isSuccess()) {
136 ATH_MSG_WARNING("Could not release " << m_ometaStore.type() << " store.");
137 }
138 }
139 // Release the ClassID service
140 if (!m_clidSvc.release().isSuccess()) {
141 ATH_MSG_WARNING("Cannot release ClassID service.");
142 }
143 return(::AthAlgTool::finalize());
144}
145
146StatusCode RootNtupleOutputMetadataTool::postInitialize() {return StatusCode::SUCCESS;}
147StatusCode RootNtupleOutputMetadataTool::preFinalize() {return StatusCode::SUCCESS;}
148StatusCode RootNtupleOutputMetadataTool::preExecute() {return StatusCode::SUCCESS;}
149StatusCode RootNtupleOutputMetadataTool::preStream() {return StatusCode::SUCCESS;}
150StatusCode RootNtupleOutputMetadataTool::postExecute() {return StatusCode::SUCCESS;}
151
152void
154{
155 ATH_MSG_DEBUG("handle() incident type: " << inc.type());
156 if (inc.type()=="BeginInputFile") {
157 // Have to clean out any previous file metadata trees
160 StatusCode pc = m_ometaStore->retrieve(titer,tend);
161 if (pc.isSuccess()) {
162 for (; titer != tend; ++titer) {
163 if (m_ometaStore->removeDataAndProxy(&*titer).isFailure()) {
164 ATH_MSG_ERROR("Unable to remove TransferTree after writing");
165 }
166 }
167 }
168 m_treesWritten.clear();
169 }
170 else if (inc.type()=="EndInputFile") {
171 if(copyMetadata().isFailure()) ATH_MSG_ERROR("Could not copy input metadata");
172 if(writeMetadata().isFailure()) ATH_MSG_ERROR("Could not connect for metadata writing");
173 }
174}
175
176StatusCode
178{
179 ATH_MSG_INFO("RootNtupleOutputMetadataTool::writeMetadata outputName = ["
180 << m_outputName <<"]");
181 // open the file thru the i/o svc
182 ServiceHandle<IIoSvc> iosvc("IoSvc/AthIoSvc", name());
183 if (!iosvc.retrieve().isSuccess()) {
184 ATH_MSG_ERROR("could not retrieve the AthIoSvc");
185 return StatusCode::FAILURE;
186 }
187 IIoSvc::Fd fd = iosvc->open(m_outputName, IIoSvc::RECREATE);
188 if (fd < 0) {
189 ATH_MSG_ERROR("could not open-recreate file [" << m_outputName << "]");
190 return StatusCode::FAILURE;
191 }
192 if (!m_metaWritten) {
193 // Write the strings
196 StatusCode pc = m_ometaStore->retrieve(iter,end);
197 bool failure = false;
198 if (pc.isSuccess()) {
199 for (; iter != end; ++iter) {
200 std::string key = iter.key();
201 if (this->addMetadata(key,&(*iter),typeid(std::string)).isFailure()) failure=true;
202 }
203 }
204 if (failure) {
205 ATH_MSG_ERROR("Problem writing metadata");
206 return StatusCode::FAILURE;
207 }
208 m_metaWritten = true;
209 }
212 StatusCode pc = m_ometaStore->retrieve(titer,tend);
213 bool failure = false;
214 if (pc.isSuccess()) {
215 for (; titer != tend; ++titer) {
216 std::string key = titer.key();
217 if (!m_treesWritten.emplace(key).second) {
218 // Not aready in the set.
219 const TTree* x = (TTree*)titer->tree();
220 try {
221 if (this->addMetadata(key,x,typeid(TTree)).isFailure()) failure=true;
222 }
223 catch (...) {
224 ATH_MSG_INFO("Error adding metadata for TTree " << key);
225 }
226 }
227 else {ATH_MSG_WARNING("Tree " << key << " already written");}
228 }
229 }
230 if (failure) {
231 ATH_MSG_ERROR("Problem writing metadata trees");
232 return StatusCode::FAILURE;
233 }
234
235 return(StatusCode::SUCCESS);
236}
237
238StatusCode
240{
243 StatusCode pc = m_imetaStore->retrieve(iter,end);
244 bool failure = false;
245 if (pc.isSuccess()) {
246 for (; iter != end; ++iter) {
247 if (!m_ometaStore->contains<std::string>(iter.key())) {
248 std::string* toCopy = new std::string(*iter);
249 if (m_ometaStore->record(toCopy,iter.key()).isFailure()) failure=true;
250 }
251 }
252 }
253 if (failure) {
254 ATH_MSG_ERROR("Problem copying metadata");
255 return StatusCode::FAILURE;
256 }
259 pc = m_imetaStore->retrieve(titer,tend);
260 failure = false;
261 if (pc.isSuccess()) {
262 for (; titer != tend; ++titer) {
263 auto toCopy = std::make_unique<TransferTree>(*titer);
264 if (!m_ometaStore->contains<TransferTree>(titer.key())) {
265 if (m_ometaStore->record(std::move(toCopy),titer.key()).isFailure()) failure=true;
266 }
267 else ATH_MSG_INFO("Retrieve TTree with null pointer from input metadata store");
268 }
269 }
270 if (failure) {
271 ATH_MSG_ERROR("Problem copying metadata trees");
272 return StatusCode::FAILURE;
273 }
274
275 return(StatusCode::SUCCESS);
276}
277
278StatusCode
279RootNtupleOutputMetadataTool::addMetadata(const std::string& /*key*/, const void* obj, const std::type_info& /*ti*/) {
280 // HACK for compilation, set m_file and m_tree = 0
281 //TFile* m_file = 0;
282 //TTree* m_tree = 0;
283 // Reject null pointers
284 if (obj==0) {
285 REPORT_MESSAGE (MSG::ERROR) << "Attempt to write null pointer metadata";
286 return StatusCode::FAILURE;
287 }
288 // Will crash past here anyway if m_file and m_tree are both null.
289 std::abort();
290#if 0
291 // Determine directory to write into
292 std::string metaname;
293 TDirectory* dir = 0;
294 if (m_tree != 0) {
295 dir = m_tree->GetDirectory();
296 }
297 else {
298 REPORT_MESSAGE (MSG::WARNING) << "No TTree to navigate from";
299 dir = m_file->CurrentDirectory();
300 if (dir == 0) {
301 REPORT_MESSAGE (MSG::ERROR) << "No file directory to navigate from";
302 return StatusCode::FAILURE;
303 }
304 }
305 std::string thekey = key;
306 std::string::size_type sep = key.find('/');
307 if (sep != std::string::npos) {
308 metaname = key.substr (0, sep);
309
310 if (m_tree != 0) {
311 // Go to the root directory of the file.
312 while (dynamic_cast<TDirectoryFile*> (dir) != 0 &&
313 dir->GetMotherDir())
314 dir = dir->GetMotherDir();
315 thekey = m_tree->GetName();
316 }
317 }
318 else {
319 if (m_tree != 0) {
320 metaname = m_tree->GetName();
321 }
322 else {
323 metaname = "eventless";
324 }
325 metaname += "Meta";
326 }
327
328 TDirectory::TContext ctx (dir);
329 TDirectory* metadir = dir->GetDirectory (metaname.c_str());
330 if (!metadir) {
331 metadir = dir->mkdir (metaname.c_str());
332 if (!metadir) {
333 REPORT_MESSAGE (MSG::ERROR)
334 << "Can't create metadata dir " << metaname
335 << "in dir " << dir->GetName();
336 return StatusCode::RECOVERABLE;
337 }
338 }
339
340 // Set info and casts for appropriate type
341 TClass* cls = gROOT->GetClass(ti);
342 if (!cls)
343 return StatusCode::RECOVERABLE;
344
345 // If we're writing strings in a common directory, make sure name is unique.
346 if (ti == typeid(TString) || ti == typeid(std::string)) {
347 TObjString ostmp;
348 if (ti == typeid(TString)) {
349 ostmp.String() = *reinterpret_cast<const TString*> (obj);
350 obj = &ostmp;
351 cls = gROOT->GetClass ("TObjString");
352 }
353 else if (ti == typeid(std::string)) {
354 ostmp.String() = *reinterpret_cast<const std::string*> (obj);
355 obj = &ostmp;
356 cls = gROOT->GetClass ("TObjString");
357 }
358 if (key.size() > 0 && key[key.size()-1] == '/') {
359 int i = 1;
360 while (metadir->FindObject (thekey.c_str())) {
361 ++i;
362 std::ostringstream ss;
363 if (m_tree)
364 ss << m_tree->GetName();
365 else
366 ss << dir->GetName();
367 ss << "-" << i;
368 thekey = ss.str();
369 }
370 }
371
372 // Treat like hadd and create new version each time
373 if (metadir->WriteObjectAny (obj, cls, thekey.c_str(), "new") == 0) {
374 REPORT_MESSAGE (MSG::ERROR)
375 << "Can't write metadata object " << thekey
376 << " for file " << metadir->GetFile()->GetName();
377 return StatusCode::RECOVERABLE;
378 }
379 }
380 else if (ti == typeid(TTree)) {
381 TTree* readTree = ((const TTree*)obj)->GetTree();
382 metadir->cd();
383
384 // If we're writing in a common directory, make sure name is unique.
385 if (key.size() > 0) {
386 TTree* outTree = (TTree*)metadir->FindObject (thekey.c_str());
387 if (outTree == 0) {
388 outTree = readTree->CloneTree();
389 }
390 else {
391 TList tc;
392 tc.Add((TObject*)readTree);
393 Long64_t temp = outTree->Merge((TCollection*)&tc);
394 if (temp==0) {
395 REPORT_MESSAGE (MSG::ERROR) << "Unable to merge with existing tree in file";
396 return StatusCode::RECOVERABLE;
397 }
398 }
399 outTree->Write();
400 }
401 else {
402 REPORT_MESSAGE (MSG::ERROR) << "Did not use proper key for metadata tree ";
403 return StatusCode::RECOVERABLE;
404 }
405 }
406 else {
407 REPORT_MESSAGE (MSG::ERROR) << "addMetadata typeid not supported";
408 return StatusCode::FAILURE;
409 }
410 return(StatusCode::SUCCESS);
411#endif
412}
413
414}//> namespace Athena
#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)
macros to associate a CLID to a type
#define REPORT_MESSAGE(LVL)
Report a message.
void readTree(AccumulateMap &map, TTree *tree, size_t nLayers, size_t nCoords)
Reads a matrix tree, accumulating its entries into a map.
static Double_t ss
static Double_t tc
#define x
virtual StatusCode postInitialize() override
AthenaOutputTool Interface method implementations:
ServiceHandle< StoreGateSvc > m_imetaStore
ServiceHandle to the data store service.
virtual void handle(const Incident &incident) override
Incident service handle listening for Begin/End InputFile incidents.
std::string m_tupleName
Name of the output tuple.
RootNtupleOutputMetadataTool()
Default constructor:
StatusCode addMetadata(const std::string &key, const void *obj, const std::type_info &ti)
virtual StatusCode initialize() override
Gaudi AlgTool Interface method implementations:
StatusCode copyMetadata()
Connect to the output stream Must writeMetadata BEFORE streaming Only specify "outputName" if one wan...
std::string m_outputName
Name of the output name.
ServiceHandle< IClassIDSvc > m_clidSvc
ServiceHandle to clid service.
@ RECREATE
Definition IIoSvc.h:46
int Fd
unix-y file descriptor
Definition IIoSvc.h:38
a const_iterator facade to DataHandle.
Definition SGIterator.h:164
const std::string & key() const
Get the key string with which the current object was stored.
Some weak symbol referencing magic... These are declared in AthenaKernel/getMessageSvc....