LArPandoraSliceIdHelper.cxx
Go to the documentation of this file.
1 /**
2  * @file larpandora/LArPandoraEventBuilding/LArPandoraSliceIdHelper.cxx
3  *
4  * @brief implementation of the slice id helper class
5  *
6  */
7 
9 
10 #include "cetlib_except/exception.h"
12 #include "canvas/Persistency/Common/FindManyP.h"
13 
16 
20 
21 namespace lar_pandora
22 {
23 
25  const std::string &mcParticleLabel, const std::string &hitLabel, const std::string &backtrackLabel, const std::string &pandoraLabel,
26  SliceMetadataVector &sliceMetadata, simb::MCNeutrino &mcNeutrino)
27 {
28  // Find the beam neutrino in MC
29  const auto beamNuMCTruth(LArPandoraSliceIdHelper::GetBeamNeutrinoMCTruth(evt, truthLabel));
30  mcNeutrino = beamNuMCTruth->GetNeutrino();
31 
32  // Collect all MC particles resulting from the beam neutrino
33  MCParticleVector mcParticles;
34  LArPandoraSliceIdHelper::CollectNeutrinoMCParticles(evt, truthLabel, mcParticleLabel, beamNuMCTruth, mcParticles);
35 
36  // Get the hits and determine which are neutrino induced
37  HitVector hits;
38  HitToBoolMap hitToIsNuInducedMap;
39  LArPandoraSliceIdHelper::GetHitOrigins(evt, hitLabel, backtrackLabel, mcParticles, hits, hitToIsNuInducedMap);
40  const unsigned int nNuHits(LArPandoraSliceIdHelper::CountNeutrinoHits(hits, hitToIsNuInducedMap));
41 
42  // Get the mapping from PFParticle to hits through clusters
43  PFParticlesToHits pfParticleToHitsMap;
44  LArPandoraSliceIdHelper::GetPFParticleToHitsMap(evt, pandoraLabel, pfParticleToHitsMap);
45 
46  // Calculate the metadata for each slice
47  LArPandoraSliceIdHelper::GetSliceMetadata(slices, pfParticleToHitsMap, hitToIsNuInducedMap, nNuHits, sliceMetadata);
48 }
49 
50 // -----------------------------------------------------------------------------------------------------------------------------------------
51 
53 {
54  // Get the MCTruth handle
56  evt.getByLabel(truthLabel, mcTruthHandle);
57 
58  if (!mcTruthHandle.isValid())
59  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::GetBeamNeutrinoMCTruth - invalid MCTruth handle" << std::endl;
60 
61  // Look for the truth block that is from the beam neutrino, and ensure we choose the one with the highest energy if there are multiple
62  bool foundNeutrino(false);
63  float maxNeutrinoEnergy(-std::numeric_limits<float>::max());
64  art::Ptr<simb::MCTruth> beamNuMCTruth;
65  for (unsigned int i = 0; i < mcTruthHandle->size(); ++i)
66  {
67  const art::Ptr<simb::MCTruth> mcTruth(mcTruthHandle, i);
68 
69  if (mcTruth->Origin() != simb::kBeamNeutrino)
70  continue;
71 
72  const float nuEnergy(mcTruth->GetNeutrino().Nu().E());
73  if (nuEnergy < maxNeutrinoEnergy)
74  continue;
75 
76  // Select this as the beam neutrino
77  maxNeutrinoEnergy = nuEnergy;
78  beamNuMCTruth = mcTruth;
79  foundNeutrino = true;
80  }
81 
82  if (!foundNeutrino)
83  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::GetBeamNeutrinoMCTruth - found no beam neutrino MCTruth blocks" << std::endl;
84 
85  return beamNuMCTruth;
86 }
87 
88 // -----------------------------------------------------------------------------------------------------------------------------------------
89 
91  const std::string &mcParticleLabel, const art::Ptr<simb::MCTruth> &beamNuMCTruth, MCParticleVector &mcParticles)
92 {
93  // Get the MCTruth handle
95  evt.getByLabel(truthLabel, mcTruthHandle);
96 
97  if (!mcTruthHandle.isValid())
98  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::CollectNeutrinoMCParticles - invalid MCTruth handle" << std::endl;
99 
100  // Find MCParticles that are associated to the beam neutrino MCTruth block
101  art::FindManyP<simb::MCParticle> truthToMCParticleAssns(mcTruthHandle, evt, mcParticleLabel);
102  mcParticles = truthToMCParticleAssns.at(beamNuMCTruth.key()); // ATTN will throw if association from beamNuMCTruth doesn't exist. We want this!
103 }
104 
105 // -----------------------------------------------------------------------------------------------------------------------------------------
106 
107 void LArPandoraSliceIdHelper::GetHitOrigins(const art::Event &evt, const std::string &hitLabel, const std::string &backtrackLabel,
108  const MCParticleVector &mcParticles, HitVector &hits, HitToBoolMap &hitToIsNuInducedMap)
109 {
110  // Collect the hits from the event
112  evt.getByLabel(hitLabel, hitHandle);
113 
114  if (!hitHandle.isValid())
115  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::GetHitOrigins - invalid hit handle" << std::endl;
116 
117  art::FindManyP<simb::MCParticle> hitToMCParticleAssns(hitHandle, evt, backtrackLabel);
118 
119  // Find the hits that are associated to a neutrino induced MCParticle using the Hit->MCParticle associations form the backtracker
120  for (unsigned int i = 0; i < hitHandle->size(); ++i)
121  {
122  const art::Ptr<recob::Hit> hit(hitHandle, i);
123  hits.push_back(hit);
124 
125  const auto &particles(hitToMCParticleAssns.at(hit.key()));
126 
127  bool foundNuParticle(false);
128  for (const auto &part : particles)
129  {
130  // If the MCParticles isn't in the list of neutrino particles
131  if (std::find(mcParticles.begin(), mcParticles.end(), part) == mcParticles.end())
132  continue;
133 
134  foundNuParticle = true;
135  break;
136  }
137 
138  if (!hitToIsNuInducedMap.emplace(hit, foundNuParticle).second)
139  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::GetHitOrigins - repeated hits in input collection" << std::endl;
140  }
141 }
142 
143 // -----------------------------------------------------------------------------------------------------------------------------------------
144 
145 unsigned int LArPandoraSliceIdHelper::CountNeutrinoHits(const HitVector &hits, const HitToBoolMap &hitToIsNuInducedMap)
146 {
147  unsigned int nNuHits(0);
148  for (const auto &hit : hits)
149  {
150  const auto it(hitToIsNuInducedMap.find(hit));
151 
152  if (it == hitToIsNuInducedMap.end())
153  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::CountNeutrinoHits - can't find hit in hitToIsNuInducedMap" << std::endl;
154 
155  nNuHits += it->second ? 1 : 0;
156  }
157 
158  return nNuHits;
159 }
160 
161 // -----------------------------------------------------------------------------------------------------------------------------------------
162 
163 void LArPandoraSliceIdHelper::GetPFParticleToHitsMap(const art::Event &evt, const std::string &pandoraLabel, PFParticlesToHits &pfParticleToHitsMap)
164 {
165  // Get the PFParticles
167  evt.getByLabel(pandoraLabel, pfParticleHandle);
168 
169  if (!pfParticleHandle.isValid())
170  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::GetPFParticleToHitsMap - invalid PFParticle handle" << std::endl;
171 
172  // Get the Clusters
174  evt.getByLabel(pandoraLabel, clusterHandle);
175 
176  if (!clusterHandle.isValid())
177  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::GetPFParticleToHitsMap - invalid cluster handle" << std::endl;
178 
179  // Get the associations between PFParticles -> Clusters -> Hits
180  art::FindManyP<recob::Cluster> pfParticleToClusterAssns(pfParticleHandle, evt, pandoraLabel);
181  art::FindManyP<recob::Hit> clusterToHitAssns(clusterHandle, evt, pandoraLabel);
182 
183  // Get the hits associated to each PFParticles
184  for (unsigned int iPart = 0; iPart < pfParticleHandle->size(); ++iPart)
185  {
186  const art::Ptr<recob::PFParticle> part(pfParticleHandle, iPart);
187  HitVector hits;
188 
189  for (const auto &cluster : pfParticleToClusterAssns.at(part.key()))
190  {
191  for (const auto &hit : clusterToHitAssns.at(cluster.key()))
192  {
193  if (std::find(hits.begin(), hits.end(), hit) != hits.end())
194  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::GetPFParticleToHitsMap - double counted hits!" << std::endl;
195 
196  hits.push_back(hit);
197  }
198  }
199 
200  if (!pfParticleToHitsMap.emplace(part, hits).second)
201  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::GetPFParticleToHitsMap - repeated input PFParticles" << std::endl;
202  }
203 }
204 
205 // -----------------------------------------------------------------------------------------------------------------------------------------
206 
207 void LArPandoraSliceIdHelper::GetReconstructedHitsInSlice(const Slice &slice, const PFParticlesToHits &pfParticleToHitsMap, HitVector &hits)
208 {
209  // ATTN here we use the PFParticles from both hypotheses to collect the hits. Hits will not be double counted
210  LArPandoraSliceIdHelper::CollectHits(slice.GetTargetHypothesis(), pfParticleToHitsMap, hits);
211  LArPandoraSliceIdHelper::CollectHits(slice.GetCosmicRayHypothesis(), pfParticleToHitsMap, hits);
212 }
213 
214 // -----------------------------------------------------------------------------------------------------------------------------------------
215 
216 void LArPandoraSliceIdHelper::CollectHits(const PFParticleVector &pfParticles, const PFParticlesToHits &pfParticleToHitsMap, HitVector &hits)
217 {
218  for (const auto &part : pfParticles)
219  {
220  const auto it(pfParticleToHitsMap.find(part));
221  if (it == pfParticleToHitsMap.end())
222  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::CollectHits - can't find any hits associated to input PFParticle" << std::endl;
223 
224  for (const auto &hit : it->second)
225  {
226  // ATTN here we ensure that we don't double count hits, even if the input PFParticles are from different Pandora instances
227  if (std::find(hits.begin(), hits.end(), hit) == hits.end())
228  hits.push_back(hit);
229  }
230  }
231 }
232 
233 // -----------------------------------------------------------------------------------------------------------------------------------------
234 
236  const HitToBoolMap &hitToIsNuInducedMap, const unsigned int nNuHits, SliceMetadataVector &sliceMetadata)
237 {
238  if (!sliceMetadata.empty())
239  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::GetSliceMetadata - non empty input metadata vector" << std::endl;
240 
241  if (slices.empty())
242  return;
243 
244  unsigned int mostCompleteSliceIndex(0);
245  unsigned int maxNuHits(0);
246 
247  for (unsigned int sliceIndex = 0; sliceIndex < slices.size(); ++sliceIndex)
248  {
249  const Slice &slice(slices.at(sliceIndex));
250  HitVector hits;
251  LArPandoraSliceIdHelper::GetReconstructedHitsInSlice(slice, pfParticleToHitsMap, hits);
252 
253  const unsigned int nHitsInSlice(hits.size());
254  const unsigned int nNuHitsInSlice(LArPandoraSliceIdHelper::CountNeutrinoHits(hits, hitToIsNuInducedMap));
255 
256  if (nNuHitsInSlice > maxNuHits)
257  {
258  mostCompleteSliceIndex = sliceIndex;
259  maxNuHits = nNuHitsInSlice;
260  }
261 
263  metadata.m_nHits = nHitsInSlice;
264  metadata.m_purity = ((nHitsInSlice == 0) ? -1.f : static_cast<float>(nNuHitsInSlice) / static_cast<float>(nHitsInSlice));
265  metadata.m_completeness = ((nNuHits == 0) ? -1.f : static_cast<float>(nNuHitsInSlice) / static_cast<float>(nNuHits));
266  metadata.m_isMostComplete = false;
267 
268  sliceMetadata.push_back(metadata);
269  }
270 
271  sliceMetadata.at(mostCompleteSliceIndex).m_isMostComplete = true;
272 }
273 
274 // -----------------------------------------------------------------------------------------------------------------------------------------
275 // -----------------------------------------------------------------------------------------------------------------------------------------
276 
278  m_purity(-std::numeric_limits<float>::max()),
279  m_completeness(-std::numeric_limits<float>::max()),
280  m_nHits(std::numeric_limits<unsigned int>::max()),
281  m_isMostComplete(false)
282 {
283 }
284 
285 } // namespace lar_pandora
double E(const int i=0) const
Definition: MCParticle.h:233
std::unordered_map< art::Ptr< recob::Hit >, bool > HitToBoolMap
Slice class.
Definition: Slice.h:18
static unsigned int CountNeutrinoHits(const HitVector &hits, const HitToBoolMap &hitToIsNuInducedMap)
Count the number of hits in an input vector that are neutrino induced.
static void CollectNeutrinoMCParticles(const art::Event &evt, const std::string &truthLabel, const std::string &mcParticleLabel, const art::Ptr< simb::MCTruth > &beamNuMCTruth, MCParticleVector &mcParticles)
Collect all MCParticles that come from the beam neutrino interaction.
float m_purity
The fraction of hits in the slice that are neutrino induced.
const simb::MCNeutrino & GetNeutrino() const
Definition: MCTruth.h:77
static void CollectHits(const PFParticleVector &pfParticles, const PFParticlesToHits &pfParticleToHitsMap, HitVector &hits)
Collect the hits in a given vector of PFParticles.
const PFParticleVector & GetCosmicRayHypothesis() const
Get the slice as reconstructed under the cosmic-ray hypothesis.
Definition: Slice.h:96
std::string string
Definition: nybbler.cc:12
const simb::MCParticle & Nu() const
Definition: MCNeutrino.h:146
simb::Origin_t Origin() const
Definition: MCTruth.h:74
unsigned int m_nHits
The number of hits in the slice.
STL namespace.
static void GetPFParticleToHitsMap(const art::Event &evt, const std::string &pandoraLabel, PFParticlesToHits &pfParticleToHitsMap)
Get the mapping from PFParticles to associated hits (via clusters)
static void GetHitOrigins(const art::Event &evt, const std::string &hitLabel, const std::string &backtrackLabel, const MCParticleVector &mcParticles, HitVector &hits, HitToBoolMap &hitToIsNuInducedMap)
For each hit in the event, determine if any of it&#39;s charge was deposited by a neutrino induced partic...
std::vector< SliceMetadata > SliceMetadataVector
Cluster finding and building.
Particle class.
helper class for slice id tools
static void GetReconstructedHitsInSlice(const Slice &slice, const PFParticlesToHits &pfParticleToHitsMap, HitVector &hits)
Collect the hits in the slice that have been added to a PFParticle (under either reconstruction hypot...
bool isValid() const noexcept
Definition: Handle.h:191
float m_completeness
The fraction of all neutrino induced hits that are in the slice.
bool getByLabel(std::string const &label, std::string const &instance, Handle< PROD > &result) const
Definition: DataViewImpl.h:633
const PFParticleVector & GetTargetHypothesis() const
Get the slice as reconstructed under the target hypothesis.
Definition: Slice.h:89
static void GetSliceMetadata(const SliceVector &slices, const art::Event &evt, const std::string &truthLabel, const std::string &mcParticleLabel, const std::string &hitLabel, const std::string &backtrackLabel, const std::string &pandoraLabel, SliceMetadataVector &sliceMetadata, simb::MCNeutrino &mcNeutrino)
Get MC metadata about each slice.
std::vector< art::Ptr< recob::PFParticle > > PFParticleVector
key_type key() const noexcept
Definition: Ptr.h:216
std::map< art::Ptr< recob::PFParticle >, HitVector > PFParticlesToHits
std::vector< art::Ptr< simb::MCParticle > > MCParticleVector
static int max(int a, int b)
std::vector< TCSlice > slices
Definition: DataStructs.cxx:12
Detector simulation of raw signals on wires.
std::vector< art::Ptr< recob::Hit > > HitVector
Declaration of signal hit object.
static art::Ptr< simb::MCTruth > GetBeamNeutrinoMCTruth(const art::Event &evt, const std::string &truthLabel)
Get the MCTruth block for the simulated beam neutrino.
std::vector< Slice > SliceVector
Definition: Slice.h:68
bool m_isMostComplete
If the slice has the highest completeness in the event.
TCEvent evt
Definition: DataStructs.cxx:7
Event generator information.
Definition: MCNeutrino.h:18
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
QTextStream & endl(QTextStream &s)
Beam neutrinos.
Definition: MCTruth.h:23