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