ATLAS Offline Software
Loading...
Searching...
No Matches
AsgxAODMetNTupleMakerAlg.cxx
Go to the documentation of this file.
1// Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2
3// Local include(s):
5
6// EDM include(s):
9
10// ROOT include(s):
11#include <TTree.h>
12
13// System include(s):
14#include <regex>
15
16// Framework include(s):
18
19
20namespace {
21
22
23class TempInterface
24 : public SG::AuxVectorData
25{
26public:
27 TempInterface (size_t size) : m_size (size) {}
28 TempInterface (size_t size, SG::auxid_t auxid, void* ptr) :
29 m_size (size)
30 {
31 setCache (auxid, ptr);
32 }
33
34 using AuxVectorData::setStore;
35
36 virtual size_t size_v() const { return m_size; }
37 virtual size_t capacity_v() const { return m_size; }
38
39private:
40 size_t m_size;
41};
42
43
44} // anonymous namespace
45
46
47namespace {
48
57 char rootType( char typeidType, MsgStream& msg ) {
58
59 // Do the hard-coded translation:
60 switch( typeidType ) {
61
62 case 'c':
63 return 'B';
64 break;
65 case 'h':
66 return 'b';
67 break;
68 case 's':
69 return 'S';
70 break;
71 case 't':
72 return 's';
73 break;
74 case 'i':
75 return 'I';
76 break;
77 case 'j':
78 return 'i';
79 break;
80 case 'f':
81 return 'F';
82 break;
83 case 'd':
84 return 'D';
85 break;
86 case 'x':
87 return 'L';
88 break;
89 case 'y':
90 case 'm': // Not sure how platform-independent this one is...
91 return 'l';
92 break;
93 case 'b':
94 return 'O';
95 break;
96 default:
97 // If we didn't find this type:
98 msg << MSG::ERROR << "Received an unknown type: " << typeidType
99 << endmsg;
100 return '\0';
101 break;
102 }
103 }
104
110 bool auxItemExists( const std::string& key ) {
111 // Get a pointer to the vector factory.
113
114 // Try to find the aux item
115 return reg.findAuxID( key ) != SG::null_auxid;
116 }
117} // private namespace
118
119namespace CP {
120
122 ISvcLocator* svcLoc )
123 : EL::AnaAlgorithm( name, svcLoc ) {
124 }
125
127
128 // Check that at least one branch is configured.
129 if( m_branches.empty() ) {
130 ATH_MSG_ERROR( "No branches set up for writing" );
131 return StatusCode::FAILURE;
132 }
133
134 // Set up the systematics list.
135 ATH_CHECK( m_systematicsService.retrieve() );
136
137 // Reset the initialisation flag:
138 m_isInitialized = false;
139
140 // Return gracefully.
141 return StatusCode::SUCCESS;
142 }
143
145
146 // Initialise the processor objects on the first event.
147 if( ! m_isInitialized ) {
148 // Initialise the output tree.
150 if( ! m_tree ) {
151 ATH_MSG_ERROR( "Could not find output tree \"" << m_treeName
152 << "\"" );
153 return StatusCode::FAILURE;
154 }
155 // Call the setup function.
156 ATH_CHECK( setupTree() );
157 // The processor objects are now set up.
158 m_isInitialized = true;
159 }
160
161 // Process the standalone objects:
162 for( auto& element_itr : m_elements ) {
163 const xAOD::MissingETContainer *met = nullptr;
164 ANA_CHECK (evtStore()->retrieve (met, element_itr.first));
165 ANA_CHECK( element_itr.second.process( *(*met)[m_termName] ) );
166 }
167
168 // Return gracefully.
169 return StatusCode::SUCCESS;
170 }
171
173
174 // Return gracefully.
175 return StatusCode::SUCCESS;
176 }
177
179
180 // First process nominal
181 CP::SystematicSet nominal{};
182 for( const std::string& branchDecl : m_branches ) {
183 ATH_CHECK( setupBranch( branchDecl, nominal ) );
184 }
185
186 // Consider all systematics but skip the nominal one
187 for( const auto& sys : m_systematicsService->makeSystematicsVector() ) {
188 // Nominal already processed
189 if( sys.empty() ) {
190 continue;
191 }
192
193 // Iterate over the branch specifications.
194 for( const std::string& branchDecl : m_branches ) {
195 ATH_CHECK( setupBranch( branchDecl, sys ) );
196 }
197 }
198
199 // Return gracefully.
200 return StatusCode::SUCCESS;
201 }
202
203 StatusCode AsgxAODMetNTupleMakerAlg::setupBranch( const std::string &branchDecl,
204 const CP::SystematicSet &sys ) {
205
206 // The regular expression used to extract the needed info. The logic
207 // is supposed to be:
208 //
209 // (match[1]).(match[2])<any whitespace>-><any whitespace>(match[3])
210 //
211 // Like:
212 // "Electrons.eta -> el_eta"
213 //
214 // , where we would pick up "Electrons", "eta" and "el_eta" as the
215 // three words using this regexp.
216 static const std::regex
217 re( "\\s*([\\w%]+)\\.([\\w%]+)\\s*->\\s*([\\w%]+)" );
218
219 // Interpret this branch declaration.
220 std::smatch match;
221 if( ! std::regex_match( branchDecl, match, re ) ) {
222 ATH_MSG_ERROR( "Expression \"" << branchDecl
223 << "\" doesn't match \"<object>.<variable> ->"
224 " <branch>\"" );
225 return StatusCode::FAILURE;
226 }
227
228 // Check if we are running nominal
229 bool nominal = sys.empty();
230 // Check if we are affected by the systematics
231 bool systematicsContainer{false};
232 bool systematicsDecoration{false};
233 bool affectedContainer{true};
234 bool affectedDecoration{true};
235
236 // Event store key for the object under consideration.
237 std::string key = match[ 1 ];
238 if( key.find( "%SYS%" ) != std::string::npos )
239 {
240 systematicsContainer = true;
241 const CP::SystematicSet affecting = m_systematicsService->getObjectSystematics( key );
242 CP::SystematicSet matching;
243 ANA_CHECK( SystematicSet::filterForAffectingSystematics( sys, affecting, matching ) );
244 if( !nominal && matching.empty() ) {
245 ATH_MSG_VERBOSE( "Container \"" << key << "\" is not affected by systematics \"" << sys.name() << "\"" );
246 affectedContainer = false;
247 }
248 ANA_CHECK( m_systematicsService->makeSystematicsName( key, match[ 1 ], matching ) );
249 }
250 // Auxiliary variable name for the object under consideration.
251 std::string auxName = match[ 2 ];
252 if( auxName.find( "%SYS%" ) != std::string::npos )
253 {
254 systematicsDecoration = true;
255 CP::SystematicSet affecting = m_systematicsService->getDecorSystematics( match[ 1 ], auxName );
256 if( affecting.empty() )
257 {
258 // Sometimes while object systematics were applied we are not interested in them,
259 // NOSYS will then be used on the container name.
260 // Decoration systematics however will only be aware of containers with %SYS% included.
261 // Some special handling is needed to translate from NOSYS back to %SYS%.
262 const auto nosysInKey = key.find( "NOSYS" );
263 if( nosysInKey != std::string::npos )
264 {
265 std::string sysKey = key;
266 sysKey.replace (nosysInKey, 5, "%SYS%");
267 // these will be all systematics (object+decor)
268 const CP::SystematicSet affectingDecor = m_systematicsService->getDecorSystematics( sysKey, auxName );
269 // we now need to filter-out object systematics
270 const CP::SystematicSet affectingObject = m_systematicsService->getObjectSystematics( sysKey );
271 for( const CP::SystematicVariation &variation : affectingDecor )
272 {
273 if( affectingObject.find( variation ) == affectingObject.end() )
274 {
275 affecting.insert( variation );
276 }
277 }
278 }
279 }
280 CP::SystematicSet matching;
281 ANA_CHECK( SystematicSet::filterForAffectingSystematics( sys, affecting, matching ) );
282 if( !nominal && matching.empty() ) {
283 ATH_MSG_VERBOSE( "Decoration \"" << auxName << "\" is not affected by systematics \"" << sys.name() << "\"" );
284 affectedDecoration = false;
285 }
286 ANA_CHECK( m_systematicsService->makeSystematicsName( auxName, match[ 2 ], matching ) );
287 }
288
289 // Ignore the branch if neither container nor decoration are affected by the systematic
290 if( !nominal
291 && ( ( systematicsContainer && systematicsDecoration && !affectedContainer && !affectedDecoration )
292 || ( !systematicsContainer && systematicsDecoration && !affectedDecoration )
293 || ( systematicsContainer && !systematicsDecoration && !affectedContainer ) ) )
294 {
295 ANA_MSG_VERBOSE( "Neither container nor decoration are affected by systematics \"" << sys.name() << "\""
296 << " for branch rule \"" << branchDecl << "\"" );
297 return StatusCode::SUCCESS;
298 }
299
300 // Branch name for the variable.
301 std::string brName = match[ 3 ];
302 if( brName.find( "%SYS%" ) != std::string::npos )
303 ANA_CHECK (m_systematicsService->makeSystematicsName( brName, match[ 3 ], sys ));
304
305 // If the %SYS% pattern was not used in this setup, then stop
306 // on non-nominal systematic.
307 if( ! nominal &&
308 ( key == match[ 1 ] ) && ( auxName == match[ 2 ] ) &&
309 ( brName == match[ 3 ] ) ) {
310 return StatusCode::SUCCESS;
311 }
312
313 // Check that we use the %SYS% pattern reasonably in the names.
314 if( ( ( key == match[ 1 ] ) && ( auxName == match[ 2 ] ) &&
315 ( brName != match[ 3 ] ) ) ||
316 ( ( ( key != match[ 1 ] ) || ( auxName != match[ 2 ] ) ) &&
317 ( brName == match[ 3 ] ) ) ) {
318 ATH_MSG_ERROR( "The systematic variation pattern is used "
319 "inconsistently in: \"" << branchDecl
320 << "\"" );
321 return StatusCode::FAILURE;
322 }
323
324 // Flag keeping track whether any branch was set up for this rule.
325 static const bool ALLOW_MISSING = false;
326 bool branchCreated = false;
327
328 {
329 bool created = false;
330 ATH_CHECK( m_elements[ key ].addBranch( *m_tree,
331 auxName,
332 brName,
333 ALLOW_MISSING,
334 created ) );
335 if( created ) {
336 ATH_MSG_DEBUG( "Writing branch \"" << brName
337 << "\" from object/variable \"" << key
338 << "." << auxName << "\"" );
339 branchCreated = true;
340 } else {
341 ATH_MSG_DEBUG( "Skipping branch \"" << brName
342 << "\" from object/variable \"" << key
343 << "." << auxName << "\"" );
344 }
345 }
346
347 // Check if the rule was meaningful or not:
348 if( ! branchCreated ) {
349 ATH_MSG_ERROR( "No branch was created for rule: \""
350 << branchDecl << "\""
351 << " and systematics: \""
352 << sys.name() << "\"" );
353 return StatusCode::FAILURE;
354 }
355
356 // Return gracefully.
357 return StatusCode::SUCCESS;
358 }
359
361 : asg::AsgMessaging( "CP::AsgxAODMetNTupleMakerAlg::ElementProcessor" ) {
362
363 }
364
366 process( const SG::AuxElement& element ) {
367
368 // Process all branches.
369 for( BranchProcessor& p : m_branches ) {
370 ATH_CHECK( p.process( element, msg() ) );
371 }
372
373 // Return gracefully.
374 return StatusCode::SUCCESS;
375 }
376
378 addBranch( TTree& tree, const std::string& auxName,
379 const std::string& branchName,
380 bool allowMissing,
381 bool &created ) {
382
384 class BranchFinder {
385 public:
387 typedef const BranchProcessor& argument_type;
389 BranchFinder( const std::string& branchName ) : m_name( branchName ) {}
391 bool operator()( argument_type bp ) const {
392 return ( bp.m_branchName == m_name );
393 }
394 private:
395 std::string m_name;
396 }; // class BranchFinder
397
398 // Check if the corresponding aux item exists
399 bool validAuxItem = auxItemExists( auxName );
400 if( ! validAuxItem ) {
401 if( allowMissing ) {
402 // Return gracefully.
403 ATH_MSG_DEBUG( "Aux item \"" << auxName
404 << "\" not readable for branch \""
405 << branchName << "\"" );
406 return StatusCode::SUCCESS;
407 } else {
408 // Return gracefully.
409 ATH_MSG_ERROR( "Aux item \"" << auxName
410 << "\" not readable for branch \""
411 << branchName << "\"" );
412 return StatusCode::FAILURE;
413 }
414 }
415
416 // Check whether this branch is already set up:
417 auto itr = std::find_if( m_branches.begin(), m_branches.end(),
418 BranchFinder( branchName ) );
419 if( itr != m_branches.end() ) {
420 ATH_MSG_WARNING( "Duplicate setup received for branch: " << branchName );
421 return StatusCode::SUCCESS;
422 }
423
424 created = true;
425
426 // Set up the new branch.
427 m_branches.emplace_back();
428 ATH_CHECK( m_branches.back().setup( tree, auxName, branchName, msg() ) );
429
430 // Return gracefully.
431 return StatusCode::SUCCESS;
432 }
433
434 StatusCode
436 setup( TTree& tree, const std::string& auxName,
437 const std::string& branchName, MsgStream& msg ) {
438
439 // Remember the branch name.
440 m_branchName = branchName;
441
442 // Create the accessor.
443 m_acc.reset( new SG::TypelessConstAccessor( auxName ) );
444
445 // Get a pointer to the vector factory.
447 const std::type_info* ti = reg.getType( m_acc->auxid() );
448 if( ! ti ) {
449 msg << MSG::ERROR
450 << "No std::type_info available for auxiliary variable: "
451 << auxName << endmsg;
452 return StatusCode::FAILURE;
453 }
454 m_factory = reg.getFactory( m_acc->auxid() );
455 if( ! m_factory ) {
456 msg << MSG::ERROR << "No factory found for auxiliary variable: "
457 << auxName << endmsg;
458 return StatusCode::FAILURE;
459 }
460
461 // Create the data object.
462 m_data = m_factory->create( m_acc->auxid(), 1, 1, false );
463
464 // Pointer to the branch, to be created.
465 TBranch* br = nullptr;
466
467 // Decide whether we're dealing with a "primitive" or an "object" branch.
468 if( strlen( ti->name() ) == 1 ) {
469
470 // This is a "primitive" variable...
471
472 // Get the type identifier for it that ROOT will understand.
473 const char rType = rootType( ti->name()[ 0 ], msg );
474 if( rType == '\0' ) {
475 msg << MSG::ERROR << "Type not recognised for variable: "
476 << branchName << endmsg;
477 return StatusCode::FAILURE;
478 }
479
480 // Construct the type description.
481 std::ostringstream typeDesc;
482 typeDesc << branchName << "/" << rType;
483
484 // Create the primitive branch.
485 br = tree.Branch( branchName.c_str(), m_data->toPtr(),
486 typeDesc.str().c_str() );
487
488 } else {
489
490 // This is an "object" variable...
491
492 // Get a proper type name for the variable.
493 const std::string typeName = SG::normalizedTypeinfoName( *ti );
494
495 // Access the dictionary for the type.
496 TClass* cl = TClass::GetClass( *ti );
497 if( ! cl ) {
498 cl = TClass::GetClass( typeName.c_str() );
499 }
500 if( ! cl ) {
501 msg << MSG::ERROR << "Couldn't find dictionary for type: "
502 << typeName << endmsg;
503 return StatusCode::FAILURE;
504 }
505 if( ! cl->GetStreamerInfo() ) {
506 msg << MSG::ERROR << "No streamer info available for type: "
507 << cl->GetName() << endmsg;
508 return StatusCode::FAILURE;
509 }
510
511 // Create the object branch.
512 m_dataPtr = m_data->toPtr();
513 br = tree.Branch( branchName.c_str(), cl->GetName(), &m_dataPtr );
514
515 }
516
517 // Check that the branch creation succeeded.
518 if( ! br ) {
519 msg << MSG::ERROR << "Failed to create branch: " << branchName
520 << endmsg;
521 return StatusCode::FAILURE;
522 }
523
524 // Return gracefully.
525 return StatusCode::SUCCESS;
526 }
527
528 StatusCode
530 process( const SG::AuxElement& element, MsgStream& msg ) {
531
532 // A security check.
533 if( ( ! m_acc ) || ( ! m_factory ) || ( ! m_data ) ) {
534 msg << MSG::FATAL << "Internal logic error detected" << endmsg;
535 return StatusCode::FAILURE;
536 }
537
538 // Get the data out of the xAOD object.
539 //const void* auxData = ( *m_acc )( element );
540
541 // Copy it into the output variable.
542 TempInterface dstiface (m_data->size(), m_acc->auxid(), m_data->toPtr());
543 m_factory->copy( m_acc->auxid(), dstiface, 0,
544 *element.container(), element.index(), 1 );
545
546 // Return gracefully.
547 return StatusCode::SUCCESS;
548 }
549
550} // namespace CP
const boost::regex re(r_e)
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
#define ANA_MSG_VERBOSE(xmsg)
Macro printing verbose messages.
#define ANA_CHECK(EXP)
check whether the given expression was successful
TTree * tree(const std::string &treeName, const std::string &tDir="", const std::string &stream="")
Simplify the retrieval of registered TTrees.
std::string m_name
Instance name.
Class writing one variable from an xAOD object into a branch.
std::unique_ptr< SG::IAuxTypeVector > m_data
The object managing the memory of the written variable.
StatusCode setup(TTree &tree, const std::string &auxName, const std::string &branchName, MsgStream &msg)
Function setting up the object, and the branch.
std::unique_ptr< SG::TypelessConstAccessor > m_acc
Object accessing the variable in question.
const SG::IAuxTypeVectorFactory * m_factory
Pointer to the helper object that handles this variable.
StatusCode process(const SG::AuxElement &element, MsgStream &msg)
Function processing the object, filling the variable.
void * m_dataPtr
Helper variable, pointing at the object to be written.
StatusCode addBranch(TTree &tree, const std::string &auxName, const std::string &branchName, bool allowMissing, bool &created)
Add one branch to the output tree.
StatusCode process(const SG::AuxElement &element)
Process the object.
std::list< BranchProcessor > m_branches
List of branch processors set up for this xAOD object.
TTree * m_tree
The tree being written.
std::unordered_map< std::string, ElementProcessor > m_elements
Objects to write branches from.
ServiceHandle< ISystematicsSvc > m_systematicsService
the handle for the systematics service
StatusCode setupBranch(const std::string &branchDecl, const CP::SystematicSet &sys)
Function setting up an individual branch on the first event.
Gaudi::Property< std::vector< std::string > > m_branches
The branches to write into this output tree.
bool m_isInitialized
Internal status flag, showing whether the algorithm is initialised.
Gaudi::Property< std::string > m_treeName
The name of the output tree to write.
StatusCode finalize() override
Function executed as part of the job finalisation.
AsgxAODMetNTupleMakerAlg(const std::string &name, ISvcLocator *svcLoc)
Algorithm constructor.
StatusCode initialize() override
Function executed as part of the job initialisation.
StatusCode setupTree()
Function setting up the internal data structures on the first event.
StatusCode execute() override
Function executed once per event.
Gaudi::Property< std::string > m_termName
Class to wrap a set of SystematicVariations.
bool empty() const
returns: whether the set is empty
const_iterator end() const
description: const iterator to the end of the set
void insert(const SystematicVariation &systematic)
description: insert a systematic into the set
iterator find(const SystematicVariation &sys) const
description: find an element in the set
static StatusCode filterForAffectingSystematics(const SystematicSet &systConfig, const SystematicSet &affectingSystematics, SystematicSet &filteredSystematics)
description: filter the systematics for the affected systematics returns: success guarantee: strong f...
AnaAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
constructor with parameters
Base class for elements of a container that can have aux data.
Definition AuxElement.h:483
const SG::AuxVectorData * container() const
Return the container holding this element.
size_t index() const
Return the index of this element within its container.
Handle mappings between names and auxid_t.
static AuxTypeRegistry & instance()
Return the singleton registry instance.
Manage lookup of vectors of auxiliary data.
Helper class to provide const generic access to aux data.
MsgStream & msg() const
The standard message stream.
AsgMessaging(const std::string &name)
Constructor with a name.
bool match(std::string s1, std::string s2)
match the individual directories of two strings
Definition hcg.cxx:357
Select isolated Photons, Electrons and Muons.
This module defines the arguments passed from the BATCH driver to the BATCH worker.
std::string normalizedTypeinfoName(const std::type_info &info)
Convert a type_info to a normalized string representation (matching the names used in the root dictio...
static const auxid_t null_auxid
To signal no aux data item.
Definition AuxTypes.h:30
size_t auxid_t
Identifier for a particular aux data item.
Definition AuxTypes.h:27
char rootType(char typeidType)
This function is used internally in the code when creating primitive dynamic auxiliary branches.
Convert a type_info to a normalized string representation (matching the names used in the root dictio...
MsgStream & msg
Definition testRead.cxx:32
TChain * tree