All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DumpMCParticles_module.cc
Go to the documentation of this file.
1 /**
2  * @file DumpMCParticles_module.cc
3  * @brief Module dumping MCarticle information on screen
4  * @date December 3rd, 2015
5  * @author Gianluca Petrillo (petrillo@fnal.gov)
6  *
7  */
8 
9 // LArSoft libraries
10 #include "lardataalg/MCDumpers/MCDumpers.h" // sim::dump namespace
12 
13 // nusimdata libraries
14 #include "nusimdata/SimulationBase/MCTruth.h"
15 #include "nusimdata/SimulationBase/MCParticle.h"
16 
17 // framework libraries
18 #include "art/Framework/Core/EDAnalyzer.h"
19 #include "art/Framework/Core/ModuleMacros.h"
20 #include "art/Framework/Principal/Event.h"
21 #include "art/Framework/Principal/Handle.h"
22 #include "canvas/Persistency/Provenance/ProductID.h"
23 #include "canvas/Persistency/Common/FindOneP.h"
24 #include "canvas/Utilities/InputTag.h"
25 #include "fhiclcpp/types/Atom.h"
26 #include "fhiclcpp/types/OptionalAtom.h"
27 #include "messagefacility/MessageLogger/MessageLogger.h"
28 
29 // C/C++ standard libraries
30 #include <memory> // std::unique_ptr<>
31 #include <string>
32 
33 namespace sim {
34  class DumpMCParticles;
35 } // namespace sim
36 
37 namespace {
38  using namespace fhicl;
39 
40  /// Collection of configuration parameters for the module
41  struct Config {
42  using Name = fhicl::Name;
43  using Comment = fhicl::Comment;
44 
45  fhicl::Atom<art::InputTag> InputParticles {
46  Name("InputParticles"),
47  Comment("data product with the MC particles to be dumped")
48  };
49 
50  fhicl::OptionalAtom<art::InputTag> ParticleTruthInfo {
51  Name("ParticleTruthInfo"),
52  Comment
53  ("label of the association to MCTruth (default: as `InputParticles`)")
54  };
55 
56  fhicl::Atom<std::string> OutputCategory {
57  Name("OutputCategory"),
58  Comment("name of the output stream (managed by the message facility)"),
59  "DumpMCParticles" /* default value */
60  };
61 
62  fhicl::Atom<unsigned int> PointsPerLine {
63  Name("PointsPerLine"),
64  Comment("trajectory points printed per line (default: 2; 0 = skip them)"),
65  2 /* default value */
66  };
67 
68  }; // struct Config
69 
70 
71 } // local namespace
72 
73 
74 class sim::DumpMCParticles: public art::EDAnalyzer {
75  public:
76  // type to enable module parameters description by art
77  using Parameters = art::EDAnalyzer::Table<Config>;
78 
79  /// Configuration-checking constructor
80  explicit DumpMCParticles(Parameters const& config);
81 
82  // Plugins should not be copied or assigned.
83  DumpMCParticles(DumpMCParticles const&) = delete;
84  DumpMCParticles(DumpMCParticles &&) = delete;
85  DumpMCParticles& operator = (DumpMCParticles const&) = delete;
86  DumpMCParticles& operator = (DumpMCParticles &&) = delete;
87 
88 
89  // Operates on the event
90  void analyze(art::Event const& event) override;
91 
92  /// May print some warnings.
93  void endJob() override;
94 
95  /**
96  * @brief Dumps the content of the specified particle in the output stream.
97  * @tparam Stream the type of output stream
98  * @param out the output stream
99  * @param particle the particle to be dumped
100  * @param truthTag input tag of the truth record the particle derived from
101  * @param truthIndex index of particle in the truth record this derived from
102  * @param indent base indentation string (default: none)
103  * @param bIndentFirst if first output line should be indented (default: yes)
104  *
105  * The indent string is prepended to every line of output, with the possible
106  * exception of the first one, in case bIndentFirst is true.
107  *
108  * If `truthTag` module label is empty, it is assumed that this information
109  * could not be retrieved, and it will be silently omitted.
110  * If `truthIndex` is `sim::NoGeneratorIndex`, it is assumed that this
111  * information could not be retrieved, and it will be silently omitted.
112  *
113  * The output starts on the current line, and the last line is NOT broken.
114  */
115  template <typename Stream>
116  void DumpMCParticle(
117  Stream&& out, simb::MCParticle const& particle,
118  art::InputTag const& truthTag, sim::GeneratedParticleInfo const& truthInfo,
119  std::string indent = "", bool bIndentFirst = true
120  ) const;
121 
122 
123  private:
124 
125  art::InputTag fInputParticles; ///< name of MCParticle's data product
126  art::InputTag fParticleTruthInfo; ///< name of MCParticle assns data product
127  std::string fOutputCategory; ///< name of the stream for output
128  unsigned int fPointsPerLine; ///< trajectory points per output line
129 
130  unsigned int fNEvents = 0U; ///< Count of processed events.
131  /// Count of events without truth association.
132  unsigned int fNMissingTruth = 0U;
133  /// Count of events without truth index.
134  unsigned int fNMissingTruthIndex = 0U;
135 
136 }; // class sim::DumpMCParticles
137 
138 
139 //------------------------------------------------------------------------------
140 //--- module implementation
141 //---
142 //------------------------------------------------------------------------------
143 namespace {
144 
145  //----------------------------------------------------------------------------
146  class ProductNameCache {
147 
148  public:
149  ProductNameCache(art::Event const& event): fEvent(event) {}
150 
151  /// Returns the input tag corresponding to the specified art product id.
152  template <typename T>
153  art::InputTag const& operator[](art::Ptr<T> const& ptr)
154  {
155  auto const iInfo = fNames.find(ptr.id());
156  return (iInfo == fNames.end())? fetch(ptr): iInfo->second;
157  }
158 
159  private:
160  art::Event const& fEvent;
161  std::map<art::ProductID, art::InputTag> fNames;
162 
163  template <typename T>
164  art::InputTag fetchTag(art::Ptr<T> const& ptr)
165  {
166  art::Handle<std::vector<T>> handle;
167  return fEvent.get(ptr.id(), handle)
168  ? handle.provenance()->inputTag()
169  : art::InputTag{}
170  ;
171  }
172 
173  template <typename T>
174  art::InputTag const& fetch(art::Ptr<T> const& ptr)
175  {
176  art::InputTag const tag = fetchTag(ptr);
177  return fNames.emplace(ptr.id(), tag).first->second;
178  }
179 
180  }; // class ProductNameCache
181 
182 
183  //----------------------------------------------------------------------------
184  template <typename Right, typename Metadata, typename Left>
185  std::unique_ptr<art::FindOneP<Right, Metadata>> makeFindOneP(
186  art::ValidHandle<std::vector<Left>> const& handle,
187  art::Event const& event,
188  art::InputTag const& tag
189  ) {
190 
191  art::Handle<art::Assns<Left, Right, Metadata>> assnsHandle;
192  if (!event.getByLabel(tag, assnsHandle)) return {};
193 
194  return std::make_unique<art::FindOneP<Right, Metadata>>
195  (handle, event, tag);
196 
197  } // makeFindOneP()
198 
199 
200  //----------------------------------------------------------------------------
201 
202 } // local namespace
203 
204 
205 //------------------------------------------------------------------------------
207  : EDAnalyzer(config)
208  , fInputParticles(config().InputParticles())
209  , fOutputCategory(config().OutputCategory())
210  , fPointsPerLine(config().PointsPerLine())
211 {
212  if (!config().ParticleTruthInfo(fParticleTruthInfo))
214 
215 }
216 
217 //------------------------------------------------------------------------------
218 template <typename Stream>
220  Stream&& out, simb::MCParticle const& particle,
221  art::InputTag const& truthTag, sim::GeneratedParticleInfo const& truthInfo,
222  std::string indent /* = "" */, bool bIndentFirst /* = true */
223 ) const {
224 
225  if (!truthTag.label().empty() || truthInfo.hasGeneratedParticleIndex()) {
226  out << "(from ";
227  if (truthTag.label().empty()) out << "unknown truth record";
228  else out << "'" << truthTag.encode() << "'";
229  if (truthInfo.hasGeneratedParticleIndex())
230  out << " particle #" << truthInfo.generatedParticleIndex();
231  out << ") ";
232  }
233 
235  (std::forward<Stream>(out), particle, indent, bIndentFirst? indent: "");
236 
237  const unsigned int nPoints = particle.NumberTrajectoryPoints();
238  if ((nPoints > 0) && (fPointsPerLine > 0)) {
239  out << ":";
241  std::forward<Stream>(out), particle.Trajectory(),
242  fPointsPerLine, indent + " "
243  );
244  } // if has points
245 
246 } // sim::DumpMCParticles::DumpMCParticle()
247 
248 
249 //------------------------------------------------------------------------------
250 void sim::DumpMCParticles::analyze(art::Event const& event) {
251 
252  ++fNEvents;
253 
254  ProductNameCache namesRegistry(event);
255 
256  // get the particles from the event
257  auto const& particleHandle
258  = event.getValidHandle<std::vector<simb::MCParticle>>(fInputParticles);
259  auto const& Particles = *particleHandle;
260 
261  // get the association to MCTruth
262  // - try first the more complete one, with true particle indices
263  // - as a fallback, go without true particle indices
264  auto particleToTruth = makeFindOneP<simb::MCTruth, sim::GeneratedParticleInfo>
265  (particleHandle, event, fParticleTruthInfo);
266  std::unique_ptr<art::FindOneP<simb::MCTruth>> particleToTruthLight;
267  if (!particleToTruth) {
268  ++fNMissingTruthIndex;
269  particleToTruthLight = makeFindOneP<simb::MCTruth, void>
270  (particleHandle, event, fParticleTruthInfo);
271  if (!particleToTruthLight) ++fNMissingTruth;
272  }
273 
274  mf::LogVerbatim(fOutputCategory) << "Event " << event.id()
275  << ": data product '" << fInputParticles.encode() << "' contains "
276  << Particles.size() << " MCParticle's";
277 
278  unsigned int iParticle = 0;
279  for (simb::MCParticle const& particle: Particles) {
280  // flush on every particle,
281  // since the output buffer might grow too large otherwise
282  mf::LogVerbatim log(fOutputCategory);
283 
284  // fetch the input tag of the truth information (if any)
285  art::Ptr<simb::MCTruth> const& truth = particleToTruth
286  ? particleToTruth->at(iParticle)
287  : particleToTruthLight
288  ? particleToTruthLight->at(iParticle)
289  : art::Ptr<simb::MCTruth>{}
290  ;
291  art::InputTag const& truthTag
292  = truth? namesRegistry[truth]: art::InputTag{};
293 
294  // fetch the index of the true particle in the truth record (if any)
295  sim::GeneratedParticleInfo truthInfo = particleToTruth
296  ? particleToTruth->data(iParticle).ref()
298  ;
299 
300  // a bit of a header
301  log << "\n[#" << (iParticle++) << "] ";
302  DumpMCParticle(log, particle, truthTag, truthInfo, " ", false);
303  } // for
304 
305  mf::LogVerbatim(fOutputCategory) << "\n";
306 
307 } // sim::DumpMCParticles::analyze()
308 
309 
310 //------------------------------------------------------------------------------
312 
313  if (fNMissingTruth > 0) {
314  mf::LogProblem(fOutputCategory)
315  << "Warning: " << fNMissingTruth << "/" << fNEvents
316  << " events lacked event generator information for '"
317  << fParticleTruthInfo << "'.";
318  }
319  else if (fNMissingTruthIndex > 0) {
320  mf::LogProblem(fOutputCategory)
321  << "Warning: " << fNMissingTruthIndex << "/" << fNEvents
322  << " events lacked information of which particles of '"
323  << fParticleTruthInfo << "' are generator particles.";
324  }
325 
326 } // sim::DumpMCParticles::endJob()
327 
328 
329 //------------------------------------------------------------------------------
330 DEFINE_ART_MODULE(sim::DumpMCParticles)
331 
332 //------------------------------------------------------------------------------
process_name opflashCryo1 flashfilter analyze
static constexpr GeneratedParticleIndex_t NoGeneratedParticleIndex
Constant representing the absence of generator truth information.
bool hasGeneratedParticleIndex() const
Returns whether the specified one is an acceptable generator index.
std::string fOutputCategory
name of the stream for output
void DumpMCParticleTrajectory(Stream &&out, simb::MCTrajectory const &trajectory, unsigned int pointsPerLine, std::string indent)
Dumps the specified particle trajectory into the output stream.
Definition: MCDumpers.h:289
Contains data associated to particles from detector simulation.
Utility functions to print MC truth information.
void DumpMCParticle(Stream &&out, simb::MCParticle const &particle, art::InputTag const &truthTag, sim::GeneratedParticleInfo const &truthInfo, std::string indent="", bool bIndentFirst=true) const
Dumps the content of the specified particle in the output stream.
BEGIN_PROLOG vertical distance to the surface Name
art::EDAnalyzer::Table< Config > Parameters
Contains information about a generated particle.
unsigned int fPointsPerLine
trajectory points per output line
art::InputTag fParticleTruthInfo
name of MCParticle assns data product
void endJob() override
May print some warnings.
void analyze(art::Event const &event) override
art::InputTag fInputParticles
name of MCParticle&#39;s data product
GeneratedParticleIndex_t generatedParticleIndex() const
Returns the generated particle index.
bnb BNB Stream
void DumpMCParticle(Stream &&out, simb::MCParticle const &particle, std::string indent, std::string firstIndent)
Dumps the content of the specified particle in the output stream.
Definition: MCDumpers.h:228
DumpMCParticles(Parameters const &config)
Configuration-checking constructor.