AsgxAODNTupleMakerAlg.h 15.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Dear emacs, this is -*- c++ -*-
//
// Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
//
#ifndef ASGANALYSISALGORITHMS_ASGXAODNTUPLEMAKERALG_H
#define ASGANALYSISALGORITHMS_ASGXAODNTUPLEMAKERALG_H

// System include(s):
#include <unordered_map>
#include <string>
#include <vector>
#include <memory>
#include <list>

// Framework include(s):
16
#include "AsgMessaging/AsgMessaging.h"
17
#include "AsgServices/ServiceHandle.h"
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
#include "AnaAlgorithm/AnaAlgorithm.h"
#include "SystematicsHandles/SysListHandle.h"

// EDM include(s):
#include "AthContainersInterfaces/IAuxTypeVector.h"
#include "AthContainers/AuxElement.h"

// Forward declaration(s):
class TClass;
class TTree;
class TVirtualCollectionProxy;
namespace SG {
   class AuxVectorBase;
   class IAuxTypeVectorFactory;
}

namespace CP {

   /// Algorithm that can write a simple ntuple from xAOD objects/variables
   ///
   /// This is meant as a simple tool for creating small ntuples in analyses,
   /// using a simple job configuration. It can create branches from any xAOD
   /// variables that are possible to write as an "xAOD variable" to begin with.
   ///
   /// It is *not* meant as a general purpose DAOD -> NTuple dumper however.
   /// It should only be used to create small ntuples, with highly processed
   /// variables.
   ///
   /// It's "main" property ("Branches") can be filled with entries of the form:
   ///
   /// <code>
   ///    writer = ...<br/>
   ///    writer.Branches = [ "<SG key>.<aux variable> -> <branch name>", ... ]
   /// </code>
   ///
   /// , where each entry sets up one branch for the output tree.
   ///
   /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch>
   ///
   class AsgxAODNTupleMakerAlg : public EL::AnaAlgorithm {

   public:
      /// Algorithm constructor
      AsgxAODNTupleMakerAlg( const std::string& name, ISvcLocator* svcLoc );

      /// @name Functions inherited from @c EL::AnaAlgorithm
      /// @{

      /// Function executed as part of the job initialisation
      StatusCode initialize() override;

      /// Function executed once per event
      StatusCode execute() override;

      /// Function executed as part of the job finalisation
      StatusCode finalize() override;

      /// @}

   private:
      /// Function setting up the internal data structures on the first event
      StatusCode setupTree();

      /// Function setting up an individual branch on the first event
      StatusCode setupBranch( const std::string &branchDecl,
                              const CP::SystematicSet &sys );

      /// @name Algorithm properties
      /// @{

      /// The name of the output tree to write
      std::string m_treeName;
      /// The branches to write into this output tree
      std::vector< std::string > m_branches;

      /// @}

      /// Class writing all variables from one standalone object
      ///
      /// It is designed to work with any type inheriting from
      /// @c SG::AuxElement. Like @c xAOD::EventInfo. Which is its main user
      /// at the moment...
      ///
      class ElementProcessor : public asg::AsgMessaging {

      public:
         /// Default constructor
         ///
         /// We have to have a default constructor to initialise the
         /// @c asg::AsgMessaging base class correctly. Members of this class
         /// would not need an explicit constructor themselves.
         ///
         ElementProcessor();

         /// Process the object
         ///
         /// This function is called during the event processing to extract
         /// all configured variables from a standalone xAOD object into the
         /// output variables set up using @c ElementProcessor::addBranch.
         ///
         /// @param element The xAOD (interface) object to process
         /// @return The usual @c StatusCode values
         ///
         StatusCode process( const SG::AuxElement& element );

         /// Add one branch to the output tree
         ///
         /// This function is used during the setup of the output tree to create
         /// one branch in it, from one specific auxiliary variable. The type of
         /// the variable is figured out at runtime using the auxiliary store
         /// infrastructure.
         ///
         /// @param tree The tree to create the branch in
         /// @param auxName Name of the auxiliary variable to create the branch
         ///                from
         /// @param branchName The name of the branch to create in the tree
         /// @param allowMissing Set to @c true to print an error message in case
         ///                     of a failure
         /// @param created Used to store if the branch was actually created
         /// @return The usual @c StatusCode values
         ///
         StatusCode addBranch( TTree& tree, const std::string& auxName,
                               const std::string& branchName,
                               bool allowMissing,
                               bool &created );

      private:
         /// Class writing one variable from an xAOD object into a branch
         ///
         /// It is used for both setting up the branch in the outut @c TTree
         /// during the setup of the tree, and then to fill the "output
         /// variable" with the right payload during the event processing.
         ///
         /// Note that since we may have a *lot* of such objects, I didn't want
         /// to make it inherit from @c asg::AsgMessaging. Which means that all
         /// of the class's functions need to receive its parent's message
         /// stream object to be able to log error messages "nicely".
         ///
         /// Also note that since this is very much an internal class, all of
         /// its members are public. Since the owner of such objects should know
         /// perfectly well how they behave.
         ///
         class BranchProcessor {

         public:
            /// Function setting up the object, and the branch
            ///
            /// This is pretty much the constructor of the class. I just decided
            /// to implement it as a regular function and not a "real"
            /// constructor, to be able to return a @c StatusCode value from the
            /// call. Since the setup of the object may very well fail.
            ///
            /// @param tree The tree to set up the new branch in
            /// @param auxName The name of the auxiliary variable to create
            ///                a branch from
            /// @param branchName Name of the branch to create in the tree
            /// @param msg Reference to the parent's @c MsgStream object
            /// @return The usual @c StatusCode values
            ///
            StatusCode setup( TTree& tree, const std::string& auxName,
                              const std::string& branchName,
                              MsgStream& msg );

            /// Function processing the object, filling the variable
            ///
            /// This function is called by @c ElementProcessor, to extract one
            /// variable from the standalone object, and move its payload into
            /// the memory address from which the output tree is writing its
            /// branch.
            ///
            /// @param element The standalone object to get the auxiliary
            ///                variable from
            /// @param msg Reference to the parent's @c MsgStream object
            /// @return The usual @c StatusCode values
            ///
            StatusCode process( const SG::AuxElement& element,
                                MsgStream& msg );

            /// Name of the branch being written
            std::string m_branchName;
            /// Object accessing the variable in question
            std::unique_ptr< SG::AuxElement::TypelessConstAccessor > m_acc;
            /// Pointer to the helper object that handles this variable
            const SG::IAuxTypeVectorFactory* m_factory = nullptr;
            /// The object managing the memory of the written variable
            std::unique_ptr< SG::IAuxTypeVector > m_data;
            /// Helper variable, pointing at the object to be written
            void* m_dataPtr = nullptr;

         }; // class BranchProcessor

         /// List of branch processors set up for this xAOD object
         ///
         /// Note that when we set up a branch, we tell @c TTree to remember a
         /// physical address in memory. To make sure that the address of the
         /// object held by the branch processors are not moved in memory after
         /// their construction, we have to use an @c std::list container here.
         /// @c std::vector would not work. (As it can relocate objects when
         /// increasing the size of the container.)
         ///
         std::list< BranchProcessor > m_branches;

      }; // class ElementProcessor

      /// Class writing all variables from one @c DataVector container
      ///
      /// It is designed to work with *any* @c DataVector<SG::AuxElement> type,
      /// it doesn't have to be an @c xAOD::IParticleContainer. But of course
      /// that is the main use case for it...
      ///
      /// It expects an @c SG::AuxVectorBase object from the caller, iterates
      /// over the elements of that container using the ROOT dictionary of the
      /// type, and writes individual variables from the elements of the
      /// container using the same machinery that @c ElementProcessor employs.
      ///
      class ContainerProcessor : public asg::AsgMessaging {

      public:
         /// Default constructor
         ///
         /// We have to have a default constructor to initialise the
         /// @c asg::AsgMessaging base class correctly. Members of this class
         /// would not need an explicit constructor themselves.
         ///
         ContainerProcessor();

         /// Process the container
         ///
         /// This function is called during the event processing to extract
         /// all configured variables from an xAOD container into the
         /// output variables set up using @c ContainerProcessor::addBranch.
         ///
         /// @param container The xAOD (interface) container to process
         /// @return The usual @c StatusCode values
         ///
         StatusCode process( const SG::AuxVectorBase& container );

         /// Add one branch to the output tree
         ///
         /// This function is used during the setup of the output tree to create
         /// one branch in it, from one specific auxiliary variable. The type of
         /// the variable is figured out at runtime using the auxiliary store
         /// infrastructure.
         ///
         /// @param tree The tree to create the branch in
         /// @param auxName Name of the auxiliary variable to create the branch
         ///                from
         /// @param branchName The name of the branch to create in the tree
         /// @param allowMissing Set to @c true to print an error message in case
         ///                     of a failure
         /// @param created Used to store if the branch was actually created
         /// @return The usual @c StatusCode values
         ///
         StatusCode addBranch( TTree& tree, const std::string& auxName,
                               const std::string& branchName,
                               bool allowMissing,
                               bool &created );

      private:
         /// Class writing one variable from an xAOD object into a branch
         ///
         /// It is used for both setting up the branch in the outut @c TTree
         /// during the setup of the tree, and then to fill the "output
         /// variable" with the right payload during the event processing.
         ///
         /// Note that since we may have a *lot* of such objects, I didn't want
         /// to make it inherit from @c asg::AsgMessaging. Which means that all
         /// of the class's functions need to receive its parent's message
         /// stream object to be able to log error messages "nicely".
         ///
         /// Also note that since this is very much an internal class, all of
         /// its members are public. Since the owner of such objects should know
         /// perfectly well how they behave.
         ///
         /// Finally, note that it is more complicated than the
         /// @c ElementProcessor::BranchProcessor class. Since in this case we
         /// need to explicitly deal with @c std::vector types, which we need to
         /// fill explicitly when extracting the variables from the xAOD
         /// objects.
         ///
         class BranchProcessor {

         public:
            /// Function setting up the object, and the branch
            StatusCode setup( TTree& tree, const std::string& auxName,
                              const std::string& branchName,
                              MsgStream& msg );
            /// Function (re)sizing the variable for a new event
            StatusCode resize( size_t size, MsgStream& msg );
            /// Function processing the object, filling the variable
            StatusCode process( const SG::AuxElement& element, size_t index,
                                MsgStream& msg );

            /// Name of the branch being written
            std::string m_branchName;
            /// Object accessing the variable in question
            std::unique_ptr< SG::AuxElement::TypelessConstAccessor > m_acc;
            /// Pointer to the helper object that handles this variable
            const SG::IAuxTypeVectorFactory* m_factory = nullptr;
            /// The object managing the memory of the written variable
            std::unique_ptr< SG::IAuxTypeVector > m_data;
            /// Helper variable, pointing at the object to be written
            void* m_dataPtr = nullptr;

         }; // class BranchProcessor

         /// List of branch processors set up for this xAOD object
         ///
         /// Note that when we set up a branch, we tell @c TTree to remember a
         /// physical address in memory. To make sure that the address of the
         /// object held by the branch processors are not moved in memory after
         /// their construction, we have to use an @c std::list container here.
         /// @c std::vector would not work. (As it can relocate objects when
         /// increasing the size of the container.)
         ///
         std::list< BranchProcessor > m_branches;
         /// Collection proxy used for iterating over the container
         TVirtualCollectionProxy* m_collProxy = nullptr;
         /// Offset of the element type to @c SG::AuxElement
         int m_auxElementOffset = -1;

      }; // class ContainerProcessor

      /// @name Variables used for the TTree filling
      /// @{

      /// The tree being written
      TTree* m_tree = nullptr;

      /// Objects to write branches from
      std::unordered_map< std::string, ElementProcessor > m_elements;
      /// Containers to write branches from
      std::unordered_map< std::string, ContainerProcessor > m_containers;

      /// Internal status flag, showing whether the algorithm is initialised
      ///
      /// This is necessary because we can only set up the output @c TTree while
      /// processing the first event, we can't do it in
      /// @c CP::AsgxAODNTupleMakerAlg::initialize.
      ///
      bool m_isInitialized = false;

360
361
      /// \brief the handle for the systematics service
      ServiceHandle<ISystematicsSvc> m_systematicsService {"SystematicsSvc", ""};
362
363
364
365
366
367
368
369

      /// @}

   }; // class AsgxAODNTupleMakerAlg

} // namespace CP

#endif // ASGANALYSISALGORITHMS_ASGXAODNTUPLEMAKERALG_H