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