LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
PathManager.cc
Go to the documentation of this file.
3 #include "cetlib/container_algorithms.h"
4 
5 #include <algorithm>
6 #include <map>
7 #include <set>
8 #include <sstream>
9 
11 
12 namespace {
13 
14  std::unique_ptr<std::set<std::string>>
15  findLegacyConfig(fhicl::ParameterSet const& ps, std::string const& param)
16  {
17  std::vector<std::string> tmp;
18  std::unique_ptr<std::set<std::string>> result;
19  if (ps.get_if_present(param, tmp)) {
20  result.reset(new std::set<std::string>);
21  result->insert(tmp.cbegin(), tmp.cend());
22  }
23  return result;
24  }
25 
26  std::string
27  stripLabel(std::string const& labelInPathConfig)
28  {
29  auto label_start = labelInPathConfig.find_first_not_of("!-");
30  if (label_start > 1) {
32  << "Module label " << labelInPathConfig << " is illegal.\n";
33  }
34  return labelInPathConfig.substr(label_start);
35  }
36 
38  filterAction(std::string const& labelInPathConfig)
39  {
40  switch (labelInPathConfig[0]) {
41  case '!':
42  return art::WorkerInPath::FilterAction::Veto;
43  case '-':
44  return art::WorkerInPath::FilterAction::Ignore;
45  default:
47  }
48  }
49 
50  void
51  check_missing_paths(std::set<std::string> const& specified_paths,
52  art::PathManager::vstring const& path_names,
53  std::string const& par_name,
54  std::ostream& error_stream)
55  {
56  art::PathManager::vstring missing_paths;
57  std::set_difference(cbegin(specified_paths),
58  cend(specified_paths),
59  cbegin(path_names),
60  cend(path_names),
61  std::back_inserter(missing_paths));
62  for (auto const& path : missing_paths) {
63  error_stream << "ERROR: Unknown path " << path << " specified by user in "
64  << par_name << ".\n";
65  }
66  }
67 
68  void
69  check_misspecified_paths(fhicl::ParameterSet const& pset,
70  std::vector<std::string> const& path_names)
71  {
72  using name_t = std::string;
73  using fhicl_t = std::string;
74 
75  std::map<name_t, fhicl_t> bad_names;
76  for (auto const& name : path_names) {
77  if (pset.is_key_to_sequence(name))
78  continue;
79  std::string const type = pset.is_key_to_table(name) ? "table" : "atom";
80  bad_names.emplace(name, type);
81  }
82 
83  if (bad_names.empty())
84  return;
85 
86  std::string err_msg =
87  "\n"
88  "You have specified the following unsupported parameters in the\n"
89  "\"physics\" block of your configuration:\n\n";
90 
91  cet::for_all(bad_names, [&err_msg](auto const& name) {
92  err_msg.append(" \"physics." + name.first + "\" (" + name.second +
93  ")\n");
94  });
95 
96  err_msg.append("\n")
97  .append("Supported parameters include the following tables:\n")
98  .append(" \"physics.producers\"\n")
99  .append(" \"physics.filters\"\n")
100  .append(" \"physics.analyzers\"\n")
101  .append(
102  "and sequences. Atomic configuration parameters are not allowed.\n\n");
103 
104  throw art::Exception(art::errors::Configuration) << err_msg;
105  }
106 }
107 
109  MasterProductRegistry& preg,
110  ProductDescriptions& productsToProduce,
111  ActionTable& exceptActions,
112  ActivityRegistry& areg)
113  : procPS_{procPS}
114  , preg_{preg}
115  , productsToProduce_{productsToProduce}
116  , exceptActions_{exceptActions}
117  , areg_{areg}
118  , trigger_paths_config_{findLegacyConfig(procPS_, "physics.trigger_paths")}
119  , end_paths_config_{findLegacyConfig(procPS_, "physics.end_paths")}
122  , endPathInfo_{0,
123  fact_,
124  procPS_,
125  preg_,
128  areg_}
129 {}
130 
133 {
134  if (!protoEndPathInfo_.empty() && endPathInfo_.pathPtrs().empty()) {
135  // Need to create path from proto information. No trigger results
136  // needed for end path.
138  }
139  return endPathInfo_;
140 }
141 
144 {
145  auto it = triggerPathsInfo_.find(sID);
146  if (it != triggerPathsInfo_.end())
147  return it->second;
148 
149  it = triggerPathsInfo_
150  .emplace(sID,
151  PathsInfo{triggerPathNames_.size(),
152  fact_,
153  procPS_,
154  preg_,
155  productsToProduce_,
156  exceptActions_,
157  areg_})
158  .first;
159  auto& pathsInfo = it->second;
160 
161  for (auto const& val : protoTrigPathMap_) {
162  pathsInfo.makeAndAppendPath(val.first, val.second);
163  };
164 
165  return pathsInfo;
166 }
167 
170 {
171  detail::ModuleConfigInfoMap all_modules;
172  std::ostringstream error_stream;
173  for (auto const& pathRootName :
175  auto const pathRoot = procPS_.get<ParameterSet>(pathRootName, {});
176  for (auto const& name : pathRoot.get_names()) {
177  try {
178  detail::ModuleConfigInfo const mci{procPS_, name, pathRootName};
179  auto actualModType = fact_.moduleType(mci.libSpec());
180  if (actualModType != mci.moduleType()) {
181  error_stream << " ERROR: Module with label " << mci.label()
182  << " of type " << mci.libSpec() << " is configured as a "
183  << to_string(mci.moduleType())
184  << " but defined in code as a "
185  << to_string(actualModType) << ".\n";
186  }
187  auto result = all_modules.emplace(mci.label(), mci);
188  if (!result.second) {
189  error_stream << " ERROR: Module label " << mci.label()
190  << " has been used in "
191  << result.first->second.configPath() << " and "
192  << pathRootName << ".\n";
193  }
194  }
195  catch (std::exception const& e) {
196  error_stream << " ERROR: Configuration of module with label " << name
197  << " encountered the following error:\n"
198  << e.what() << "\n";
199  }
200  }
201  }
202  auto error_messages = error_stream.str();
203  if (!error_messages.empty()) {
205  << "The following were encountered while processing the module "
206  "configurations:\n"
207  << error_messages;
208  }
209  return all_modules;
210 }
211 
214 {
215  vstring trigger_path_names;
216  auto nSchedules[[gnu::unused]] =
217  procPS_.get<size_t>("services.scheduler.num_schedules", 1);
218  // Identify and process paths.
219  std::set<std::string> known_pars{
220  "analyzers", "filters", "producers", "trigger_paths", "end_paths"};
221  ParameterSet empty;
222  auto const physics = procPS_.get<ParameterSet>("physics", empty);
223  auto const keys = physics.get_names();
224  vstring path_names;
225  std::set_difference(keys.cbegin(),
226  keys.cend(),
227  known_pars.cbegin(),
228  known_pars.cend(),
229  std::back_inserter(path_names));
230  std::set<std::string> specified_modules;
231  std::ostringstream error_stream;
232 
233  // Check for missing specified paths.
234  if (trigger_paths_config_) {
235  check_missing_paths(
236  *trigger_paths_config_, path_names, "trigger_paths", error_stream);
237  }
238  if (end_paths_config_) {
239  check_missing_paths(
240  *end_paths_config_, path_names, "end_paths", error_stream);
241  }
242 
243  check_misspecified_paths(physics, path_names);
244 
245  // Process each path.
246  size_t num_end_paths{0};
247  for (auto const& path_name : path_names) {
248  auto const path_seq = physics.get<vstring>(path_name);
250  path_name, path_seq, trigger_path_names, error_stream)) {
251  ++num_end_paths;
252  }
253  for (auto const& mod : path_seq) {
254  specified_modules.insert(stripLabel(mod));
255  }
256  }
257  if (num_end_paths > 1) {
258  mf::LogInfo("PathConfiguration")
259  << "Multiple end paths have been combined into one end path,\n"
260  << "\"end_path\" since order is irrelevant.\n";
261  }
262 
263  vstring unused_modules;
264  std::set<std::string> all_module_labels;
265  for (auto const& val : allModules_) {
266  all_module_labels.insert(val.first);
267  }
268 
269  std::set_difference(all_module_labels.cbegin(),
270  all_module_labels.cend(),
271  specified_modules.cbegin(),
272  specified_modules.cend(),
273  std::back_inserter(unused_modules));
274 
275  // Complain about unused modules.
276  if (!unused_modules.empty()) {
277  std::ostringstream unusedStream;
278  unusedStream << "The following module label"
279  << ((unused_modules.size() == 1) ? " is" : "s are")
280  << " not assigned to any path:\n"
281  << "'" << unused_modules.front() << "'";
282  for (auto i = unused_modules.cbegin() + 1, e = unused_modules.cend();
283  i != e;
284  ++i) {
285  unusedStream << ", '" << *i << "'";
286  }
287  mf::LogInfo("path") << unusedStream.str() << "\n";
288  }
289 
290  // Check for fatal errors.
291  auto error_messages = error_stream.str();
292  if (!error_messages.empty()) {
293  throw Exception(errors::Configuration, "Path configuration: ")
294  << "The following were encountered while processing path "
295  "configurations:\n"
296  << error_messages;
297  }
298  return trigger_path_names;
299 }
300 
301 bool // Is wanted end path.
302 art::PathManager::processOnePathConfig_(std::string const& path_name,
303  vstring const& path_seq,
304  vstring& trigger_path_names,
305  std::ostream& error_stream)
306 {
307  enum class mod_cat_t { UNSET, OBSERVER, MODIFIER };
308  mod_cat_t cat{mod_cat_t::UNSET};
309  for (auto const& modname : path_seq) {
310  auto const label = stripLabel(modname);
311  auto const it = allModules_.find(label);
312  if (it == cend(allModules_)) {
313  error_stream << " ERROR: Entry " << modname << " in path " << path_name
314  << " refers to a module label " << label
315  << " which is not configured.\n";
316  continue;
317  }
318  auto const& mci = it->second;
319  auto mtype =
320  is_observer(mci.moduleType()) ? mod_cat_t::OBSERVER : mod_cat_t::MODIFIER;
321  if (cat == mod_cat_t::UNSET) {
322  cat = mtype;
323  // Efficiency.
324  if (cat == mod_cat_t::MODIFIER) {
325  if (trigger_paths_config_ && (trigger_paths_config_->find(path_name) ==
326  trigger_paths_config_->cend())) {
327  mf::LogInfo("DeactivatedPath")
328  << "Detected trigger path \"" << path_name
329  << "\" which was not found in\n"
330  << "parameter \"physics.trigger_paths\". "
331  << "Path will be ignored.";
332  return false;
333  }
334  // Handle case where user accidentally specified a trigger
335  // path as an end path.
336  if (end_paths_config_ &&
337  (end_paths_config_->find(path_name) != end_paths_config_->cend())) {
338  error_stream
339  << " ERROR: Path "
340  << "'" << path_name << "'"
341  << " is configured as an end path but is actually a trigger path.";
342  }
343  trigger_path_names.push_back(path_name);
344  protoTrigPathMap_[path_name].reserve(path_seq.size());
345  } else {
346  if (end_paths_config_ &&
347  (end_paths_config_->find(path_name) == end_paths_config_->cend())) {
348  mf::LogInfo("DeactivatedPath") << "Detected end path \"" << path_name
349  << "\" which was not found in\n"
350  << "parameter \"physics.end_paths\". "
351  << "Path will be ignored.";
352  return false;
353  }
354  // Handle case where user accidentally specified an end path
355  // as a trigger path.
356  if (trigger_paths_config_ && (trigger_paths_config_->find(path_name) !=
357  trigger_paths_config_->cend())) {
358  error_stream
359  << " ERROR: Path "
360  << "'" << path_name << "'"
361  << " is configured as a trigger path but is actually an end path.";
362  }
363  protoEndPathInfo_.reserve(protoEndPathInfo_.size() + path_seq.size());
364  }
365  } else if (cat != mtype) {
366  error_stream << " ERROR: Entry " << modname << " in path " << path_name
367  << " is a"
368  << (cat == mod_cat_t::OBSERVER ? " modifier" : "n observer")
369  << " while previous entries in the same path are all "
370  << (cat == mod_cat_t::OBSERVER ? "observers" : "modifiers")
371  << ".\n";
372  }
373 
374  auto const filtAction = filterAction(modname);
375  if (mci.moduleType() != ModuleType::FILTER &&
376  filtAction != WorkerInPath::Normal) {
377  error_stream << " ERROR: Module " << stripLabel(modname) << " in path "
378  << path_name << " is"
379  << (cat == mod_cat_t::OBSERVER ? " an " : " a ")
380  << to_string(mci.moduleType())
381  << " and cannot have a '!' or '-' prefix.\n";
382  }
383 
384  if (cat == mod_cat_t::MODIFIER) {
385  protoTrigPathMap_[path_name].emplace_back(mci, filtAction);
386  } else { // Only one end path.
387  protoEndPathInfo_.emplace_back(mci, filtAction);
388  }
389  }
390  return (cat == mod_cat_t::OBSERVER);
391 }
detail::ModuleConfigInfoMap allModules_
Definition: PathManager.h:82
std::unique_ptr< std::set< std::string > > end_paths_config_
Definition: PathManager.h:79
ProductDescriptions & productsToProduce_
Definition: PathManager.h:71
vstring triggerPathNames_
Definition: PathManager.h:85
detail::ModuleConfigInfoMap fillAllModules_()
Definition: PathManager.cc:169
ModuleType moduleType(std::string const &libspec)
const std::string label
vstring processPathConfigs_()
Definition: PathManager.cc:213
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
std::string name_t
Definition: KeyAssembler.h:72
Float_t tmp
Definition: plot.C:37
std::vector< BranchDescription > ProductDescriptions
ActivityRegistry & areg_
Definition: PathManager.h:73
std::map< ScheduleID, PathsInfo > triggerPathsInfo_
Definition: PathManager.h:87
detail::ModuleFactory fact_
Definition: PathManager.h:81
bool is_key_to_sequence(std::string const &key) const
Definition: ParameterSet.h:155
bool is_key_to_table(std::string const &key) const
Definition: ParameterSet.h:149
std::unique_ptr< std::set< std::string > > trigger_paths_config_
Definition: PathManager.h:78
std::vector< std::string > vstring
Definition: PathManager.h:42
ActionTable & exceptActions_
Definition: PathManager.h:72
T get(std::string const &key) const
Definition: ParameterSet.h:231
bool get_if_present(std::string const &key, T &value) const
Definition: ParameterSet.h:208
PathsInfo endPathInfo_
Definition: PathManager.h:86
std::map< std::string, ModInfos > protoTrigPathMap_
Definition: PathManager.h:83
MasterProductRegistry & preg_
Definition: PathManager.h:70
PathsInfo & endPathInfo()
Definition: PathManager.cc:132
PathsInfo & triggerPathsInfo(ScheduleID sID)
Definition: PathManager.cc:143
static std::vector< std::string > const & allModulePathRoots()
bool is_observer(ModuleType mt)
Definition: ModuleType.h:53
bool processOnePathConfig_(std::string const &path_name, vstring const &path_seq, vstring &trigger_path_names, std::ostream &error_stream)
Definition: PathManager.cc:302
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
void makeAndAppendPath(std::string const &pathName, ModInfos const &modInfos, bool trigResultsNeeded=true)
Definition: PathsInfo.cc:29
std::vector< std::string > get_names() const
PathManager(PathManager const &)=delete
ModInfos protoEndPathInfo_
Definition: PathManager.h:84
std::string to_string(ModuleType mt)
Definition: ModuleType.h:32
Float_t e
Definition: plot.C:34
fhicl::ParameterSet procPS_
Definition: PathManager.h:69
PathPtrs const & pathPtrs() const
Definition: PathsInfo.h:87
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
std::map< std::string, ModuleConfigInfo > ModuleConfigInfoMap