All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AssnsChainTest_module.cc
Go to the documentation of this file.
1 /**
2  * @file AssnsChainTest_module.cc
3  * @brief Module running through a predefined set of associations.
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date June 23, 2017
6  *
7  * This test does not test almost anything.
8  * The output should be manually checked to make sure it makes sense.
9  */
10 
11 // LArSoft libraries
17 #include "larcorealg/CoreUtils/MetaUtils.h" // std::always_true_v
18 
19 // framework libraries
20 #include "art/Framework/Core/EDAnalyzer.h"
21 #include "art/Framework/Principal/Event.h"
22 #include "art/Framework/Principal/Handle.h"
23 #include "art/Framework/Core/ModuleMacros.h"
24 
25 #include "canvas/Persistency/Common/Ptr.h"
26 #include "canvas/Persistency/Common/Assns.h"
27 #include "canvas/Persistency/Provenance/ProductID.h"
28 #include "canvas/Utilities/InputTag.h"
29 
30 #include "messagefacility/MessageLogger/MessageLogger.h"
31 #include "fhiclcpp/types/Atom.h"
32 #include "fhiclcpp/types/Name.h"
33 #include "fhiclcpp/types/Comment.h"
34 
35 // C/C++ standard libraries
36 #include <set>
37 #include <cassert>
38 
39 
40 namespace lar {
41  namespace test {
42 
43  // -------------------------------------------------------------------------
44  /**
45  * @brief Prints all the hits associated to the specified shower.
46  *
47  * The hits are searched transversing associations from showers to particle
48  * flow objects to clusters to hits.
49  *
50  * Configuration parameters
51  * =========================
52  *
53  * * *showers* (input tag, required): the shower collection
54  * * *hitsPerLine* (positive integer, default: 10): how many associated hits
55  * to print per line
56  * * *nShowers* _(positive integer, mandatory)_: total number of expected
57  * showers
58  * * *nParticles* _(positive integer, mandatory)_: total number of expected
59  * particle flow objects
60  * * *nClusters* _(positive integer, mandatory)_: total number of expected
61  * clusters
62  * * *nHits* _(positive integer, mandatory)_: total number of expected hits
63  *
64  */
65  class AssnsChainTest: public art::EDAnalyzer {
66  public:
67 
68  struct Config {
69  using Name = fhicl::Name;
70  using Comment = fhicl::Comment;
71 
72  fhicl::Atom<art::InputTag> showers{
73  Name("showers"),
74  Comment("label of the shower collection to be explored")
75  };
76 
77  fhicl::Atom<unsigned int> hitsPerLine {
78  Name("hitsPerLine"),
79  Comment("how many associated hits to print per line"),
80  10
81  };
82 
83  fhicl::Atom<unsigned int> nHits {
84  Name("nHits"),
85  Comment("total number of expected hits"),
86  };
87 
88  fhicl::Atom<unsigned int> nClusters {
89  Name("nClusters"),
90  Comment("total number of expected clusters"),
91  };
92 
93  fhicl::Atom<unsigned int> nParticles {
94  Name("nParticles"),
95  Comment("total number of expected particle flow objects"),
96  };
97 
98  fhicl::Atom<unsigned int> nShowers {
99  Name("nShowers"),
100  Comment("total number of expected showers"),
101  };
102 
103  }; // struct Config
104 
105  using Parameters = art::EDAnalyzer::Table<Config>;
106 
107  explicit AssnsChainTest(Parameters const& config);
108 
109  virtual void analyze(art::Event const& event) override;
110 
111  private:
112  art::InputTag showerTag; ///< Label of the input collection of showers.
113  unsigned int nObjectsPerLine; ///< Number of objects to print on one line.
114  unsigned int nShowers; ///< Total number of expected showers.
115  unsigned int nPFOs; ///< Total number of expected particles.
116  unsigned int nClusters; ///< Total number of expected clusters.
117  unsigned int nHits; ///< Total number of expected hits.
118 
119  template <typename ShowerHandle>
121  (art::Event const& event, ShowerHandle const& showers) const;
122 
123  template <typename ShowerHandle>
125  (art::Event const& event, ShowerHandle const& showers) const;
126 
127  template <typename ShowerHandle>
129  (art::Event const& event, ShowerHandle const& showers) const;
130 
131  }; // AssnsChainTest
132 
133 
134  // -------------------------------------------------------------------------
135 
136  } // namespace test
137 } // namespace lar
138 
139 
140 // -----------------------------------------------------------------------------
142  : art::EDAnalyzer(config)
143  , showerTag(config().showers())
144  , nObjectsPerLine(config().hitsPerLine())
145  , nShowers(config().nShowers())
146  , nPFOs(config().nParticles())
147  , nClusters(config().nClusters())
148  , nHits(config().nHits())
149  {}
150 
151 
152 // -----------------------------------------------------------------------------
153 void lar::test::AssnsChainTest::analyze(art::Event const& event) {
154 
155  //
156  // read the input collection
157  //
158  auto showers = event.getValidHandle<std::vector<recob::Shower>>(showerTag);
159  mf::LogVerbatim("AssnsChainTest") << event.id() << " contains "
160  << showers->size() << " showers from '" << showerTag.encode() << "'";
161 
162  if (showers->size() != nShowers) {
163  throw cet::exception("AssnsChainTest")
164  << "Data product '" << showerTag.encode() << "' contains "
165  << showers->size() << " showers, " << nShowers << " were expected.\n";
166  }
167 
168  mf::LogVerbatim("AssnsChainTest") << "\nPrinting: shower particle";
169  printAssociatedPFOs(event, showers);
170 
171  mf::LogVerbatim("AssnsChainTest") << "\nPrinting: shower clusters";
172  printAssociatedClusters(event, showers);
173 
174  mf::LogVerbatim("AssnsChainTest") << "\nPrinting: shower hits";
175  printAssociatedHits(event, showers);
176 
177 } // lar::test::AssnsChainTest::analyze()
178 
179 
180 // -----------------------------------------------------------------------------
181 template <typename ShowerHandle>
183  (art::Event const& event, ShowerHandle const& showers) const
184 {
185 
186  //
187  // get the associated hits
188  //
190  showerHits(showers, event, showerTag);
191  assert(showerHits.size() == showers->size());
192 
193  //
194  // print the associated hits (just the art pointer so far)
195  //
196  unsigned int nDuplicates = 0;
197  std::set<art::Ptr<recob::Hit>> foundHits; // all hits found
198  std::set<art::ProductID> foundHitProducts;
199 
200  unsigned int const pageSize = nObjectsPerLine; // hits per line
201  mf::LogVerbatim log("AssnsChainTest");
202  for (std::size_t iShower = 0; iShower < showers->size(); ++iShower) {
203  auto const& hits = showerHits.at(iShower);
204  log << "\n #" << iShower << ": " << hits.size() << " hits";
205  if (hits.empty()) continue;
206 
207  unsigned int hitsLeft = pageSize;
208  for (art::Ptr<recob::Hit> const& hit: hits) {
209  if (foundHits.count(hit) == 0) {
210  foundHits.insert(hit);
211  foundHitProducts.insert(hit.id());
212  }
213  else {
214  mf::LogProblem("AssnsChainTest")
215  << "ERROR: Hit " << hit << " appears in more than one shower!";
216  ++nDuplicates;
217  }
218  if (hitsLeft-- == 0) {
219  hitsLeft = pageSize;
220  log << "\n ";
221  }
222  log << " " << hit; // just print the art pointer
223  } // for hits
224 
225  } // for iShower
226 
227  mf::LogVerbatim("AssnsChainTest")
228  << foundHits.size() << " hits collected for "
229  << showers->size() << " showers ('"
230  << showers.provenance()->inputTag().encode() << "') from "
231  << foundHitProducts.size() << " data products:";
232  for (art::ProductID const& PID: foundHitProducts) {
233  art::Handle<std::vector<recob::Hit>> hits;
234  if (event.get(PID, hits)) {
235  mf::LogVerbatim("AssnsChainTest") << " - '"
236  << hits.provenance()->inputTag().encode() << "' (contains "
237  << hits->size() << " hits)";
238  }
239  else {
240  mf::LogVerbatim("AssnsChainTest") << " - <" << PID << "> (not found!)";
241  }
242  } // for PIDs
243 
244  if (nDuplicates > 0) {
245  throw cet::exception("AssnsChainTest")
246  << "Test failed: " << nDuplicates
247  << " hits appear in more than one shower.\n";
248  }
249  if (foundHits.size() != nHits) {
250  throw cet::exception("AssnsChainTest")
251  << "Test failed: counted " << foundHits.size()
252  << " hits, expected " << nHits << ".\n";
253  }
254 
255 } // lar::test::AssnsChainTest::printAssociatedHits()
256 
257 
258 // -----------------------------------------------------------------------------
259 template <typename ShowerHandle>
261  (art::Event const& event, ShowerHandle const& showers) const
262 {
263  std::string const objectsDesc = "clusters";
264 
265  //
266  // get the associated objects
267  //
269  (showers, event, showerTag);
270  assert(showerObjects.size() == showers->size());
271 
272  using ObjectPtr_t = decltype(showerObjects)::TargetPtr_t;
273 
274  //
275  // print the associated objects (just the art pointer so far)
276  //
277  unsigned int nDuplicates = 0;
278  std::set<art::Ptr<recob::Cluster>> foundObjects; // all objects found
279  std::set<art::ProductID> foundObjectProducts;
280 
281  unsigned int const pageSize = nObjectsPerLine; // objects per line
282  mf::LogVerbatim log("AssnsChainTest");
283  for (std::size_t iShower = 0; iShower < showers->size(); ++iShower) {
284  auto const& objects = showerObjects.at(iShower);
285  log << "\n #" << iShower << ": " << objects.size() << " " << objectsDesc;
286  if (objects.empty()) continue;
287 
288  unsigned int objectsLeft = pageSize;
289  for (ObjectPtr_t const& object: objects) {
290  if (foundObjects.count(object) == 0) {
291  foundObjects.insert(object);
292  foundObjectProducts.insert(object.id());
293  }
294  else {
295  mf::LogProblem("AssnsChainTest")
296  << "ERROR: Cluster " << object << " appears in more than one shower!";
297  ++nDuplicates;
298  }
299  if (objectsLeft-- == 0) {
300  objectsLeft = pageSize;
301  log << "\n ";
302  }
303  log << " " << object; // just print the art pointer
304  } // for objects
305 
306  } // for iShower
307 
308  mf::LogVerbatim("AssnsChainTest")
309  << foundObjects.size() << " " << objectsDesc << " collected for "
310  << showers->size() << " showers ('"
311  << showers.provenance()->inputTag().encode() << "') from "
312  << foundObjectProducts.size() << " data products:";
313  for (art::ProductID const& PID: foundObjectProducts) {
314  art::Handle<std::vector<recob::Cluster>> objects;
315  if (event.get(PID, objects)) {
316  mf::LogVerbatim("AssnsChainTest") << " - '"
317  << objects.provenance()->inputTag().encode() << "' (contains "
318  << objects->size() << " " << objectsDesc << ")";
319  }
320  else {
321  mf::LogVerbatim("AssnsChainTest") << " - <" << PID << "> (not found!)";
322  }
323  } // for PIDs
324 
325  if (nDuplicates > 0) {
326  throw cet::exception("AssnsChainTest")
327  << "Test failed: " << nDuplicates
328  << " clusters appear in more than one shower.\n";
329  }
330  if (foundObjects.size() != nClusters) {
331  throw cet::exception("AssnsChainTest")
332  << "Test failed: counted " << foundObjects.size()
333  << " clusters, expected " << nClusters << ".\n";
334  }
335 
336 } // lar::test::AssnsChainTest::printAssociatedClusters()
337 
338 
339 // -----------------------------------------------------------------------------
340 template <typename ShowerHandle>
342  (art::Event const& event, ShowerHandle const& showers) const
343 {
344  std::string const objectsDesc = "particle flow objects";
345 
346  //
347  // get the associated objects
348  //
350  (showers, event, showerTag);
351  assert(showerObjects.size() == showers->size());
352 
353  using ObjectPtr_t = decltype(showerObjects)::TargetPtr_t;
354 
355  //
356  // print the associated objects (just the art pointer so far)
357  //
358  unsigned int nDuplicates = 0;
359  std::set<art::Ptr<recob::PFParticle>> foundObjects; // all objects found
360  std::set<art::ProductID> foundObjectProducts;
361 
362  unsigned int const pageSize = nObjectsPerLine; // objects per line
363  mf::LogVerbatim log("AssnsChainTest");
364  for (std::size_t iShower = 0; iShower < showers->size(); ++iShower) {
365  auto const& objects = showerObjects.at(iShower);
366  log << "\n #" << iShower << ": " << objects.size() << " " << objectsDesc;
367 
368  unsigned int objectsLeft = pageSize;
369  for (ObjectPtr_t const& object: objects) {
370  if (foundObjects.count(object) == 0) {
371  foundObjects.insert(object);
372  foundObjectProducts.insert(object.id());
373  }
374  else {
375  mf::LogProblem("AssnsChainTest")
376  << "ERROR: Particle " << object
377  << " appears in more than one shower!";
378  ++nDuplicates;
379  }
380  if (objectsLeft-- == 0) {
381  objectsLeft = pageSize;
382  log << "\n ";
383  }
384  log << " " << object; // just print the art pointer
385  } // for objects
386 
387  if (objects.size() != 1) {
388  throw cet::exception("AssnsChainTest")
389  << "all showers are expected to have one PFParticle associated, while #"
390  << iShower << " has " << objects.size() << "\n";
391  }
392 
393  } // for iShower
394 
395  mf::LogVerbatim("AssnsChainTest")
396  << foundObjects.size() << " " << objectsDesc << " collected for "
397  << showers->size() << " showers ('"
398  << showers.provenance()->inputTag().encode() << "') from "
399  << foundObjectProducts.size() << " data products:";
400  for (art::ProductID const& PID: foundObjectProducts) {
401  art::Handle<std::vector<recob::PFParticle>> objects;
402  if (event.get(PID, objects)) {
403  mf::LogVerbatim("AssnsChainTest") << " - '"
404  << objects.provenance()->inputTag().encode() << "' (contains "
405  << objects->size() << " " << objectsDesc << ")";
406  }
407  else {
408  mf::LogVerbatim("AssnsChainTest") << " - <" << PID << "> (not found!)";
409  }
410  } // for PIDs
411 
412  if (nDuplicates > 0) {
413  throw cet::exception("AssnsChainTest")
414  << "Test failed: " << nDuplicates
415  << " particle flow objects appear in more than one shower.\n";
416  }
417  if (foundObjects.size() != nPFOs) {
418  throw cet::exception("AssnsChainTest")
419  << "Test failed: counted " << foundObjects.size()
420  << " particle flow objects, expected " << nPFOs << ".\n";
421  }
422 
423 } // lar::test::AssnsChainTest::printAssociatedPFOs()
424 
425 
426 // -----------------------------------------------------------------------------
427 DEFINE_ART_MODULE(lar::test::AssnsChainTest)
428 
429 // -----------------------------------------------------------------------------
Utility to navigate chains of associations.
Basic C++ metaprogramming utilities.
void printAssociatedHits(art::Event const &event, ShowerHandle const &showers) const
unsigned int nShowers
Total number of expected showers.
Declaration of signal hit object.
TargetPtrCollection_t const & at(std::size_t i) const
Returns all the Target objects associated to specified object.
fhicl::Atom< art::InputTag > showers
fhicl::Atom< unsigned int > nShowers
Prints all the hits associated to the specified shower.
process_name hit
Definition: cheaterreco.fcl:51
unsigned int nPFOs
Total number of expected particles.
art::EDAnalyzer::Table< Config > Parameters
fhicl::Atom< unsigned int > nParticles
BEGIN_PROLOG vertical distance to the surface Name
Declaration of cluster object.
Query object collecting a list of associated objects.
unsigned int nHits
Total number of expected hits.
std::size_t size() const noexcept
Returns the number of Source objects we have information about.
fhicl::Atom< unsigned int > nClusters
unsigned int nClusters
Total number of expected clusters.
fhicl::Atom< unsigned int > nHits
art::InputTag showerTag
Label of the input collection of showers.
BEGIN_PROLOG hitmakerfive clustermakerfour pfparticlemakerthree showermakertwo END_PROLOG hitmakerfive clustermakerfour pfparticlemakerthree sequence::inline_paths sequence::inline_paths sequence::inline_paths showermakers test
virtual void analyze(art::Event const &event) override
AssnsChainTest(Parameters const &config)
unsigned int nObjectsPerLine
Number of objects to print on one line.
void printAssociatedPFOs(art::Event const &event, ShowerHandle const &showers) const
void printAssociatedClusters(art::Event const &event, ShowerHandle const &showers) const
fhicl::Atom< unsigned int > hitsPerLine