LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
BasicOutputOptionsHandler.cc
Go to the documentation of this file.
2 
10 #include "cetlib/canonical_string.h"
11 #include "fhiclcpp/coding.h"
14 #include "fhiclcpp/parse.h"
15 
16 #include "TError.h"
17 
18 #include <iostream>
19 #include <regex>
20 #include <string>
21 #include <vector>
22 
23 using namespace std::string_literals;
25 
29 
30 using stringvec = std::vector<std::string>;
31 
33  bpo::options_description& desc)
34 {
35  bpo::options_description output_options{"Output options"};
36  auto options = output_options.add_options();
37  add_opt(options,
38  "TFileName,T",
39  bpo::value<std::string>(),
40  "File name for TFileService.");
41  add_opt(
42  options,
43  "tmpdir",
44  bpo::value<std::string>(&tmpDir_),
45  "Temporary directory for in-progress output files (defaults to directory "
46  "of specified output file names).");
47  add_opt(options,
48  "tmpDir",
49  bpo::value<std::string>(&tmpDir_),
50  "Synonym for --tmpdir.");
51  add_opt(options,
52  "output,o",
53  bpo::value<stringvec>()->composing(),
54  "Event output stream file (optionally specify stream with "
55  "stream-label:fileName in which case multiples are OK).");
56  add_opt(options, "no-output", "Disable all output streams.");
57  desc.add(output_options);
58 }
59 
60 int
62 {
63  return 0;
64 }
65 
66 namespace {
67  using art::ensureTable;
68 
69  // Remove any occurrences of a single module label (key) from the
70  // fully qualified sequence parameter pathName in raw_config.
71  // Returns true if path exists and is now empty.
72  bool
73  maybeRemoveFromPath(fhicl::intermediate_table& raw_config,
74  std::string const& pathName,
75  std::string const& key)
76  {
77  bool result = false;
78  if (exists_outside_prolog(raw_config, pathName)) {
79  sequence_t& path = raw_config.get<sequence_t&>(pathName);
80  auto path_end = std::remove_if(
81  path.begin(), path.end(), [&key](fhicl::extended_value const& s) {
82  return cet::canonical_string(key) == fhicl::extended_value::atom_t(s);
83  });
84  if (path_end != path.end()) { // Shrunk!
85  path.resize(std::distance(path.begin(), path_end));
86  }
87  if (path.empty()) {
88  result = true;
89  }
90  }
91  return result;
92  }
93 
94  // Remove a given key from all paths.
95  void
96  removeFromEndPaths(fhicl::intermediate_table& raw_config,
97  std::string const& key)
98  {
99  std::string const& physicsKey{"physics"};
100  if (!exists_outside_prolog(raw_config, physicsKey)) {
101  return;
102  }
103  auto& physics_table(raw_config.get<table_t&>(physicsKey));
104  std::vector<std::string> const ignoredParameters(
105  {"analyzers", "filters", "producers", "end_paths", "trigger_paths"});
106  auto i = physics_table.begin();
107  auto e = physics_table.end();
108  for (; i != e;) {
109  if (std::find(ignoredParameters.cbegin(),
110  ignoredParameters.cend(),
111  i->first) == ignoredParameters.end() &&
112  i->second.is_a(fhicl::SEQUENCE) &&
113  maybeRemoveFromPath(raw_config, physicsKey + '.' + i->first, key)) {
114  // Remove empty path from end_paths.
115  maybeRemoveFromPath(raw_config, physicsKey + ".end_paths", i->first);
116  // Remove empty path from table.
117  i = physics_table.erase(i);
118  } else {
119  ++i;
120  }
121  }
122  }
123 
124  void
125  processSpecifiedOutputs(fhicl::intermediate_table& raw_config,
126  stringvec outputs)
127  {
128  auto const b = outputs.begin(), e = outputs.end();
129  for (auto i = b; i != e; ++i) {
130  auto& output = *i;
131  bool new_path_entry(false);
132  auto const outputsKey = "outputs"s;
133  ensureTable(raw_config, outputsKey);
134 
135  auto& outputs_table(raw_config.get<table_t&>(outputsKey));
136  std::smatch splitResult;
137  static std::regex const streamSplitter("([[:alnum:]]+):(?:/[^/]|[^/]).*");
138  std::string streamName;
139  if (std::regex_match(output, splitResult, streamSplitter)) {
140  streamName = splitResult[1];
141  output.erase(0ull, streamName.size() + 1ull);
142  } else if (b != i) {
144  << "While processing specified output " << output
145  << ": only the first specified output may omit the stream "
146  "specification\n"
147  "(\"label:fileName\").\n";
148  } else if (outputs_table.size() == 1ull) {
149  streamName = outputs_table.cbegin()->first;
150  } else {
151  streamName = "out"s;
152  }
153 
154  if (outputs_table.size() > 1ull && splitResult.empty()) {
156  << "Output configuration is ambiguous: configuration has "
157  << "multiple output modules. Cannot decide where to add "
158  << "specified output filename " << output
159  << ".\nUse stream-specification (\"label:fileName\") to resolve the "
160  "ambiguity.";
161  }
162 
163  if (outputs_table.find(streamName) == outputs_table.cend()) {
164  new_path_entry = true;
165  raw_config.put(outputsKey + '.' + streamName + '.' + "module_type",
166  "RootOutput");
167  }
168  std::string out_table_path(outputsKey);
169  out_table_path += '.' + streamName;
170  raw_config.put(out_table_path + ".fileName", output);
171  if (new_path_entry) {
172  // If we created a new output module config, we need to make a
173  // path for it and add it to end paths. We will *not* detect the
174  // case where an *existing* output module config is not
175  // referenced in a path.
176  ensureTable(raw_config, "physics");
177  auto& physics_table = raw_config.get<table_t&>("physics");
178  // Find an unique name for the end_path into which we'll insert
179  // our new module.
180  std::string end_path = "injected_end_path_";
181  size_t n = physics_table.size() + 2;
182  for (size_t i = 1; i < n; ++i) {
183  std::ostringstream os;
184  os << end_path << i;
185  if (physics_table.find(os.str()) == physics_table.end()) {
186  end_path = os.str();
187  break;
188  }
189  }
190  // Make our end_path with the output module label in it.
191  raw_config.put("physics."s + end_path + "[0]", streamName);
192  // Add it to the end_paths list.
193  auto const key = "physics.end_paths"s;
194  if (exists_outside_prolog(raw_config, key)) {
195  size_t const index =
196  raw_config.get<sequence_t&>("physics.end_paths").size();
197  raw_config.put("physics.end_paths["s + std::to_string(index) + ']',
198  end_path);
199  }
200  }
201  }
202  }
203 
204  void
205  processFileOutputOptions(bpo::variables_map const& vm,
206  fhicl::intermediate_table& raw_config)
207  {
208  // File output.
209  if (vm.count("no-output") == 1) {
210  if (vm.count("output")) {
212  << "Output configuration is ambiguous: command-line specifies "
213  << "--output and --no-output simultaneously.";
214  }
215  std::string const& key{"outputs"};
216  if (exists_outside_prolog(raw_config, key)) {
217  auto& outputs_table(raw_config.get<table_t&>(key));
218  // No outputs.
219  for (auto const& p : outputs_table) {
220  removeFromEndPaths(raw_config, p.first);
221  }
222  raw_config.erase(key);
223  }
224  } else if (vm.count("output") == 1) {
225  processSpecifiedOutputs(raw_config, vm["output"].as<stringvec>());
226  }
227  }
228 
229  struct RootErrorHandlerSentry {
230  RootErrorHandlerSentry(bool const reset)
231  {
233  }
234  ~RootErrorHandlerSentry() { SetErrorHandler(DefaultErrorHandler); }
235  };
236 
237 } // namespace
238 
239 int
241  bpo::variables_map const& vm,
242  fhicl::intermediate_table& raw_config)
243 {
244  // TFileService output.
245  if (vm.count("TFileName") == 1) {
246  std::string tFileName(vm["TFileName"].as<std::string>());
247  std::string const& key{"services.TFileService"};
248  if (tFileName.empty() && detail::exists_outside_prolog(raw_config, key) &&
249  raw_config.get<table_t const&>(key).empty()) {
250  tFileName = "hist.root";
251  }
252  if (!tFileName.empty()) {
253  raw_config.put(key + ".fileName", tFileName);
254  }
255  }
256  // Output stream options.
257  processFileOutputOptions(vm, raw_config);
258  // tmpDir option for TFileService and output streams.
259  if (!tmpDir_.empty()) {
260  std::string const& tfile_key = fhicl_key("services", "TFileService");
261  if (detail::exists_outside_prolog(raw_config, tfile_key)) {
262  assert(detail::supports_key(
263  art::suffix_type::service, "TFileService", "tmpDir"));
264  raw_config.put(fhicl_key(tfile_key, "tmpDir"), tmpDir_);
265  }
266 
267  // Inject tmpDir for output modules that support the 'tmpDir' parameter.
268  std::string const outputs_stem{"outputs"};
269  if (detail::exists_outside_prolog(raw_config, outputs_stem)) {
270  auto const& table = raw_config.get<table_t const&>(outputs_stem);
271  for (auto const& output : table) {
272  auto const& module_label = fhicl_key(outputs_stem, output.first);
273  auto const& module_type = fhicl_key(module_label, "module_type");
274  if (!detail::exists_outside_prolog(raw_config, module_type))
275  continue;
276 
277  auto const& spec = raw_config.get<std::string>(module_type);
278  if (!detail::supports_key(art::suffix_type::module, spec, "tmpDir"))
279  continue;
280 
281  raw_config.put(fhicl_key(module_label, "tmpDir"), tmpDir_);
282  }
283  }
284  }
285 
286  // Init ROOT handlers facility
287  auto const unload_key = fhicl_key("scheduler", "unloadRootSigHandler");
288  auto const unloadRSHandler =
289  detail::exists_outside_prolog(raw_config, unload_key) ?
290  raw_config.get<bool>(unload_key) :
291  true;
292  if (unloadRSHandler) {
294  }
295 
296  auto const reset_key = fhicl_key("scheduler", "resetRootErrHandler");
297  auto const maybe_reset =
298  detail::exists_outside_prolog(raw_config, reset_key) ?
299  raw_config.get<bool>(reset_key) :
300  true;
301  RootErrorHandlerSentry re_sentry{maybe_reset};
303 
304  return 0;
305 }
Float_t s
Definition: plot.C:23
bool exists_outside_prolog(fhicl::intermediate_table const &config, std::string const &key)
void add_opt(T &t, Args &&...args)
void unloadRootSigHandler()
BasicOutputOptionsHandler(bpo::options_description &desc)
void erase(std::string const &name, bool in_prolog=false)
void ensureTable(fhicl::intermediate_table &table, std::string const &fhicl_spec)
Definition: ensureTable.cc:6
std::vector< std::string > stringvec
int doCheckOptions(bpo::variables_map const &vm) override
std::vector< extended_value > sequence_t
shims::map< std::string, extended_value > table_t
void setRootErrorHandler(bool const want_custom)
bool put(std::string const &name, std::string const &value, bool in_prolog=false)
std::enable_if_t< std::is_convertible< T, std::string >::value, std::string > fhicl_key(T const &name)
Definition: fhicl_key.h:13
fhicl::extended_value::sequence_t sequence_t
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
std::string to_string(Flag_t< Storage > const flag)
Convert a flag into a stream (shows its index).
Definition: BitMask.h:187
void completeRootHandlers()
T get(std::string const &name)
Char_t n[5]
Float_t e
Definition: plot.C:34
bool supports_key(suffix_type st, std::string const &spec, std::string const &key)
int doProcessOptions(bpo::variables_map const &vm, fhicl::intermediate_table &raw_config) override