ATLAS Offline Software
Loading...
Searching...
No Matches
TreeBranchHelpers.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5//
6// includes
7//
8
10
11// EDM include(s):
19
20// ROOT include(s):
21#include <TClass.h>
22#include <TTree.h>
23#include <TBranch.h>
24#include <TVirtualCollectionProxy.h>
25
26// System include(s):
27#include <regex>
28#include <algorithm>
29#include <functional>
30#include <sstream>
31
32//
33// method implementations
34//
35
36namespace {
37
38
39class TempInterface
40 : public SG::AuxVectorData
41{
42public:
43 TempInterface (size_t size) : m_size (size) {}
44 TempInterface (size_t size, SG::auxid_t auxid, void* ptr) :
45 m_size (size)
46 {
47 setCache (auxid, ptr);
48 }
49
50 using AuxVectorData::setStore;
51
52 virtual size_t size_v() const { return m_size; }
53 virtual size_t capacity_v() const { return m_size; }
54
55private:
56 size_t m_size;
57};
58
59
60} // anonymous namespace
61
62
63namespace {
64
65#ifdef XAOD_STANDALONE
66
79 const SG::AuxVectorBase* getVector( const std::string& key,
80 asg::SgTEvent& evtStore,
81 bool allowMissing,
82 const TClass*& cl,
83 MsgStream& msg ) {
84 if( allowMissing &&
85 ( ! evtStore.contains< const SG::AuxVectorBase >( key ) ) ) {
86 return nullptr;
87 }
88 const SG::AuxVectorBase* c = nullptr;
89 if( ! evtStore.retrieve( c, key ).isSuccess() ) {
90 msg << MSG::ERROR << "Couldn't retrieve container with key \"" << key
91 << "\"" << endmsg;
92 return nullptr;
93 }
94 const xAOD::THolder* holder = evtStore.tds()->holder( key );
95 if( holder != nullptr ) {
96 // If the object is in the transient store, get the type of it from
97 // the transient store itself. So that ConstDataVector types would be
98 // handled correctly.
99 const std::type_info* ti = holder->getTypeInfo();
100 cl = TClass::GetClass( *ti );
101 } else {
102 // If the object is not in the transient store, let's just use its
103 // "actual type".
104 cl = TClass::GetClass( typeid( *c ) );
105 }
106 if( ( allowMissing == false ) && ( cl == nullptr ) ) {
107 msg << MSG::ERROR
108 << "Couldn't find TClass dictionary for container \"" << key
109 << "\"" << endmsg;
110 return nullptr;
111 }
112
113 // Return the vector object.
114 return c;
115 }
116
128 const SG::AuxElement* getElement( const std::string& key,
129 asg::SgTEvent& evtStore,
130 bool allowMissing,
131 MsgStream& msg ) {
132 if( allowMissing &&
133 ( ! evtStore.contains< const SG::AuxElement >( key ) ) ) {
134 return nullptr;
135 }
136 const SG::AuxElement* e = nullptr;
137 if( ! evtStore.retrieve( e, key ).isSuccess() ) {
138 msg << MSG::ERROR << "Couldn't retrieve object with key \"" << key
139 << "\"" << endmsg;
140 return nullptr;
141 }
142 return e;
143 }
144
145#else
146
148 class ProxyWithName {
149 public:
151 typedef const SG::DataProxy* argument_type;
153 ProxyWithName( const std::string& name ) : m_name( name ) {}
155 bool operator()( argument_type proxy ) const {
156 return ( proxy->name() == m_name );
157 }
158 private:
159 std::string m_name;
160 }; // class ProxyWithName
161
174 const SG::AuxVectorBase* getVector ATLAS_NOT_CONST_THREAD_SAFE ( const std::string& key,
175 IProxyDict& evtStore,
176 bool allowMissing,
177 const TClass*& cl,
178 MsgStream& msg ) {
179
180 // Find all proxies with this key:
181 auto proxies = evtStore.proxies();
182 proxies.erase( std::remove_if( proxies.begin(), proxies.end(),
183 std::not_fn( ProxyWithName( key ) ) ),
184 proxies.end() );
185 // Now iterate over them:
186 for( const SG::DataProxy* proxy : proxies ) {
187 // We need a non-const version of it... :-(
188 SG::DataProxy* proxy_nc = const_cast< SG::DataProxy* >( proxy );
189 // Try to get the right object out of it.
190 DataBucketBase* bucket =
191 dynamic_cast< DataBucketBase* >( proxy_nc->accessData() );
192 if( ! bucket ) {
193 // This is a big problem in the job. Return right away.
194 msg << MSG::ERROR
195 << "Couldn't access data object as a data bucket?!?" << endmsg;
196 return nullptr;
197 }
198 // Get the dictionary for the type:
199 cl = TClass::GetClass( bucket->tinfo() );
200 if( ! cl ) {
201 if( msg.level() <= MSG::VERBOSE ) {
202 msg << MSG::VERBOSE << "No dictionary found for: "
203 << bucket->tinfo().name() << endmsg;
204 }
205 continue;
206 }
207 // Check whether the object inherits from AuxVectorBase:
208 if( ! cl->InheritsFrom( "SG::AuxVectorBase" ) ) {
209 if( msg.level() <= MSG::VERBOSE ) {
210 msg << MSG::VERBOSE << "Object \"" << key << "/" << cl->GetName()
211 << "\" does not inherit from SG::AuxVectorBase" << endmsg;
212 }
213 continue;
214 }
215 // If all is well, just assume that the inheritance is direct/simple:
217 reinterpret_cast< const SG::AuxVectorBase* >( bucket->object() );
218 return result;
219 }
220
221 // Apparently we failed...
222 if( ! allowMissing ) {
223 msg << MSG::ERROR << "Couldn't retrieve object \"" << key
224 << "\" as SG::AuxVectorBase" << endmsg;
225 }
226 return nullptr;
227 }
228
240 const SG::AuxElement* getElement ATLAS_NOT_CONST_THREAD_SAFE ( const std::string& key,
241 StoreGateSvc& evtStore,
242 bool allowMissing,
243 MsgStream& msg ) {
244
245
246 const SG::AuxElement* e = nullptr;
247 if( !evtStore.retrieve( e, key ).isSuccess() ) {
248 if(!allowMissing) {
249 msg << MSG::ERROR << "Couldn't retrieve object with key \"" << key
250 << "\"" << endmsg;
251 }
252 return nullptr;
253 }
254 return e;
255
256 }
257#endif // XAOD_STANDALONE
258
267 char rootType( char typeidType, MsgStream& msg ) {
268
269 // Do the hard-coded translation:
270 switch( typeidType ) {
271
272 case 'c':
273 return 'B';
274 break;
275 case 'h':
276 return 'b';
277 break;
278 case 's':
279 return 'S';
280 break;
281 case 't':
282 return 's';
283 break;
284 case 'i':
285 return 'I';
286 break;
287 case 'j':
288 return 'i';
289 break;
290 case 'f':
291 return 'F';
292 break;
293 case 'd':
294 return 'D';
295 break;
296 case 'x':
297 return 'L';
298 break;
299 case 'y':
300 case 'm': // Not sure how platform-independent this one is...
301 return 'l';
302 break;
303 case 'b':
304 return 'O';
305 break;
306 default:
307 // If we didn't find this type:
308 msg << MSG::ERROR << "Received an unknown type: " << typeidType
309 << endmsg;
310 return '\0';
311 break;
312 }
313 }
314} // private namespace
315
316namespace CP
317{
318 namespace TreeBranchHelpers
319 {
320 StatusCode BranchConfig ::
321 parse (const std::string& branchDecl, MsgStream& msg)
322 {
323 // The regular expression used to extract the needed info. The logic
324 // is supposed to be:
325 //
326 // (match[1]).(match[2])<any whitespace>-><any whitespace>(match[3])[<any whitespace>type=(match[5])][<any whitespace>metTerm=(match[7])][<any whitespace>basketSize=(match[9])]
327 //
328 // Like:
329 // "Electrons.eta -> el_eta"
330 // "Electrons.eta -> el_eta type=float"
331 // "MissingET.px -> met_px metTerm=Final"
332 static const std::regex
333 re( "\\s*([\\w%]+)\\.([\\w%]+)\\s*->\\s*([\\w%]+)(\\s+type=([\\w%]+))?(\\s+metTerm=([\\w%]+))?(\\s+basketSize=([\\w%]+))?" );
334
335 // Interpret this branch declaration.
336 std::smatch match;
337 if( ! std::regex_match( branchDecl, match, re ) ) {
338 msg << MSG::ERROR << "Expression \"" << branchDecl << "\" doesn't match \"<object>.<variable> -> <branch>\"" << endmsg;
339 return StatusCode::FAILURE;
340 }
341 this->branchDecl = branchDecl;
342 sgName = match[ 1 ];
343 auxName = match[ 2 ];
344 branchName = match[ 3 ];
345 typeName = match[ 5 ];
346 metTermName = match[ 7 ];
347 if (match[9].matched) {
348 try {
349 basketSize = std::stoi(match[9]);
350 } catch (const std::exception& ) {
351 msg << MSG::ERROR << "Could not parse basket size value: " << match[9] << endmsg;
352 return StatusCode::FAILURE;
353 }
354 }
355 return StatusCode::SUCCESS;
356 }
357
358
359
360 StatusCode BranchConfig ::
361 configureTypes (std::set<std::string>& decosWithoutType, MsgStream& msg)
362 {
363 std::string nominalAuxName = auxName;
364 if (auto pos = nominalAuxName.find ("%SYS%"); pos != std::string::npos)
365 nominalAuxName.replace (pos, 5, "NOSYS");
366 if (!typeName.empty())
367 {
368 if (typeName == "char")
369 SG::ConstAccessor<char> {nominalAuxName};
370 else if (typeName == "float")
371 SG::ConstAccessor<float> {nominalAuxName};
372 else if (typeName == "int")
373 SG::ConstAccessor<int> {nominalAuxName};
374 else if (typeName == "unsigned")
375 SG::ConstAccessor<unsigned> {nominalAuxName};
376 else if (typeName == "unsigned_char")
377 SG::ConstAccessor<unsigned char> {nominalAuxName};
378 else if (typeName == "unsigned_long_long")
380 else if (typeName == "int8")
381 SG::ConstAccessor<std::int8_t> {nominalAuxName};
382 else if (typeName == "int16")
383 SG::ConstAccessor<std::int16_t> {nominalAuxName};
384 else if (typeName == "int32")
385 SG::ConstAccessor<std::int32_t> {nominalAuxName};
386 else if (typeName == "int64")
387 SG::ConstAccessor<std::int64_t> {nominalAuxName};
388 else if (typeName == "uint8")
389 SG::ConstAccessor<std::uint8_t> {nominalAuxName};
390 else if (typeName == "uint16")
391 SG::ConstAccessor<std::uint16_t> {nominalAuxName};
392 else if (typeName == "uint32")
393 SG::ConstAccessor<std::uint32_t> {nominalAuxName};
394 else if (typeName == "uint64")
395 SG::ConstAccessor<std::uint64_t> {nominalAuxName};
396 else if (typeName == "vector_float")
397 SG::ConstAccessor<std::vector<float>> {nominalAuxName};
398 else if (typeName == "vector_int")
399 SG::ConstAccessor<std::vector<int>> {nominalAuxName};
400 else if (typeName == "vector_vector_float")
402 else if (typeName == "vector_vector_int")
404 else
405 {
406 unsigned line = __LINE__ - 2;
407 std::string file = __FILE__;
408 file = file.substr (file.find_last_of("/\\") + 1);
409 msg << MSG::ERROR << "Unknown type requested, please extend " << file << " near line " << line << " for type " << typeName << endmsg;
410 return StatusCode::FAILURE;
411 }
412 }
415 {
416 nominalAuxId = reg.findAuxID (nominalAuxName);
418 {
419 decosWithoutType.insert (nominalAuxName);
420 msg << MSG::DEBUG << "No aux ID found for auxiliary variable: " << nominalAuxName << endmsg;
421 // just returning SUCCESS here, our caller will report failure
422 return StatusCode::SUCCESS;
423 }
424 }
425 if (auxType == nullptr)
426 {
427 auxType = reg.getType (nominalAuxId);
428 if (auxType == nullptr)
429 {
430 msg << MSG::ERROR
431 << "No std::type_info available for aux-store variable: "
432 << nominalAuxName << endmsg;
433 return StatusCode::FAILURE;
434 }
435 }
436 if (auxVecType == nullptr)
437 {
438 auxVecType = reg.getVecType (nominalAuxId);
439 if (auxVecType == nullptr)
440 {
441 msg << MSG::ERROR
442 << "No std::type_info available for aux-store variable: "
443 << nominalAuxName << endmsg;
444 return StatusCode::FAILURE;
445 }
446 }
447 if (auxFactory == nullptr)
448 {
449 auxFactory = reg.getFactory (nominalAuxId);
450 if (auxFactory == nullptr)
451 {
452 msg << MSG::ERROR
453 << "No factory found for auxiliary variable: "
454 << nominalAuxName << endmsg;
455 return StatusCode::FAILURE;
456 }
457 }
458 return StatusCode::SUCCESS;
459 }
460
461
462
463 StatusCode BranchConfig ::
464 configureSystematics (ISystematicsSvc& sysSvc, MsgStream& msg)
465 {
466 if (sgName.find ("%SYS%") == std::string::npos &&
467 auxName.find ("%SYS%") == std::string::npos &&
468 branchName.find ("%SYS%") == std::string::npos)
469 {
470 nominalOnly = true;
471 }
472 if (!nominalOnly)
473 {
474 if (branchName.find ("%SYS%") == std::string::npos)
475 {
476 msg << MSG::ERROR << "Branch with systematics without %SYS% in branch name: "
477 << branchName << endmsg;
478 return StatusCode::FAILURE;
479 }
480 if (sgName.find ("%SYS%") == std::string::npos &&
481 auxName.find ("%SYS%") == std::string::npos)
482 {
483 msg << MSG::ERROR << "Branch with systematics without %SYS% in SG or aux name: "
484 << sgName << "." << auxName << endmsg;
485 return StatusCode::FAILURE;
486 }
487 if (auxName.find ("NOSYS") != std::string::npos)
488 {
489 msg << MSG::ERROR << "Branch with systematics with NOSYS in aux name: "
490 << sgName << "." << auxName << endmsg;
491 return StatusCode::FAILURE;
492 }
493 if (sgName.find ("NOSYS") != std::string::npos && auxName.find ("%SYS%") == std::string::npos)
494 {
495 msg << MSG::ERROR << "Branch with NOSYS in SG name but without %SYS% in aux name: "
496 << sgName << "." << auxName << endmsg;
497 return StatusCode::FAILURE;
498 }
499
500 if (sgName.find ("%SYS%") != std::string::npos)
502
503 if (auxName.find ("%SYS%") != std::string::npos)
504 {
505 if (auto pos = sgName.find ("NOSYS"); pos == std::string::npos)
507 else
508 {
509 // Sometimes while object systematics were applied we are not interested in them,
510 // NOSYS will then be used on the container name.
511 // Decoration systematics however will only be aware of containers with %SYS% included.
512 // Some special handling is needed to translate from NOSYS back to %SYS%.
513 std::string sgNameSys = sgName;
514 sgNameSys.replace (pos, 5, "%SYS%");
515
516 // these will be the object systematics
517 auto objectSys = sysSvc.getObjectSystematics (sgNameSys);
518
519 // these will be all systematics (object+decor)
520 auto allSys = sysSvc.getDecorSystematics (sgNameSys, auxName);
521
522 // we now need to filter-out object systematics
523 for (auto& variation : allSys)
524 {
525 if (objectSys.find (variation) == objectSys.end())
526 auxNameFilterSys.insert (variation);
527 }
528 }
529 }
530
533 if (branchNameFilterSys.empty())
534 nominalOnly = true;
535 }
536
537 return StatusCode::SUCCESS;
538 }
539
540
541
542 StatusCode OutputBranchData ::
543 configureNames (const BranchConfig& branchConfig, const CP::SystematicSet& sys, ISystematicsSvc& sysSvc, MsgStream& msg)
544 {
545 isNominal = true;
546
547 if (branchConfig.sgName.find ("%SYS%") != std::string::npos)
548 {
549 CP::SystematicSet matching;
550 if (SystematicSet::filterForAffectingSystematics (sys, branchConfig.sgNameFilterSys, matching).isFailure())
551 return StatusCode::FAILURE;
552 if (sysSvc.makeSystematicsName (sgName, branchConfig.sgName, matching).isFailure())
553 return StatusCode::FAILURE;
554 if (!matching.empty())
555 isNominal = false;
556 } else
557 sgName = branchConfig.sgName;
558
559 if (branchConfig.auxName.find ("%SYS%") != std::string::npos)
560 {
561 CP::SystematicSet matching;
562 if (SystematicSet::filterForAffectingSystematics (sys, branchConfig.auxNameFilterSys, matching).isFailure())
563 return StatusCode::FAILURE;
564 if (sysSvc.makeSystematicsName (auxName, branchConfig.auxName, matching).isFailure())
565 return StatusCode::FAILURE;
566 if (!matching.empty())
567 isNominal = false;
568 } else
569 auxName = branchConfig.auxName;
570
571 if (branchConfig.branchName.find ("%SYS%") != std::string::npos)
572 {
573 CP::SystematicSet matching;
574 if (SystematicSet::filterForAffectingSystematics (sys, branchConfig.branchNameFilterSys, matching).isFailure())
575 return StatusCode::FAILURE;
576 if (sysSvc.makeSystematicsName (branchName, branchConfig.branchName, matching).isFailure())
577 return StatusCode::FAILURE;
578 if (matching.empty() && !isNominal)
579 {
580 msg << MSG::FATAL << "Branch \"" << branchName << "\" is not affected by any of the requested systematics but is not nominal." << endmsg;
581 return StatusCode::FAILURE;
582 }
583 } else
584 {
585 branchName = branchConfig.branchName;
586 if (!sys.empty())
587 {
588 msg << MSG::FATAL << "Branch \"" << branchName << "\" without systematics is evaluated in a non-nominal context." << endmsg;
589 return StatusCode::FAILURE;
590 }
591 }
592
593 return StatusCode::SUCCESS;
594 }
595
596
597
598 StatusCode
600 setup( TTree& tree, const BranchConfig& branchConfig, OutputBranchData& outputData, MsgStream& msg ) {
601
602 // Remember the branch name.
603 m_branchName = outputData.branchName;
604
605 // Create the accessor.
606 m_acc.reset( new SG::TypelessConstAccessor( *branchConfig.auxType, outputData.auxName ) );
607
608 // Get a pointer to the vector factory.
609 m_factory = branchConfig.auxFactory;
610
611 // Create the data object.
612 m_data = m_factory->create( m_acc->auxid(), 1, 1, false );
613
614 // Pointer to the branch, to be created.
615 TBranch* br = nullptr;
616
617 // Decide whether we're dealing with a "primitive" or an "object" branch.
618 if( strlen( branchConfig.auxType->name() ) == 1 ) {
619
620 // This is a "primitive" variable...
621
622 // Get the type identifier for it that ROOT will understand.
623 const char rType = rootType( branchConfig.auxType->name()[ 0 ], msg );
624 if( rType == '\0' ) {
625 msg << MSG::ERROR << "Type not recognised for variable: "
626 << outputData.branchName << endmsg;
627 return StatusCode::FAILURE;
628 }
629
630 // Construct the type description.
631 std::ostringstream typeDesc;
632 typeDesc << outputData.branchName << "/" << rType;
633
634 // Create the primitive branch.
635 br = tree.Branch( outputData.branchName.c_str(), m_data->toPtr(),
636 typeDesc.str().c_str() );
637 if (branchConfig.basketSize.has_value())
638 br->SetBasketSize(branchConfig.basketSize.value());
639
640 } else {
641
642 // This is an "object" variable...
643
644 // Get a proper type name for the variable.
645 const std::string typeName = SG::normalizedTypeinfoName( *branchConfig.auxType );
646
647 // Access the dictionary for the type.
648 TClass* cl = TClass::GetClass( *branchConfig.auxType );
649 if( ! cl ) {
650 cl = TClass::GetClass( typeName.c_str() );
651 }
652 if( ! cl ) {
653 msg << MSG::ERROR << "Couldn't find dictionary for type: "
654 << typeName << endmsg;
655 return StatusCode::FAILURE;
656 }
657 if( ! cl->GetStreamerInfo() ) {
658 msg << MSG::ERROR << "No streamer info available for type: "
659 << cl->GetName() << endmsg;
660 return StatusCode::FAILURE;
661 }
662
663 // Create the object branch.
664 m_dataPtr = m_data->toPtr();
665 br = tree.Branch( outputData.branchName.c_str(), cl->GetName(), &m_dataPtr );
666 if (branchConfig.basketSize.has_value())
667 br->SetBasketSize(branchConfig.basketSize.value());
668
669 }
670
671 // Check that the branch creation succeeded.
672 if( ! br ) {
673 msg << MSG::ERROR << "Failed to create branch: " << outputData.branchName
674 << endmsg;
675 return StatusCode::FAILURE;
676 }
677
678 // Return gracefully.
679 return StatusCode::SUCCESS;
680 }
681
682 StatusCode
684 process( const SG::AuxElement& element, MsgStream& msg ) {
685
686 // A security check.
687 if( ( ! m_acc ) || ( ! m_factory ) || ( ! m_data ) ) {
688 msg << MSG::FATAL << "Internal logic error detected" << endmsg;
689 return StatusCode::FAILURE;
690 }
691
692 // Get the data out of the xAOD object.
693 //const void* auxData = ( *m_acc )( element );
694
695 // Copy it into the output variable.
696 TempInterface dstiface (m_data->size(), m_acc->auxid(), m_data->toPtr());
697 m_factory->copy( m_acc->auxid(), dstiface, 0,
698 *element.container(), element.index(), 1 );
699
700 // Return gracefully.
701 return StatusCode::SUCCESS;
702 }
703
705 setup( TTree& tree, const BranchConfig& branchConfig, OutputBranchData& outputData, MsgStream& msg ) {
706
707 // Remember the branch name.
708 m_branchName = outputData.branchName;
709
710 // Create the accessor.
711 m_acc.reset( new SG::TypelessConstAccessor( *branchConfig.auxType, outputData.auxName ) );
712
713 // Get a pointer to the vector factory.
714 m_factory = branchConfig.auxFactory;
715
716 // Create the data object.
717 m_data = m_factory->create( m_acc->auxid(), 0, 0, false );
718
719 // Get a proper type name for the variable.
720 const std::string typeName = SG::normalizedTypeinfoName( *branchConfig.auxVecType );
721
722 // Access the dictionary for the type.
723 TClass* cl = TClass::GetClass( *branchConfig.auxVecType );
724 if( ! cl ) {
725 cl = TClass::GetClass( typeName.c_str() );
726 }
727 if( ! cl ) {
728 msg << MSG::ERROR << "Couldn't find dictionary for type: "
729 << typeName << endmsg;
730 return StatusCode::FAILURE;
731 }
732 if( ! cl->GetStreamerInfo() ) {
733 msg << MSG::ERROR << "No streamer info available for type: "
734 << cl->GetName() << endmsg;
735 return StatusCode::FAILURE;
736 }
737
738 // Create the branch.
739 m_dataPtr = m_data->toVector();
740 TBranch* br = tree.Branch( outputData.branchName.c_str(), cl->GetName(),
741 &m_dataPtr );
742 if( ! br ) {
743 msg << MSG::ERROR << "Failed to create branch: " << outputData.branchName
744 << endmsg;
745 return StatusCode::FAILURE;
746 }
747 if (branchConfig.basketSize.has_value())
748 br->SetBasketSize(branchConfig.basketSize.value());
749
750 // Return gracefully.
751 return StatusCode::SUCCESS;
752 }
753
755 resize( size_t size, MsgStream& msg ) {
756
757 // A security check.
758 if( ! m_data ) {
759 msg << MSG::FATAL << "Internal logic error detected" << endmsg;
760 return StatusCode::FAILURE;
761 }
762
763 // Do the deed.
764 m_data->resize( 0 );
765 m_data->resize( size );
766
767 // Return gracefully.
768 return StatusCode::SUCCESS;
769 }
770
772 process( const SG::AuxElement& element, size_t index, MsgStream& msg ) {
773
774 // A security check.
775 if( ( ! m_acc ) || ( ! m_factory ) || ( ! m_data ) ) {
776 msg << MSG::FATAL << "Internal logic error detected" << endmsg;
777 return StatusCode::FAILURE;
778 }
779
780 // Get the data out of the xAOD object.
781 //const void* auxData = ( *m_acc )( element );
782
783 // Copy it into the output variable.
784 TempInterface dstiface (m_data->size(), m_acc->auxid(), m_data->toPtr());
785 m_factory->copy( m_acc->auxid(), dstiface, index,
786 *element.container(), element.index(), 1 );
787
788 // Return gracefully.
789 return StatusCode::SUCCESS;
790 }
791
792
793
794
795
797 : asg::AsgMessaging( ("CP::TreeBranchHelpers::ElementProcessorRegular/" + sgName).c_str() ),
798 m_sgName(sgName) {
799
800 }
801
803 retrieveProcess( StoreType& evtStore ) {
804
805 // Retrieve the object:
806 static const bool ALLOW_MISSING = false;
807 const SG::AuxElement* el = getElement( m_sgName,
808 evtStore,
809 ALLOW_MISSING, msg() );
810 if( ! el ) {
811 ATH_MSG_ERROR( "Failed to retrieve object \"" << m_sgName
812 << "\"" );
813 return StatusCode::FAILURE;
814 }
815 const SG::AuxElement& element = *el;
816
817 // Process all branches.
818 for( auto& p : m_branches ) {
819 ATH_CHECK( p->process( element, msg() ) );
820 }
821
822 // Return gracefully.
823 return StatusCode::SUCCESS;
824 }
825
827 addBranch( TTree& tree, const BranchConfig& branchConfig, OutputBranchData& outputData ) {
828
829 // Set up the new branch.
830 m_branches.emplace_back(std::make_unique<ElementBranchProcessor>());
831 ATH_CHECK( m_branches.back()->setup( tree, branchConfig, outputData, msg() ) );
832
833 // Return gracefully.
834 return StatusCode::SUCCESS;
835 }
836
838 : asg::AsgMessaging( ("CP::TreeBranchHelpers::ContainerProcessorRegular/" + sgName).c_str() ),
839 m_sgName(sgName) {
840
841 }
842
844 retrieveProcess( StoreType& evtStore ) {
845
846 // Retrieve the container:
847 static const bool ALLOW_MISSING = false;
848 const TClass* cl = nullptr;
849 const SG::AuxVectorBase* vec = getVector( m_sgName,
850 evtStore,
851 ALLOW_MISSING, cl, msg() );
852 if( ! vec ) {
853 ATH_MSG_ERROR( "Failed to retrieve container \""
854 << m_sgName << "\"" );
855 return StatusCode::FAILURE;
856 }
858
859 // Get the collection proxy for the type if it's not available yet.
860 if( ! m_collProxy ) {
861
862 // Get the collection proxy from the dictionary.
863 m_collProxy = cl->GetCollectionProxy();
864 if( ! m_collProxy ) {
865 ATH_MSG_ERROR( "No collection proxy provided by type: "
866 << cl->GetName() );
867 return StatusCode::FAILURE;
868 }
869
870 // Get the offset that one needs to use to get from the element
871 // pointers to SG::AuxElement pointers.
872 static const TClass* const auxElementClass =
873 TClass::GetClass( typeid( SG::AuxElement ) );
875 m_collProxy->GetValueClass()->GetBaseClassOffset( auxElementClass );
876 if( m_auxElementOffset < 0 ) {
877 ATH_MSG_ERROR( "Vector element type \""
878 << m_collProxy->GetValueClass()->GetName()
879 << "\" doesn't seem to inherit from \""
880 << auxElementClass->GetName() << "\"" );
881 return StatusCode::FAILURE;
882 }
883 }
884
885 // Set up the iteration over the elements of the container. In a really
886 // low level / ugly way...
887 void* cPtr =
888 const_cast< void* >( static_cast< const void* >( &container ) );
889 TVirtualCollectionProxy::TPushPop helper( m_collProxy, cPtr );
890 const UInt_t cSize = m_collProxy->Size();
891
892 // Tell all branch processors to resize their variables.
893 for( auto& p : m_branches ) {
894 ATH_CHECK( p->resize( cSize, msg() ) );
895 }
896
897 // Now iterate over the container.
898 for( UInt_t i = 0; i < cSize; ++i ) {
899
900 // Get the element.
901 char* elPtr = static_cast< char* >( m_collProxy->At( i ) );
902 if( ! elPtr ) {
903 ATH_MSG_ERROR( "Failed to get element " << i << " from container" );
904 return StatusCode::FAILURE;
905 }
906 const SG::AuxElement* element =
907 reinterpret_cast< const SG::AuxElement* >( elPtr +
909
910 // Execute all branch processors on this element.
911 for( auto& p : m_branches ) {
912 ATH_CHECK( p->process( *element, i, msg() ) );
913 }
914 }
915
916 // Return gracefully.
917 return StatusCode::SUCCESS;
918 }
919
921 addBranch( TTree& tree, const BranchConfig& branchConfig, OutputBranchData& outputData ) {
922
923 // Set up the new branch.
924 m_branches.emplace_back(std::make_unique<ContainerBranchProcessor>());
925 ATH_CHECK( m_branches.back()->setup( tree, branchConfig, outputData, msg() ) );
926
927 // Return gracefully.
928 return StatusCode::SUCCESS;
929 }
930
931 ElementProcessorMet::ElementProcessorMet (const std::string& sgName, const std::string& termName)
932 : asg::AsgMessaging( ("CP::TreeBranchHelpers::ElementProcessorMet/" + sgName).c_str() ),
933 m_sgName(sgName),
934 m_termName(termName) {
935
936 }
937
939 retrieveProcess( StoreType& evtStore ) {
940
941 const xAOD::MissingETContainer *met = nullptr;
942 ANA_CHECK (evtStore.retrieve (met, m_sgName));
943 const SG::AuxElement& element = *(*met)[m_termName];
944 // Process all branches.
945 for( auto& p : m_branches ) {
946 ATH_CHECK( p->process( element, msg() ) );
947 }
948
949 // Return gracefully.
950 return StatusCode::SUCCESS;
951 }
952
954 addBranch( TTree& tree, const BranchConfig& branchConfig, OutputBranchData& outputData ) {
955
956 // Set up the new branch.
957 m_branches.emplace_back(std::make_unique<ElementBranchProcessor>());
958 ATH_CHECK( m_branches.back()->setup( tree, branchConfig, outputData, msg() ) );
959
960 // Return gracefully.
961 return StatusCode::SUCCESS;
962 }
963
964
965
966 StatusCode ProcessorList ::
967 setupTree(const std::vector<std::string>& branches, std::unordered_set<std::string> nonContainers, ISystematicsSvc& sysSvc, TTree& tree) {
968
969 m_nonContainers = std::move (nonContainers);
970
971 std::vector<BranchConfig> branchConfigs;
972 branchConfigs.reserve( branches.size() );
973 for ( const std::string& branchDecl : branches ) {
974 branchConfigs.emplace_back();
975 ATH_CHECK( branchConfigs.back().parse( branchDecl, msg() ) );
976 if (!branchConfigs.back().basketSize.has_value())
977 branchConfigs.back().basketSize = defaultBasketSize;
978 }
979
980 // This will loop over all branches, collect the name of any
981 // aux-store decorations that have no type and report them at the
982 // end. This allows to get the full list of missing decorations in
983 // a single run, as opposed to having to re-run the job once per
984 // missing decoration.
985 std::set<std::string> decosWithoutType;
986 for (auto& branchConfig : branchConfigs) {
987 ATH_CHECK ( branchConfig.configureTypes (decosWithoutType, msg()) );
988 }
989 if (!decosWithoutType.empty()) {
990 msg() << MSG::ERROR << "The following decorations have no type information:";
991 for (const auto& deco : decosWithoutType) {
992 msg() << " " << deco;
993 }
994 msg() << endmsg;
995 return StatusCode::FAILURE;
996 }
997
998
999 for (auto& branchConfig : branchConfigs) {
1000 ATH_CHECK ( branchConfig.configureSystematics (sysSvc, msg()) );
1001 }
1002
1003 auto sysVector = sysSvc.makeSystematicsVector();
1004 // Ensure that the nominal systematic is first
1005 if (!sysVector.at(0).empty()) {
1006 ATH_MSG_ERROR ("The first systematic in the list is not nominal!");
1007 return StatusCode::FAILURE;
1008 }
1009
1010 // The branches we intend to write out
1011 std::vector<OutputBranchData> outputBranches;
1012
1013 // All the branches that will be created
1014 std::unordered_set<std::string> allBranches;
1015
1016 // Iterate over the branch specifications.
1017 for( const auto& branchConfig : branchConfigs ) {
1018
1019 // All the branches that will be created for this rule
1020 std::unordered_set<std::string> branchesForRule;
1021
1022 // Consider all systematics but skip the nominal one
1023 for( const auto& sys : sysVector ) {
1024
1025 if (branchConfig.nominalOnly && !sys.empty()) continue;
1026 OutputBranchData outputData;
1027 outputData.branchConfig = &branchConfig;
1028 outputData.sysIndex = &sys - &sysVector.front();
1029 ATH_CHECK( outputData.configureNames (branchConfig, sys, sysSvc, msg()) );
1030
1031 // Skip branches that have already been created for other
1032 // systematics for this rule. That's mostly nominal, but for
1033 // systematics correlation studies it can also do other things.
1034 if (branchesForRule.contains(outputData.branchName))
1035 {
1036 ANA_MSG_VERBOSE ("Branch \"" << outputData.branchName << "\" for rule \"" << branchConfig.branchDecl << "\" and systematic \"" << sys.name() << "\" already exists, skipping." );
1037 continue;
1038 }
1039 branchesForRule.insert(outputData.branchName);
1040
1041 // If this branch already exists from another rule, report
1042 // it as an error.
1043 if (allBranches.contains(outputData.branchName))
1044 {
1045 ANA_MSG_ERROR ("Branch \"" << outputData.branchName << "\" would be created twice!" );
1046 return StatusCode::FAILURE;
1047 }
1048 allBranches.insert(outputData.branchName);
1049 outputBranches.push_back(std::move(outputData));
1050 }
1051 }
1052
1053 // Group all branches by systematic index to ensure that when
1054 // reading a single systematic the branches are contiguous on
1055 // disk.
1056 std::stable_sort (outputBranches.begin(), outputBranches.end(),
1057 [](const OutputBranchData& a, const OutputBranchData& b) {
1058 return a.sysIndex < b.sysIndex; });
1059
1060 for (auto &outputData : outputBranches)
1061 ATH_CHECK( setupBranch( *outputData.branchConfig, outputData, tree ) );
1062
1063 // Return gracefully.
1064 return StatusCode::SUCCESS;
1065 }
1066
1067 StatusCode ProcessorList::setupBranch( const BranchConfig& branchConfig, OutputBranchData& outputData, TTree& tree ) {
1068
1069 ATH_CHECK( getObjectProcessor( branchConfig, outputData.sgName ).addBranch( tree,
1070 branchConfig, outputData ) );
1071 ATH_MSG_DEBUG( "Writing branch \"" << outputData.branchName
1072 << "\" from container/variable \"" << outputData.sgName
1073 << "." << outputData.auxName << "\"" );
1074
1075 // Return gracefully.
1076 return StatusCode::SUCCESS;
1077 }
1078
1079 StatusCode ProcessorList ::
1080 process (StoreType& evtStore)
1081 {
1082 // Process the standalone objects:
1083 for( auto& [name, processor] : m_processors )
1084 {
1085 // Process it:
1086 ATH_CHECK (processor->retrieveProcess (evtStore));
1087 }
1088 return StatusCode::SUCCESS;
1089 }
1090
1091
1092
1093 IObjectProcessor& ProcessorList ::
1094 getObjectProcessor( const BranchConfig& branchConfig, const std::string& sgName )
1095 {
1096 std::string processorName = sgName;
1097 if (!branchConfig.metTermName.empty())
1098 processorName += ":metTerm=" + branchConfig.metTermName;
1099
1100 if (auto iter = m_processors.find(processorName); iter != m_processors.end())
1101 return *iter->second;
1102
1103 if (!branchConfig.metTermName.empty())
1104 return *m_processors.emplace (processorName, std::make_unique<ElementProcessorMet>(sgName, branchConfig.metTermName)).first->second;
1105
1106 if (m_nonContainers.contains(sgName))
1107 return *m_processors.emplace (processorName, std::make_unique<ElementProcessorRegular>(sgName)).first->second;
1108
1109 return *m_processors.emplace (processorName, std::make_unique<ContainerProcessorRegular>(sgName)).first->second;
1110 }
1111 }
1112}
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_DEBUG(x)
Base class for elements of a container that can have aux data.
Manage index tracking and synchronization of auxiliary data.
std::vector< size_t > vec
#define ANA_MSG_ERROR(xmsg)
Macro printing error messages.
#define ANA_MSG_VERBOSE(xmsg)
Macro printing verbose messages.
#define ANA_CHECK(EXP)
check whether the given expression was successful
Interface providing I/O for a generic auxiliary store.
Interface for factory objects that create vectors.
static Double_t a
static HEPVis_BooleanProcessor processor
#define ATLAS_NOT_CONST_THREAD_SAFE
the interface for the central systematics service
virtual CP::SystematicSet getObjectSystematics(const std::string &name) const =0
get the systematics for the given object in the event store
virtual std::vector< CP::SystematicSet > makeSystematicsVector() const =0
get the list of systematics
virtual CP::SystematicSet getDecorSystematics(const std::string &objectName, const std::string &decorName) const =0
get the systematics for the given object in the event store
virtual StatusCode makeSystematicsName(std::string &result, const std::string &name, const CP::SystematicSet &sys) const =0
make the name for the given systematics
Class to wrap a set of SystematicVariations.
bool empty() const
returns: whether the set is empty
static StatusCode filterForAffectingSystematics(const SystematicSet &systConfig, const SystematicSet &affectingSystematics, SystematicSet &filteredSystematics)
description: filter the systematics for the affected systematics returns: success guarantee: strong f...
std::string m_branchName
Name of the branch being written.
StatusCode resize(size_t size, MsgStream &msg)
Function (re)sizing the variable for a new event.
std::unique_ptr< SG::IAuxTypeVector > m_data
The object managing the memory of the written variable.
StatusCode process(const SG::AuxElement &element, size_t index, MsgStream &msg)
Function processing the object, filling the variable.
std::unique_ptr< SG::TypelessConstAccessor > m_acc
Object accessing the variable in question.
StatusCode setup(TTree &tree, const BranchConfig &branchConfig, OutputBranchData &outputData, MsgStream &msg)
Function setting up the object, and the branch.
const SG::IAuxTypeVectorFactory * m_factory
Pointer to the helper object that handles this variable.
void * m_dataPtr
Helper variable, pointing at the object to be written.
TVirtualCollectionProxy * m_collProxy
Collection proxy used for iterating over the container.
std::string m_sgName
Name of the object in the event store.
int m_auxElementOffset
Offset of the element type to SG::AuxElement.
StatusCode retrieveProcess(StoreType &evtStore) override
retrieve and process the object
StatusCode addBranch(TTree &tree, const BranchConfig &branchConfig, OutputBranchData &outputData) override
Add one branch to the output tree.
std::vector< std::unique_ptr< ContainerBranchProcessor > > m_branches
List of branch processors set up for this xAOD object.
ContainerProcessorRegular(const std::string &sgName)
Default constructor.
std::unique_ptr< SG::IAuxTypeVector > m_data
The object managing the memory of the written variable.
void * m_dataPtr
Helper variable, pointing at the object to be written.
const SG::IAuxTypeVectorFactory * m_factory
Pointer to the helper object that handles this variable.
std::string m_branchName
Name of the branch being written.
StatusCode setup(TTree &tree, const BranchConfig &branchConfig, OutputBranchData &outputData, MsgStream &msg)
Function setting up the object, and the branch.
std::unique_ptr< SG::TypelessConstAccessor > m_acc
Object accessing the variable in question.
StatusCode process(const SG::AuxElement &element, MsgStream &msg)
Function processing the object, filling the variable.
std::vector< std::unique_ptr< ElementBranchProcessor > > m_branches
List of branch processors set up for this xAOD object.
std::string m_termName
Name of the MET term to retrieve.
StatusCode addBranch(TTree &tree, const BranchConfig &branchConfig, OutputBranchData &outputData) override
Add one branch to the output tree.
ElementProcessorMet(const std::string &sgName, const std::string &termName)
Default constructor.
StatusCode retrieveProcess(StoreType &evtStore) override
retrieve and process the object
std::string m_sgName
Name of the object in the event store.
StatusCode retrieveProcess(StoreType &evtStore) override
retrieve and process the object
StatusCode addBranch(TTree &tree, const BranchConfig &branchConfig, OutputBranchData &outputData) override
Add one branch to the output tree.
std::string m_sgName
Name of the object in the event store.
ElementProcessorRegular(const std::string &sgName)
Default constructor.
std::vector< std::unique_ptr< ElementBranchProcessor > > m_branches
List of branch processors set up for this xAOD object.
the interface class for classes reading an object from the event store and processing it
virtual StatusCode addBranch(TTree &tree, const BranchConfig &branchConfig, OutputBranchData &outputData)=0
Add one branch to the output tree.
StatusCode setupBranch(const BranchConfig &branchConfig, OutputBranchData &outputData, TTree &tree)
Function setting up an individual branch on the first event.
std::unordered_set< std::string > m_nonContainers
the non-containers
IObjectProcessor & getObjectProcessor(const BranchConfig &branchConfig, const std::string &sgName)
std::optional< int > defaultBasketSize
the default basket size
std::unordered_map< std::string, std::unique_ptr< IObjectProcessor > > m_processors
object processors
A non-templated base class for DataBucket, allows to access the transient object address as a void*.
virtual void * object()=0
virtual const std::type_info & tinfo() const =0
Return the type_info for the stored object.
virtual std::vector< const SG::DataProxy * > proxies() const =0
Return the list of all current proxies in store.
Base class for elements of a container that can have aux data.
Definition AuxElement.h:484
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 index tracking and synchronization of auxiliary data.
Manage lookup of vectors of auxiliary data.
Helper class to provide constant type-safe access to aux data.
DataObject * accessData()
Access DataObject on-demand using conversion service.
Helper class to provide const generic access to aux data.
The Athena Transient Store API.
StatusCode retrieve(const T *&ptr) const
Retrieve the default object into a const T*.
MsgStream & msg() const
The standard message stream.
MsgStream & msg() const
The standard message stream.
AsgMessaging(const std::string &name)
Constructor with a name.
Wrapper for TEvent to make it look like StoreGate.
Definition SgTEvent.h:44
bool contains(const std::string &name) const
Check if an object is available for constant access.
T * retrieve(const std::string &name) const
Function retrieving a constant or non-constant object.
xAOD::TStore * tds() const
Return the underlying transient data store.
Definition SgTEvent.cxx:33
This class takes care of holding EDM objects in memory.
Definition THolder.h:35
const std::type_info * getTypeInfo() const
Definition THolder.cxx:412
const THolder * holder(const std::string &key) const
return holder for key
Definition TStore.cxx:50
bool match(std::string s1, std::string s2)
match the individual directories of two strings
Definition hcg.cxx:357
a namespace for helper functions and objects for filling tree branches
StoreGateSvc StoreType
the type of the event store in the current environment
Select isolated Photons, Electrons and Muons.
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
cl
print [x.__class__ for x in toList(dqregion.getSubRegions()) ]
Definition index.py:1
void stable_sort(DataModel_detail::iterator< DVL > beg, DataModel_detail::iterator< DVL > end)
Specialization of stable_sort for DataVector/List.
DataModel_detail::iterator< DVL > remove_if(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end, Predicate pred)
Specialization of remove_if for DataVector/List.
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...
the user configuration of an output branch
std::string branchDecl
the original user configuration string
std::string sgName
the SG name of the object to read from
const SG::IAuxTypeVectorFactory * auxFactory
pointer to the aux vector factory
std::string auxName
the aux data variable name to read from
const std::type_info * auxVecType
the vector type of the decoration we read
std::optional< int > basketSize
the basket size for this branch
CP::SystematicSet auxNameFilterSys
the affecting systematics for the auxName
CP::SystematicSet sgNameFilterSys
the affecting systematics for the sgName
CP::SystematicSet branchNameFilterSys
the affecting systematics for the branchName
const std::type_info * auxType
the type of the decoration we read
SG::auxid_t nominalAuxId
the aux-id for the nominal decoration
std::string branchName
the name of the output branch
std::string metTermName
MET ONLY: the name of the MET term to write out.
bool nominalOnly
whether we only want to write out the nominal
std::string typeName
the name of the type (or empty to read from aux-registry)
the data for a single output branch
bool isNominal
whether this is unaffected by systematics (i.e. nominal)
const BranchConfig * branchConfig
the BranchConfig we are based on
std::size_t sysIndex
the index in the systematics list
StatusCode configureNames(const BranchConfig &branchConfig, const CP::SystematicSet &sys, ISystematicsSvc &sysSvc, MsgStream &msg)
configure names for systematics
std::string auxName
the name of the decoration in the aux-store
std::string sgName
the SG name of the object to read from
std::string branchName
the name of the output branch
MsgStream & msg
Definition testRead.cxx:32
TChain * tree
TFile * file