19 #include "art/Framework/Core/EDAnalyzer.h"
20 #include "art/Framework/Core/ModuleMacros.h"
21 #include "art/Framework/Principal/Event.h"
22 #include "art/Framework/Principal/Handle.h"
23 #include "art/Framework/Principal/Run.h"
24 #include "art/Framework/Principal/SubRun.h"
25 #include "art/Framework/Services/Registry/ServiceHandle.h"
26 #include "canvas/Utilities/InputTag.h"
27 #include "fhiclcpp/ParameterSet.h"
28 #include "messagefacility/MessageLogger/MessageLogger.h"
30 #include "canvas/Persistency/Common/FindManyP.h"
42 class ClusterTrackAna;
55 void analyze(art::Event
const&
e)
override;
74 std::array<float, 5>
Cnts{{0}};
77 std::array<float, 5>
ESums{{0}};
79 std::array<float, 5>
PSums{{0}};
92 unsigned int& firstHitIndex,
93 unsigned int& lastHitIndex);
100 fHitModuleLabel = pset.get<art::InputTag>(
"HitModuleLabel");
101 bool validModuleLabel =
false;
102 fClusterModuleLabel =
"NA";
103 fTrackModuleLabel =
"NA";
104 fClusterModuleLabel = pset.get<art::InputTag>(
"ClusterModuleLabel",
"NA");
105 if (fClusterModuleLabel !=
"NA") validModuleLabel =
true;
106 fTrackModuleLabel = pset.get<art::InputTag>(
"TrackModuleLabel",
"NA");
107 if (validModuleLabel && fTrackModuleLabel !=
"NA")
108 throw cet::exception(
"ClusterTrackAna")
109 <<
"You must specify either a ClusterModuleLabel OR a TrackModuleLabel\n";
110 if (!validModuleLabel && fTrackModuleLabel !=
"NA") validModuleLabel =
true;
112 int tmp = pset.get<
int>(
"TruthOrigin", 0);
113 fTruthOrigin = (simb::Origin_t)tmp;
114 fPrintLevel = pset.get<
short>(
"PrintLevel", 0);
115 if (pset.has_key(
"SkipPDGCodes")) fSkipPDGCodes = pset.get<std::vector<int>>(
"SkipPDGCodes");
116 fBadEP = pset.get<
float>(
"BadEP", 0.);
118 int intpc = pset.get<
int>(
"InTPC", -1);
119 if (intpc >= 0) fInTPC = intpc;
135 auto const* geom = lar::providerFrom<geo::Geometry>();
137 if (!evt.getByLabel(fHitModuleLabel, fHitHandle))
138 throw cet::exception(
"ClusterTrackAna")
139 <<
"Failed to get a handle to hit collection '" << fHitModuleLabel.label() <<
"'\n";
141 auto mcpHandle = art::Handle<std::vector<simb::MCParticle>>();
142 if (!evt.getByLabel(
"largeant", mcpHandle))
143 throw cet::exception(
"ClusterTrackAna")
144 <<
"Failed to get a handle to MCParticles using largeant\n";
148 bool anySource = (fTruthOrigin == simb::kUnknown);
150 if (fPrintLevel > 0 && evt.run() != fCurrentRun) {
151 mf::LogVerbatim(
"ClusterTrackAna") <<
"Run: " << evt.run();
152 fCurrentRun = evt.run();
155 art::ServiceHandle<cheat::BackTrackerService const> bt_serv;
156 art::ServiceHandle<cheat::ParticleInventoryService const> pi_serv;
157 sim::ParticleList
const& plist = pi_serv->ParticleList();
158 auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
162 std::vector<int> trkIDs;
164 std::vector<unsigned int> MCPIs;
165 for (sim::ParticleList::const_iterator ipart = plist.begin(); ipart != plist.end(); ++ipart) {
166 const simb::MCParticle* part = (*ipart).second;
167 int trackID = part->TrackId();
168 art::Ptr<simb::MCTruth> theTruth = pi_serv->TrackIdToMCTruth_P(trackID);
169 if (!anySource && theTruth->Origin() != fTruthOrigin)
continue;
170 int pdg =
abs(part->PdgCode());
171 bool isCharged = (pdg == 11) || (pdg == 13) || (pdg == 211) || (pdg == 321) || (pdg == 2212);
172 if (!isCharged)
continue;
173 if (std::find(fSkipPDGCodes.begin(), fSkipPDGCodes.end(),
pdg) != fSkipPDGCodes.end())
continue;
174 float TMeV = 1000 * (part->E() - part->Mass());
176 if (TMeV < 1)
continue;
178 unsigned int mcpi = UINT_MAX;
179 for (mcpi = 0; mcpi < (*mcpHandle).size(); ++mcpi)
180 if ((*mcpHandle)[mcpi].TrackId() == trackID)
break;
181 if (mcpi == UINT_MAX) {
182 std::cout <<
"Failed to find a MCParticle from ParticleList\n";
185 trkIDs.push_back(trackID);
186 MCPIs.push_back(mcpi);
188 if (trkIDs.empty())
return;
191 fHitMCPIndex.resize((*fHitHandle).size(), UINT_MAX);
194 std::vector<std::pair<unsigned int, unsigned int>> hitRange(geom->NTPC() + 1);
198 for (
auto& hr : hitRange)
199 hr = std::make_pair(UINT_MAX, UINT_MAX);
200 for (
size_t iht = 0; iht < (*fHitHandle).size(); ++iht) {
201 auto&
hit = (*fHitHandle)[iht];
203 unsigned int tpc =
hit.WireID().TPC;
204 if (fInTPC != UINT_MAX && tpc != fInTPC)
continue;
206 auto tides = bt_serv->HitToTrackIDEs(clockData,
hit);
211 for (
auto& tide : tides) {
213 if (tide.energyFrac < 0.5)
continue;
214 int trackID = tide.trackID;
216 for (
size_t indx = 0; indx < trkIDs.size(); ++indx) {
217 if (trkIDs[indx] == trackID) {
218 fHitMCPIndex[iht] = MCPIs[indx];
224 if (fHitMCPIndex[iht] == UINT_MAX)
continue;
227 if (hitRange[tpc].
first == UINT_MAX) hitRange[tpc].first = iht;
228 hitRange[tpc].second = iht;
232 fHitMCPIndex.resize(0);
236 if (fPrintLevel > 3) {
238 mf::LogVerbatim myprt(
"ClusterTrackAna");
239 myprt <<
"Checking " << trkIDs.size() <<
" selected MCParticles with the requested TruthOrigin";
240 if (fInTPC == UINT_MAX) { myprt <<
" in all TPCs\n"; }
242 myprt <<
" in TPC " << fInTPC;
244 myprt <<
" in Run " << evt.run() <<
" Event " << evt.event();
246 myprt <<
"Found " << nMatch <<
" MC-matched hits with the requested TruthOrigin";
247 myprt <<
" out of " << nInTPC <<
" total hits.\n";
248 myprt <<
"Found " << noMatch <<
" hits not matched to ANY MCParticle.\n";
251 std::vector<std::pair<unsigned int, unsigned int>> mcpCnt;
252 for (
auto mcpi : fHitMCPIndex) {
253 if (mcpi == UINT_MAX)
continue;
254 unsigned short mIndx = 0;
255 for (mIndx = 0; mIndx < mcpCnt.size(); ++mIndx)
256 if (mcpCnt[mIndx].
first == mcpi)
break;
257 if (mIndx == mcpCnt.size()) mcpCnt.push_back(std::make_pair(mcpi, 0));
259 ++mcpCnt[mIndx].second;
261 myprt <<
" MCPI TrackID PDGCode T(MeV) nHits Process";
262 for (
auto mcpcnt : mcpCnt) {
264 unsigned int mcpi = mcpcnt.first;
265 auto& mcp = (*mcpHandle)[mcpi];
266 myprt << std::setw(5) << mcpi;
267 myprt << std::setw(8) << mcp.TrackId();
268 myprt << std::setw(8) <<
abs(mcp.PdgCode());
269 int TMeV = 1000 * (mcp.E() - mcp.Mass());
270 myprt << std::setw(9) << TMeV;
271 myprt << std::setw(8) << mcpcnt.second;
272 myprt <<
" " << mcp.Process();
277 std::vector<std::vector<unsigned int>> recoHits;
279 std::vector<unsigned int> recoIndex;
282 art::Handle<std::vector<recob::Cluster>> inputClusters;
283 art::Handle<std::vector<recob::Track>> inputTracks;
284 if (fClusterModuleLabel.label() !=
"NA") {
286 if (!evt.getByLabel(fClusterModuleLabel, inputClusters))
287 throw cet::exception(
"ClusterTrackAna")
288 <<
"Failed to get a handle to the cluster collection '" << fClusterModuleLabel.label()
290 art::FindManyP<recob::Hit> hitsFromCls(inputClusters, evt, fClusterModuleLabel);
291 if (!hitsFromCls.isValid())
292 throw cet::exception(
"ClusterTrackAna") <<
"Failed to get a handle to Cluster -> Hit assns\n";
293 for (
unsigned int icl = 0; icl < (*inputClusters).size(); ++icl) {
294 std::vector<art::Ptr<recob::Hit>> cluhits = hitsFromCls.at(icl);
295 if (cluhits.empty())
continue;
296 if (fCompareProductIDs) {
297 if (cluhits[0].
id() != fHitHandle.id())
298 throw cet::exception(
"ClusterTrackAna")
299 <<
"Hits associated with ClusterModuleLabel are in a different collection than "
301 fCompareProductIDs =
false;
306 std::vector<unsigned int> hitsIndex;
307 for (
auto& cluhit : cluhits) {
308 if (fHitMCPIndex[cluhit.key()] != UINT_MAX) hitsIndex.push_back(cluhit.key());
310 if (hitsIndex.empty())
continue;
311 recoIndex.push_back(icl);
312 recoHits.push_back(hitsIndex);
317 if (!evt.getByLabel(fTrackModuleLabel, inputTracks))
318 throw cet::exception(
"ClusterTrackAna")
319 <<
"Failed to get a handle to the track collection '" << fTrackModuleLabel.label() <<
"'\n";
320 art::FindManyP<recob::Hit> hitsFromTrk(inputTracks, evt, fTrackModuleLabel);
321 if (!hitsFromTrk.isValid())
322 throw cet::exception(
"ClusterTrackAna") <<
"Failed to get a handle to Track -> Hit assns\n";
323 for (
unsigned int itk = 0; itk < (*inputTracks).size(); ++itk) {
324 std::vector<art::Ptr<recob::Hit>> trkhits = hitsFromTrk.at(itk);
325 if (trkhits.empty())
continue;
326 if (fCompareProductIDs) {
327 if (trkhits[0].
id() != fHitHandle.id())
328 throw cet::exception(
"ClusterTrackAna")
329 <<
"Hits associated with TrackModuleLabel are in a different collection than "
331 fCompareProductIDs =
false;
333 std::vector<unsigned int> hitsIndex;
334 for (
auto& trkhit : trkhits) {
335 if (fHitMCPIndex[trkhit.key()] != UINT_MAX) hitsIndex.push_back(trkhit.key());
337 if (hitsIndex.empty())
continue;
338 recoIndex.push_back(itk);
339 recoHits.push_back(hitsIndex);
343 for (
const auto& tpcid : geom->IterateTPCIDs()) {
344 unsigned int tpc = tpcid.TPC;
345 if (hitRange[tpc].
first == UINT_MAX)
continue;
347 for (
unsigned short plane = 0; plane < geom->Nplanes(); ++plane) {
348 unsigned int tpcMatHitCnt = 0;
349 unsigned int tpcTotHitCnt = 0;
352 std::vector<std::pair<unsigned int, float>> mcpCnt;
354 std::vector<std::vector<std::pair<unsigned int, float>>> mcpClsCnt;
355 for (
unsigned int iht = hitRange[tpc].
first; iht <= hitRange[tpc].second; ++iht) {
356 auto&
hit = (*fHitHandle)[iht];
357 if (
hit.WireID().TPC != tpc)
continue;
358 if (
hit.WireID().Plane != plane)
continue;
362 if (fHitMCPIndex[iht] == UINT_MAX)
continue;
364 unsigned int mcpi = fHitMCPIndex[iht];
365 unsigned short mIndx = 0;
366 for (mIndx = 0; mIndx < mcpCnt.size(); ++mIndx)
367 if (mcpCnt[mIndx].
first == mcpi)
break;
368 if (mIndx == mcpCnt.size()) {
370 mcpCnt.push_back(std::make_pair(mcpi, 0));
371 mcpClsCnt.resize(mcpCnt.size());
374 ++mcpCnt[mIndx].second;
377 if (fPrintLevel > 2) {
378 mf::LogVerbatim myprt(
"ClusterTrackAna");
379 myprt <<
"TPC:" << tpc <<
" Plane:" << plane <<
" has " << tpcMatHitCnt <<
"/"
381 myprt <<
" (MC-matched hits) / (all hits)";
383 if (tpcMatHitCnt < 3)
continue;
385 for (
unsigned int ii = 0; ii < recoHits.size(); ++ii) {
386 float nRecoHitsInPlane = 0;
387 float nRecoMatHitsInPlane = 0;
388 for (
auto iht : recoHits[ii]) {
389 auto&
hit = (*fHitHandle)[iht];
390 if (
hit.WireID().TPC != tpc)
continue;
391 if (
hit.WireID().Plane != plane)
continue;
393 if (fHitMCPIndex[iht] == UINT_MAX)
continue;
394 ++nRecoMatHitsInPlane;
395 unsigned int mcpi = fHitMCPIndex[iht];
398 unsigned short mIndx = 0;
399 for (mIndx = 0; mIndx < mcpCnt.size(); ++mIndx)
400 if (mcpCnt[mIndx].
first == mcpi)
break;
401 if (mIndx == mcpCnt.size()) {
402 std::cout <<
"Logic error: fHitMCPIndex = " << fHitMCPIndex[iht]
403 <<
" is valid but isn't in the list of MCParticles to use. Please send email "
404 "to baller@fnal.gov.\n";
407 unsigned short cIndx = 0;
408 for (cIndx = 0; cIndx < mcpClsCnt[mIndx].size(); ++cIndx)
409 if (mcpClsCnt[mIndx][cIndx].
first == ii)
break;
410 if (cIndx == mcpClsCnt[mIndx].
size()) mcpClsCnt[mIndx].push_back(std::make_pair(ii, 0));
411 ++mcpClsCnt[mIndx][cIndx].second;
413 if (nRecoMatHitsInPlane == 0)
continue;
416 for (
unsigned short mIndx = 0; mIndx < mcpCnt.size(); ++mIndx) {
418 if (mcpCnt[mIndx].
second < 3)
continue;
419 unsigned int mcpi = mcpCnt[mIndx].first;
420 auto& mcp = (*mcpHandle)[mcpi];
421 unsigned int pdgCode =
abs(mcp.PdgCode());
422 unsigned short pIndx = USHRT_MAX;
423 if (pdgCode == 11) pIndx = 0;
424 if (pdgCode == 13) pIndx = 1;
425 if (pdgCode == 211) pIndx = 2;
426 if (pdgCode == 321) pIndx = 3;
427 if (pdgCode == 2212) pIndx = 4;
428 if (mcpClsCnt[mIndx].
empty()) {
432 if (fPrintLevel > 0) {
433 mf::LogVerbatim myprt(
"ClusterTrackAna");
434 myprt <<
" MCPI " << mcpi;
435 int TMeV = 1000 * (mcp.E() - mcp.Mass());
436 myprt <<
" " << TMeV <<
" MeV";
438 if (pdgCode == 11) partName =
"El";
439 if (pdgCode == 13) partName =
"Mu";
440 if (pdgCode == 211) partName =
"Pi";
441 if (pdgCode == 311) partName =
"Ka";
442 if (pdgCode == 2212) partName =
"Pr";
443 myprt << std::setw(5) << partName;
445 unsigned int firstHitIndex = UINT_MAX;
446 unsigned int lastHitIndex = UINT_MAX;
447 FirstLastHitInPlane(tpc, plane, mcpi, firstHitIndex, lastHitIndex);
448 myprt <<
" Failed to reconstruct. Truth-matched hit range from ";
449 myprt << HitLocation(firstHitIndex);
451 myprt << HitLocation(lastHitIndex);
452 myprt <<
" <- EP = 0!";
456 std::pair<unsigned int, float> big = std::make_pair(UINT_MAX, 0);
457 for (
unsigned short cIndx = 0; cIndx < mcpClsCnt[mIndx].size(); ++cIndx) {
458 auto& mcc = mcpClsCnt[mIndx][cIndx];
459 if (mcc.second > big.second) big = mcc;
461 if (big.first == UINT_MAX) {
462 if (fPrintLevel > 2) {
463 mf::LogVerbatim myprt(
"ClusterTrackAna");
464 unsigned int mcpi = mcpCnt[mIndx].first;
465 auto& mcp = (*mcpHandle)[mcpi];
466 myprt <<
"Match failed: mcpi " << mcpi <<
" pdg " << mcp.PdgCode();
468 std::cout <<
"match failed mIndx " << mIndx <<
"\n";
471 unsigned int ii = big.first;
472 float eff = big.second / mcpCnt[mIndx].second;
473 float nRecoHitsInPlane = 0;
475 unsigned int firstRecoHitIndex = UINT_MAX;
476 unsigned int lastRecoHitIndex = UINT_MAX;
477 for (
auto iht : recoHits[ii]) {
478 auto&
hit = (*fHitHandle)[iht];
479 if (
hit.WireID().TPC != tpc)
continue;
480 if (
hit.WireID().Plane != plane)
continue;
482 if (firstRecoHitIndex == UINT_MAX) {
483 firstRecoHitIndex = iht;
484 lastRecoHitIndex = iht;
486 unsigned int wire = (*fHitHandle)[iht].WireID().Wire;
487 if (wire < (*fHitHandle)[firstRecoHitIndex].
WireID().Wire) firstRecoHitIndex = iht;
488 if (wire > (*fHitHandle)[lastRecoHitIndex].
WireID().Wire) lastRecoHitIndex = iht;
490 float pur = big.second / nRecoHitsInPlane;
492 float ep = eff * pur;
496 bool hasBadEP = (ep < fBadEP);
497 if (hasBadEP) ++fNBadEP;
498 bool prt = fPrintLevel > 1 || (fPrintLevel == 1 && hasBadEP);
500 mf::LogVerbatim myprt(
"ClusterTrackAna");
502 myprt <<
"Hit location format is TPC:Plane:Wire:Tick\n";
503 myprt <<
" MCPI Ptcl T(MeV) nMCPHits ____From____ _____To_____";
504 if (inputClusters.isValid()) { myprt <<
" clsID"; }
509 <<
" ____From____ _____To_____ nRecoHits nMCPRecoHits Eff Pur EP\n";
512 myprt << std::setw(5) << mcpi;
515 if (pdgCode == 11) partName =
" Electron";
516 if (pdgCode == 13) partName =
" Muon";
517 if (pdgCode == 211) partName =
" Pion";
518 if (pdgCode == 311) partName =
" Kaon";
519 if (pdgCode == 2212) partName =
" Proton";
521 int TMeV = 1000 * (mcp.E() - mcp.Mass());
522 myprt << std::setw(7) << TMeV;
524 myprt << std::setw(10) << mcpCnt[mIndx].second;
525 unsigned int firstTruHitIndex = UINT_MAX;
526 unsigned int lastTruHitIndex = UINT_MAX;
527 FirstLastHitInPlane(tpc, plane, mcpi, firstTruHitIndex, lastTruHitIndex);
528 myprt << std::setw(14) << HitLocation(firstTruHitIndex);
529 myprt << std::setw(14) << HitLocation(lastTruHitIndex);
531 if (inputClusters.isValid()) {
533 auto& cls = (*inputClusters)[recoIndex[ii]];
536 else if (inputTracks.isValid()) {
538 auto& trk = (*inputTracks)[recoIndex[ii]];
541 myprt << std::setw(6) << id;
542 myprt << std::setw(14) << HitLocation(firstRecoHitIndex);
543 myprt << std::setw(14) << HitLocation(lastRecoHitIndex);
544 myprt << std::setw(12) << (int)nRecoHitsInPlane;
545 myprt << std::setw(13) << (int)big.second;
546 myprt << std::fixed << std::setprecision(2);
547 myprt << std::setw(8) << eff;
548 myprt << std::setw(8) << pur;
549 myprt << std::setw(8) << ep;
550 if (hasBadEP) myprt <<
" <- BadEP";
551 myprt <<
" Evt: " << evt.event();
552 myprt <<
" Evt Cnt " << fEventCnt;
558 fHitMCPIndex.resize(0);
567 if (iht >= (*fHitHandle).size())
return "NA";
568 auto&
hit = (*fHitHandle)[iht];
578 unsigned int& firstHitIndex,
579 unsigned int& lastHitIndex)
583 firstHitIndex = UINT_MAX;
584 lastHitIndex = UINT_MAX;
585 for (
unsigned int iht = 0; iht < (*fHitHandle).size(); ++iht) {
586 if (fHitMCPIndex[iht] != mcpi)
continue;
587 auto&
hit = (*fHitHandle)[iht];
588 if (
hit.WireID().TPC != tpc)
continue;
589 if (
hit.WireID().Plane != plane)
continue;
590 if (firstHitIndex == UINT_MAX) {
594 unsigned int wire = (*fHitHandle)[iht].WireID().Wire;
595 if (wire < (*fHitHandle)[firstHitIndex].
WireID().Wire) firstHitIndex = iht;
596 if (wire > (*fHitHandle)[lastHitIndex].
WireID().Wire) lastHitIndex = iht;
605 mf::LogVerbatim myprt(
"ClusterTrackAna");
606 myprt <<
"ClusterTrackAna summary results for " << fEventCnt;
607 if (fClusterModuleLabel.label() !=
"NA") {
608 myprt <<
" events using ClusterModuleLabel: " << fClusterModuleLabel.label();
611 myprt <<
" events using TrackModuleLabel: " << fTrackModuleLabel.label();
613 myprt <<
" Origin: " << fTruthOrigin;
614 if (fInTPC != UINT_MAX) { myprt <<
" in TPC " << fInTPC; }
616 myprt <<
" in all TPCs";
620 for (
unsigned short pIndx = 0; pIndx < 5; ++pIndx)
623 myprt <<
"No ClusterTrackAna results";
629 myprt <<
"Efficiency (Eff), Purity (Pur) and Eff * Pur (EP) by selected truth particle types\n";
630 std::array<std::string, 5> pName = {{
"El",
"Mu",
"Pi",
"K ",
"P "}};
631 myprt <<
"particle Eff Pur EP\n";
632 myprt <<
"-------------------------------";
633 for (
unsigned short pIndx = 0; pIndx < 5; ++pIndx) {
634 if (Cnts[pIndx] == 0)
continue;
636 myprt <<
"\n " << pName[pIndx] <<
" ";
637 myprt << std::fixed << std::setprecision(3);
638 ave = ESums[pIndx] / Cnts[pIndx];
639 myprt << std::setw(8) << ave;
640 ave = PSums[pIndx] / Cnts[pIndx];
641 myprt << std::setw(8) << ave;
642 ave = EPSums[pIndx] / Cnts[pIndx];
643 myprt << std::setw(8) << ave;
644 if (pIndx == 0)
continue;
645 sumEP += EPSums[pIndx];
646 sumE += ESums[pIndx];
647 sumP += PSums[pIndx];
649 if (cnts == 0)
return;
651 myprt <<
"Averages for all selected truth particles\n";
652 myprt <<
"Ave Eff " << sumE / cnts;
653 myprt <<
" Ave Pur " << sumP / cnts;
654 myprt <<
" Ave EP " << sumEP / cnts;
655 myprt <<
" nBadEP " << fNBadEP;
656 myprt <<
" (EP < " << std::fixed << std::setprecision(2) << fBadEP <<
")";
658 myprt <<
"MCParticle counts in all TPCs and Planes:";
659 for (
unsigned short pIndx = 0; pIndx < 5; ++pIndx) {
660 if (Cnts[pIndx] == 0)
continue;
661 myprt <<
" " << pName[pIndx] <<
" " << (int)Cnts[pIndx];
art::InputTag fTrackModuleLabel
ClusterTrackAna(fhicl::ParameterSet const &p)
Utilities related to art service access.
art::InputTag fClusterModuleLabel
ClusterTrackAna & operator=(ClusterTrackAna const &)=delete
Declaration of signal hit object.
std::array< float, 5 > PSums
std::size_t size(FixedBins< T, C > const &) noexcept
std::string HitLocation(unsigned int iht)
packs hit WireID and PeakTime into a compact format
std::array< float, 5 > Cnts
void analyze(art::Event const &e) override
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
std::array< float, 5 > EPSums
void FirstLastHitInPlane(unsigned int tpc, unsigned int plane, unsigned int mcpi, unsigned int &firstHitIndex, unsigned int &lastHitIndex)
Declaration of cluster object.
Provides recob::Track data product.
std::vector< int > fSkipPDGCodes
art::InputTag fHitModuleLabel
std::string to_string(WindowPattern const &pattern)
simb::Origin_t fTruthOrigin
bool fCompareProductIDs
compare Hit and Cluster-> Hit art product IDs on the first event
art::Handle< std::vector< recob::Hit > > fHitHandle
std::array< float, 5 > ESums
bool empty(FixedBins< T, C > const &) noexcept
art framework interface to geometry description
BEGIN_PROLOG could also be cout
std::vector< unsigned int > fHitMCPIndex