ATLAS Offline Software
DynamicDataHelper.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3 */
6 #include "GaudiKernel/AlgTool.h"
7 #include "GaudiKernel/IClassIDSvc.h"
8 
9 #include <string_view>
10 #include <sstream>
11 
12 
13 namespace Ath {
14  namespace {
15  void insertHandles(DataObjIDPtrColl &handle_set, const std::vector<Gaudi::DataHandle*> &new_handles) {
16  for( const Gaudi::DataHandle*handle : new_handles) {
17  handle_set.insert( &handle->fullKey() );
18  }
19  }
20 
21  bool msgLvl(const MsgStream &out, const MSG::Level level) {
22  return level<= out.level();
23  }
24  }
25 
26  StatusCode DynamicDataHelper::addExtraDependencies(IClassIDSvc &clid_svc, std::vector<std::string> &undeclared_output_data, MsgStream &out) {
27  std::stringstream error;
28  if (!m_extraOutputIDs.empty()) {
29  out << MSG::FATAL << "Logic erroor. Already added some extra output data IDs. This method can only be called once." << endmsg;
30  return StatusCode::FAILURE;
31  }
32  m_extraOutputIDs.reserve( undeclared_output_data.size() );
33  for(const std::string &type_and_name : undeclared_output_data) {
34  std::string::size_type pos = type_and_name.find('/');
35  if (pos == std::string::npos) {
36  error << " " << type_and_name;
37  }
38  else {
39  std::string_view type_name(type_and_name.data(), pos);
40  std::string_view var_name(&(type_and_name.data()[pos+1]), type_and_name.size()-pos-1);
41  CLID clid;
42  if (clid_svc.getIDOfTypeName(std::string(type_name), clid).isFailure() ) {
43  // out << MSG::FATAL << " Failed to get CLID for " << type_name << endmsg;
44  // return StatusCode::FAILURE;
45  error << " no clid: " << type_name;
46  }
47  else {
48  m_extraOutputIDs.push_back( DataObjID(clid, std::string(var_name)) );
49  if (msgLvl(out,MSG::VERBOSE)) {
50  out << MSG::VERBOSE << "DEBUG add extra dependency " << type_name << " / " << var_name << " -> " << clid << endmsg;
51  }
52  }
53  }
54  }
55  if (!error.str().empty()) {
56  out << MSG::FATAL << "Invaid alements in property " << error.str().c_str() << endmsg;
57  return StatusCode::FAILURE;
58  }
59  for (const DataObjID &id : m_extraOutputIDs ) {
60  m_outputHandles.insert( &id );
61  }
62  return StatusCode::SUCCESS;
63  }
64 
65  void DynamicDataHelper::gatherDataHandlesAndDynamicConsumers(const std::string &/*parent_name*/, Gaudi::Algorithm *theAlgorithm) {
66  // |> debugging
67  auto algorithm_visitor =
68  [this](Gaudi::Algorithm *an_alg) {
69  IDynamicDataConsumer *a_dyn_data_consumer=dynamic_cast<IDynamicDataConsumer *>(an_alg);
70  if (a_dyn_data_consumer) {
71  std::vector<Gaudi::Algorithm *> &alg_list = m_dynDataConsumer[a_dyn_data_consumer];
72  if (std::find(alg_list.begin(),alg_list.end(),an_alg)==alg_list.end()) {
73  alg_list.push_back(an_alg);
74  }
75  }
76  // have to collect input and output handles because the sequence will only collect them after initialize
77  insertHandles(m_inputHandles, an_alg->inputHandles());
78  insertHandles(m_outputHandles, an_alg->outputHandles());
79  std::vector<IAlgTool *> &tools ATLAS_THREAD_SAFE
80  = const_cast< std::vector<IAlgTool *> &>(const_cast<const Gaudi::Algorithm *>(an_alg)->tools());
81  // |> debugging
82  auto tool_visitor = [this, an_alg](IAlgTool *alg_tool) {
83  IDynamicDataConsumer *a_dyn_data_consumer=dynamic_cast<IDynamicDataConsumer *>(alg_tool);
84  if (a_dyn_data_consumer) {
85  std::vector<Gaudi::Algorithm *> &alg_list = m_dynDataConsumer[a_dyn_data_consumer];
86  if (std::find(alg_list.begin(),alg_list.end(),an_alg)==alg_list.end()) {
87  alg_list.push_back(an_alg);
88  }
89  }
90  if (auto* tool_impl = dynamic_cast<AlgTool*>( alg_tool ); tool_impl) {
91  insertHandles(m_inputHandles, tool_impl->inputHandles());
92  insertHandles(m_outputHandles, tool_impl->outputHandles());
93  }
94  };
95  xGaudi::ToolVisitor::visit( tools,tool_visitor);
96  };
97  xGaudi::AlgorithmVisitor::visit({theAlgorithm},algorithm_visitor);
98  }
99 
100  void DynamicDataHelper::updateDataNeeds(unsigned int max_pass,
101  MsgStream &out) {
102  if (msgLvl(out,MSG::VERBOSE)) out << MSG::VERBOSE << "Allow dynamic data consumers to update their data dependencies." << endmsg;
103  std::vector<const DataObjID *> all_input_data;
104  std::vector<const DataObjID *> all_output_data;
105  all_input_data.insert( all_input_data.end(), m_inputHandles.begin(), m_inputHandles.end());
106  all_output_data.insert( all_output_data.end(), m_outputHandles.begin(), m_outputHandles.end());
107 
108  std::vector<const DataObjID *> new_input_data;
109  std::vector<const DataObjID *> new_output_data;
110  unsigned int pass_i=max_pass;
111  unsigned last_out_size=new_output_data.size();
112  for (; --pass_i>0 && updateDataNeeds(all_input_data, all_output_data, new_input_data, new_output_data,out); ) {
113  if (last_out_size == new_output_data.size() ) break;
114  last_out_size=new_output_data.size();
115  };
116  if (last_out_size != new_output_data.size()) {
117  out << MSG::WARNING << "Not iterating any further, although after " << max_pass << " iterations there are still algorithms which updated their data needs. " << endmsg;
118  }
119  }
120 
121  bool DynamicDataHelper::updateDataNeeds(const std::vector<const DataObjID *> &input_data_in,
122  const std::vector<const DataObjID *> &output_data_in,
123  std::vector<const DataObjID *> &input_data_out,
124  std::vector<const DataObjID *> &output_data_out,
125  MsgStream &out) {
126  bool updated=false;
127  if (msgLvl(out,MSG::VERBOSE)) {
128  out<< MSG::VERBOSE << " inputs:";
129  for (const DataObjID *id : input_data_in) {
130  out << " " << *id ;
131  }
132  out << endmsg;
133  out << MSG::VERBOSE << " outputs:";
134  for (const DataObjID *id : output_data_in) {
135  out << " " << *id ;
136  }
137  out << endmsg;
138  }
139  for (std::pair<IDynamicDataConsumer * const,std::vector<Gaudi::Algorithm *> > &dyn_data_consumer : m_dynDataConsumer ) {
140  std::vector<Gaudi::DataHandle *> tmp_new_input_handles;
141  std::vector<Gaudi::DataHandle *> tmp_new_output_handles;
142  bool ret = dyn_data_consumer.first->updateDataNeeds(input_data_in, output_data_in, tmp_new_input_handles, tmp_new_output_handles);
143  if (msgLvl(out,MSG::VERBOSE)) {
144  out << MSG::VERBOSE << " new data for";
145  for (const Gaudi::Algorithm *parent_alg : dyn_data_consumer.second) {
146  out << " " << parent_alg->name();
147  }
148  out << " i:" << tmp_new_input_handles.size()
149  << " o:" << tmp_new_output_handles.size()
150  << endmsg;
151  }
152  updated |= ret;
153  if (ret) {
154  if (msgLvl(out,MSG::DEBUG)) {
155  if (Gaudi::Algorithm * const an_alg = dynamic_cast<Gaudi::Algorithm * const>(dyn_data_consumer.first); an_alg) {
156  out << MSG::DEBUG << an_alg->name() << " updated its data needs." << endmsg;
157  // DEBUG:
158  out << MSG::DEBUG << an_alg->name() << " inputs:";
159  for (const Gaudi::DataHandle *handle : an_alg->inputHandles()) {
160  out << " " << handle->fullKey();
161  }
162  out << endmsg;
163  }
164  else if (AlgTool *alg_tool = dynamic_cast<AlgTool * const>(dyn_data_consumer.first); alg_tool) {
165  out << MSG::DEBUG << alg_tool->name() << " updated its data needs." << endmsg;
166  // DEBUG:
167  out << MSG::DEBUG << alg_tool->name() << " inputs:";
168  for (const Gaudi::DataHandle *handle : alg_tool->inputHandles()) {
169  out << " " << handle->fullKey();
170  }
171  out << endmsg;
172  }
173  else {
174  out << MSG::WARNING << "Unknown dynamic data consumer type " << typeid(dyn_data_consumer.first).name() << endmsg;
175  }
176  }
177  }
178  for (Gaudi::Algorithm *parent_alg : dyn_data_consumer.second) {
179  input_data_out.reserve(input_data_out.size()+tmp_new_input_handles.size());
180  for (Gaudi::DataHandle *a_handle : tmp_new_input_handles) {
181  parent_alg->addDependency(a_handle->fullKey(), Gaudi::DataHandle::Reader);
182  input_data_out.push_back(&(a_handle->fullKey()));
183  if (msgLvl(out,MSG::DEBUG)) out << MSG::DEBUG << " addDependency new input for " << parent_alg->name() << " "
184  << a_handle->fullKey().className() << " / " << a_handle->objKey() << endmsg;
185  }
186  output_data_out.reserve(output_data_out.size()+tmp_new_output_handles.size());
187  for (Gaudi::DataHandle *a_handle : tmp_new_output_handles) {
188  parent_alg->addDependency(a_handle->fullKey(), Gaudi::DataHandle::Writer);
189  output_data_out.push_back(&(a_handle->fullKey()));
190  if (msgLvl(out,MSG::DEBUG)) out << MSG::DEBUG << " addDependency new output for " << parent_alg->name() << " "
191  << a_handle->fullKey().className() << " / " << a_handle->objKey() << endmsg;
192  }
193  }
194  }
195  return updated;
196  }
197 }
python.Constants.FATAL
int FATAL
Definition: Control/AthenaCommon/python/Constants.py:19
find
std::string find(const std::string &s)
return a remapped string
Definition: hcg.cxx:135
CheckAppliedSFs.var_name
var_name
Definition: CheckAppliedSFs.py:241
IDynamicDataConsumer
Definition: IDynamicDataConsumer.h:15
python.FakeAthena.Algorithm
def Algorithm(name)
Definition: FakeAthena.py:41
python.AthDsoLogger.out
out
Definition: AthDsoLogger.py:71
Ath::DataObjIDPtrColl
std::unordered_set< const DataObjID *, DataObjID_PtrHasher, DataObjID_PtrEqual > DataObjIDPtrColl
Definition: DynamicDataHelper.h:21
const
bool const RAWDATA *ch2 const
Definition: LArRodBlockPhysicsV0.cxx:562
python.iconfTool.models.loaders.level
level
Definition: loaders.py:20
Ath::DynamicDataHelper::m_extraOutputIDs
std::vector< DataObjID > m_extraOutputIDs
Definition: DynamicDataHelper.h:65
TrigConf::MSGTC::Level
Level
Definition: Trigger/TrigConfiguration/TrigConfBase/TrigConfBase/MsgStream.h:21
ret
T ret(T t)
Definition: rootspy.cxx:260
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
Ath
Definition: DynamicDataHelper.h:13
LHEF::Reader
Pythia8::Reader Reader
Definition: Prophecy4fMerger.cxx:11
CLID
uint32_t CLID
The Class ID type.
Definition: Event/xAOD/xAODCore/xAODCore/ClassID_traits.h:47
Ath::DynamicDataHelper::m_outputHandles
DataObjIDPtrColl m_outputHandles
Definition: DynamicDataHelper.h:67
Ath::DynamicDataHelper::gatherDataHandlesAndDynamicConsumers
void gatherDataHandlesAndDynamicConsumers(const std::string &parent_name, Gaudi::Algorithm *theAlgorithm)
Gather the input and output data declared by the given algorithm, its child algorithms and their tool...
Definition: DynamicDataHelper.cxx:65
id
SG::auxid_t id
Definition: Control/AthContainers/Root/debug.cxx:191
tools
Definition: DataQuality/ZLumiScripts/python/tools/__init__.py:1
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:192
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:18
Ath::DynamicDataHelper::m_inputHandles
DataObjIDPtrColl m_inputHandles
Definition: DynamicDataHelper.h:66
DEBUG
#define DEBUG
Definition: page_access.h:11
Ath::DynamicDataHelper::updateDataNeeds
void updateDataNeeds(unsigned int max_pass, MsgStream &out)
Update the data dependencies of all components which dynamically declare tehm.
Definition: DynamicDataHelper.cxx:100
DynamicDataHelper.h
ATLAS_THREAD_SAFE
#define ATLAS_THREAD_SAFE
Definition: checker_macros.h:211
LHEF::Writer
Pythia8::Writer Writer
Definition: Prophecy4fMerger.cxx:12
python.Constants.VERBOSE
int VERBOSE
Definition: Control/AthenaCommon/python/Constants.py:14
get_generator_info.error
error
Definition: get_generator_info.py:40
checker_macros.h
Define macros for attributes used to control the static checker.
error
Definition: IImpactPoint3dEstimator.h:70
Ath::DynamicDataHelper::m_dynDataConsumer
std::unordered_map< IDynamicDataConsumer *, std::vector< Gaudi::Algorithm * > > m_dynDataConsumer
Definition: DynamicDataHelper.h:69
Ath::DynamicDataHelper::addExtraDependencies
StatusCode addExtraDependencies(IClassIDSvc &clid_svc, std::vector< std::string > &undeclared_output_data, MsgStream &out)
Add extra output data which is not declared by any of the gathered components.
Definition: DynamicDataHelper.cxx:26