ATLAS Offline Software
Loading...
Searching...
No Matches
RootD3PD.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
4
11
12#include "RootD3PD.h"
13#include "FakeProxy.h"
15#include "GaudiKernel/System.h"
16#include "TTree.h"
17#include "TLeaf.h"
18#include "TBranch.h"
19#include "TBranchElement.h"
20#include "TVirtualCollectionProxy.h"
21#include "TMethodCall.h"
22#include "TString.h"
23#include "TObjString.h"
24#include "TDirectory.h"
25#include "TDirectoryFile.h"
26#include "TROOT.h"
27#include "TFile.h"
28#include "TDataType.h"
29#include "TPRegexp.h"
30#include <sstream>
31#include <cstdlib>
32#include <cstring>
33#include <cassert>
34#include <algorithm>
35#include <functional>
36
37
38namespace {
39
40
45char find_typecode (const std::type_info& ti)
46{
47 if (ti == typeid (char*))
48 return 'C';
49 else if (ti == typeid (Char_t))
50 return 'B';
51 else if (ti == typeid (UChar_t))
52 return 'b';
53 else if (ti == typeid (Short_t))
54 return 'S';
55 else if (ti == typeid (UShort_t))
56 return 's';
57 else if (ti == typeid (Int_t))
58 return 'I';
59 else if (ti == typeid (UInt_t))
60 return 'i';
61 else if (ti == typeid (Long_t))
62 return 'G';
63 else if (ti == typeid (ULong_t))
64 return 'g';
65 else if (ti == typeid (Float_t))
66 return 'F';
67 else if (ti == typeid (Double_t))
68 return 'D';
69 else if (ti == typeid (Long64_t))
70 return 'L';
71 else if (ti == typeid (ULong64_t))
72 return 'l';
73 else if (ti == typeid (Bool_t))
74 return 'O';
75
76 return '\0';
77}
78
79
91class NameMatches {
92public:
94 NameMatches( const std::string& name ) : m_name( name ) {}
95
97 bool operator()( const std::string& pattern ) {
98
99 return TPRegexp( pattern ).Match( m_name );
100 }
101
102private:
103 std::string m_name;
104
105}; // class NameMatches
106
107
108} // anonymous namespace
109
110
111namespace D3PD {
112
113
114/****************************************************************************
115 * We support several different ways to clear a variable, depending
116 * on the type.
117 * To prevent having to do dictionary lookups, etc, on each event,
118 * we do it once, and save the results in a table. The table is called
119 * @c Cleartable; it is a collection of @c Clearinfo objects.
120 */
121
122
123namespace Root {
124
125
130{
131public:
133 Clearinfo();
134
135
146 StatusCode init (TBranch* br, char* defval, size_t defsize);
147
148
150 void clear();
151
152
155 void free();
156
157
158private:
180
182 TLeaf* m_leaf;
183
185 TBranchElement *m_bre;
186
188 TVirtualCollectionProxy* m_proxy;
189
191 TMethodCall m_meth;
192
195
197 size_t m_defsize;
198};
199
200
207 : m_type (INVALID),
208 m_leaf (0),
209 m_bre (0),
210 m_proxy (0),
211 m_default (0),
212 m_defsize (0)
213{
214}
215
216
227StatusCode Clearinfo::init (TBranch* br, char* defval, size_t defsize)
228{
229 if (typeid (*br) == typeid (TBranch)) {
230 // Atomic type
231 TLeaf* leaf = br->GetLeaf (br->GetName());
232 if (!leaf) {
233 REPORT_MESSAGE (MSG::ERROR) << "For tree " << br->GetTree()->GetName()
234 << " can't find leaf for branch "
235 << br->GetName();
236 return StatusCode::FAILURE;
237 }
238
239 if (defval) {
240 m_type = COPY;
241 m_default = defval;
242 m_defsize = defsize;
243 }
244 else
245 m_type = ZERO;
246
247 m_leaf = leaf;
248 }
249
250 else if (TBranchElement* bre = dynamic_cast<TBranchElement*> (br)) {
251 assert (defval == 0);
252
253 // Class type. See if it seems to be a container.
254 if (TVirtualCollectionProxy* collprox = bre->GetCollectionProxy()) {
255 // A collection.
257 m_bre = bre;
258 m_proxy = collprox;
259 }
260 else {
261 // See if the class has a clear() method.
262 TClass* cl = gROOT->GetClass (bre->GetClassName());
263 if (!cl) {
264 REPORT_MESSAGE (MSG::ERROR) << "For tree " << br->GetTree()->GetName()
265 << " branch " << br->GetName()
266 << " can't find class "
267 << bre->GetClassName();
268 return StatusCode::FAILURE;
269 }
270
271 TMethodCall meth (cl, "clear", "");
272 if (meth.IsValid()) {
273 // There's a @c clear() method. Use that.
274 m_type = CLEAR;
275 m_bre = bre;
276 m_meth = meth;
277 }
278 else {
279 // Free and reallocate object.
280 m_type = RESET;
281 m_bre = bre;
282 }
283 }
284 }
285 else {
286 // Someone else must have made this?
287 REPORT_MESSAGE (MSG::ERROR) << "For tree " << br->GetTree()->GetName()
288 << " branch " << br->GetName()
289 << " has unknown type "
290 << typeid(*br).name();
291 return StatusCode::FAILURE;
292 }
293
294 return StatusCode::SUCCESS;
295}
296
297
302{
303 switch (m_type) {
304 case ZERO:
305 // Fill with zeros.
306 std::memset (m_leaf->GetValuePointer(), 0,
307 m_leaf->GetLen() * m_leaf->GetLenType());
308 break;
309
310 case COLLECTION:
311 // Clear via collection proxy.
312 {
313 void* obj = m_bre->GetObject();
314 TVirtualCollectionProxy::TPushPop pushcont(m_proxy, obj);
315 m_proxy->Clear();
316 break;
317 }
318
319 case CLEAR:
320 // Clear by calling @c clear().
321 {
322 void* obj = m_bre->GetObject();
323 m_meth.Execute (obj);
324 break;
325 }
326
327 case RESET:
328 // Free and reallocate object.
329 m_bre->SetAddress(0);
330 break;
331
332 case COPY:
333 // Copy from default.
334 std::memcpy (m_leaf->GetValuePointer(), m_default, m_defsize);
335 break;
336
337 default:
338 std::abort();
339
340 }
341}
342
343
347{
348 delete [] m_default;
349}
350
351
356{
357public:
359 ~Cleartable();
360
361
372 StatusCode add (TBranch* br, char* defval, size_t defsize);
373
374
376 void clear ();
377
378
379private:
380 std::vector<Clearinfo> m_info;
381};
382
383
388{
389 for (size_t i = 0; i < m_info.size(); i++)
390 m_info[i].free();
391}
392
393
404StatusCode Cleartable::add (TBranch* br, char* defval, size_t defsize)
405{
406 m_info.push_back (Clearinfo());
407 CHECK( m_info.back().init (br, defval, defsize) );
408 m_info.back().clear(); // Make sure the variable is clear at the start.
409 return StatusCode::SUCCESS;
410}
411
412
417{
418 for (size_t i = 0; i < m_info.size(); i++)
419 m_info[i].clear();
420}
421
422
423} // namespace Root
424
425
426/****************************************************************************
427 * RootD3PD class.
428 */
429
430
440 const std::string& master,
441 const std::vector< std::string >& allowedNames,
442 const std::vector< std::string >& vetoedNames,
443 int basketSize /*= -1*/,
444 int entryOffsetLen /*= -1*/)
445 : m_tree (tree),
447 m_basketSize (basketSize),
448 m_entryOffsetLen (entryOffsetLen),
449 m_cleartable (new Root::Cleartable),
450 m_allowedNames (allowedNames),
451 m_vetoedNames (vetoedNames),
452 m_fakeVars()
453{
454}
455
456
461{
462 delete m_cleartable;
463 std::map< std::string, FakeProxy* >::iterator itr = m_fakeVars.begin();
464 std::map< std::string, FakeProxy* >::iterator end = m_fakeVars.end();
465 for( ; itr != end; ++itr ) {
466 delete itr->second;
467 }
468}
469
470
485StatusCode RootD3PD::addVariable (const std::string& name,
486 const std::type_info& ti,
487 void* & ptr,
488 const std::string& docstring /*= ""*/,
489 const void* defval /*= 0*/)
490{
491 TBranch* br = 0;
492
493 // If the variable is not to be put into the output tree, let's
494 // just create it in memory:
495 if( ! isAllowed( name ) ) {
496 CHECK( addFakeVariable( name, ti, ptr ) );
497 return StatusCode::SUCCESS;
498 }
499
500 // Make sure that there's not already a branch with this name.
501 if (m_tree->GetBranch (name.c_str()) != 0) {
502 REPORT_MESSAGE (MSG::ERROR) << "Duplicate branch name " << name
503 << " in tree " << m_tree->GetName();
504 return StatusCode::FAILURE;
505 }
506
507 char* defcopied = 0;
508 size_t defsize = 0;
509
510 // See if it's a basic type.
511 char typecode = find_typecode (ti);
512 if (typecode != '\0') {
513 // Yes. Make a simple branch for it.
514 br = m_tree->Branch (name.c_str(), 0, (name + '/' + typecode).c_str());
515 if (!br)
516 return StatusCode::FAILURE;
517
518 // Find the (single) leaf for the branch.
519 TLeaf* leaf = br->GetLeaf (name.c_str());
520 if (!leaf)
521 return StatusCode::FAILURE;
522
523 // Set the pointer.
524 ptr = leaf->GetValuePointer();
525
526 if (defval) {
527 EDataType dt = TDataType::GetType (ti);
528 TDataType* tdt = gROOT->GetType (TDataType::GetTypeName (dt));
529 assert (tdt != 0);
530 defsize = tdt->Size();
531 defcopied = new char[defsize];
532 std::memcpy (defcopied, defval, defsize);
533 }
534 }
535 else {
536
537 // Default value not supported for class types.
538 if (defval) {
539 REPORT_MESSAGE (MSG::ERROR)
540 << "Requested a default value for variable " << name
541 << " of type " << System::typeinfoName (ti)
542 << "; but default values are only supported for basic types.";
543 return StatusCode::FAILURE;
544 }
545
546 // A class type. Try to find the class.
547 TClass* cls = getClass (ti);
548 if (!cls)
549 return StatusCode::FAILURE;
550
551 // Create the branch.
552 br = m_tree->Bronch (name.c_str(), cls->GetName(), 0);
553 if (!br)
554 return StatusCode::FAILURE;
555
556 TBranchElement* bre = dynamic_cast<TBranchElement*> (br);
557 if (!bre) {
558 REPORT_MESSAGE (MSG::ERROR) << "Unexpected branch type created for "
559 << name;
560 return StatusCode::FAILURE;
561 }
562
563 // Set the pointer.
564 ptr = bre->GetObject();
565 }
566
567 // Set the branch docstring.
568 br->SetTitle (docstring.c_str());
569
570 // Set the branch buffer sizes as requested.
571 if (m_basketSize != -1)
572 br->SetBasketSize (m_basketSize);
573
574 if (m_entryOffsetLen != -1)
575 br->SetEntryOffsetLen (m_entryOffsetLen);
576
577 CHECK( m_cleartable->add (br, defcopied, defsize) );
578
579 // If we're extending an already-started tuple, then we need
580 // to write the correct number of blank entries at the start.
581 for (Long64_t i = 0; i < m_tree->GetEntries(); i++)
582 br->Fill();
583
584 return StatusCode::SUCCESS;
585}
586
587
604StatusCode
605RootD3PD::addDimensionedVariable (const std::string& /*name*/,
606 const std::type_info& /*ti*/,
607 void* & /*ptr*/,
608 const std::string& /*dim*/,
609 const std::string& /*docstring = ""*/,
610 const void* /*defval = 0*/)
611{
612 REPORT_MESSAGE (MSG::ERROR)
613 << "addDimensionedVariable not yet implemented.";
614 return StatusCode::FAILURE;
615}
616
617
621StatusCode RootD3PD::capture ()
622{
623 // Handle pending pool file association.
625
626 if (m_tree->Fill() < 0)
627 return StatusCode::FAILURE;
628 return StatusCode::SUCCESS;
629}
630
631
636{
637 if (!m_poolFile.empty()) {
638 TIter next (gROOT->GetListOfFiles());
639 while (TFile* f = dynamic_cast<TFile*>(next())) {
640 if (std::string(f->GetName()) == m_poolFile) {
641 m_tree->SetDirectory (f);
642 m_poolFile.clear();
643 break;
644 }
645 }
646 if (!m_poolFile.empty()) {
647 REPORT_MESSAGE (MSG::ERROR) << "Can't find root file " << m_poolFile
648 << " to attach tree " << m_tree->GetName();
649 return StatusCode::FAILURE;
650 }
651 }
652 return StatusCode::SUCCESS;
653}
654
655
659StatusCode RootD3PD::clear ()
660{
661 m_cleartable->clear();
662 return StatusCode::SUCCESS;
663}
664
665
667StatusCode RootD3PD::redim (const Dim_t* /*ptr*/)
668{
669 return StatusCode::FAILURE;
670}
671
672
676const TTree* RootD3PD::tree() const
677{
678 return m_tree;
679}
680
682{
683 return m_tree;
684}
685
686
690const std::string& RootD3PD::master() const
691{
692 return m_master;
693}
694
695
709StatusCode RootD3PD::addMetadata (const std::string& key,
710 const void* obj,
711 const std::type_info& ti)
712{
713 TObjString ostmp;
714
715 TClass* cls = getClass (ti);
716 if (!cls)
717 return StatusCode::RECOVERABLE;
718
719 if (ti == typeid(TString)) {
720 ostmp.String() = *reinterpret_cast<const TString*> (obj);
721 obj = &ostmp;
722 cls = gROOT->GetClass ("TObjString");
723 }
724 else if (ti == typeid(std::string)) {
725 ostmp.String() = *reinterpret_cast<const std::string*> (obj);
726 obj = &ostmp;
727 cls = gROOT->GetClass ("TObjString");
728 }
729
730 std::string metaname;
731 TDirectory* dir = m_tree->GetDirectory();
732 std::string thekey = key;
733
734 if (key.size() > 0 && key[key.size()-1] == '/') {
735 // Go to the root directory of the file.
736 while (dynamic_cast<TDirectoryFile*> (dir) != 0 &&
737 dir->GetMotherDir())
738 dir = dir->GetMotherDir();
739
740 metaname = key.substr (0, key.size()-1);
741 thekey = m_tree->GetName();
742 }
743 else {
744 metaname = m_tree->GetName();
745 metaname += "Meta";
746 }
747
748 TDirectory::TContext ctx (dir);
749 TDirectory* metadir = dir->GetDirectory (metaname.c_str());
750 if (!metadir) {
751 metadir = dir->mkdir (metaname.c_str());
752 if (!metadir) {
753 REPORT_MESSAGE (MSG::ERROR)
754 << "Can't create metadata dir " << metaname
755 << "in dir " << dir->GetName();
756 return StatusCode::RECOVERABLE;
757 }
758 }
759
760 // If we're writing in a common directory, make sure name is unique.
761 if (key.size() > 0 && key[key.size()-1] == '/') {
762 int i = 1;
763 while (metadir->FindObject (thekey.c_str())) {
764 ++i;
765 std::ostringstream ss;
766 ss << m_tree->GetName() << "-" << i;
767 thekey = ss.str();
768 }
769 }
770
771 if (metadir->WriteObjectAny (obj, cls, thekey.c_str(), "overwrite") == 0) {
772 REPORT_MESSAGE (MSG::ERROR)
773 << "Can't write metadata object " << thekey
774 << " for tree " << m_tree->GetName();
775 return StatusCode::RECOVERABLE;
776 }
777
778 return StatusCode::SUCCESS;
779}
780
781
788TClass* RootD3PD::getClass (const std::type_info& ti)
789{
790 TClass* cls = gROOT->GetClass (ti);
791 if (!cls) {
792 // Can't do autoloading via type_info.
793 // Try to convert back to a name...
794 std::string tiname = System::typeinfoName (ti);
795 cls = gROOT->GetClass (tiname.c_str());
796 }
797
798 if (!cls) {
799 REPORT_MESSAGE (MSG::ERROR) << "Can't find class for typeinfo "
800 << ti.name();
801 }
802
803 return cls;
804}
805
806
815bool RootD3PD::isAllowed (const std::string& name)
816{
817 // If the list of allowed names is not empty, the name has to match
818 // one of them:
819 if( m_allowedNames.size() ) {
820 if( std::find_if( m_allowedNames.begin(), m_allowedNames.end(),
821 NameMatches( name ) ) == m_allowedNames.end() ) {
822 return false;
823 }
824 }
825
826 // Now check that the name doesn't appear on the veto list:
827 if( std::find_if( m_vetoedNames.begin(), m_vetoedNames.end(),
828 NameMatches( name ) ) != m_vetoedNames.end() ) {
829 return false;
830 }
831
832 // If all of these passed, then the variable is allowed to
833 // be put into the output:
834 return true;
835}
836
837
838StatusCode RootD3PD::addFakeVariable (const std::string& name,
839 const std::type_info& ti,
840 void*& ptr)
841{
842 // Check if this variable already exists:
843 std::map< std::string, FakeProxy* >::const_iterator itr =
844 m_fakeVars.find( name );
845 if( itr != m_fakeVars.end() ) {
846 REPORT_MESSAGE_WITH_CONTEXT( MSG::FATAL, "RootD3PD" )
847 << "\"Fake\" variable with name \"" << name << "\" already created";
848 return StatusCode::FAILURE;
849 }
850
851 // Check if we have a dictionary for this type:
852 ::TClass* cls = FakeProxy::getClass( ti );
853 if( cls ) {
854 // Create and store the new object:
855 ptr = cls->New();
856 m_fakeVars[ name ] = new FakeProxy( ptr, ti );
857 return StatusCode::SUCCESS;
858 }
859
860 // If not, then try to see if it's a primitive type:
861 ptr = FakeProxy::newPrimitive( ti );
862 if( ptr ) {
863 m_fakeVars[ name ] = new FakeProxy( ptr, ti );
864 return StatusCode::SUCCESS;
865 }
866
867 // If both of these failed, then let's bail:
868 REPORT_MESSAGE_WITH_CONTEXT( MSG::FATAL, "RootD3PD" )
869 << "Couldn't create \"fake\" variable of type: " << ti.name();
870 return StatusCode::FAILURE;
871}
872
873
885void RootD3PD::setPoolFile (const std::string& poolFile)
886{
887 m_poolFile = poolFile;
888}
889
890
891} // namespace D3PD
892
Helpers for checking error return status codes and reporting errors.
#define REPORT_MESSAGE(LVL)
Report a message.
#define REPORT_MESSAGE_WITH_CONTEXT(LVL, CONTEXT_NAME)
Report a message, with an explicitly specified context name.
#define CHECK(...)
Evaluate an expression and check for errors.
static Double_t ss
Root-based D3PD tree.
Proxy class for storing any kind of object.
Definition FakeProxy.h:33
static void * newPrimitive(const std::type_info &ti)
Create a new instance of a primitive.
::TClass * getClass(const std::type_info &ti)
Access the dictionary of a specific object.
Definition FakeProxy.cxx:79
unsigned int Dim_t
Currently unimplemented — see design note.
Definition ID3PD.h:52
int m_entryOffsetLen
Specified entry offset buffer length.
Definition RootD3PD.h:214
TTree * m_tree
The underlying root tree.
Definition RootD3PD.h:205
bool isAllowed(const std::string &name)
Decide if a given variable name is allowed.
Definition RootD3PD.cxx:815
virtual StatusCode addVariable(const std::string &name, const std::type_info &ti, void *&ptr, const std::string &docstring="", const void *defval=0) override
Add a variable to the tuple.
Definition RootD3PD.cxx:485
std::vector< std::string > m_vetoedNames
List of names/regular expressions not allowed to be put into the output tree.
Definition RootD3PD.h:225
std::map< std::string, FakeProxy * > m_fakeVars
"Fake" variables, only kept in memory
Definition RootD3PD.h:228
int m_basketSize
Specified basket size.
Definition RootD3PD.h:211
virtual StatusCode addDimensionedVariable(const std::string &name, const std::type_info &ti, void *&ptr, const std::string &dim, const std::string &docstring="", const void *defval=0) override
Add a variable to the tuple.
Definition RootD3PD.cxx:605
std::string m_poolFile
If set, the name of a pool data file to which we should attach ourself.
Definition RootD3PD.h:231
std::vector< std::string > m_allowedNames
List of names/regular expressions allowed to be put into the output tree.
Definition RootD3PD.h:221
const TTree * tree() const
Return the underlying root tree.
Definition RootD3PD.cxx:676
RootD3PD(TTree *tree, const std::string &master, const std::vector< std::string > &allowedNames=std::vector< std::string >(), const std::vector< std::string > &vetoedNames=std::vector< std::string >(), int basketSize=-1, int entryOffsetLen=-1)
Constructor.
Definition RootD3PD.cxx:439
virtual StatusCode capture() override
Capture the current state of all variables and write to the tuple.
Definition RootD3PD.cxx:621
Root::Cleartable * m_cleartable
Helper to clear variables.
Definition RootD3PD.h:217
std::string m_master
The name of the master tree.
Definition RootD3PD.h:208
StatusCode attachPoolFile()
Try to attach to a pool file, if we haven't yet done so.
Definition RootD3PD.cxx:635
virtual StatusCode clear() override
Clear all the tuple variables.
Definition RootD3PD.cxx:659
TClass * getClass(const std::type_info &ti)
Try to convert from a std::type_info to a TClass.
Definition RootD3PD.cxx:788
~RootD3PD()
Destructor.
Definition RootD3PD.cxx:460
const std::string & master() const
Return the name of the master tree.
Definition RootD3PD.cxx:690
virtual StatusCode addMetadata(const std::string &key, const void *obj, const std::type_info &ti) override
Add a new piece of metadata to the tuple.
Definition RootD3PD.cxx:709
void setPoolFile(const std::string &poolFile)
Set the name of a pool file to which we should attach.
Definition RootD3PD.cxx:885
StatusCode addFakeVariable(const std::string &name, const std::type_info &ti, void *&ptr)
Create a variable in memory only.
Definition RootD3PD.cxx:838
virtual StatusCode redim(const Dim_t *ptr) override
Currently unimplemented — see design note.
Definition RootD3PD.cxx:667
Hold information on how to clear one variable.
Definition RootD3PD.cxx:130
enum D3PD::Root::Clearinfo::Cleartype m_type
TVirtualCollectionProxy * m_proxy
The collection proxy for this variable. Used for COLLECTION.
Definition RootD3PD.cxx:188
TMethodCall m_meth
The clear method for this variable. Used for CLEAR.
Definition RootD3PD.cxx:191
Cleartype
The method to use to clear this variable.
Definition RootD3PD.cxx:160
@ CLEAR
Clear variable by calling clear().
Definition RootD3PD.cxx:171
@ COLLECTION
Clear variable via collection proxy.
Definition RootD3PD.cxx:168
@ COPY
Copy from a default (only for basic types).
Definition RootD3PD.cxx:177
@ INVALID
Not set yet.
Definition RootD3PD.cxx:162
@ ZERO
Clear variable by filling with zeros.
Definition RootD3PD.cxx:165
@ RESET
Clear variable by deleting and recreating.
Definition RootD3PD.cxx:174
TBranchElement * m_bre
The branch element for this variable, Used for COLLECTION, CLEAR, RESET.
Definition RootD3PD.cxx:185
StatusCode init(TBranch *br, char *defval, size_t defsize)
Initialize for clearing a variable.
Definition RootD3PD.cxx:227
size_t m_defsize
Default value size for COPY.
Definition RootD3PD.cxx:197
char * m_default
Default value for COPY. We own this.
Definition RootD3PD.cxx:194
void free()
Free allocated memory.
Definition RootD3PD.cxx:346
Clearinfo()
Constructor.
Definition RootD3PD.cxx:206
void clear()
Clear the variable.
Definition RootD3PD.cxx:301
TLeaf * m_leaf
The leaf for this variable. Used for ZERO.
Definition RootD3PD.cxx:182
Table giving information on how to clear all variables in a tree.
Definition RootD3PD.cxx:356
~Cleartable()
Destructor.
Definition RootD3PD.cxx:387
void clear()
Clear all branches.
Definition RootD3PD.cxx:416
StatusCode add(TBranch *br, char *defval, size_t defsize)
Initialize for clearing a variable.
Definition RootD3PD.cxx:404
std::vector< Clearinfo > m_info
Definition RootD3PD.cxx:380
Block filler tool for noisy FEB information.