All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
FilterOnArtPathOutcome_module.cc
Go to the documentation of this file.
1 /**
2  * @file FilterOnArtPathOutcome_module.cc
3  * @brief An _art_ filter picking its response from a previous one.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date August 4, 2022
6  *
7  */
8 
9 // framework libraries
10 #include "art/Framework/Core/SharedFilter.h"
11 #include "art/Framework/Core/ModuleMacros.h"
12 #include "art/Framework/Principal/Event.h"
13 #include "art/Framework/Principal/Handle.h"
14 #include "canvas/Persistency/Common/TriggerResults.h"
15 #include "canvas/Persistency/Common/HLTGlobalStatus.h"
16 #include "canvas/Persistency/Common/HLTPathStatus.h"
17 #include "canvas/Persistency/Common/HLTenums.h"
18 #include "canvas/Utilities/InputTag.h"
19 #include "canvas/Utilities/Exception.h"
20 #include "fhiclcpp/types/Atom.h"
21 #include "fhiclcpp/ParameterSetRegistry.h"
22 #include "fhiclcpp/ParameterSet.h"
23 #include "cetlib_except/exception.h"
24 
25 // C/C++ standard libraries
26 #include <algorithm> // std::find()
27 #include <vector>
28 #include <string>
29 #include <optional>
30 
31 
32 //------------------------------------------------------------------------------
33 /**
34  * @brief Filter module using a response an existing trigger path response.
35  *
36  * This filter emits the same response as for a _art_ path (not just a filter)
37  * that was run previously.
38  *
39  *
40  * Input
41  * ------
42  *
43  * Given a configured `Path`, this module reads from the event the data product
44  * named `TriggerResults` (`art::TriggerResults` type) from the process
45  * specified in that configuration parameter.
46  *
47  *
48  * Configuration parameters
49  * =========================
50  *
51  * * `Path` (string, _mandatory_): the trigger path specification in the form
52  * `process:path name`.
53  *
54  */
55 class FilterOnArtPathOutcome: public art::SharedFilter {
56 
57  public:
58 
59  struct Config {
60  using Name = fhicl::Name;
61  using Comment = fhicl::Comment;
62 
63  fhicl::Atom<std::string> Path {
64  Name{ "Path" },
65  Comment{ "trigger path specification: \"<process name:path name>\"" }
66  };
67 
68  fhicl::Atom<bool> ResponseWhenNotRun {
69  Name{ "ResponseWhenNotRun" },
70  Comment{ "filter response when the reference path was not run" },
71  false
72  };
73 
74  fhicl::Atom<bool> ResponseOnError {
75  Name{ "ResponseOnError" },
76  Comment{ "filter response when the reference path threw an exception" },
77  false
78  };
79 
80  }; // Config
81 
82  using Parameters = art::SharedFilter::Table<Config>;
83 
84 
85  /// Constructor. No surprise here.
86  FilterOnArtPathOutcome(Parameters const& params, const art::ProcessingFrame&);
87 
88 
89  virtual bool filter(art::Event& event, const art::ProcessingFrame&) override;
90 
91 
92  private:
93 
94  struct TriggerSpec {
95  art::InputTag const tag; ///< Input tag of the trigger result data product.
96  std::string const path; ///< Name of the path to be read.
97  }; // TriggerSpec;
98 
99 
100  TriggerSpec const fTriggerSpec; ///< Trigger configuration.
101  bool const fResponseWhenNotRun; ///< What to do if path was not run at all.
102  bool const fResponseOnError; ///< What to do if path ended with error.
103 
104 
105  /// Reads the needed trigger data product, and throws if not found.
106  art::TriggerResults const& readTriggerResults
107  (art::Event const& event, art::InputTag const& tag) const;
108 
109  /// Returns the status of the path with the required `name`.
110  /// @throw cet::exception if not found
111  art::HLTPathStatus const& findPath
112  (art::TriggerResults const& results, std::string const& name) const;
113 
114  /// Returns the list of path names stored in `results`.
115  /// @throw art::Exception (code: `art::errors::Unknown`) on logic errors
116  std::vector<std::string> pathNames(art::TriggerResults const& results) const;
117 
118  /// Translates a path status into the response from this filter.
119  bool responseFromPath(art::HLTPathStatus const& path) const;
120 
121  /// Parses a trigger path specification.
122  static TriggerSpec parseTriggerSpec(std::string const& spec);
123 
124 }; // class FilterOnArtPathOutcome
125 
126 
127 //------------------------------------------------------------------------------
129  (Parameters const& params, art::ProcessingFrame const&)
130  : art::SharedFilter{ params }
131  , fTriggerSpec { parseTriggerSpec(params().Path()) }
132  , fResponseWhenNotRun{ params().ResponseWhenNotRun() }
133  , fResponseOnError { params().ResponseOnError() }
134 {
135 
136  async<art::InEvent>();
137 
138 } // FilterOnArtPathOutcome::FilterOnArtPathOutcome()
139 
140 
141 //------------------------------------------------------------------------------
143  (art::Event& event, const art::ProcessingFrame&)
144 {
145 
146  art::TriggerResults const& trgResults
147  = readTriggerResults(event, fTriggerSpec.tag);
148 
149  art::HLTPathStatus const& path = findPath(trgResults, fTriggerSpec.path);
150 
151  return responseFromPath(path);
152 
153 } // FilterOnArtPathOutcome::filter()
154 
155 
156 //------------------------------------------------------------------------------
157 art::TriggerResults const& FilterOnArtPathOutcome::readTriggerResults
158  (art::Event const& event, art::InputTag const& tag) const
159 {
160 
161  try {
162  return event.getProduct<art::TriggerResults>(tag);
163  }
164  catch (art::Exception const& e) {
165  if (e.categoryCode() != art::errors::ProductNotFound) throw;
166 
167  std::optional<std::vector<art::InputTag>> available;
168  try {
169  std::vector<art::Handle<art::TriggerResults>> const& triggerHandles
170  = event.getMany<art::TriggerResults>();
171  available.emplace();
172  for (art::Handle<art::TriggerResults> const& handle: triggerHandles) {
173  if (handle.isValid() && handle.provenance())
174  available->push_back(handle.provenance()->inputTag());
175  } // for
176  }
177  catch (...) {} // we tried to be nice, and failed.
178 
179  art::Exception msg { e.categoryCode(), "", e };
180  msg << "Trigger data product '" << tag.encode() << "' not found.";
181  if (available) {
182  msg << "\n" << available->size() << " trigger products available";
183  if (available->empty()) msg << ".";
184  else {
185  msg << ":";
186  for (art::InputTag const& tag: *available)
187  msg << "\n - '" << tag.encode() << "'";
188  } // if ... else
189  } // if available
190  throw msg << "\n";
191  }
192 
193 } // FilterOnArtPathOutcome::readTriggerResults()
194 
195 
196 //------------------------------------------------------------------------------
197 art::HLTPathStatus const& FilterOnArtPathOutcome::findPath
198  (art::TriggerResults const& results, std::string const& name) const
199 {
200  std::vector<std::string> const names = pathNames(results);
201 
202  //
203  // find the proper one...
204  //
205 
206  auto iPathName = names.end();
207  do { // quick-exit block
208 
209  // try verbatim first:
210  iPathName = std::find(names.begin(), names.end(), name);
211  if (iPathName != names.end()) break;
212 
213  // art has the custom of prepending an index to the name ("<index>:<name>");
214  // let's try to ignore it
215  iPathName = std::find_if(names.begin(), names.end(),
216  [name](std::string const& s)
217  {
218  std::size_t const iSep = s.find(':');
219  return ((iSep == std::string::npos)? s: s.substr(iSep+1)) == name;
220  }
221  );
222 
223  } while (false);
224 
225  if (iPathName == names.end()) {
226  cet::exception e{ "FilterOnArtPathOutcome" };
227  e << "The trigger path '" << fTriggerSpec.tag.process()
228  << "' does not include '" << name << "'! The " << names.size()
229  << " available paths are:";
230  for (std::string const& pathName: names)
231  e << "\n - '" << pathName << "'";
232  throw e << "\n";
233  }
234 
235  // in principle we could also extract the index from the name; we don't.
236  std::size_t const pathIndex = std::distance(names.begin(), iPathName);
237 
238  return results.at(pathIndex);
239 
240 } // FilterOnArtPathOutcome::findPath()
241 
242 
243 //------------------------------------------------------------------------------
244 std::vector<std::string> FilterOnArtPathOutcome::pathNames
245  (art::TriggerResults const& results) const
246 {
247  //
248  // list of paths for this event;
249  // copied from art/Framework/Core/EventSelector.cc of art 3.9.3, `dataFor()`:
250  //
251  fhicl::ParameterSet pset;
252  if (!fhicl::ParameterSetRegistry::get(results.parameterSetID(), pset)) {
253  // "This should never happen";
254  // just in case, I leave the message and blame to art
255  throw art::Exception(art::errors::Unknown)
256  << "FilterOnArtPathOutcome::findPath cannot find the trigger names for\n"
257  << "a process for which the configuration has requested that the\n"
258  << "OutputModule use TriggerResults to select events from. This should\n"
259  << "be impossible, please send information to reproduce this problem to\n"
260  << "the art developers at artists@fnal.gov.\n";
261  }
262  auto const names = pset.get<std::vector<std::string>>("trigger_paths", {});
263  if (names.size() != results.size()) {
264  throw art::Exception(art::errors::Unknown)
265  << "FilterOnArtPathOutcome::findPath: path names vector and\n"
266  << "TriggerResults are different sizes (" << names.size()
267  << " vs. " << results.size() << "). This should be impossible,\n"
268  << "please send information to reproduce this problem to\n"
269  << "the art developers.\n";
270  }
271 
272  return names;
273 
274 } // FilterOnArtPathOutcome::pathNames()
275 
276 
277 //------------------------------------------------------------------------------
279  (art::HLTPathStatus const& path) const
280 {
281 
282  if (!path.wasrun()) { // path was not run at all
283  return fResponseWhenNotRun;
284  }
285  else if (path.error()) { // path terminated with an exception
286  return fResponseOnError;
287  }
288  else return path.accept();
289 
290 } // FilterOnArtPathOutcome::responseFromPath()
291 
292 
293 //------------------------------------------------------------------------------
294 auto FilterOnArtPathOutcome::parseTriggerSpec(std::string const& spec)
295  -> TriggerSpec
296 {
297  std::string processName, pathName;
298  auto const iSep = spec.find(':');
299  if (iSep == std::string::npos) {
300  pathName = spec;
301  }
302  else {
303  processName = spec.substr(0, iSep);
304  pathName = spec.substr(iSep + 1);
305  }
306 
307  return { art::InputTag{ "TriggerResults", "", processName }, pathName };
308 
309 } // FilterOnArtPathOutcome::parseTriggerSpec()
310 
311 
312 //------------------------------------------------------------------------------
313 DEFINE_ART_MODULE(FilterOnArtPathOutcome)
314 
315 
316 //------------------------------------------------------------------------------
317 
std::string const path
Name of the path to be read.
art::HLTPathStatus const & findPath(art::TriggerResults const &results, std::string const &name) const
bool const fResponseOnError
What to do if path ended with error.
FilterOnArtPathOutcome(Parameters const &params, const art::ProcessingFrame &)
Constructor. No surprise here.
art::InputTag const tag
Input tag of the trigger result data product.
std::vector< std::string > pathNames(art::TriggerResults const &results) const
BEGIN_PROLOG triggeremu_data_config_icarus settings PMTADCthresholds sequence::icarus_stage0_multiTPC_TPC physics sequence::icarus_stage0_EastHits_TPC physics sequence::icarus_stage0_WestHits_TPC physics producers purityana0 caloskimCalorimetryCryoE physics caloskimCalorimetryCryoW physics path
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode.
art::SharedFilter::Table< Config > Parameters
bool responseFromPath(art::HLTPathStatus const &path) const
Translates a path status into the response from this filter.
Filter module using a response an existing trigger path response.
BEGIN_PROLOG vertical distance to the surface Name
virtual bool filter(art::Event &event, const art::ProcessingFrame &) override
static const std::vector< std::string > names
then echo File list $list not found else cat $list while read file do echo $file sed s
Definition: file_to_url.sh:60
do i e
TriggerSpec const fTriggerSpec
Trigger configuration.
static TriggerSpec parseTriggerSpec(std::string const &spec)
Parses a trigger path specification.
bool const fResponseWhenNotRun
What to do if path was not run at all.
then echo fcl name
art::TriggerResults const & readTriggerResults(art::Event const &event, art::InputTag const &tag) const
Reads the needed trigger data product, and throws if not found.