All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
HitDataProductChecker_module.cc
Go to the documentation of this file.
1 /**
2  * @file HitDataProductChecker_module.cc
3  * @brief Module verifying the presence of data products.
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date June 12, 2017
6  */
7 
8 // LArSoft libraries
10 
11 // framework libraries
12 #include "art/Framework/Core/ModuleMacros.h"
13 #include "art/Framework/Core/EDAnalyzer.h"
14 #include "art/Framework/Principal/Event.h"
15 
16 #include "fhiclcpp/types/Atom.h"
17 #include "fhiclcpp/types/Sequence.h"
18 #include "fhiclcpp/types/Table.h"
19 #include "fhiclcpp/types/OptionalAtom.h"
20 #include "fhiclcpp/types/Name.h"
21 #include "fhiclcpp/types/Comment.h"
22 
23 // C/C++ standard libraries
24 #include <string>
25 #include <iterator> // std::back_inserter()
26 
27 
28 namespace recob {
29  namespace test {
30 
31  /**
32  * @brief Module verifying the presence of data products.
33  *
34  * Throws an exception on failure.
35  *
36  * Service requirements
37  * =====================
38  *
39  * This module requires no service.
40  *
41  * Configuration parameters
42  * =========================
43  *
44  * * *hits* (list, _mandatory_) each entry defines a check on a single
45  * hit collection data product (`std::vector<recob::Hit>`). Each entry
46  * is a table containing:
47  * * *name* (string, _mandatory_): input tag of the data product
48  * * *exists* (boolean, default: _true_): if `true`, the data product is
49  * expected to exist, if false it is expected not to exist
50  * * *expected* (non-negative integral number): if specified, data
51  * collection size is checked to match this number
52  *
53  */
54  class HitDataProductChecker: public art::EDAnalyzer {
55 
56  public:
57 
58  struct Config {
59 
60  using Name = fhicl::Name;
61  using Comment = fhicl::Comment;
62 
63  struct TargetInfo {
64 
65  fhicl::Atom<art::InputTag> name {
66  Name("name"),
67  Comment("Input tag of the data product to be checked")
68  };
69 
70  fhicl::Atom<bool> exists {
71  Name("exists"),
72  Comment("whether the data product must exist or must not exist"),
73  true
74  };
75 
76  fhicl::OptionalAtom<unsigned int> expected {
77  Name("expected"),
78  Comment
79  ("Number of expected entries (not checked if not specified).")
80  };
81 
82  }; // TargetInfo subclass
83 
84  fhicl::Sequence<fhicl::Table<TargetInfo>> hits {
85  Name("hits"),
86  Comment("list of hit collections and number of expected entries")
87  };
88 
89  }; // Config
90 
91  using Parameters = art::EDAnalyzer::Table<Config>;
92 
93 
94  explicit HitDataProductChecker(Parameters const& config);
95 
96  virtual void analyze(const art::Event& event) override;
97 
98 
99  private:
100 
101  /// Configuration for a single data product check.
102  struct TargetInfo_t {
103 
104  art::InputTag name; ///< Data product name.
105 
106  unsigned int expectedEntries; ///< Number of expected entries.
107 
108  /// Whether data product must exist or must not exist.
109  bool bExists = true;
110 
111  bool bCheckEntries; ///< Whether to check the number of entries.
112 
113 
114  TargetInfo_t() = default;
115 
117  : name(config.name())
118  , bExists(config.exists())
119  {
121  }
122 
123  }; // TargetInfo_t
124 
125  /// Configuration of all checks on hit collections.
126  std::vector<TargetInfo_t> fHitTargets;
127 
128 
129  /**
130  * @brief Checks the specified data product.
131  * @tparam DATA type of data product to be checked
132  * @param event the event to read the data product from
133  * @param targetInfo details of the data product expected information
134  * @param desc description of the content of the data product
135  * @throw art::Exception (`art::errors::ProductNotFound`) when unexpected
136  *
137  * The checks include:
138  * * existence of the data product
139  * * size of the data product collection (optional)
140  *
141  */
142  template <typename DATA>
143  void checkDataProducts(
144  art::Event const& event, TargetInfo_t const& targetInfo,
145  std::string desc
146  );
147 
148 
149  }; // HitDataProductChecker
150 
151  DEFINE_ART_MODULE(HitDataProductChecker)
152 
153  } // namespace test
154 } // namespace recob
155 
156 
157 //------------------------------------------------------------------------------
158 //--- implementation
159 //---
160 //----------------------------------------------------------------------------
162  (Parameters const& config)
163  : EDAnalyzer(config)
164 {
165  decltype(auto) hits = config().hits();
166  fHitTargets.reserve(hits.size());
167  std::copy(hits.begin(), hits.end(), std::back_inserter(fHitTargets));
168 } // HitDataProductChecker::HitDataProductChecker()
169 
170 
171 //----------------------------------------------------------------------------
172 void recob::test::HitDataProductChecker::analyze(art::Event const& event) {
173 
174  for (auto const& targetInfo: fHitTargets)
175  checkDataProducts<std::vector<recob::Hit>>(event, targetInfo, "hits");
176 
177 } // HitCollectionCreatorTest::analyze()
178 
179 
180 //----------------------------------------------------------------------------
181 template <typename DATA>
183  (art::Event const& event, TargetInfo_t const& targetInfo, std::string desc)
184 {
185  using Product_t = DATA;
186 
187  art::InputTag tag = targetInfo.name;
188 
189  art::Handle<Product_t> data;
190  bool found = event.getByLabel<Product_t>(tag, data);
191  if (found && !targetInfo.bExists) {
192  throw art::Exception(art::errors::ProductNotFound)
193  << "Data product '" << tag << "' (" << desc
194  << ") was expected not to exist, and there it is instead! (with "
195  << data->size() << " elements)";
196  }
197  if (!found && targetInfo.bExists) {
198  throw art::Exception(art::errors::ProductNotFound)
199  << "Data product '" << tag << "' (" << desc
200  << ") was expected, but there is none.";
201  }
202 
203  if (targetInfo.bCheckEntries && (data->size() != targetInfo.expectedEntries))
204  {
205  throw art::Exception(art::errors::ProductNotFound)
206  << "Data product '" << tag << "' (" << desc
207  << ") was expected to have " << targetInfo.expectedEntries
208  << " entires, but it has " << data->size() << "!";
209  }
210 
211 } // recob::test::HitDataProductChecker::HitCollectionCreator_test()
212 
213 
214 //----------------------------------------------------------------------------
bool bExists
Whether data product must exist or must not exist.
unsigned int expectedEntries
Number of expected entries.
bool bCheckEntries
Whether to check the number of entries.
Declaration of signal hit object.
void checkDataProducts(art::Event const &event, TargetInfo_t const &targetInfo, std::string desc)
Checks the specified data product.
bool exists(std::string path)
art::EDAnalyzer::Table< Config > Parameters
virtual void analyze(const art::Event &event) override
BEGIN_PROLOG vertical distance to the surface Name
fhicl::Sequence< fhicl::Table< TargetInfo > > hits
std::vector< TargetInfo_t > fHitTargets
Configuration of all checks on hit collections.
T copy(T const &v)
Module verifying the presence of data products.
Configuration for a single data product check.
BEGIN_PROLOG hitmakerfive clustermakerfour pfparticlemakerthree showermakertwo END_PROLOG hitmakerfive clustermakerfour pfparticlemakerthree sequence::inline_paths sequence::inline_paths sequence::inline_paths showermakers test