xAODWriterAlg.cxx 7.11 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//
// Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
//

// System include(s):
#include <regex>

// ROOT include(s):
#include <TClass.h>
#include <TFile.h>

// Core include(s):
#include "AthContainers/normalizedTypeinfoName.h"
#include "EventLoop/Worker.h"
#include "SystematicsHandles/Helpers.h"

// Local include(s):
#include "StandaloneAnalysisAlgorithms/xAODWriterAlg.h"

namespace CP {

   xAODWriterAlg::xAODWriterAlg( const std::string& name, ISvcLocator* svcLoc )
      : EL::AnaAlgorithm( name, svcLoc ) {

      // Declare the algorithm's properties.
      declareProperty( "OutputStreamName", m_outputStreamName = "ANALYSIS",
                       "Stream name of the output file to use" );
      declareProperty( "ItemList", m_itemList,
                       "Objects to write to the output file" );
      declareProperty( "BasketSize", m_basketSize = 32000,
                       "(Starter) Basket size for the created branches" );
      declareProperty( "SplitLevel", m_splitLevel = 0,
                       "Split level for the created branches" );
   }

   StatusCode xAODWriterAlg::initialize() {

38
39
40
41
      // Make sure that the xAOD::TEvent object managed by EventLoop is the
      // "active" one.
      evtStore()->event()->setActive();

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
      // Set up the systematics list.
      ATH_CHECK( m_systematicsList.initialize() );

      // Access the file of the output stream.
      TFile* ofile = wk()->getOutputFile( m_outputStreamName );
      if( ! ofile ) {
         ATH_MSG_FATAL( "Couldn't access output file for stream \""
                        << m_outputStreamName << "\"" );
         return StatusCode::FAILURE;
      }

      // Write to this output file.
      ANA_CHECK( m_event.writeTo( ofile ) );

      // Reset the internal flag(s).
      m_itemListInitialized = false;

      // Return gracefully.
      return StatusCode::SUCCESS;
   }

   StatusCode xAODWriterAlg::execute() {

      // If this is the first event, figure out which objects can actually be
      // written out.
      if( ! m_itemListInitialized ) {
         ANA_CHECK( setup() );
         m_itemListInitialized = true;
      }

      // Write all objects to the output file.
      xAOD::TEvent* event = evtStore()->event();
      for( const Item& item : m_writtenItemList ) {

         // Get the object. See the description in @c xAOD::TEvent::retrieve
         // (the const version) for an explanation of this implementation.
         static const bool SILENT = true;
         static const bool METADATA = false;
         const void* obj = event->getOutputObject( item.name, *( item.type ),
                                                   METADATA );
         if( ! obj ) {
            obj = event->getInputObject( item.name, *( item.type ), SILENT,
                                         METADATA );
         } else {
            event->getInputObject( item.name, *( item.type ), SILENT,
                                   METADATA );
         }

         // Check that we succeeded.
         if( ! obj ) {
            ATH_MSG_FATAL( "Couldn't retrieve object \"" << item.name << "\"" );
            return StatusCode::FAILURE;
         }

         // Record it to the output for the current event.
         ANA_CHECK( m_event.record( const_cast< void* >( obj ),
                                    SG::normalizedTypeinfoName( *( item.type ) ),
                                    item.name, m_basketSize, m_splitLevel ) );
      }

      // Write the event.
      if( m_event.fill() <= 0 ) {
         ATH_MSG_FATAL( "There was an error writing out the event" );
         return StatusCode::FAILURE;
      }

      // Return gracefully.
      return StatusCode::SUCCESS;
   }

   StatusCode xAODWriterAlg::finalize() {

      // Access the file of the output stream.
      TFile* ofile = wk()->getOutputFile( m_outputStreamName );
      if( ! ofile ) {
         ATH_MSG_FATAL( "Couldn't access output file for stream \""
                        << m_outputStreamName << "\"" );
         return StatusCode::FAILURE;
      }

      // Finish writing to this output file.
      ANA_CHECK( m_event.finishWritingTo( ofile ) );

      // Return gracefully.
      return StatusCode::SUCCESS;
   }

   StatusCode xAODWriterAlg::setup() {

      // Loop over all of the declared items.
      for( const std::string& stringItem : m_itemList ) {

         // Interpret the item string.
         static const std::regex itemRegex( "([^#]+)#([^\\.]+\\.?)(.*)" );
         std::smatch itemMatch;
         if( ! std::regex_match( stringItem, itemMatch, itemRegex ) ) {
            ATH_MSG_FATAL( "Item \"" << stringItem
                           << "\" is not of the form: \"Type#Name\"" );
            return StatusCode::FAILURE;
         }
         ATH_MSG_VERBOSE( "Found item: " << itemMatch[ 1 ] << "#"
                          << itemMatch[ 2 ] << itemMatch[ 3 ] );

         // Consider all systematics. Not usin CP::SysListHandle::foreach, to
         // be able to exit the for-loop early if necessary.
         auto sysVector = m_systematicsList.systematicsVector();
         for( const auto& sys : sysVector ) {

            // Event store key for the object under consideration.
            const std::string key = makeSystematicsName( itemMatch[ 2 ], sys );

            // Whether or not the object will be available, as long as
            // variable selection rules were set up for it, let xAOD::TEvent
            // know about them.
            if( itemMatch[ 3 ] != "" ) {
               ATH_MSG_DEBUG( "Calling setAuxItemList( \"" << key << "\""
                              << ", \"" << itemMatch[ 3 ]
                              << "\" )" );
               m_event.setAuxItemList( key, itemMatch[ 3 ] );
            }

            // Construct an Item object.
            Item item;
            item.name = key;
            TClass* cl = TClass::GetClass( itemMatch[ 1 ].str().c_str() );
            if( ! cl ) {
               ATH_MSG_FATAL( "Type \"" << itemMatch[ 1 ] << "\" not found" );
               return StatusCode::FAILURE;
            }
            item.type = cl->GetTypeInfo();
            if( ! item.type ) {
               ATH_MSG_FATAL( "No compiled dictionary found for \""
                              << itemMatch[ 1 ] << "\"" );
               return StatusCode::FAILURE;
            }

            // Check if the item is available.
            static const bool SILENT = true;
            static const bool METADATA = false;
            xAOD::TEvent* event = evtStore()->event();
            if( event->getOutputObject( item.name, *( item.type ), METADATA ) ||
                event->getInputObject( item.name, *( item.type ), SILENT,
                                       METADATA ) ) {
                  m_writtenItemList.push_back( item );
                  ATH_MSG_DEBUG( "Scheduling \"" << itemMatch[ 1 ] << "#"
                                 << key << "\" for writing" );
            }

            // If there was no %SYS% pattern in the object name, stop the loop
            // over the systematics now.
            if( key == itemMatch[ 2 ] ) {
               break;
            }
         }
      }

      // Return gracefully.
      return StatusCode::SUCCESS;
   }

} // namespace CP