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