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