All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 
13 #include "nusimdata/SimulationBase/MCTruth.h"
14 
15 #include "art/Framework/Principal/Event.h"
16 #include "art/Framework/Principal/Handle.h"
17 #include "canvas/Persistency/Common/FindManyP.h"
18 
19 namespace lar_pandora
20 {
21 
22 void LArPandoraSliceIdHelper::GetSliceMetadata(const SliceVector &slices, const art::Event &evt, const std::string &truthLabel,
23  const std::string &mcParticleLabel, const std::string &hitLabel, const std::string &backtrackLabel, const std::string &pandoraLabel,
24  SliceMetadataVector &sliceMetadata, simb::MCNeutrino &mcNeutrino)
25 {
26  // Find the beam neutrino in MC
27  const auto beamNuMCTruth(LArPandoraSliceIdHelper::GetBeamNeutrinoMCTruth(evt, truthLabel));
28  mcNeutrino = beamNuMCTruth->GetNeutrino();
29 
30  // Collect all MC particles resulting from the beam neutrino
31  MCParticleVector mcParticles;
32  LArPandoraSliceIdHelper::CollectNeutrinoMCParticles(evt, truthLabel, mcParticleLabel, beamNuMCTruth, mcParticles);
33 
34  // Get the hits and determine which are neutrino induced
35  HitVector hits;
36  HitToBoolMap hitToIsNuInducedMap;
37  LArPandoraSliceIdHelper::GetHitOrigins(evt, hitLabel, backtrackLabel, mcParticles, hits, hitToIsNuInducedMap);
38  const unsigned int nNuHits(LArPandoraSliceIdHelper::CountNeutrinoHits(hits, hitToIsNuInducedMap));
39 
40  // Get the mapping from PFParticle to hits through clusters
41  PFParticlesToHits pfParticleToHitsMap;
42  LArPandoraSliceIdHelper::GetPFParticleToHitsMap(evt, pandoraLabel, pfParticleToHitsMap);
43 
44  // Calculate the metadata for each slice
45  LArPandoraSliceIdHelper::GetSliceMetadata(slices, pfParticleToHitsMap, hitToIsNuInducedMap, nNuHits, sliceMetadata);
46 }
47 
48 // -----------------------------------------------------------------------------------------------------------------------------------------
49 
50 art::Ptr<simb::MCTruth> LArPandoraSliceIdHelper::GetBeamNeutrinoMCTruth(const art::Event &evt, const std::string &truthLabel)
51 {
52  // Get the MCTruth handle
53  art::Handle< std::vector<simb::MCTruth> > mcTruthHandle;
54  evt.getByLabel(truthLabel, mcTruthHandle);
55 
56  if (!mcTruthHandle.isValid())
57  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::GetBeamNeutrinoMCTruth - invalid MCTruth handle" << std::endl;
58 
59  // 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
60  bool foundNeutrino(false);
61  float maxNeutrinoEnergy(-std::numeric_limits<float>::max());
62  art::Ptr<simb::MCTruth> beamNuMCTruth;
63  for (unsigned int i = 0; i < mcTruthHandle->size(); ++i)
64  {
65  const art::Ptr<simb::MCTruth> mcTruth(mcTruthHandle, i);
66 
67  if (mcTruth->Origin() != simb::kBeamNeutrino)
68  continue;
69 
70  const float nuEnergy(mcTruth->GetNeutrino().Nu().E());
71  if (nuEnergy < maxNeutrinoEnergy)
72  continue;
73 
74  // Select this as the beam neutrino
75  maxNeutrinoEnergy = nuEnergy;
76  beamNuMCTruth = mcTruth;
77  foundNeutrino = true;
78  }
79 
80  if (!foundNeutrino)
81  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::GetBeamNeutrinoMCTruth - found no beam neutrino MCTruth blocks" << std::endl;
82 
83  return beamNuMCTruth;
84 }
85 
86 // -----------------------------------------------------------------------------------------------------------------------------------------
87 
88 void LArPandoraSliceIdHelper::CollectNeutrinoMCParticles(const art::Event &evt, const std::string &truthLabel,
89  const std::string &mcParticleLabel, const art::Ptr<simb::MCTruth> &beamNuMCTruth, MCParticleVector &mcParticles)
90 {
91  // Get the MCTruth handle
92  art::Handle< std::vector<simb::MCTruth> > mcTruthHandle;
93  evt.getByLabel(truthLabel, mcTruthHandle);
94 
95  if (!mcTruthHandle.isValid())
96  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::CollectNeutrinoMCParticles - invalid MCTruth handle" << std::endl;
97 
98  // Find MCParticles that are associated to the beam neutrino MCTruth block
99  art::FindManyP<simb::MCParticle> truthToMCParticleAssns(mcTruthHandle, evt, mcParticleLabel);
100  mcParticles = truthToMCParticleAssns.at(beamNuMCTruth.key()); // ATTN will throw if association from beamNuMCTruth doesn't exist. We want this!
101 }
102 
103 // -----------------------------------------------------------------------------------------------------------------------------------------
104 
105 void LArPandoraSliceIdHelper::GetHitOrigins(const art::Event &evt, const std::string &hitLabel, const std::string &backtrackLabel,
106  const MCParticleVector &mcParticles, HitVector &hits, HitToBoolMap &hitToIsNuInducedMap)
107 {
108  // Collect the hits from the event
109  art::Handle< std::vector<recob::Hit> > hitHandle;
110  evt.getByLabel(hitLabel, hitHandle);
111 
112  if (!hitHandle.isValid())
113  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::GetHitOrigins - invalid hit handle" << std::endl;
114 
115  art::FindManyP<simb::MCParticle> hitToMCParticleAssns(hitHandle, evt, backtrackLabel);
116 
117  // Find the hits that are associated to a neutrino induced MCParticle using the Hit->MCParticle associations form the backtracker
118  for (unsigned int i = 0; i < hitHandle->size(); ++i)
119  {
120  const art::Ptr<recob::Hit> hit(hitHandle, i);
121  hits.push_back(hit);
122 
123  const auto &particles(hitToMCParticleAssns.at(hit.key()));
124 
125  bool foundNuParticle(false);
126  for (const auto &part : particles)
127  {
128  // If the MCParticles isn't in the list of neutrino particles
129  if (std::find(mcParticles.begin(), mcParticles.end(), part) == mcParticles.end())
130  continue;
131 
132  foundNuParticle = true;
133  break;
134  }
135 
136  if (!hitToIsNuInducedMap.emplace(hit, foundNuParticle).second)
137  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::GetHitOrigins - repeated hits in input collection" << std::endl;
138  }
139 }
140 
141 // -----------------------------------------------------------------------------------------------------------------------------------------
142 
143 unsigned int LArPandoraSliceIdHelper::CountNeutrinoHits(const HitVector &hits, const HitToBoolMap &hitToIsNuInducedMap)
144 {
145  unsigned int nNuHits(0);
146  for (const auto &hit : hits)
147  {
148  const auto it(hitToIsNuInducedMap.find(hit));
149 
150  if (it == hitToIsNuInducedMap.end())
151  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::CountNeutrinoHits - can't find hit in hitToIsNuInducedMap" << std::endl;
152 
153  nNuHits += it->second ? 1 : 0;
154  }
155 
156  return nNuHits;
157 }
158 
159 // -----------------------------------------------------------------------------------------------------------------------------------------
160 
161 void LArPandoraSliceIdHelper::GetPFParticleToHitsMap(const art::Event &evt, const std::string &pandoraLabel, PFParticlesToHits &pfParticleToHitsMap)
162 {
163  // Get the PFParticles
164  art::Handle< std::vector<recob::PFParticle> > pfParticleHandle;
165  evt.getByLabel(pandoraLabel, pfParticleHandle);
166 
167  if (!pfParticleHandle.isValid())
168  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::GetPFParticleToHitsMap - invalid PFParticle handle" << std::endl;
169 
170  // Get the Clusters
171  art::Handle< std::vector<recob::Cluster> > clusterHandle;
172  evt.getByLabel(pandoraLabel, clusterHandle);
173 
174  if (!clusterHandle.isValid())
175  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::GetPFParticleToHitsMap - invalid cluster handle" << std::endl;
176 
177  // Get the associations between PFParticles -> Clusters -> Hits
178  art::FindManyP<recob::Cluster> pfParticleToClusterAssns(pfParticleHandle, evt, pandoraLabel);
179  art::FindManyP<recob::Hit> clusterToHitAssns(clusterHandle, evt, pandoraLabel);
180 
181  // Get the hits associated to each PFParticles
182  for (unsigned int iPart = 0; iPart < pfParticleHandle->size(); ++iPart)
183  {
184  const art::Ptr<recob::PFParticle> part(pfParticleHandle, iPart);
185  HitVector hits;
186 
187  for (const auto &cluster : pfParticleToClusterAssns.at(part.key()))
188  {
189  for (const auto &hit : clusterToHitAssns.at(cluster.key()))
190  {
191  if (std::find(hits.begin(), hits.end(), hit) != hits.end())
192  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::GetPFParticleToHitsMap - double counted hits!" << std::endl;
193 
194  hits.push_back(hit);
195  }
196  }
197 
198  if (!pfParticleToHitsMap.emplace(part, hits).second)
199  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::GetPFParticleToHitsMap - repeated input PFParticles" << std::endl;
200  }
201 }
202 
203 // -----------------------------------------------------------------------------------------------------------------------------------------
204 
205 void LArPandoraSliceIdHelper::GetReconstructedHitsInSlice(const Slice &slice, const PFParticlesToHits &pfParticleToHitsMap, HitVector &hits)
206 {
207  // ATTN here we use the PFParticles from both hypotheses to collect the hits. Hits will not be double counted
208  LArPandoraSliceIdHelper::CollectHits(slice.GetTargetHypothesis(), pfParticleToHitsMap, hits);
209  LArPandoraSliceIdHelper::CollectHits(slice.GetCosmicRayHypothesis(), pfParticleToHitsMap, hits);
210 }
211 
212 // -----------------------------------------------------------------------------------------------------------------------------------------
213 
214 void LArPandoraSliceIdHelper::CollectHits(const PFParticleVector &pfParticles, const PFParticlesToHits &pfParticleToHitsMap, HitVector &hits)
215 {
216  for (const auto &part : pfParticles)
217  {
218  const auto it(pfParticleToHitsMap.find(part));
219  if (it == pfParticleToHitsMap.end())
220  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::CollectHits - can't find any hits associated to input PFParticle" << std::endl;
221 
222  for (const auto &hit : it->second)
223  {
224  // ATTN here we ensure that we don't double count hits, even if the input PFParticles are from different Pandora instances
225  if (std::find(hits.begin(), hits.end(), hit) == hits.end())
226  hits.push_back(hit);
227  }
228  }
229 }
230 
231 // -----------------------------------------------------------------------------------------------------------------------------------------
232 
234  const HitToBoolMap &hitToIsNuInducedMap, const unsigned int nNuHits, SliceMetadataVector &sliceMetadata)
235 {
236  if (!sliceMetadata.empty())
237  throw cet::exception("LArPandora") << " LArPandoraSliceIdHelper::GetSliceMetadata - non empty input metadata vector" << std::endl;
238 
239  if (slices.empty())
240  return;
241 
242  unsigned int mostCompleteSliceIndex(0);
243  unsigned int maxNuHits(0);
244 
245  for (unsigned int sliceIndex = 0; sliceIndex < slices.size(); ++sliceIndex)
246  {
247  const Slice &slice(slices.at(sliceIndex));
248  HitVector hits;
249  LArPandoraSliceIdHelper::GetReconstructedHitsInSlice(slice, pfParticleToHitsMap, hits);
250 
251  const unsigned int nHitsInSlice(hits.size());
252  const unsigned int nNuHitsInSlice(LArPandoraSliceIdHelper::CountNeutrinoHits(hits, hitToIsNuInducedMap));
253 
254  if (nNuHitsInSlice > maxNuHits)
255  {
256  mostCompleteSliceIndex = sliceIndex;
257  maxNuHits = nNuHitsInSlice;
258  }
259 
260  SliceMetadata metadata;
261  metadata.m_nHits = nHitsInSlice;
262  metadata.m_purity = ((nHitsInSlice == 0) ? -1.f : static_cast<float>(nNuHitsInSlice) / static_cast<float>(nHitsInSlice));
263  metadata.m_completeness = ((nNuHits == 0) ? -1.f : static_cast<float>(nNuHitsInSlice) / static_cast<float>(nNuHits));
264  metadata.m_isMostComplete = false;
265 
266  sliceMetadata.push_back(metadata);
267  }
268 
269  sliceMetadata.at(mostCompleteSliceIndex).m_isMostComplete = true;
270 }
271 
272 // -----------------------------------------------------------------------------------------------------------------------------------------
273 // -----------------------------------------------------------------------------------------------------------------------------------------
274 
276  m_purity(-std::numeric_limits<float>::max()),
277  m_completeness(-std::numeric_limits<float>::max()),
278  m_nHits(std::numeric_limits<unsigned int>::max()),
279  m_isMostComplete(false)
280 {
281 }
282 
283 } // namespace lar_pandora
std::unordered_map< art::Ptr< recob::Hit >, bool > HitToBoolMap
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.
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
Definition: UtilFunc.cxx:42
float m_purity
The fraction of hits in the slice that are neutrino induced.
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.
process_name cluster
Definition: cheaterreco.fcl:51
Declaration of signal hit object.
unsigned int m_nHits
The number of hits in the slice.
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
process_name hit
Definition: cheaterreco.fcl:51
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...
float m_completeness
The fraction of all neutrino induced hits that are in the slice.
const PFParticleVector & GetTargetHypothesis() const
Get the slice as reconstructed under the target hypothesis.
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
std::map< art::Ptr< recob::PFParticle >, HitVector > PFParticlesToHits
std::vector< art::Ptr< simb::MCParticle > > MCParticleVector
Declaration of cluster object.
std::vector< TCSlice > slices
Definition: DataStructs.cxx:13
std::vector< art::Ptr< recob::Hit > > HitVector
static art::Ptr< simb::MCTruth > GetBeamNeutrinoMCTruth(const art::Event &evt, const std::string &truthLabel)
Get the MCTruth block for the simulated beam neutrino.
bool m_isMostComplete
If the slice has the highest completeness in the event.
TCEvent evt
Definition: DataStructs.cxx:8