LArPandoraExternalEventBuilding_module.cc
Go to the documentation of this file.
1 /**
2  * @file larpandora/LArPandoraEventBuilding/LArPandoraExternalEventBuilding.cc
3  *
4  * @brief module for lar pandora external event building
5  */
6 
11 
13 
14 #include "fhiclcpp/ParameterSet.h"
15 
17 
19 
23 
26 
27 #include "TTree.h"
28 
29 namespace lar_pandora
30 {
31 
33 {
34 public:
36 
41 
42  void produce(art::Event &evt) override;
43 
44 private:
45  typedef std::map<art::Ptr<recob::PFParticle>, art::Ptr<larpandoraobj::PFParticleMetadata> > PFParticleToMetadata;
46 
47  /**
48  * @brief Collect PFParticles from the ART event and their mapping to metadata objects
49  *
50  * @param evt the ART event
51  * @param particlesToMetadata the output mapping from PFParticles to their metadata
52  * @param particles the output vector of particles
53  */
54  void CollectPFParticles(const art::Event &evt, PFParticleToMetadata &particlesToMetadata, PFParticleVector &particles) const;
55 
56  /**
57  * @brief Build mapping from ID to PFParticle for fast navigation through the hierarchy
58  *
59  * @param particlesToMetadata the input mapping from PFParticles to their metadata
60  * @param particleMap the output mapping from ID to PFParticle
61  */
62  void BuildPFParticleMap(const PFParticleToMetadata &particlesToMetadata, PFParticleMap &particleMap) const;
63 
64  /**
65  * @brief Collect PFParticles that have been identified as clear cosmic ray muons by pandora
66  *
67  * @param allParticles input vector of all particles
68  * @param particlesToMetadata the input mapping from PFParticles to their metadata
69  * @param particleMap the input mapping from ID to PFParticle
70  * @param clearCosmics the output vector of clear cosmic rays
71  */
72  void CollectClearCosmicRays(const PFParticleVector &allParticles, const PFParticleToMetadata &particlesToMetadata, const PFParticleMap &particleMap, PFParticleVector &clearCosmics) const;
73 
74  /**
75  * @brief Collect slices
76  *
77  * @param allParticles input vector of all particles
78  * @param particlesToMetadata the input mapping from PFParticles to their metadata
79  * @param particleMap the input mapping from ID to PFParticle
80  * @param slices the output vector of slices
81  */
82  void CollectSlices(const PFParticleVector &allParticles, const PFParticleToMetadata &particlesToMetadata, const PFParticleMap &particleMap, SliceVector &slices) const;
83 
84  /**
85  * @brief Get the consolidated collection of particles based on the slice ids
86  *
87  * @param allParticles input vector of all particles
88  * @param clearCosmics the input vector of clear cosmic ray muons
89  * @param slices the input vector of slices
90  * @param consolidatedParticles the output vector of particles to include in the consolidated output
91  */
92  void CollectConsolidatedParticles(const PFParticleVector &allParticles, const PFParticleVector &clearCosmics, const SliceVector &slices, PFParticleVector &consolidatedParticles) const;
93 
94  /**
95  * @brief Query a metadata object for a given key and return the corresponding value
96  *
97  * @param metadata the metadata object to query
98  * @param key the key to search for
99  *
100  * @return the value in the metadata corresponding to the input key
101  */
103 
104  /**
105  * @brief Query a metadata object to see if it is a target particle
106  *
107  * @param metadata the metadata object to query
108  *
109  * @return boolean - if the particle is a target
110  */
112 
113  std::string m_inputProducerLabel; ///< Label for the Pandora instance that produced the collections we want to consolidated
114  std::string m_trackProducerLabel; ///< Label for the track producer using the Pandora instance that produced the collections we want to consolidate
115  std::string m_showerProducerLabel; ///< Label for the shower producer using the Pandora instance that produced the collections we want to consolidate
116  std::string m_hitProducerLabel; ///< Label for the hit producer that was used as input to the Pandora instance specified
117  bool m_shouldProduceT0s; ///< If we should produce T0s (relevant when stitching over multiple drift volumes)
118  art::InputTag m_pandoraTag; ///< The input tag for the pandora producer
119  std::unique_ptr<SliceIdBaseTool> m_sliceIdTool; ///< The slice id tool
120  bool m_useTestBeamMode; ///< If we should expect a test-beam (instead of a neutrino) slice
121  std::string m_targetKey; ///< The metadata key for a PFParticle to determine if it is the target
122  std::string m_scoreKey; ///< The metadata key for the score of the target slice from Pandora
123 };
124 
126 
127 } // namespace lar_pandora
128 
129 //------------------------------------------------------------------------------------------------------------------------------------------
130 // implementation follows
131 
132 #include "Pandora/PdgTable.h"
133 
134 namespace lar_pandora
135 {
136 
138  EDProducer{pset},
139  m_inputProducerLabel(pset.get<std::string>("InputProducerLabel")),
140  m_trackProducerLabel(pset.get<std::string>("TrackProducerLabel")),
141  m_showerProducerLabel(pset.get<std::string>("ShowerProducerLabel")),
142  m_hitProducerLabel(pset.get<std::string>("HitProducerLabel")),
143  m_shouldProduceT0s(pset.get<bool>("ShouldProduceT0s")),
145  m_sliceIdTool(art::make_tool<SliceIdBaseTool>(pset.get<fhicl::ParameterSet>("SliceIdTool"))),
146  m_useTestBeamMode(pset.get<bool>("ShouldUseTestBeamMode", false)),
147  m_targetKey(m_useTestBeamMode ? "IsTestBeam" : "IsNeutrino"),
148  m_scoreKey(m_useTestBeamMode ? "TestBeamScore" : "NuScore")
149 {
150  produces< std::vector<recob::PFParticle> >();
151  produces< std::vector<recob::SpacePoint> >();
152  produces< std::vector<recob::Cluster> >();
153  produces< std::vector<recob::Vertex> >();
154  produces< std::vector<recob::Slice> >();
155  produces< std::vector<recob::Track> >();
156  produces< std::vector<recob::Shower> >();
157  produces< std::vector<recob::PCAxis> >();
158  produces< std::vector<larpandoraobj::PFParticleMetadata> >();
159 
160  produces< art::Assns<recob::PFParticle, recob::SpacePoint> >();
161  produces< art::Assns<recob::PFParticle, recob::Cluster> >();
162  produces< art::Assns<recob::PFParticle, recob::Vertex> >();
163  produces< art::Assns<recob::PFParticle, recob::Slice> >();
164  produces< art::Assns<recob::PFParticle, recob::Track> >();
165  produces< art::Assns<recob::PFParticle, recob::Shower> >();
166  produces< art::Assns<recob::PFParticle, recob::PCAxis> >();
167  produces< art::Assns<recob::PFParticle, larpandoraobj::PFParticleMetadata> >();
168  produces< art::Assns<recob::Track, recob::Hit, recob::TrackHitMeta> >();
169  produces< art::Assns<recob::Shower, recob::Hit> >();
170  produces< art::Assns<recob::Shower, recob::PCAxis> >();
171  produces< art::Assns<recob::SpacePoint, recob::Hit> >();
172  produces< art::Assns<recob::Cluster, recob::Hit> >();
173  produces< art::Assns<recob::Slice, recob::Hit> >();
174 
175  if (m_shouldProduceT0s)
176  {
177  produces< std::vector<anab::T0> >();
178  produces< art::Assns<recob::PFParticle, anab::T0> >();
179  }
180  }
181 
182 //------------------------------------------------------------------------------------------------------------------------------------------
183 
185 {
186  PFParticleVector particles;
187  PFParticleToMetadata particlesToMetadata;
188  this->CollectPFParticles(evt, particlesToMetadata, particles);
189 
190  PFParticleMap particleMap;
191  this->BuildPFParticleMap(particlesToMetadata, particleMap);
192 
193  PFParticleVector clearCosmics;
194  this->CollectClearCosmicRays(particles, particlesToMetadata, particleMap, clearCosmics);
195 
197  this->CollectSlices(particles, particlesToMetadata, particleMap, slices);
198 
199  m_sliceIdTool->ClassifySlices(slices, evt);
200 
201  PFParticleVector consolidatedParticles;
202  this->CollectConsolidatedParticles(particles, clearCosmics, slices, consolidatedParticles);
203 
205  const LArPandoraEvent consolidatedEvent(LArPandoraEvent(this, &evt, labels, m_shouldProduceT0s), consolidatedParticles);
206 
207  consolidatedEvent.WriteToEvent();
208 }
209 
210 //------------------------------------------------------------------------------------------------------------------------------------------
211 
213 {
215  evt.getByLabel(m_pandoraTag, pfParticleHandle);
216 
217  art::FindManyP<larpandoraobj::PFParticleMetadata> pfParticleMetadataAssoc(pfParticleHandle, evt, m_pandoraTag);
218 
219  for (unsigned int i = 0; i < pfParticleHandle->size(); ++i)
220  {
221  const art::Ptr<recob::PFParticle> part(pfParticleHandle, i);
222  const auto &metadata(pfParticleMetadataAssoc.at(part.key()));
223 
224  particles.push_back(part);
225 
226  if (metadata.size() != 1)
227  throw cet::exception("LArPandora") << " LArPandoraExternalEventBuilding::CollectPFParticles -- Found a PFParticle without exactly 1 metadata associated." << std::endl;
228 
229  if (!particlesToMetadata.insert(PFParticleToMetadata::value_type(part, metadata.front())).second)
230  throw cet::exception("LArPandoraExternalEventBuilding") << "Repeated PFParticles" << std::endl;
231  }
232 }
233 
234 //------------------------------------------------------------------------------------------------------------------------------------------
235 
237 {
238  for (const auto &entry : particlesToMetadata)
239  {
240  if (!particleMap.insert(PFParticleMap::value_type(entry.first->Self(), entry.first)).second)
241  throw cet::exception("LArPandoraExternalEventBuilding") << "Repeated PFParticles" << std::endl;
242  }
243 }
244 
245 //------------------------------------------------------------------------------------------------------------------------------------------
246 
247 void LArPandoraExternalEventBuilding::CollectClearCosmicRays(const PFParticleVector &allParticles, const PFParticleToMetadata &particlesToMetadata, const PFParticleMap &particleMap, PFParticleVector &clearCosmics) const
248 {
249  for (const auto &part : allParticles)
250  {
251  // Get the parent of the particle
252  const auto parentIt(particlesToMetadata.find(LArPandoraHelper::GetParentPFParticle(particleMap, part)));
253  if (parentIt == particlesToMetadata.end())
254  throw cet::exception("LArPandoraExternalEventBuilding") << "Found PFParticle without metadata" << std::endl;
255 
256  // ATTN particles without the "IsClearCosmic" parameter are not clear cosmics
257  try
258  {
259  if (static_cast<bool>(std::round(this->GetMetadataValue(parentIt->second, "IsClearCosmic"))))
260  clearCosmics.push_back(part);
261  }
262  catch (const cet::exception &)
263  {
264  }
265  }
266 }
267 
268 //------------------------------------------------------------------------------------------------------------------------------------------
269 
270 void LArPandoraExternalEventBuilding::CollectSlices(const PFParticleVector &allParticles, const PFParticleToMetadata &particlesToMetadata, const PFParticleMap &particleMap, SliceVector &slices) const
271 {
272  std::map<unsigned int, float> targetScores;
273  std::map<unsigned int, PFParticleVector> crHypotheses;
274  std::map<unsigned int, PFParticleVector> targetHypotheses;
275  std::vector<unsigned int> usedSliceIds;
276 
277  // Collect the slice information
278  for (const auto &part : allParticles)
279  {
280  // Find the parent PFParticle
281  const auto parentIt(particlesToMetadata.find(LArPandoraHelper::GetParentPFParticle(particleMap, part)));
282  if (parentIt == particlesToMetadata.end())
283  throw cet::exception("LArPandoraExternalEventBuilding") << "Found PFParticle without metadata" << std::endl;
284 
285  // Skip PFParticles that are clear cosmics
286  try
287  {
288  if (static_cast<bool>(std::round(this->GetMetadataValue(parentIt->second, "IsClearCosmic"))))
289  continue;
290  }
291  catch (const cet::exception &)
292  {
293  }
294 
295  const unsigned int sliceId(static_cast<unsigned int>(std::round(this->GetMetadataValue(parentIt->second, "SliceIndex"))));
296  const float targetScore(this->GetMetadataValue(parentIt->second, m_scoreKey));
297 
298  // Keep track of the slice IDs we have used, and their corresponding score
299  if (std::find(usedSliceIds.begin(), usedSliceIds.end(), sliceId) == usedSliceIds.end())
300  {
301  usedSliceIds.push_back(sliceId);
302 
303  // ATTN all PFParticles in the same slice will have the same targetScore
304  targetScores[sliceId] = targetScore;
305  }
306 
307  if (this->IsTarget(parentIt->second))
308  {
309  targetHypotheses[sliceId].push_back(part);
310  }
311  else
312  {
313  crHypotheses[sliceId].push_back(part);
314  }
315  }
316 
317  // Sort the slice IDs to ensure reproducibility
318  std::sort(usedSliceIds.begin(), usedSliceIds.end());
319 
320  // ATTN: we need to ensure that for each slice there is a cosmic and neutrino hypothesis, even if the pass created no PFOs
321  // in such a case we add an empty vector of pfparticles
322  const PFParticleVector emptyPFParticleVector;
323 
324  // Produce the slices
325  for (const unsigned int sliceId : usedSliceIds)
326  {
327  // Get the target score
328  const auto targetScoresIter(targetScores.find(sliceId));
329  if (targetScoresIter == targetScores.end())
330  throw cet::exception("LArPandoraExternalEventBuilding") << "Scrambled slice information - can't find target score with id = " << sliceId << std::endl;
331 
332  PFParticleVector targetPFParticleVector, crPFParticleVector;
333 
334  // Get the target hypothesis
335  const auto targetHypothesisIter(targetHypotheses.find(sliceId));
336  targetPFParticleVector = ((targetHypothesisIter == targetHypotheses.end()) ? emptyPFParticleVector : targetHypothesisIter->second);
337 
338  // Get the cosmic hypothesis
339  const auto crHypothesisIter(crHypotheses.find(sliceId));
340  crPFParticleVector = ((crHypothesisIter == crHypotheses.end()) ? emptyPFParticleVector : crHypothesisIter->second);
341  slices.emplace_back(targetScoresIter->second, targetPFParticleVector, crPFParticleVector);
342  }
343 }
344 
345 //------------------------------------------------------------------------------------------------------------------------------------------
346 
348 {
349  const auto &propertiesMap(metadata->GetPropertiesMap());
350  const auto &it(propertiesMap.find(key));
351 
352  if (it == propertiesMap.end())
353  throw cet::exception("LArPandoraExternalEventBuilding") << "No key \"" << key << "\" found in metadata properties map" << std::endl;
354 
355  return it->second;
356 }
357 
358 //------------------------------------------------------------------------------------------------------------------------------------------
359 
360 void LArPandoraExternalEventBuilding::CollectConsolidatedParticles(const PFParticleVector &allParticles, const PFParticleVector &clearCosmics, const SliceVector &slices, PFParticleVector &consolidatedParticles) const
361 {
362  PFParticleVector collectedParticles;
363  collectedParticles.insert(collectedParticles.end(), clearCosmics.begin(), clearCosmics.end());
364 
365  for (const auto &slice : slices)
366  {
367  const PFParticleVector &particles(slice.IsTaggedAsTarget() ? slice.GetTargetHypothesis() : slice.GetCosmicRayHypothesis());
368  collectedParticles.insert(collectedParticles.end(), particles.begin(), particles.end());
369  }
370 
371  // ATTN the collected particles are the ones we want to output, but here we loop over all particles to ensure that the consolidated
372  // particles have the same ordering.
373  for (const auto &part : allParticles)
374  {
375  if (std::find(collectedParticles.begin(), collectedParticles.end(), part) != collectedParticles.end())
376  consolidatedParticles.push_back(part);
377  }
378 }
379 
380 //------------------------------------------------------------------------------------------------------------------------------------------
381 
383 {
384  try
385  {
386  return static_cast<bool>(std::round(this->GetMetadataValue(metadata, m_targetKey)));
387  }
388  catch (const cet::exception &)
389  {
390  return false;
391  }
392 }
393 
394 } // namespace lar_pandora
void CollectSlices(const PFParticleVector &allParticles, const PFParticleToMetadata &particlesToMetadata, const PFParticleMap &particleMap, SliceVector &slices) const
Collect slices.
void CollectPFParticles(const art::Event &evt, PFParticleToMetadata &particlesToMetadata, PFParticleVector &particles) const
Collect PFParticles from the ART event and their mapping to metadata objects.
std::unique_ptr< SliceIdBaseTool > m_sliceIdTool
The slice id tool.
QList< Entry > entry
std::map< art::Ptr< recob::PFParticle >, art::Ptr< larpandoraobj::PFParticleMetadata > > PFParticleToMetadata
LArPandoraEvent class.
std::string string
Definition: nybbler.cc:12
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.h:20
LArPandoraExternalEventBuilding & operator=(LArPandoraExternalEventBuilding const &)=delete
static art::Ptr< recob::PFParticle > GetParentPFParticle(const PFParticleMap &particleMap, const art::Ptr< recob::PFParticle > daughterParticle)
Return the top-level parent particle by navigating up the chain of parent/daughter associations...
std::map< int, art::Ptr< recob::PFParticle > > PFParticleMap
QCollection::Item first()
Definition: qglist.cpp:807
void CollectClearCosmicRays(const PFParticleVector &allParticles, const PFParticleToMetadata &particlesToMetadata, const PFParticleMap &particleMap, PFParticleVector &clearCosmics) const
Collect PFParticles that have been identified as clear cosmic ray muons by pandora.
header for the lar pandora slice ID base tool
std::string m_trackProducerLabel
Label for the track producer using the Pandora instance that produced the collections we want to cons...
std::string m_showerProducerLabel
Label for the shower producer using the Pandora instance that produced the collections we want to con...
bool getByLabel(std::string const &label, std::string const &instance, Handle< PROD > &result) const
Definition: DataViewImpl.h:633
std::string m_hitProducerLabel
Label for the hit producer that was used as input to the Pandora instance specified.
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
A description of all outputs from an instance of pandora with functionality to filter and merge multi...
def key(type, name=None)
Definition: graph.py:13
std::vector< art::Ptr< recob::PFParticle > > PFParticleVector
key_type key() const noexcept
Definition: Ptr.h:216
const PropertiesMap & GetPropertiesMap() const
std::string m_targetKey
The metadata key for a PFParticle to determine if it is the target.
header for the lar pandora slice class
std::string m_scoreKey
The metadata key for the score of the target slice from Pandora.
std::vector< TCSlice > slices
Definition: DataStructs.cxx:12
float GetMetadataValue(const art::Ptr< larpandoraobj::PFParticleMetadata > &metadata, const std::string &key) const
Query a metadata object for a given key and return the corresponding value.
std::vector< Slice > SliceVector
Definition: Slice.h:68
bool m_useTestBeamMode
If we should expect a test-beam (instead of a neutrino) slice.
bool m_shouldProduceT0s
If we should produce T0s (relevant when stitching over multiple drift volumes)
art::InputTag m_pandoraTag
The input tag for the pandora producer.
Class to handle the required producer labels.
std::string m_inputProducerLabel
Label for the Pandora instance that produced the collections we want to consolidated.
void BuildPFParticleMap(const PFParticleToMetadata &particlesToMetadata, PFParticleMap &particleMap) const
Build mapping from ID to PFParticle for fast navigation through the hierarchy.
void CollectConsolidatedParticles(const PFParticleVector &allParticles, const PFParticleVector &clearCosmics, const SliceVector &slices, PFParticleVector &consolidatedParticles) const
Get the consolidated collection of particles based on the slice ids.
bool IsTarget(const art::Ptr< larpandoraobj::PFParticleMetadata > &metadata) const
Query a metadata object to see if it is a target particle.
TCEvent evt
Definition: DataStructs.cxx:7
helper function for LArPandoraInterface producer module
Definition: fwd.h:31
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
QTextStream & endl(QTextStream &s)
void WriteToEvent() const
Write (put) the collections in this LArPandoraEvent to the art::Event.