43 class ClusterTrackAna;
75 std::array<float, 5>
Cnts{{0}};
78 std::array<float, 5>
ESums{{0}};
80 std::array<float, 5>
PSums{{0}};
93 unsigned int& firstHitIndex,
94 unsigned int& lastHitIndex);
102 bool validModuleLabel =
false;
110 <<
"You must specify either a ClusterModuleLabel OR a TrackModuleLabel\n";
113 int tmp = pset.get<
int>(
"TruthOrigin", 0);
116 if (pset.has_key(
"SkipPDGCodes"))
fSkipPDGCodes = pset.get<std::vector<int>>(
"SkipPDGCodes");
117 fBadEP = pset.get<
float>(
"BadEP", 0.);
119 int intpc = pset.get<
int>(
"InTPC", -1);
120 if (intpc >= 0)
fInTPC = intpc;
135 auto const* geom = lar::providerFrom<geo::Geometry>();
145 <<
"Failed to get a handle to MCParticles using largeant\n";
163 std::vector<int> trkIDs;
165 std::vector<unsigned int> MCPIs;
172 bool isCharged = (pdg == 11) || (pdg == 13) || (pdg == 211) || (pdg == 321) || (pdg == 2212);
173 if (!isCharged)
continue;
175 float TMeV = 1000 * (part->
E() - part->
Mass());
177 if (TMeV < 1)
continue;
179 unsigned int mcpi = UINT_MAX;
180 for (mcpi = 0; mcpi < (*mcpHandle).size(); ++mcpi)
181 if ((*mcpHandle)[mcpi].TrackId() == trackID)
break;
182 if (mcpi == UINT_MAX) {
183 std::cout <<
"Failed to find a MCParticle from ParticleList\n";
186 trkIDs.push_back(trackID);
187 MCPIs.push_back(mcpi);
189 if (trkIDs.empty())
return;
195 std::vector<std::pair<unsigned int, unsigned int>> hitRange(geom->NTPC() + 1);
199 for (
auto& hr : hitRange)
200 hr = std::make_pair(UINT_MAX, UINT_MAX);
201 for (
size_t iht = 0; iht < (*fHitHandle).size(); ++iht) {
202 auto&
hit = (*fHitHandle)[iht];
204 unsigned int tpc =
hit.WireID().TPC;
212 for (
auto& tide : tides) {
214 if (tide.energyFrac < 0.5)
continue;
215 int trackID = tide.trackID;
217 for (
size_t indx = 0; indx < trkIDs.size(); ++indx) {
218 if (trkIDs[indx] == trackID) {
228 if (hitRange[tpc].first == UINT_MAX) hitRange[tpc].first = iht;
229 hitRange[tpc].second = iht;
240 myprt <<
"Checking " << trkIDs.size() <<
" selected MCParticles with the requested TruthOrigin";
241 if (
fInTPC == UINT_MAX) { myprt <<
" in all TPCs\n"; }
243 myprt <<
" in TPC " <<
fInTPC;
245 myprt <<
" in Run " << evt.
run() <<
" Event " << evt.
event();
247 myprt <<
"Found " << nMatch <<
" MC-matched hits with the requested TruthOrigin";
248 myprt <<
" out of " << nInTPC <<
" total hits.\n";
249 myprt <<
"Found " << noMatch <<
" hits not matched to ANY MCParticle.\n";
252 std::vector<std::pair<unsigned int, unsigned int>> mcpCnt;
254 if (mcpi == UINT_MAX)
continue;
255 unsigned short mIndx = 0;
256 for (mIndx = 0; mIndx < mcpCnt.size(); ++mIndx)
257 if (mcpCnt[mIndx].first == mcpi)
break;
258 if (mIndx == mcpCnt.size()) mcpCnt.push_back(std::make_pair(mcpi, 0));
260 ++mcpCnt[mIndx].second;
262 myprt <<
" MCPI TrackID PDGCode T(MeV) nHits Process";
263 for (
auto mcpcnt : mcpCnt) {
265 unsigned int mcpi = mcpcnt.first;
266 auto& mcp = (*mcpHandle)[mcpi];
267 myprt << std::setw(5) << mcpi;
268 myprt << std::setw(8) << mcp.TrackId();
269 myprt << std::setw(8) <<
abs(mcp.PdgCode());
270 int TMeV = 1000 * (mcp.E() - mcp.Mass());
271 myprt << std::setw(9) << TMeV;
272 myprt << std::setw(8) << mcpcnt.second;
273 myprt <<
" " << mcp.Process();
278 std::vector<std::vector<unsigned int>> recoHits;
280 std::vector<unsigned int> recoIndex;
292 if (!hitsFromCls.isValid())
293 throw cet::exception(
"ClusterTrackAna") <<
"Failed to get a handle to Cluster -> Hit assns\n";
294 for (
unsigned int icl = 0; icl < (*inputClusters).size(); ++icl) {
295 std::vector<art::Ptr<recob::Hit>> cluhits = hitsFromCls.at(icl);
296 if (cluhits.empty())
continue;
300 <<
"Hits associated with ClusterModuleLabel are in a different collection than " 307 std::vector<unsigned int> hitsIndex;
308 for (
auto& cluhit : cluhits) {
309 if (
fHitMCPIndex[cluhit.key()] != UINT_MAX) hitsIndex.push_back(cluhit.key());
311 if (hitsIndex.empty())
continue;
312 recoIndex.push_back(icl);
313 recoHits.push_back(hitsIndex);
322 if (!hitsFromTrk.isValid())
323 throw cet::exception(
"ClusterTrackAna") <<
"Failed to get a handle to Track -> Hit assns\n";
324 for (
unsigned int itk = 0; itk < (*inputTracks).size(); ++itk) {
325 std::vector<art::Ptr<recob::Hit>> trkhits = hitsFromTrk.at(itk);
326 if (trkhits.empty())
continue;
330 <<
"Hits associated with TrackModuleLabel are in a different collection than " 334 std::vector<unsigned int> hitsIndex;
335 for (
auto& trkhit : trkhits) {
336 if (
fHitMCPIndex[trkhit.key()] != UINT_MAX) hitsIndex.push_back(trkhit.key());
338 if (hitsIndex.empty())
continue;
339 recoIndex.push_back(itk);
340 recoHits.push_back(hitsIndex);
344 for (
const auto& tpcid : geom->Iterate<
geo::TPCID>()) {
345 unsigned int tpc = tpcid.TPC;
346 if (hitRange[tpc].first == UINT_MAX)
continue;
348 for (
unsigned short plane = 0; plane < wireReadoutGeom.Nplanes(); ++plane) {
349 unsigned int tpcMatHitCnt = 0;
350 unsigned int tpcTotHitCnt = 0;
353 std::vector<std::pair<unsigned int, float>> mcpCnt;
355 std::vector<std::vector<std::pair<unsigned int, float>>> mcpClsCnt;
356 for (
unsigned int iht = hitRange[tpc].first; iht <= hitRange[tpc].second; ++iht) {
357 auto&
hit = (*fHitHandle)[iht];
358 if (
hit.WireID().TPC != tpc)
continue;
359 if (
hit.WireID().Plane != plane)
continue;
366 unsigned short mIndx = 0;
367 for (mIndx = 0; mIndx < mcpCnt.size(); ++mIndx)
368 if (mcpCnt[mIndx].first == mcpi)
break;
369 if (mIndx == mcpCnt.size()) {
371 mcpCnt.push_back(std::make_pair(mcpi, 0));
372 mcpClsCnt.resize(mcpCnt.size());
375 ++mcpCnt[mIndx].second;
380 myprt <<
"TPC:" << tpc <<
" Plane:" << plane <<
" has " << tpcMatHitCnt <<
"/" 382 myprt <<
" (MC-matched hits) / (all hits)";
384 if (tpcMatHitCnt < 3)
continue;
386 for (
unsigned int ii = 0; ii < recoHits.size(); ++ii) {
387 float nRecoHitsInPlane = 0;
388 float nRecoMatHitsInPlane = 0;
389 for (
auto iht : recoHits[ii]) {
390 auto&
hit = (*fHitHandle)[iht];
391 if (
hit.WireID().TPC != tpc)
continue;
392 if (
hit.WireID().Plane != plane)
continue;
395 ++nRecoMatHitsInPlane;
399 unsigned short mIndx = 0;
400 for (mIndx = 0; mIndx < mcpCnt.size(); ++mIndx)
401 if (mcpCnt[mIndx].first == mcpi)
break;
402 if (mIndx == mcpCnt.size()) {
403 std::cout <<
"Logic error: fHitMCPIndex = " <<
fHitMCPIndex[iht]
404 <<
" is valid but isn't in the list of MCParticles to use. Please send email " 405 "to baller@fnal.gov.\n";
408 unsigned short cIndx = 0;
409 for (cIndx = 0; cIndx < mcpClsCnt[mIndx].size(); ++cIndx)
410 if (mcpClsCnt[mIndx][cIndx].first == ii)
break;
411 if (cIndx == mcpClsCnt[mIndx].
size()) mcpClsCnt[mIndx].push_back(std::make_pair(ii, 0));
412 ++mcpClsCnt[mIndx][cIndx].second;
414 if (nRecoMatHitsInPlane == 0)
continue;
417 for (
unsigned short mIndx = 0; mIndx < mcpCnt.size(); ++mIndx) {
419 if (mcpCnt[mIndx].
second < 3)
continue;
420 unsigned int mcpi = mcpCnt[mIndx].first;
421 auto& mcp = (*mcpHandle)[mcpi];
422 unsigned int pdgCode =
abs(mcp.PdgCode());
423 unsigned short pIndx = USHRT_MAX;
424 if (pdgCode == 11) pIndx = 0;
425 if (pdgCode == 13) pIndx = 1;
426 if (pdgCode == 211) pIndx = 2;
427 if (pdgCode == 321) pIndx = 3;
428 if (pdgCode == 2212) pIndx = 4;
429 if (mcpClsCnt[mIndx].
empty()) {
435 myprt <<
" MCPI " << mcpi;
436 int TMeV = 1000 * (mcp.E() - mcp.Mass());
437 myprt <<
" " << TMeV <<
" MeV";
439 if (pdgCode == 11) partName =
"El";
440 if (pdgCode == 13) partName =
"Mu";
441 if (pdgCode == 211) partName =
"Pi";
442 if (pdgCode == 311) partName =
"Ka";
443 if (pdgCode == 2212) partName =
"Pr";
444 myprt << std::setw(5) << partName;
446 unsigned int firstHitIndex = UINT_MAX;
447 unsigned int lastHitIndex = UINT_MAX;
449 myprt <<
" Failed to reconstruct. Truth-matched hit range from ";
453 myprt <<
" <- EP = 0!";
457 std::pair<unsigned int, float> big = std::make_pair(UINT_MAX, 0);
458 for (
unsigned short cIndx = 0; cIndx < mcpClsCnt[mIndx].size(); ++cIndx) {
459 auto& mcc = mcpClsCnt[mIndx][cIndx];
460 if (mcc.second > big.second) big = mcc;
462 if (big.first == UINT_MAX) {
465 unsigned int mcpi = mcpCnt[mIndx].first;
466 auto& mcp = (*mcpHandle)[mcpi];
467 myprt <<
"Match failed: mcpi " << mcpi <<
" pdg " << mcp.PdgCode();
469 std::cout <<
"match failed mIndx " << mIndx <<
"\n";
472 unsigned int ii = big.first;
473 float eff = big.second / mcpCnt[mIndx].second;
474 float nRecoHitsInPlane = 0;
476 unsigned int firstRecoHitIndex = UINT_MAX;
477 unsigned int lastRecoHitIndex = UINT_MAX;
478 for (
auto iht : recoHits[ii]) {
479 auto&
hit = (*fHitHandle)[iht];
480 if (
hit.WireID().TPC != tpc)
continue;
481 if (
hit.WireID().Plane != plane)
continue;
483 if (firstRecoHitIndex == UINT_MAX) {
484 firstRecoHitIndex = iht;
485 lastRecoHitIndex = iht;
487 unsigned int wire = (*fHitHandle)[iht].WireID().Wire;
488 if (wire < (*
fHitHandle)[firstRecoHitIndex].
WireID().Wire) firstRecoHitIndex = iht;
489 if (wire > (*
fHitHandle)[lastRecoHitIndex].
WireID().Wire) lastRecoHitIndex = iht;
491 float pur = big.second / nRecoHitsInPlane;
493 float ep = eff * pur;
497 bool hasBadEP = (ep <
fBadEP);
503 myprt <<
"Hit location format is TPC:Plane:Wire:Tick\n";
504 myprt <<
" MCPI Ptcl T(MeV) nMCPHits ____From____ _____To_____";
505 if (inputClusters.
isValid()) { myprt <<
" clsID"; }
510 <<
" ____From____ _____To_____ nRecoHits nMCPRecoHits Eff Pur EP\n";
513 myprt << std::setw(5) << mcpi;
516 if (pdgCode == 11) partName =
" Electron";
517 if (pdgCode == 13) partName =
" Muon";
518 if (pdgCode == 211) partName =
" Pion";
519 if (pdgCode == 311) partName =
" Kaon";
520 if (pdgCode == 2212) partName =
" Proton";
522 int TMeV = 1000 * (mcp.E() - mcp.Mass());
523 myprt << std::setw(7) << TMeV;
525 myprt << std::setw(10) << mcpCnt[mIndx].second;
526 unsigned int firstTruHitIndex = UINT_MAX;
527 unsigned int lastTruHitIndex = UINT_MAX;
529 myprt << std::setw(14) <<
HitLocation(firstTruHitIndex);
530 myprt << std::setw(14) <<
HitLocation(lastTruHitIndex);
534 auto& cls = (*inputClusters)[recoIndex[ii]];
537 else if (inputTracks.
isValid()) {
539 auto&
trk = (*inputTracks)[recoIndex[ii]];
542 myprt << std::setw(6) << id;
543 myprt << std::setw(14) <<
HitLocation(firstRecoHitIndex);
544 myprt << std::setw(14) <<
HitLocation(lastRecoHitIndex);
545 myprt << std::setw(12) << (int)nRecoHitsInPlane;
546 myprt << std::setw(13) << (int)big.second;
547 myprt << std::fixed << std::setprecision(2);
548 myprt << std::setw(8) << eff;
549 myprt << std::setw(8) << pur;
550 myprt << std::setw(8) << ep;
551 if (hasBadEP) myprt <<
" <- BadEP";
552 myprt <<
" Evt: " << evt.
event();
567 if (iht >= (*fHitHandle).size())
return "NA";
568 auto&
hit = (*fHitHandle)[iht];
577 unsigned int& firstHitIndex,
578 unsigned int& lastHitIndex)
582 firstHitIndex = UINT_MAX;
583 lastHitIndex = UINT_MAX;
584 for (
unsigned int iht = 0; iht < (*fHitHandle).size(); ++iht) {
586 auto&
hit = (*fHitHandle)[iht];
587 if (
hit.WireID().TPC != tpc)
continue;
588 if (
hit.WireID().Plane != plane)
continue;
589 if (firstHitIndex == UINT_MAX) {
593 unsigned int wire = (*fHitHandle)[iht].WireID().Wire;
604 myprt <<
"ClusterTrackAna summary results for " <<
fEventCnt;
612 if (
fInTPC != UINT_MAX) { myprt <<
" in TPC " <<
fInTPC; }
614 myprt <<
" in all TPCs";
618 for (
unsigned short pIndx = 0; pIndx < 5; ++pIndx)
621 myprt <<
"No ClusterTrackAna results";
627 myprt <<
"Efficiency (Eff), Purity (Pur) and Eff * Pur (EP) by selected truth particle types\n";
628 std::array<std::string, 5> pName = {{
"El",
"Mu",
"Pi",
"K ",
"P "}};
629 myprt <<
"particle Eff Pur EP\n";
630 myprt <<
"-------------------------------";
631 for (
unsigned short pIndx = 0; pIndx < 5; ++pIndx) {
632 if (
Cnts[pIndx] == 0)
continue;
634 myprt <<
"\n " << pName[pIndx] <<
" ";
635 myprt << std::fixed << std::setprecision(3);
637 myprt << std::setw(8) << ave;
639 myprt << std::setw(8) << ave;
641 myprt << std::setw(8) << ave;
642 if (pIndx == 0)
continue;
644 sumE +=
ESums[pIndx];
645 sumP +=
PSums[pIndx];
647 if (cnts == 0)
return;
649 myprt <<
"Averages for all selected truth particles\n";
650 myprt <<
"Ave Eff " << sumE / cnts;
651 myprt <<
" Ave Pur " << sumP / cnts;
652 myprt <<
" Ave EP " << sumEP / cnts;
653 myprt <<
" nBadEP " <<
fNBadEP;
654 myprt <<
" (EP < " << std::fixed << std::setprecision(2) <<
fBadEP <<
")";
656 myprt <<
"MCParticle counts in all TPCs and Planes:";
657 for (
unsigned short pIndx = 0; pIndx < 5; ++pIndx) {
658 if (
Cnts[pIndx] == 0)
continue;
659 myprt <<
" " << pName[pIndx] <<
" " << (int)
Cnts[pIndx];
double E(const int i=0) const
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
art::InputTag fTrackModuleLabel
ClusterTrackAna(fhicl::ParameterSet const &p)
Utilities related to art service access.
std::vector< sim::TrackIDE > HitToTrackIDEs(detinfo::DetectorClocksData const &clockData, recob::Hit const &hit) const
art::InputTag fClusterModuleLabel
ClusterTrackAna & operator=(ClusterTrackAna const &)=delete
Declaration of signal hit object.
std::array< float, 5 > PSums
list_type::const_iterator const_iterator
simb::Origin_t Origin() const
enum simb::_ev_origin Origin_t
event origin types
constexpr auto abs(T v)
Returns the absolute value of the argument.
cout<< "Opened file "<< fin<< " ixs= "<< ixs<< endl;if(ixs==0) hhh=(TH1F *) fff-> Get("h1")
Cluster finding and building.
std::string HitLocation(unsigned int iht)
packs hit WireID and PeakTime into a compact format
std::array< float, 5 > Cnts
EDAnalyzer(fhicl::ParameterSet const &pset)
bool isValid() const noexcept
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
void analyze(art::Event const &e) override
#define DEFINE_ART_MODULE(klass)
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
decltype(auto) constexpr to_string(T &&obj)
ADL-aware version of std::to_string.
const art::Ptr< simb::MCTruth > & TrackIdToMCTruth_P(int id) const
std::array< float, 5 > EPSums
EventNumber_t event() const
void FirstLastHitInPlane(unsigned int tpc, unsigned int plane, unsigned int mcpi, unsigned int &firstHitIndex, unsigned int &lastHitIndex)
The data type to uniquely identify a TPC.
Declaration of cluster object.
Detector simulation of raw signals on wires.
const sim::ParticleList & ParticleList() const
std::vector< int > fSkipPDGCodes
bool getByLabel(std::string const &label, std::string const &instance, Handle< PROD > &result) const
Provides recob::Track data product.
art::InputTag fHitModuleLabel
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
second_as<> second
Type of time stored in seconds, in double precision.
art framework interface to geometry description
cet::coded_exception< error, detail::translate > exception
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
std::vector< unsigned int > fHitMCPIndex