ATLAS Offline Software
ViewHelper.h
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 #ifndef ATHVIEWS_VIEWHELPER_HH
6 #define ATHVIEWS_VIEWHELPER_HH
7 
8 #include "GaudiKernel/SmartIF.h"
9 #include "GaudiKernel/IScheduler.h"
10 #include "GaudiKernel/EventContext.h"
11 #include "GaudiKernel/StatusCode.h"
13 #include "StoreGate/WriteHandle.h"
14 #include "StoreGate/ReadHandle.h"
15 #include "AthViews/View.h"
18 
19 
20 namespace ViewHelper
21 {
22  //Function to create a vector of views, each populated with one data object
23  template< typename T >
24  inline StatusCode makeAndPopulate( std::string const& viewNameRoot, ViewContainer* viewVector,
25  SG::WriteHandleKey< T > const& populateKey, EventContext const& sourceContext,
26  std::vector< T > const& inputData, bool const allowFallThrough = true )
27  {
28  //Check for spaces in the name
29  if ( viewNameRoot.find( ' ' ) != std::string::npos )
30  {
31  return StatusCode::FAILURE;
32  }
33 
34  //Make a WriteHandle to use
35  SG::WriteHandle<T> populateHandle( populateKey, sourceContext );
36 
37  //Loop over all input data
38  unsigned int const viewNumber = inputData.size();
39  for ( unsigned int viewIndex = 0; viewIndex < viewNumber; ++viewIndex )
40  {
41  //Create view
42  SG::View * outputView = new SG::View( viewNameRoot, viewIndex, allowFallThrough );
43  viewVector->push_back( outputView );
44 
45  //Attach a handle to the view
46  StatusCode sc = populateHandle.setProxyDict( outputView );
47  if ( !sc.isSuccess() )
48  {
49  viewVector->clear();
50  return sc;
51  }
52 
53  //Populate the view
54  sc = populateHandle.record( std::make_unique< T >( inputData[ viewIndex ] ) );
55  if ( !sc.isSuccess() )
56  {
57  viewVector->clear();
58  return sc;
59  }
60  }
61 
62  return StatusCode::SUCCESS;
63  }
64 
65  //Function to pass a single view to the scheduler
66  inline StatusCode scheduleSingleView( SG::View* view, std::string const& nodeName, EventContext const& sourceContext,
67  EventIDBase::number_type conditionsRun, SmartIF<IScheduler> scheduler )
68  {
69  //Make a new context with the view attached
70  auto viewContext = std::make_unique< EventContext >( sourceContext );
71  if ( view->getROI().isValid() ) {
72  Atlas::setExtendedEventContext( *viewContext,
73  Atlas::ExtendedEventContext( view, conditionsRun, *view->getROI() ) );
74  } else {
75  Atlas::setExtendedEventContext( *viewContext,
76  Atlas::ExtendedEventContext( view, conditionsRun ) );
77  }
78 
79  //Attach the view to the named node
80  return scheduler->scheduleEventView( &sourceContext, nodeName, std::move( viewContext ) );
81  }
82 
83  //Function to attach a set of views to a graph node
84  inline StatusCode scheduleViews( ViewContainer * viewVector, std::string const& nodeName,
85  EventContext const& sourceContext, SmartIF<IScheduler> scheduler, bool reverseOrder = false )
86  {
87  //Require the information of the extended context (should always be there, but check anyway)
88  if ( !Atlas::hasExtendedEventContext( sourceContext ) ) {
89  return StatusCode::FAILURE;
90  }
91  Atlas::ExtendedEventContext const extendedContext = Atlas::getExtendedEventContext( sourceContext );
92 
93  //Prevent view nesting - test if source context has view attached
94  if ( dynamic_cast< SG::View* >( extendedContext.proxy() ) ) {
95  return StatusCode::FAILURE;
96  }
97 
98  //Retrieve the scheduler
99  if ( !scheduler ) {
100  return StatusCode::FAILURE;
101  }
102 
103  if ( viewVector->empty() ) {
104 
105  //Disable the node if no views
106  return scheduler->scheduleEventView( &sourceContext, nodeName, 0 );
107  }
108  else {
109  if ( reverseOrder ) {
110  for ( auto iter = viewVector->rbegin(); iter != viewVector->rend(); ++iter ) {
111 
112  //Schedule each view in reverse (should make no difference, just a debugging tool)
113  if ( scheduleSingleView( *iter, nodeName, sourceContext,
114  extendedContext.conditionsRun(), scheduler ).isFailure() ) {
115  return StatusCode::FAILURE;
116  }
117  }
118  }
119  else {
120  for ( SG::View* view : *viewVector ) {
121 
122  //Schedule each view
123  if ( scheduleSingleView( view, nodeName, sourceContext,
124  extendedContext.conditionsRun(), scheduler ).isFailure() ) {
125  return StatusCode::FAILURE;
126  }
127  }
128  }
129  }
130 
131  return StatusCode::SUCCESS;
132  }
133 
134  class ViewMerger {
135  private:
137  MsgStream& m_msg;
138  public:
139  ViewMerger(StoreGateSvc* sg, MsgStream& msg ) : m_sg( sg ), m_msg( msg ) {}
140 
141  //Function merging view data into a single collection
142  template< typename T >
143  inline StatusCode mergeViewCollection( ViewContainer const& viewVector, SG::ReadHandleKey< T > const& queryKey, EventContext const& sourceContext, T & outputData )
144  {
145  //Make a ReadHandle to use
146  SG::ReadHandle<T> queryHandle( queryKey, sourceContext );
147 
148  //Loop over all views
149  for ( SG::View* inputView : viewVector )
150  {
151  //Attach the handle to the view
152  StatusCode sc = queryHandle.setProxyDict( inputView );
153  if ( !sc.isSuccess() )
154  {
155  m_msg << MSG::ERROR <<"Failed to use view " << inputView->name() << " to read " << queryHandle.key() << " resetting output" << endmsg;
156  outputData.clear();
157  return sc;
158  }
159 
160  //Merge the data
161  T inputData = *queryHandle;
162  outputData.insert( outputData.end(), inputData.begin(), inputData.end() );
163  }
164 
165  return StatusCode::SUCCESS;
166  }
167 
168  //Function merging view data into a single collection - overload for datavectors to do all the bookkeeping
169  //Adds aux data element "viewIndex" to indicate which element of the merged collection came from where
170  //Calls remap for ElementLinks so that they point to the merged collection
171  template< typename T >
172  inline StatusCode mergeViewCollection( ViewContainer const& viewVector, SG::ReadHandleKey< DataVector< T > > const& queryKey, EventContext const& sourceContext, DataVector< T > & outputData )
173  {
174  //Check that there's a non-const aux store for output bookkeeping
175  if ( !outputData.getStore() )
176  {
177  m_msg << MSG::ERROR << "output data does not have the store" << endmsg;
178  return StatusCode::FAILURE;
179  }
180 
181  //Make ReadHandle to access views
182  SG::ReadHandle< DataVector< T > > queryHandle( queryKey, sourceContext );
183 
184  //Make accessor for bookkeeping
186 
187  //Loop over all views
188  unsigned int offset = outputData.size(); //allow for existing objects in the container
189  for ( auto inputView : viewVector )
190  {
191  //Attach the handle to the view
192  StatusCode sc = queryHandle.setProxyDict( inputView );
193  if ( !sc.isSuccess() )
194  {
195  m_msg << MSG::ERROR << "Failed to use view " << inputView->name() << " to read " << queryHandle.key() << endmsg;
196  return sc;
197  }
198 
199  //Nothing to do for empty collections
200  if ( queryHandle->size() == 0 )
201  {
202  if (m_msg.level() <= MSG::DEBUG) {
203  m_msg << MSG::DEBUG << "Empty collection " << queryHandle.key() <<" in a view " << inputView->name() <<endmsg;
204  continue;
205  }
206  }
207 
208  //Merge the data
209  for ( const auto inputObject : *queryHandle.cptr() )
210  {
211  //Element-wise copy data (looks a bit weird, but necessary for xAOD objects)
212  T * outputObject = new T();
213  outputData.push_back( outputObject );
214  *outputObject = *inputObject;
215 
216  //Add aux data for bookkeeping
217  viewBookkeeper( *outputObject ) = inputView->getROI();
218  }
219 
220  if (m_msg.level() <= MSG::DEBUG) {
221  m_msg << MSG::DEBUG << "Copied " << queryHandle->size() << " objects from collection in view " << inputView->name() << endmsg;
222  }
223 
224  //Declare remapping
225  auto proxy = inputView->proxy( queryHandle.clid(), queryHandle.key() ); //shouldn't need to test validity since queryHandle already used
227  proxy->name(),
228  queryHandle.name(),
229  offset );
230  offset += queryHandle->size();
231  }
232 
233  return StatusCode::SUCCESS;
234  }
235  };
236 
237 
241  inline SG::View* makeView( const std::string& common_name, int const unique_index = -1, bool const allowFallThrough = true )
242  {
243  //Check for spaces in the name
244  if ( common_name.find( ' ' ) != std::string::npos )
245  {
246  return nullptr;
247  }
248 
249  return new SG::View( common_name, unique_index, allowFallThrough );
250  }
251 
252 
257  template<typename T>
258  SG::ReadHandle<T> makeHandle( const SG::View* view , const SG::ReadHandleKey<T>& rhKey, const EventContext& context )
259  {
260  SG::View* nview ATLAS_THREAD_SAFE = const_cast< SG::View* >( view ); //We need it until reading from const IProxyDict is supported
261 
262  auto handle = SG::makeHandle( rhKey, context );
263  if ( handle.setProxyDict( nview ).isFailure() ) {
264  //We ignore it because the handle will be invalid anyway if this call is unsuccessful
265  throw std::runtime_error( "Can't make ReadHandle of key " + rhKey.key() + " type " + ClassID_traits<T>::typeName() + " in view " + view->name() );
266  }
267  return handle;
268  }
269 
270 
275  template<typename T>
276  ElementLink<T> makeLink( const SG::View* view, const SG::ReadHandle<T>& handle, size_t index )
277  {
278  auto proxy = view->proxy( handle.clid(), handle.key() );
279  if ( proxy == nullptr ) throw std::runtime_error( "Attempting to make element link with invalid key " + handle.key() );
280  return ElementLink<T>( proxy->name(), index );
281  }
282 
283 } // EOF namspace ViewHelper
284 
285 #endif
ViewContainer::rbegin
reverse_iterator rbegin()
Definition: View.h:187
StateLessPT_NewConfig.proxy
proxy
Definition: StateLessPT_NewConfig.py:392
ID
std::vector< Identifier > ID
Definition: CalibHitIDCheck.h:24
SG::ReadHandle::cptr
const_pointer_type cptr()
Dereference the pointer.
SG::Accessor
Helper class to provide type-safe access to aux data.
Definition: Control/AthContainers/AthContainers/Accessor.h:66
Atlas::ExtendedEventContext::conditionsRun
EventIDBase::number_type conditionsRun() const
Definition: ExtendedEventContext.h:38
SG::ReadHandle
Definition: StoreGate/StoreGate/ReadHandle.h:70
index
Definition: index.py:1
SG::VarHandleBase::name
const std::string & name() const
Return the StoreGate ID for the referenced object.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleBase.cxx:75
ExtendedEventContext.h
ViewHelper::makeLink
ElementLink< T > makeLink(const SG::View *view, const SG::ReadHandle< T > &handle, size_t index)
Create EL to a collection in view.
Definition: ViewHelper.h:276
SG::VarHandleBase::clid
CLID clid() const
Return the class ID for the referenced object.
ViewHelper::makeHandle
SG::ReadHandle< T > makeHandle(const SG::View *view, const SG::ReadHandleKey< T > &rhKey, const EventContext &context)
navigate from the TrigComposite to nearest view and fetch object from it
Definition: ViewHelper.h:258
Atlas::hasExtendedEventContext
bool hasExtendedEventContext(const EventContext &ctx)
Test whether a context object has an extended context installed.
Definition: ExtendedEventContext.cxx:23
ViewContainer::rend
reverse_iterator rend()
Definition: View.h:188
ViewHelper::scheduleSingleView
StatusCode scheduleSingleView(SG::View *view, std::string const &nodeName, EventContext const &sourceContext, EventIDBase::number_type conditionsRun, SmartIF< IScheduler > scheduler)
Definition: ViewHelper.h:66
AtlasMcWeight::number_type
unsigned int number_type
Definition: AtlasMcWeight.h:20
SG::VarHandleKey::key
const std::string & key() const
Return the StoreGate ID for the referenced object.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleKey.cxx:141
SG::ReadHandleKey
Property holding a SG store/key/clid from which a ReadHandle is made.
Definition: StoreGate/StoreGate/ReadHandleKey.h:39
AthenaPoolTestRead.sc
sc
Definition: AthenaPoolTestRead.py:27
ViewContainer::clear
void clear()
Definition: View.h:180
SG::makeHandle
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
Definition: ReadCondHandle.h:269
Atlas::getExtendedEventContext
const ExtendedEventContext & getExtendedEventContext(const EventContext &ctx)
Retrieve an extended context from a context object.
Definition: ExtendedEventContext.cxx:32
WriteHandle.h
Handle class for recording to StoreGate.
StoreGateSvc
The Athena Transient Store API.
Definition: StoreGateSvc.h:128
ViewContainer::push_back
void push_back(SG::View *ptr)
Definition: View.h:177
SG::WriteHandleKey
Property holding a SG store/key/clid from which a WriteHandle is made.
Definition: StoreGate/StoreGate/WriteHandleKey.h:40
SG::VarHandleBase::setProxyDict
virtual StatusCode setProxyDict(IProxyDict *store)
Explicitly set the event store.
Definition: StoreGate/src/VarHandleBase.cxx:534
ViewHelper::makeView
SG::View * makeView(const std::string &common_name, int const unique_index=-1, bool const allowFallThrough=true)
Definition: ViewHelper.h:241
Atlas::ExtendedEventContext
Definition: ExtendedEventContext.h:23
endmsg
#define endmsg
Definition: AnalysisConfig_Ntuple.cxx:63
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ViewHelper::scheduleViews
StatusCode scheduleViews(ViewContainer *viewVector, std::string const &nodeName, EventContext const &sourceContext, SmartIF< IScheduler > scheduler, bool reverseOrder=false)
Definition: ViewHelper.h:84
ClassID_traits
Default, invalid implementation of ClassID_traits.
Definition: Control/AthenaKernel/AthenaKernel/ClassID_traits.h:40
DataVector< T >
ViewHelper::ViewMerger::m_sg
StoreGateSvc * m_sg
Definition: ViewHelper.h:136
ViewHelper::makeAndPopulate
StatusCode makeAndPopulate(std::string const &viewNameRoot, ViewContainer *viewVector, SG::WriteHandleKey< T > const &populateKey, EventContext const &sourceContext, std::vector< T > const &inputData, bool const allowFallThrough=true)
Definition: ViewHelper.h:24
ViewHelper::ViewMerger::mergeViewCollection
StatusCode mergeViewCollection(ViewContainer const &viewVector, SG::ReadHandleKey< DataVector< T > > const &queryKey, EventContext const &sourceContext, DataVector< T > &outputData)
Definition: ViewHelper.h:172
ViewHelper::ViewMerger::ViewMerger
ViewMerger(StoreGateSvc *sg, MsgStream &msg)
Definition: ViewHelper.h:139
DataVector::push_back
value_type push_back(value_type pElem)
Add an element to the end of the collection.
ViewHelper::ViewMerger::mergeViewCollection
StatusCode mergeViewCollection(ViewContainer const &viewVector, SG::ReadHandleKey< T > const &queryKey, EventContext const &sourceContext, T &outputData)
Definition: ViewHelper.h:143
SG::VarHandleBase::key
virtual const std::string & key() const override final
Return the StoreGate ID for the referenced object.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleBase.cxx:64
SG::WriteHandle
Definition: StoreGate/StoreGate/WriteHandle.h:76
DataVector.h
An STL vector of pointers that by default owns its pointed-to elements.
StoreGateSvc::remap
void remap(CLID clid, const TKEY &source, const TKEY &target, off_t index_offset)
Declare a remapping.
SG::WriteHandle::record
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
ViewHelper::ViewMerger::m_msg
MsgStream & m_msg
Definition: ViewHelper.h:137
DEBUG
#define DEBUG
Definition: page_access.h:11
convertTimingResiduals.offset
offset
Definition: convertTimingResiduals.py:71
ViewHelper::ViewMerger
Definition: ViewHelper.h:134
ATLAS_THREAD_SAFE
#define ATLAS_THREAD_SAFE
Definition: checker_macros.h:211
ViewContainer::empty
bool empty() const
Definition: View.h:179
View.h
ViewHelper
Definition: ViewHelper.h:21
ReadHandle.h
Handle class for reading from StoreGate.
SG::View
Definition: View.h:25
DataVector::size
size_type size() const noexcept
Returns the number of elements in the collection.
python.AutoConfigFlags.msg
msg
Definition: AutoConfigFlags.py:7
Atlas::setExtendedEventContext
void setExtendedEventContext(EventContext &ctx, ExtendedEventContext &&ectx)
Move an extended context into a context object.
Definition: ExtendedEventContext.cxx:50
AuxElement.h
Base class for elements of a container that can have aux data.
drawFromPickle.view
view
Definition: drawFromPickle.py:294
ViewContainer
Definition: View.h:161