LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
TCTruth.cxx
Go to the documentation of this file.
3 
4 
7 
12 
16 
17 namespace tca {
18 
21  {
22  // Initialize the variables used to calculate Efficiency * Purity (aka EP) for matching to truth
23  EPCnts.fill(0);
24  TSums.fill(0.0);
25  EPTSums.fill(0.0);
26  TruVxCounts.fill(0);
27  nBadEP = 0;
28  } // Initialize
29 
31  void TruthMatcher::MatchTruth(std::vector<simb::MCParticle*> const& mcpList, std::vector<unsigned int> const& mcpListIndex)
32  {
33  // Match trajectories, PFParticles, etc to the MC truth matched hits then
34  // calculate reconstruction efficiency and purity. This function should only be
35  // called once per event after reconstruction has been done in all slices
36 
37  // mcpList is a vector of all MCParticles that have been selected in the module
38  if(mcpList.empty()) return;
39  // mcpListIndex points to the MCParticle to which each hit is matched
40  if(mcpListIndex.size() != (*evt.allHits).size()) return;
41 
42 
43 /* TODO: fix this later
44  // Form a list of mother-daughter pairs that should be considered as a single particle
45  std::vector<std::pair<unsigned int, unsigned int>> moda;
46  for(unsigned int part = 0; part < mcpList.size(); ++part) {
47  auto& mcp = mcpList[part];
48  if(mcp->NumberDaughters() == 0) continue;
49  unsigned int ndtr = 0;
50  unsigned int dtrSelIndex = 0;
51  for(int idtr = 0; idtr < mcp->NumberDaughters(); ++idtr) {
52  int dtrTrackId = mcp->Daughter(idtr);
53  // ignore it if it's not in the list
54  bool ignore = true;
55  for(unsigned short dpart = part + 1; dpart < mcpList.size(); ++dpart) {
56  auto& dmcp = mcpList[dpart];
57  if(dmcp->TrackId() == dtrTrackId) {
58  dtrSelIndex = dpart;
59  ignore = false;
60  }
61  } // dpart
62  if(ignore) continue;
63  ++ndtr;
64  } // idtr
65  // require only one daughter
66  if(ndtr != 1) continue;
67  // require that the daughter have the same PDG code
68  auto& dtr = mcpList[dtrSelIndex];
69  if(dtr->PdgCode() != mcp->PdgCode()) continue;
70  if(tcc.matchTruth[1] > 1) mf::LogVerbatim("TC")<<"Daughter MCP "<<dtrSelIndex<<" -> Mother MCP "<<part;
71  moda.push_back(std::make_pair(mcpListIndex[part], mcpListIndex[dtrSelIndex]));
72  } // part
73  if(!moda.empty()) {
74  // over-write the hit -> daughter MCParticle association to the mother MCParticle.
75  // Note that mother-daughter pairs are ordered by increasing generation. Reverse
76  // moda so that the grand-daughters come first. Grand-daughters will then be
77  // over-written by daughters in the previous generation
78  if(moda.size() > 1) std::reverse(moda.begin(), moda.end());
79  for(unsigned int iht = 0; iht < (*evt.allHits).size(); ++iht) {
80  for(auto& md : moda) if(md.second == mcpListIndex[iht]) mcpListIndex[iht] = md.first;
81  } // iht
82  } // moda not empty
83 */
84  // decide if electrons inside showers should be associated with the eve electron
85 // bool showerRecoMode = (tcc.showerTag[0] == 2) || (tcc.showerTag[0] == 4);
86 
87  MatchAndSum(mcpList, mcpListIndex);
88 
89  // print electron likelihood to output to create an ntuple
90  if(tcc.modes[kStudy2]) {
91  for(auto& slc : slices) {
92  for(auto& tj : slc.tjs) {
93  if(tj.AlgMod[kKilled]) continue;
94  if(tj.mcpListIndex != 0) continue;
95  auto& mcp = mcpList[tj.mcpListIndex];
96  int pdg = abs(mcp->PdgCode());
97  short TMeV = 1000 * (mcpList[0]->E() - mcpList[0]->Mass());
98  float asym;
99  float eLike = ElectronLikelihood(slc, tj, asym);
100  mf::LogVerbatim myprt("TC");
101  myprt<<"ntp "<<pdg<<" "<<TMeV;
102  myprt<<" "<<tj.MCSMom;
103  myprt<<" "<<tj.PDGCode;
104  myprt<<" "<<std::fixed<<std::setprecision(1);
105  myprt<<" "<<TrajPointSeparation(tj.Pts[tj.EndPt[0]], tj.Pts[tj.EndPt[1]]);
106  myprt<<" "<<std::fixed<<std::setprecision(2);
107  myprt<<" "<<asym;
108  myprt<<" "<<std::setprecision(3)<<tj.ChgRMS;
109  myprt<<" "<<eLike;
110  myprt<<" "<<tj.EffPur;
111  if(pdg == 13 && eLike > 0.5) mf::LogVerbatim("TC")<<"Bad mu "<<eLike<<" "<<evt.eventsProcessed;
112  if(pdg == 11 && eLike < 0.5) mf::LogVerbatim("TC")<<"Bad el "<<eLike<<" "<<evt.eventsProcessed;
113  } // tj
114  } // slc
115  } // study2
116 
117  } // MatchTruth
118 
120  void TruthMatcher::MatchAndSum(std::vector<simb::MCParticle*> const& mcpList, std::vector<unsigned int> const& mcpListIndex)
121  {
122  // Match Tjs and PFParticles and accumulate performance statistics
123 
124  // A MCParticle may span more than one TPC but trajectories and PFParticles are
125  // reconstructed in only one TPC so we need to consider them separately
126  for(const geo::TPCID& tpcid : tcc.geom->IterateTPCIDs()) {
127  unsigned int tpc = tpcid.TPC;
128  unsigned int cstat = tpcid.Cryostat;
129  // select the MCParticles with matched hits in this TPC
130  // mcpList list of hits in this TPC
131  std::vector<std::vector<unsigned int>> mcpHits(mcpList.size());
132  bool hitsInTPC = false;
133  for(unsigned int iht = 0; iht < (*evt.allHits).size(); ++iht) {
134  if(mcpListIndex[iht] > mcpList.size() - 1) continue;
135  auto& hit = (*evt.allHits)[iht];
136  if(hit.WireID().Cryostat != cstat) continue;
137  if(hit.WireID().TPC != tpc) continue;
138  mcpHits[mcpListIndex[iht]].push_back(iht);
139  hitsInTPC = true;
140  } // iht
141  // no sense continuing if there are no selected MCParticles that have hits
142  // in this TPC
143  if(!hitsInTPC) continue;
144  // get the location of a tj in terms of (slice index, tj index)
145  std::vector<std::pair<unsigned short, unsigned short>> tjLocs;
146  // and the hits
147  std::vector<std::vector<unsigned int>> tjHits;
148  // do the same for pfps
149  std::vector<std::pair<unsigned short, unsigned short>> pfpLocs;
150  std::vector<std::vector<unsigned int>> pfpHits;
151  for(unsigned short isl = 0; isl < slices.size(); ++isl) {
152  auto& slc = slices[isl];
153  for(auto& tj : slc.tjs) {
154  if(tj.AlgMod[kKilled]) continue;
155  if(DecodeCTP(tj.CTP).TPC != tpc) continue;
156  tj.mcpListIndex = UINT_MAX;
157  tj.EffPur = 0;
158  tjLocs.push_back(std::make_pair(isl, (unsigned short)(tj.ID-1)));
159  tjHits.push_back(PutTrajHitsInVector(tj, kUsedHits));
160  } // tj
161  for(auto& pfp : slc.pfps) {
162  if(pfp.ID <= 0) continue;
163  if(pfp.TPCID != tpcid) continue;
164  // ignore neutrino PFParticles
165  if(pfp.PDGCode == 14 || pfp.PDGCode == 12) continue;
166  pfp.mcpListIndex = UINT_MAX;
167  pfp.EffPur = 0;
168  pfpLocs.push_back(std::make_pair(isl, (unsigned short)(pfp.ID-1)));
169  std::vector<unsigned int> tmp;
170  for(auto tjid : pfp.TjIDs) {
171  auto& tj = slc.tjs[tjid - 1];
172  auto thits = PutTrajHitsInVector(tj, kUsedHits);
173  tmp.insert(tmp.end(), thits.begin(), thits.end());
174  } // tjid
175  pfpHits.push_back(tmp);
176  } // pfp
177  } // slc
178  unsigned short nplanes = tcc.geom->Nplanes(tpc, cstat);
179  // match them
180  for(unsigned int imcp = 0; imcp < mcpList.size(); ++imcp) {
181  if(mcpHits[imcp].empty()) continue;
182  // ignore if it isn't reconstructable in 3D
183  if(!CanReconstruct(mcpHits[imcp], 3, tpcid)) continue;
184  auto& mcp = mcpList[imcp];
185  unsigned short pdgIndex = PDGCodeIndex(mcp->PdgCode());
186  if(pdgIndex > 4) continue;
187  std::string particleName = "Other";
188  int pdg = abs(mcp->PdgCode());
189  if(pdg == 11) particleName = "Electron";
190  if(pdg == 22) particleName = "Photon";
191  if(pdg == 13) particleName = "Muon";
192  if(pdg == 211) particleName = "Pion";
193  if(pdg == 321) particleName = "Kaon";
194  if(pdg == 2212) particleName = "Proton";
195  if(particleName == "Other") particleName = "PDG_" + std::to_string(pdg);
196  float TMeV = 1000 * (mcp->E() - mcp->Mass());
197  ++MCP_Cnt;
198  MCP_TSum += TMeV;
199  for(unsigned short plane = 0; plane < nplanes; ++plane) {
200  // get the MCP hits in this plane
201  std::vector<unsigned int> mcpPlnHits;
202  for(auto iht : mcpHits[imcp]) {
203  auto& hit = (*evt.allHits)[iht];
204  if(hit.WireID().Plane == plane) mcpPlnHits.push_back(iht);
205  } // iht
206  // require 2 truth-matched hits
207  if(mcpPlnHits.size() < 2) continue;
208  if((float)mcpPlnHits.size() >= tcc.matchTruth[3]) ++nLongInPln;
209  TSums[pdgIndex] += TMeV;
210  ++EPCnts[pdgIndex];
211  // the tjSlIDs index of the tj that has the highest EP
212  unsigned short mtjLoc = USHRT_MAX;
213  float maxEP = 0;
214  for(unsigned short iit = 0; iit < tjLocs.size(); ++iit) {
215  // check for hits in this TPC and plane
216  if(tjHits[iit].empty()) continue;
217  // find hits that are common
218  auto shared = SetIntersection(mcpPlnHits, tjHits[iit]);
219  if(shared.empty()) continue;
220  float eff = (float)shared.size() / (float)mcpPlnHits.size();
221  float pur = (float)shared.size() / (float)tjHits[iit].size();
222  float ep = eff * pur;
223  if(ep > maxEP) {
224  maxEP = ep;
225  mtjLoc = iit;
226  } // ep > tj.EffPur
227  } // iit
228  if(mtjLoc == USHRT_MAX) {
229  if((float)mcpPlnHits.size() > tcc.matchTruth[3]) {
230  ++nBadEP;
231  mf::LogVerbatim myprt("TC");
232  myprt<<particleName<<" BadEP TMeV "<<(int)TMeV<<" No matched trajectory to imcp "<<imcp;
233  myprt<<" nTrue hits "<<mcpPlnHits.size();
234 // myprt<<" extent "<<PrintHit(slc.slHits[mcpPlnHits[0]])<<"-"<<PrintHit(slc.slHits[mcpPlnHits[mcpPlnHits.size() - 1]]);
235  myprt<<" events processed "<<evt.eventsProcessed;
236  } // BadEP
237  } else {
238  // set EffPur for the best matching tj
239  auto& tj = slices[tjLocs[mtjLoc].first].tjs[tjLocs[mtjLoc].second];
240  if(maxEP > tj.EffPur) {
241  tj.EffPur = maxEP;
242  tj.mcpListIndex = imcp;
243  EPTSums[pdgIndex] += TMeV * tj.EffPur;
244  }
245  // print BadEP ignoring electrons
246  if(tj.EffPur < tcc.matchTruth[2] && (float)mcpPlnHits.size() >= tcc.matchTruth[3] && pdgIndex > 0) {
247  ++nBadEP;
248  mf::LogVerbatim myprt("TC");
249  myprt<<particleName<<" BadEP: "<<std::fixed<<std::setprecision(2)<<tj.EffPur;
250  myprt<<" imcp "<<imcp;
251  myprt<<" TMeV "<<(int)TMeV<<" MCP hits "<<mcpPlnHits.size();
252  // myprt<<" extent "<<PrintHit(slc.slHits[mcpPlnHits[0]])<<"-"<<PrintHit(slc.slHits[mcpPlnHits[mcpPlnHits.size() - 1]]);
253  myprt<<" T"<<tj.ID;
254  myprt<<" Algs";
255  for(unsigned short ib = 0; ib < AlgBitNames.size(); ++ib) if(tj.AlgMod[ib]) myprt<<" "<<AlgBitNames[ib];
256  myprt<<" events processed "<<evt.eventsProcessed;
257  } // print BadEP
258  } // matched tj in this plane
259  } // plane
260  // pfp matching
261  bool longMCP = (pdgIndex > 0 && pdgIndex < 5 && (float)mcpHits[imcp].size() >= 2 * tcc.matchTruth[3]);
262  float maxEP = 0;
263  unsigned short mpfpLoc = USHRT_MAX;
264  for(unsigned short iit = 0; iit < pfpLocs.size(); ++iit) {
265  // check for hits in this TPC and plane
266  if(pfpHits[iit].empty()) continue;
267  // find hits that are common
268  auto shared = SetIntersection(mcpHits[imcp], pfpHits[iit]);
269  if(shared.empty()) continue;
270  float eff = (float)shared.size() / (float)mcpHits[imcp].size();
271  float pur = (float)shared.size() / (float)pfpHits[iit].size();
272  float ep = eff * pur;
273  if(ep > maxEP) {
274  maxEP = ep;
275  mpfpLoc = iit;
276  } // ep > tj.EffPur
277  } // iit
278  if(mpfpLoc == USHRT_MAX) {
279  // no matching pfp
280  if(TMeV > 30) {
281  mf::LogVerbatim myprt("TC");
282  myprt<<"BadPFP: MCParticle "<<imcp<<" w PDGCode "<<mcp->PdgCode()<<" T "<<(int)TMeV<<" not reconstructed.";
283  myprt<<" events processed "<<evt.eventsProcessed;
284  } // TMeV > 30
285  } else {
286  // matched pfp
287  auto& pfp = slices[pfpLocs[mpfpLoc].first].pfps[pfpLocs[mpfpLoc].second];
288  if(maxEP > pfp.EffPur) {
289  pfp.EffPur = maxEP;
290  pfp.mcpListIndex = imcp;
291  MCP_EPTSum += TMeV * maxEP;
292  ++MCP_PFP_Cnt;
293  if(longMCP && maxEP > 0.8) ++nGoodLongMCP;
294  } // maxEP > pfp.EffPur
295  } // matched pfp
296  } // imcp
297  // debug primary electron reconstruction
298 // if(tcc.modes[kStudy2] && !mcpList.empty() && abs(mcpList[0]->PdgCode()) == 11 && mcpHits[0].size() > 20) {
299  if(tcc.modes[kStudy3] && !mcpList.empty() && mcpHits[0].size() > 10) {
300  short TMeV = 1000 * (mcpList[0]->E() - mcpList[0]->Mass());
301  std::cout<<"Study3: Find Tjs matched to primary w PDGCode "<<mcpList[0]->PdgCode()<<". T = "<<TMeV<<"\n";
302  std::array<bool, 3> inPln {{false}};
303  for(auto& slc : slices) {
304  for(auto& tj : slc.tjs) {
305  if(tj.AlgMod[kKilled]) continue;
306  if(tj.mcpListIndex != 0) continue;
307  unsigned short plane = DecodeCTP(tj.CTP).Plane;
308  inPln[plane] = true;
309  std::cout<<"T"<<tj.UID<<" start ";
310  auto& tp = tj.Pts[tj.EndPt[0]];
311  std::cout<<PrintPos(slc, tp);
312  std::cout<<" PDGCode "<<tj.PDGCode;
313  std::cout<<" len "<<tj.EndPt[1] - tj.EndPt[0] + 1;
314  std::cout<<" MCSMom "<<tj.MCSMom;
315  std::cout<<" ChgRMS "<<std::fixed<<std::setprecision(2)<<tj.ChgRMS;
316  std::cout<<" BraggPeak? "<<tj.StopFlag[1][kBragg];
317  float asym;
318  std::cout<<" eLike "<<ElectronLikelihood(slc, tj, asym);
319 /*
320  auto plist = GetAssns(slc, "T", tj.ID, "P");
321  if(!plist.empty()) std::cout<<" P"<<plist[0];
322  std::cout<<" WorkID "<<tj.WorkID;
323  unsigned int firstiht = 0;
324  unsigned int firstwire = 5000;
325  unsigned int lastiht = 0;
326  unsigned int lastwire = 0;
327  unsigned short cntInPln = 0;
328  for(auto iht : mcpHits[0]) {
329  auto& hit = (*evt.allHits)[iht];
330  if(hit.WireID().Plane != plane) continue;
331  ++cntInPln;
332  if(hit.WireID().Wire < firstwire) {
333  firstwire = hit.WireID().Wire;
334  firstiht = iht;
335  }
336  if(hit.WireID().Wire > lastwire) {
337  lastwire = hit.WireID().Wire;
338  lastiht = iht;
339  }
340  } // iht
341  auto& firstHit = (*evt.allHits)[firstiht];
342  std::cout<<" "<<firstHit.WireID().Wire<<":"<<(int)firstHit.PeakTime();
343  auto& lastHit = (*evt.allHits)[lastiht];
344  std::cout<<" - "<<lastHit.WireID().Wire<<":"<<(int)lastHit.PeakTime();
345  std::cout<<" cnt "<<cntInPln;
346 */
347  std::cout<<"\n";
348  } // tj
349  if(!slc.pfps.empty()) {
350  auto& pfp = slc.pfps[0];
351  std::cout<<"P"<<pfp.UID<<" PDGCode "<<pfp.PDGCode<<" dtrs";
352  for(auto dtruid : pfp.DtrUIDs) std::cout<<" P"<<dtruid;
353  std::cout<<"\n";
354  } // pfps exist
355  } // slc
356  for(unsigned short plane = 0; plane < 3; ++plane) if(!inPln[plane]) std::cout<<"No match in plane "<<plane<<"\n";
357  } // kStudy2
358  } // tpcid
359 
360  } // MatchAndSum
361 
362 
364  void TruthMatcher::PrintResults(int eventNum) const
365  {
366  // Print performance metrics for each selected event
367 
368  mf::LogVerbatim myprt("TC");
369  myprt<<"Evt "<<eventNum;
370  float sum = 0;
371  float sumt = 0;
372  for(unsigned short pdgIndex = 0; pdgIndex < TSums.size(); ++pdgIndex) {
373  if(TSums[pdgIndex] == 0) continue;
374  if(pdgIndex == 0) myprt<<" El";
375  if(pdgIndex == 1) myprt<<" Mu";
376  if(pdgIndex == 2) myprt<<" Pi";
377  if(pdgIndex == 3) myprt<<" K";
378  if(pdgIndex == 4) myprt<<" P";
379  float ave = EPTSums[pdgIndex] / (float)TSums[pdgIndex];
380  myprt<<" "<<std::fixed<<std::setprecision(2)<<ave;
381 // myprt<<" "<<EPCnts[pdgIndex];
382  if(pdgIndex > 0) {
383  sum += TSums[pdgIndex];
384  sumt += EPTSums[pdgIndex];
385  }
386  } // pdgIndex
387  if(sum > 0) myprt<<" MuPiKP "<<std::fixed<<std::setprecision(2)<<sumt / sum;
388  myprt<<" BadEP "<<nBadEP;
389  if(nLongInPln > 0) {
390  float longGood = 1 - (float)nBadEP / (float)nLongInPln;
391  myprt<<" longGood "<<std::fixed<<std::setprecision(2)<<longGood;
392  }
393  if(MCP_TSum > 0) {
394  // PFParticle statistics
395  float ep = MCP_EPTSum / MCP_TSum;
396  myprt<<" MCP cnt "<<(int)MCP_Cnt<<" PFP "<<std::fixed<<std::setprecision(2)<<ep;
397  }
398  if(Prim_TSum > 0) {
399  float ep = Prim_EPTSum / Prim_TSum;
400  myprt<<" PrimPFP "<<std::fixed<<std::setprecision(2)<<ep;
401  }
402  if(nLongMCP > 0) {
403  float longGood = (float)nGoodLongMCP / (float)nLongMCP;
404  myprt<<" longGood "<<std::fixed<<std::setprecision(2)<<longGood;
405  }
406  if(TruVxCounts[1] > 0) {
407  // True vertex is reconstructable
408  float frac = (float)TruVxCounts[2] / (float)TruVxCounts[1];
409  myprt<<" NuVx correct "<<std::fixed<<std::setprecision(2)<<frac;
410  }
411 
412  } // PrintResults
413 
415  bool TruthMatcher::CanReconstruct(std::vector<unsigned int> mcpHits, unsigned short nDimensions, const geo::TPCID& inTPCID)
416  {
417  // returns true if the MCParticle that is matched to the hits in mcpHits can be reconstructed
418  // in nDimensions in inTPCID
419  if(mcpHits.empty()) return false;
420  if(nDimensions < 2 || nDimensions > 3) return false;
421  unsigned short tpc = inTPCID.TPC;
422  unsigned short cstat = inTPCID.Cryostat;
423  unsigned short nplanes = tcc.geom->Nplanes(tpc, cstat);
424  std::vector<unsigned short> cntInPln(nplanes);
425  for(auto iht : mcpHits) {
426  if(iht > (*evt.allHits).size()) return false;
427  auto& hit = (*evt.allHits)[iht];
428  if(hit.WireID().TPC != tpc) continue;
429  if(hit.WireID().Cryostat != cstat) continue;
430  ++cntInPln[hit.WireID().Plane];
431  } // hit
432  unsigned short nPlnOK = 0;
433  // Require at least 2 truth-matched hits in a plane
434  for(unsigned short plane = 0; plane < nplanes; ++plane) if(cntInPln[plane] > 1) ++nPlnOK;
435  return (nPlnOK >= 2);
436  } // CanReconstruct
437  /* This code was used to develop the TMVA showerParentReader. The MakeCheatShower function needs
438  to be re-written if this function is used in the future
440  void TruthMatcher::StudyShowerParents(TCSlice& slc, HistStuff& hist)
441  {
442  // study characteristics of shower parent pfps. This code is adapted from TCShower FindParent
443  if(slc.pfps.empty()) return;
444  if(slc.mcpList.empty()) return;
445 
446  // Look for truth pfp primary electron
447  Point3_t primVx {{-666.0, -666.0, -666.0}};
448  // the primary should be the first one in the list as selected in GetHitCollection
449  auto& primMCP = slc.mcpList[0];
450  primVx[0] = primMCP->Vx();
451  primVx[1] = primMCP->Vy();
452  primVx[2] = primMCP->Vz();
453  geo::Vector_t posOffsets;
454  auto const* SCE = lar::providerFrom<spacecharge::SpaceChargeService>();
455  posOffsets = SCE->GetPosOffsets({primVx[0], primVx[1], primVx[2]});
456  posOffsets.SetX(-posOffsets.X());
457  primVx[0] += posOffsets.X();
458  primVx[1] += posOffsets.Y();
459  primVx[2] += posOffsets.Z();
460  geo::TPCID inTPCID;
461  // ignore if the primary isn't inside a TPC
462  if(!InsideTPC(primVx, inTPCID)) return;
463  // or if it is inside the wrong tpc
464  if(inTPCID != slc.TPCID) return;
465 
466  std::string fcnLabel = "SSP";
467  // Create a truth shower for each primary electron
468  art::ServiceHandle<cheat::ParticleInventoryService> pi_serv;
469  MCParticleListUtils mcpu{slc};
470  for(unsigned int part = 0; part < slc.mcpList.size(); ++part) {
471  auto& mcp = slc.mcpList[part];
472  // require electron or photon
473  if(abs(mcp->PdgCode()) != 11 && abs(mcp->PdgCode()) != 111) continue;
474  int eveID = pi_serv->ParticleList().EveId(mcp->TrackId());
475  // require that it is primary
476  if(mcp->TrackId() != eveID) continue;
477  int truPFP = 0;
478  auto ss3 = mcpu.MakeCheatShower(slc, part, primVx, truPFP);
479  if(ss3.ID == 0) continue;
480  if(truPFP == 0) continue;
481  if(!StoreShower(fcnLabel, slc, ss3)) {
482  std::cout<<"Failed to store 3S"<<ss3.ID<<"\n";
483  break;
484  } // store failed
485  // now fill the TTree
486  float ss3Energy = ShowerEnergy(ss3);
487  for(auto& pfp : slc.pfps) {
488  if(pfp.TPCID != ss3.TPCID) continue;
489  // ignore neutrinos
490  if(pfp.PDGCode == 12 || pfp.PDGCode == 14) continue;
491  // ignore shower pfps
492  if(pfp.PDGCode == 1111) continue;
493  float pfpEnergy = 0;
494  float minEnergy = 1E6;
495  for(auto tid : pfp.TjIDs) {
496  auto& tj = slc.tjs[tid - 1];
497  float energy = ChgToMeV(tj.TotChg);
498  pfpEnergy += energy;
499  if(energy < minEnergy) minEnergy = energy;
500  }
501  pfpEnergy -= minEnergy;
502  pfpEnergy /= (float)(pfp.TjIDs.size() - 1);
503  // find the end that is farthest away
504  unsigned short pEnd = FarEnd(slc, pfp, ss3.ChgPos);
505  auto pToS = PointDirection(pfp.XYZ[pEnd], ss3.ChgPos);
506  // take the absolute value in case the shower direction isn't well known
507  float costh1 = std::abs(DotProd(pToS, ss3.Dir));
508  float costh2 = DotProd(pToS, pfp.Dir[pEnd]);
509  // distance^2 between the pfp end and the shower start, charge center, and shower end
510  float distToStart2 = PosSep2(pfp.XYZ[pEnd], ss3.Start);
511  float distToChgPos2 = PosSep2(pfp.XYZ[pEnd], ss3.ChgPos);
512  float distToEnd2 = PosSep2(pfp.XYZ[pEnd], ss3.End);
513  // mf::LogVerbatim("TC")<<" 3S"<<ss3.ID<<" P"<<pfp.ID<<"_"<<pEnd<<" distToStart "<<sqrt(distToStart2)<<" distToChgPos "<<sqrt(distToChgPos2)<<" distToEnd "<<sqrt(distToEnd2);
514  // find the end of the shower closest to the pfp
515  unsigned short shEnd = 0;
516  if(distToEnd2 < distToStart2) shEnd = 1;
517  if(shEnd == 0 && distToChgPos2 < distToStart2) continue;
518  if(shEnd == 1 && distToChgPos2 < distToEnd2) continue;
519  // mf::LogVerbatim("TC")<<" 3S"<<ss3.ID<<"_"<<shEnd<<" P"<<pfp.ID<<"_"<<pEnd<<" costh1 "<<costh1;
520  Point2_t alongTrans;
521  // find the longitudinal and transverse components of the pfp start point relative to the
522  // shower center
523  FindAlongTrans(ss3.ChgPos, ss3.Dir, pfp.XYZ[pEnd], alongTrans);
524  // mf::LogVerbatim("TC")<<" alongTrans "<<alongTrans[0]<<" "<<alongTrans[1];
525  hist.fSep = sqrt(distToChgPos2);
526  hist.fShEnergy = ss3Energy;
527  hist.fPfpEnergy = pfpEnergy;
528  hist.fPfpLen = PosSep(pfp.XYZ[0], pfp.XYZ[1]);
529  hist.fMCSMom = MCSMom(slc, pfp.TjIDs);
530  hist.fDang1 = acos(costh1);
531  hist.fDang2 = acos(costh2);
532  hist.fChgFrac = 0;
533  float chgFrac = 0;
534  float totSep = 0;
535  // find the charge fraction btw the pfp start and the point that is
536  // half the distance to the charge center in each plane
537  for(unsigned short plane = 0; plane < slc.nPlanes; ++plane) {
538  CTP_t inCTP = EncodeCTP(ss3.TPCID.Cryostat, ss3.TPCID.TPC, plane);
539  int ssid = 0;
540  for(auto cid : ss3.CotIDs) {
541  auto& ss = slc.cots[cid - 1];
542  if(ss.CTP != inCTP) continue;
543  ssid = ss.ID;
544  break;
545  } // cid
546  if(ssid == 0) continue;
547  auto tpFrom = MakeBareTP(slc, pfp.XYZ[pEnd], pToS, inCTP);
548  auto& ss = slc.cots[ssid - 1];
549  auto& stp1 = slc.tjs[ss.ShowerTjID - 1].Pts[1];
550  float sep = PosSep(tpFrom.Pos, stp1.Pos);
551  float toPos = tpFrom.Pos[0] + 0.5 * tpFrom.Dir[0] * sep;
552  float cf = ChgFracBetween(slc, tpFrom, toPos, false);
553  // weight by the separation in the plane
554  totSep += sep;
555  chgFrac += sep * cf;
556  } // plane
557  if(totSep > 0) hist.fChgFrac = chgFrac / totSep;
558  hist.fAlong = alongTrans[0];
559  hist.fTrans = alongTrans[1];
560  hist.fInShwrProb = InShowerProbLong(ss3Energy, -hist.fSep);
561  bool isBad = (hist.fDang1 > 2 || hist.fChgFrac < 0.5 || hist.fInShwrProb < 0.05);
562  if(pfp.ID == truPFP && isBad) {
563  mf::LogVerbatim myprt("TC");
564  myprt<<"SSP: 3S"<<ss3.ID<<" shEnergy "<<(int)ss3Energy<<" P"<<pfp.ID<<" pfpEnergy "<<(int)pfpEnergy;
565  myprt<<" MCSMom "<<hist.fMCSMom<<" len "<<hist.fPfpLen;
566  myprt<<" Dang1 "<<hist.fDang1<<" Dang2 "<<hist.fDang2<<" chgFrac "<<hist.fChgFrac;
567  myprt<<" fInShwrProb "<<hist.fInShwrProb;
568  myprt<<" EventsProcessed "<<evt.eventsProcessed;
569  }
570  if(pfp.ID == truPFP) {
571  hist.fShowerParentSig->Fill();
572  } else {
573  hist.fShowerParentBkg->Fill();
574  }
575  } // pfp
576  } // part
577  // PrintShowers(fcnLabel, tjs);
578  // Print2DShowers(fcnLabel, slc, USHRT_MAX, false);
579  // kill the cheat showers
580  for(auto& ss3 : slc.showers) {
581  if(ss3.ID == 0) continue;
582  if(!ss3.Cheat) continue;
583  for(auto cid : ss3.CotIDs) {
584  auto& ss = slc.cots[cid - 1];
585  ss.ID = 0;
586  auto& stj = slc.tjs[ss.ShowerTjID - 1];
587  stj.AlgMod[kKilled] = true;
588  } // cid
589  ss3.ID = 0;
590  } // ss3
591  } // StudyShowerParents
592  */
593 } // namespace tca
float MCP_TSum
Definition: TCTruth.h:61
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
unsigned short nLongInPln
Definition: TCTruth.h:70
const std::vector< std::string > AlgBitNames
Definition: DataStructs.cxx:13
TCConfig tcc
Definition: DataStructs.cxx:6
std::vector< unsigned int > PutTrajHitsInVector(Trajectory const &tj, HitStatus_t hitRequest)
Definition: Utils.cxx:2416
call study functions to develop cuts, etc
Definition: DataStructs.h:452
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:130
float TrajPointSeparation(TrajPoint &tp1, TrajPoint &tp2)
Definition: Utils.cxx:2368
Float_t tmp
Definition: plot.C:37
std::vector< float > matchTruth
Match to MC truth.
Definition: DataStructs.h:477
unsigned int eventsProcessed
Definition: DataStructs.h:540
void Initialize()
Definition: TCTruth.cxx:20
IteratorBox< TPC_id_iterator,&GeometryCore::begin_TPC_id,&GeometryCore::end_TPC_id > IterateTPCIDs() const
Enables ranged-for loops on all TPC IDs of the detector.
std::vector< T > SetIntersection(const std::vector< T > &set1, const std::vector< T > &set2)
Definition: Utils.h:231
void MatchAndSum(std::vector< simb::MCParticle * > const &mcpList, std::vector< unsigned int > const &mcpListIndex)
Definition: TCTruth.cxx:120
float Prim_EPTSum
Definition: TCTruth.h:66
bool CanReconstruct(std::vector< unsigned int > mcpHits, unsigned short nDimensions, const geo::TPCID &inTPCID)
Definition: TCTruth.cxx:415
float MCP_EPTSum
Definition: TCTruth.h:62
unsigned int Nplanes(unsigned int tpc=0, unsigned int cstat=0) const
Returns the total number of wire planes in the specified TPC.
void MatchTruth(std::vector< simb::MCParticle * > const &mcpList, std::vector< unsigned int > const &mcpListIndex)
Definition: TCTruth.cxx:31
std::array< float, 5 > TSums
Definition: TCTruth.h:58
std::array< float, 5 > EPTSums
Definition: TCTruth.h:59
std::array< short, 5 > EPCnts
Definition: TCTruth.h:57
const geo::GeometryCore * geom
Definition: DataStructs.h:493
unsigned short nLongMCP
Definition: TCTruth.h:71
The data type to uniquely identify a TPC.
Definition: geo_types.h:195
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:258
unsigned short nBadEP
Definition: TCTruth.h:69
unsigned short nGoodLongMCP
Definition: TCTruth.h:72
std::vector< TCSlice > slices
Definition: DataStructs.cxx:10
Detector simulation of raw signals on wires.
std::bitset< 16 > modes
number of points to find AveChg
Definition: DataStructs.h:524
float ElectronLikelihood(TCSlice &slc, Trajectory &tj, float &asym)
Definition: Utils.cxx:2679
std::string to_string(Flag_t< Storage > const flag)
Convert a flag into a stream (shows its index).
Definition: BitMask.h:187
call study functions to develop cuts, etc
Definition: DataStructs.h:451
geo::PlaneID DecodeCTP(CTP_t CTP)
float MCP_PFP_Cnt
Definition: TCTruth.h:64
unsigned short PDGCodeIndex(int PDGCode)
Definition: Utils.cxx:1908
std::vector< recob::Hit > const * allHits
Definition: DataStructs.h:536
std::string PrintPos(TCSlice &slc, const TrajPoint &tp)
Definition: Utils.cxx:5712
TCEvent evt
Definition: DataStructs.cxx:5
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:203
void PrintResults(int eventNum) const
Definition: TCTruth.cxx:364
std::array< unsigned short, 3 > TruVxCounts
Definition: TCTruth.h:78
float Prim_TSum
Definition: TCTruth.h:65