MatchingPerformance_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 // Class: MatchingPerformance
3 // Plugin Type: analyzer (art v2_11_02)
4 // File: MatchingPerformance_module.cc
5 //
6 // Generated 25 Sep 2020 by Leo Bellantoni
7 //
8 // For each reco track:
9 // Use backtracker to get matching MCparticles. Take charged & stable
10 // matching MCParticle with largest energy fraction for the track
11 // Only use MCParticles which go eventually into the ECAL?
12 // Use backtracker info to determine "starting" end of the track.
13 // Record chi-2 and NTPC clusters in the track (and other stuff)
14 // List all the clusters that match back to the MCParticle, and all
15 // that match to the track. Tabulate the number and energy sum
16 // For clusters on track & not MCParticle
17 // For clusters on MCParticle & not on track
18 // For clusters on both
19 //
20 ////////////////////////////////////////////////////////////////////////////////
21 
28 #include "art_root_io/TFileService.h"
30 #include "fhiclcpp/ParameterSet.h"
33 #include "canvas/Persistency/Common/FindOne.h"
34 #include "canvas/Persistency/Common/FindOneP.h"
35 #include "canvas/Persistency/Common/FindMany.h"
36 #include "canvas/Persistency/Common/FindManyP.h"
37 
38 #include "Geometry/GeometryGAr.h"
41 
43 #include "MCCheater/BackTracker.h"
45 #include "MCCheater/BackTracker.h"
49 
50 
51 #include "TH1D.h"
52 #include "TH2D.h"
53 #include "TTree.h"
54 #include "TDatabasePDG.h"
55 #include "TParticlePDG.h"
56 #include "Math/ProbFuncMathCore.h"
57 
58 #include <string>
59 #include <vector>
60 #include <unordered_map>
61 
62 
63 
64 
65 
66 namespace gar {
67 
69  public:
70  explicit MatchingPerformance(fhicl::ParameterSet const & p);
71  // The compiler-generated destructor is fine for non-base
72  // classes without bare pointers or other resource use.
73 
74  // Plugins should not be copied or assigned.
75  MatchingPerformance(MatchingPerformance const &) = delete;
79 
80  virtual void beginJob() override;
81 
82  // Required functions.
83  void analyze(art::Event const & e) override;
84 
85 
86 
87  private:
88  void ClearVectors();
89  bool FillVectors(art::Event const & e);
90 
91 
92 
93  // Position of TPC from geometry service; 1 S Boston Ave.
94  float ItsInTulsa[3];
95 
96  // Input data labels
101  std::string fInstanceLabelECAL; ///< Instance name for ECAL
102 
103  // the analysis tree
104  TTree *fTree;
105 
106  // Geometry service
108  // Backtracker service
110  // PDG database from ROOT
111  TDatabasePDG* pdgInstance;
112  // Detector properties
116 
117  // Keepin an eye on it all
119  int fClusterDirNhitCut; ///< Do not use cluster direction unless you have this many hits or more
120  float fMinPvalCut; ///< Do not analyse track fits with this pVal or less
121  TH1F* chargeFrac; ///< Fraction total ionization from theMCPart in any given track
122  float fMinIonFracCut; ///< Do not analyse track fits with low ionization fraction
123 
124 
125 
126  // The analysis tree. Use Rtypes.h here, as these data get used by root
127  // global event info
128  Int_t fRun;
129  Int_t fSubRun;
130  Int_t fEvent;
131 
132  // This analysis starts from reco'd tracks
133  std::vector<ULong64_t> fTrackIDNumber;
134  std::vector<Float_t> fTrackX;
135  std::vector<Float_t> fTrackY;
136  std::vector<Float_t> fTrackZ;
137  std::vector<Float_t> fTrackPX;
138  std::vector<Float_t> fTrackPY;
139  std::vector<Float_t> fTrackPZ;
140  std::vector<Float_t> fTrackPmag;
141  std::vector<Int_t> fTrackQ;
142  std::vector<Float_t> fTrackLen;
143  std::vector<Float_t> fTrackChi2;
144  std::vector<Int_t> fNTPCClustersOnTrack;
145  std::vector<Float_t> fTrackPval;
146  std::vector<Double_t> fTrackTime;
147 
148  // Which match to qualified MCParticles
149  std::vector<Int_t> fMCPDG;
150  std::vector<Int_t> fMCPDGMother;
151  std::vector<Float_t> fMCPStartX;
152  std::vector<Float_t> fMCPStartY;
153  std::vector<Float_t> fMCPStartZ;
154  std::vector<Float_t> fMCPStartPX;
155  std::vector<Float_t> fMCPStartPY;
156  std::vector<Float_t> fMCPStartPZ;
157  std::vector<Float_t> fMCPStartE;
158  std::vector<std::string> fMCPProc;
159  std::vector<std::string> fMCPEndProc;
160  std::vector<Float_t> fMCPTime;
161 
162  // Track - ECAL energy info
163  std::vector<Float_t> fEassocNoInTruth;
164  std::vector<Int_t> fNassocNoInTruth;
165  std::vector<Float_t> fEunassocInTruth;
166  std::vector<Int_t> fNunassocInTruth;
167  std::vector<Float_t> fEisassocInTruth;
168  std::vector<Int_t> fNisassocInTruth;
169 
170  // The matching variables here; they will have one entry for each
171  // cluster, for each "nice" track end; all other vectors here will
172  // have just one entry for each track
173  std::vector<Float_t> fRadClusTrackTru;
174  std::vector<Float_t> fRadClusTrackFal;
175  std::vector<Float_t> fXClusTrackOver25Tru;
176  std::vector<Float_t> fXClusTrackOver25Fal;
177  std::vector<Float_t> fXClusTrackUnder25Tru;
178  std::vector<Float_t> fXClusTrackUnder25Fal;
179  std::vector<Float_t> fRPhiClusTrackTru;
180  std::vector<Float_t> fRPhiClusTrackFal;
181  std::vector<Float_t> fDotClustTrackTru;
182  std::vector<Float_t> fDotClustTrackFal;
183  std::vector<Float_t> fDistClustTrackTru;
184  std::vector<Float_t> fDistClustTrackFal;
185  };
186 }
187 
188 
189 
190 
191 
192 //==============================================================================
193 //==============================================================================
194 //==============================================================================
196 
197  fGeantLabel = p.get<std::string>("GEANTLabel", "geant");
198  fTrackLabel = p.get<std::string>("TrackLabel", "track");
199  fClusterLabel = p.get<std::string>("ClusterLabel", "calocluster");
200  fECALAssnLabel = p.get<std::string>("ECALAssnLabel", "trkecalassn");
201  fInstanceLabelECAL = p.get<std::string>("InstanceLabelCalo","ECAL");
202  fVerbosity = p.get<int> ("Verbosity", 0);
203  fClusterDirNhitCut = p.get<int> ("ClusterDirNhitCut", 5);
204  fMinPvalCut = p.get<float> ("MinPvalCut", 0.0);
205  fMinIonFracCut = p.get<float> ("MinIonFracCut", 0.50);
206 
207  pdgInstance = TDatabasePDG::Instance();
208 
209  consumesMany<std::vector<simb::MCTruth> >();
210  consumes<std::vector<simb::MCParticle> >(fGeantLabel);
211  consumes<std::vector<rec::Track> >(fTrackLabel);
212  consumes<std::vector<rec::Cluster> >(fClusterLabel);
213  consumes<art::Assns<rec::Cluster, rec::Track>>(fECALAssnLabel);
214 
215  return;
216 } // end constructor
217 
218 
219 
220 
221 
222 //==============================================================================
223 //==============================================================================
224 //==============================================================================
226 
227  fGeo = gar::providerFrom<geo::GeometryGAr>();
228  ItsInTulsa[0] = fGeo->TPCXCent(); // 1 S Boston Ave
229  ItsInTulsa[1] = fGeo->TPCYCent();
230  ItsInTulsa[2] = fGeo->TPCZCent();
231 
232 
233 
235  fTree = tfs->make<TTree>("GArPerfTree","GArPerfTree");
236 
237  if (fVerbosity>0) {
238  chargeFrac = tfs->make<TH1F>("chargeFrac", "Fraction of MCPart's ionization in track",
239  101,0.00,1.01);
240  }
241 
242 
243 
244  fTree->Branch("Run", &fRun, "Run/I");
245  fTree->Branch("SubRun", &fSubRun, "SubRun/I");
246  fTree->Branch("Event", &fEvent, "Event/I");
247 
248  fTree->Branch("TrackIDNumber", &fTrackIDNumber);
249  fTree->Branch("TrackX", &fTrackX);
250  fTree->Branch("TrackY", &fTrackY);
251  fTree->Branch("TrackZ", &fTrackZ);
252  fTree->Branch("TrackPX", &fTrackPX);
253  fTree->Branch("TrackPY", &fTrackPY);
254  fTree->Branch("TrackPZ", &fTrackPZ);
255  fTree->Branch("TrackPmag", &fTrackPmag);
256  fTree->Branch("TrackQ", &fTrackQ);
257  fTree->Branch("TrackLen", &fTrackLen);
258  fTree->Branch("TrackChi2", &fTrackChi2);
259  fTree->Branch("NTPCClustersOnTrack", &fNTPCClustersOnTrack);
260  fTree->Branch("TrackPval", &fTrackPval);
261  fTree->Branch("TrackTime", &fTrackTime);
262 
263  fTree->Branch("PDG", &fMCPDG);
264  fTree->Branch("PDGMother", &fMCPDGMother);
265  fTree->Branch("MCPStartX", &fMCPStartX);
266  fTree->Branch("MCPStartY", &fMCPStartY);
267  fTree->Branch("MCPStartZ", &fMCPStartZ);
268  fTree->Branch("MCPStartPX", &fMCPStartPX);
269  fTree->Branch("MCPStartPY", &fMCPStartPY);
270  fTree->Branch("MCPStartPZ", &fMCPStartPZ);
271  fTree->Branch("MCPTime", &fMCPTime);
272 
273  fTree->Branch("EassocNoInTruth", &fEassocNoInTruth);
274  fTree->Branch("NassocNoInTruth", &fNassocNoInTruth);
275  fTree->Branch("EunassocInTruth", &fEunassocInTruth);
276  fTree->Branch("NunassocInTruth", &fNunassocInTruth);
277  fTree->Branch("EisassocInTruth", &fEisassocInTruth);
278  fTree->Branch("NisassocInTruth", &fNisassocInTruth);
279 
280  fTree->Branch("RadClusTrackTru", &fRadClusTrackTru);
281  fTree->Branch("RadClusTrackFal", &fRadClusTrackFal);
282  fTree->Branch("XClusTrackOver25Tru", &fXClusTrackOver25Tru);
283  fTree->Branch("XClusTrackOver25Fal", &fXClusTrackOver25Fal);
284  fTree->Branch("XClusTrackUnder25Tru", &fXClusTrackUnder25Tru);
285  fTree->Branch("XClusTrackUnder25Fal", &fXClusTrackUnder25Fal);
286  fTree->Branch("RPhiClusTrackTru", &fRPhiClusTrackTru);
287  fTree->Branch("RPhiClusTrackFal", &fRPhiClusTrackFal);
288  fTree->Branch("DotClustTrackTru", &fDotClustTrackTru);
289  fTree->Branch("DotClustTrackFal", &fDotClustTrackFal);
290  fTree->Branch("DistClustTrackTru", &fDistClustTrackTru);
291  fTree->Branch("DistClustTrackFal", &fDistClustTrackFal);
292  return;
293 } // End of :MatchingPerformance::beginJob
294 
295 
296 
297 
298 
299 //==============================================================================
300 //==============================================================================
301 //==============================================================================
303 
304  // Need this here because the clock service is invoked at preProcessEvent.
305  fDetProp = gar::providerFrom<detinfo::DetectorPropertiesService>();
306  fClocks = gar::providerFrom<detinfo::DetectorClocksServiceGAr>();
309  *fClocks->SpillLength();
310 
311  // Is the backtracker good to go? Need to fill fBack on per-event basis
312  // not in beginJob()
313  cheat::BackTrackerCore const* const_bt = gar::providerFrom<cheat::BackTracker>();
314  fBack = const_cast<cheat::BackTrackerCore*>(const_bt);
315  if ( !fBack->HasTracks() || !fBack->HasClusters() ) {
316  throw cet::exception("MatchingPerformance") << " Not enough backtracker info"
317  << " Line " << __LINE__ << " in file " << __FILE__ << std::endl;
318  }
319 
320  ClearVectors();
321  if ( FillVectors(event) ) {
322  fTree->Fill();
323  }
324 
325  return;
326 }
327 
328 
329 
330 
331 
332 //==============================================================================
333 //==============================================================================
334 //==============================================================================
336  // clear out all our vectors
337 
338  fTrackIDNumber.clear();
339  fTrackX.clear();
340  fTrackY.clear();
341  fTrackZ.clear();
342  fTrackPX.clear();
343  fTrackPY.clear();
344  fTrackPZ.clear();
345  fTrackPmag.clear();
346  fTrackQ.clear();
347  fTrackLen.clear();
348  fTrackChi2.clear();
349  fNTPCClustersOnTrack.clear();
350  fTrackPval.clear();
351  fTrackTime.clear();
352 
353  fMCPDG.clear();
354  fMCPDGMother.clear();
355  fMCPStartX.clear();
356  fMCPStartY.clear();
357  fMCPStartZ.clear();
358  fMCPStartPX.clear();
359  fMCPStartPY.clear();
360  fMCPStartPZ.clear();
361  fMCPTime.clear();
362 
363  fEassocNoInTruth.clear();
364  fNassocNoInTruth.clear();
365  fEunassocInTruth.clear();
366  fNunassocInTruth.clear();
367  fEisassocInTruth.clear();
368  fNisassocInTruth.clear();
369 
370  fRadClusTrackTru.clear();
371  fRadClusTrackFal.clear();
372  fXClusTrackOver25Tru.clear();
373  fXClusTrackOver25Fal.clear();
374  fXClusTrackUnder25Tru.clear();
375  fXClusTrackUnder25Fal.clear();
376  fRPhiClusTrackTru.clear();
377  fRPhiClusTrackFal.clear();
378  fDotClustTrackTru.clear();
379  fDotClustTrackFal.clear();
380  fDistClustTrackTru.clear();
381  fDistClustTrackFal.clear();
382 
383  return;
384 } // end :MatchingPerformance::ClearVectors
385 
386 
387 
388 
389 
390 //==============================================================================
391 //==============================================================================
392 //==============================================================================
394 
395  // ============= Get art handles ==========================================
396  // Get handles for Tracks, clusters, associations between them
397  auto TrackHandle = event.getHandle< std::vector<rec::Track> >(fTrackLabel);
398  if (!TrackHandle) {
399  throw cet::exception("MatchingPerformance") << " No rec::Track"
400  << " Line " << __LINE__ << " in file " << __FILE__ << std::endl;
401  }
402 
404  auto ClusterHandle = event.getHandle< std::vector<rec::Cluster> >(ecalclustertag);
405  if (!ClusterHandle) {
406  throw cet::exception("MatchingPerformance") << " No rec::Cluster branch."
407  << " Line " << __LINE__ << " in file " << __FILE__ << std::endl;
408  }
409 
410  art::FindMany<rec::Cluster, rec::TrackEnd>* findManyTrackEndCAL = NULL;
412  findManyTrackEndCAL = new art::FindMany<rec::Cluster, rec::TrackEnd>
413  (TrackHandle,event,ecalassntag);
414  if ( !findManyTrackEndCAL->isValid() ) {
415  throw cet::exception("MatchingPerformance") << " Bad TrackEnd-ECAL Assn."
416  << " Line " << __LINE__ << " in file " << __FILE__ << std::endl;
417  }
418 
419  // Get handles for MCinfo, also good for MCPTrajectory. Want to get all
420  // MCTruths, regardless of generator label.
421 
422  auto mctruthHandles = event.getMany<std::vector<simb::MCTruth> >();
423 
424  if (mctruthHandles.size()!=1) {
425  throw cet::exception("MatchingPerformance") << " Need just 1 simb::MCTruth"
426  << " Line " << __LINE__ << " in file " << __FILE__ << std::endl;
427  }
428 
429  auto MCPHandle = event.getHandle< std::vector<simb::MCParticle> >(fGeantLabel);
430  if (!MCPHandle) {
431  throw cet::exception("MatchingPerformance") << " No simb::MCParticle"
432  << " Line " << __LINE__ << " in file " << __FILE__ << std::endl;
433  }
434 
435 
436 
437  // Need something to look at!
438  if ( TrackHandle->size()==0 || ClusterHandle->size()==0 ) return false;
439 
440  // Make the usual map for the MC info
441  typedef int TrkId;
442  std::unordered_map<TrkId, Int_t> TrackIdToIndex;
443  Int_t index = 0;
444  for ( auto const& mcp : (*MCPHandle) ) {
445  int TrackId = mcp.TrackId();
446  TrackIdToIndex[TrackId] = index++;
447  }
448 
449  // Will need a vector of art::Ptrs to all the ECAL clusters for the
450  // backtracker calls.
451  std::vector<art::Ptr<rec::Cluster>> ClusterGrabber;
452  art::PtrMaker<rec::Cluster> makeClusterPtr(event,ClusterHandle.id());
453  for (size_t iCluster=0; iCluster<ClusterHandle->size(); ++iCluster) {
454  art::Ptr<rec::Cluster> aPtr = makeClusterPtr(iCluster);
455  ClusterGrabber.push_back(aPtr);
456  }
457  // Will need a vector<art::Ptr<rec::Track>> of tracks also
458  std::vector<art::Ptr<rec::Track>> TrackGrabber;
459  art::PtrMaker<rec::Track> makeTrackPtr(event,TrackHandle.id());
460  for (size_t iTrack=0; iTrack<TrackHandle->size(); ++iTrack) {
461  art::Ptr<rec::Track> aPtr = makeTrackPtr(iTrack);
462  TrackGrabber.push_back(aPtr);
463  }
464 
465 
466 
467 
468 
469  // ============= Pull art's handles =======================================
470  fRun = event.run();
471  fSubRun = event.subRun();
472  fEvent = event.id().event();
473 
474 
475 
476  // Require tracks match to right kind of MC first
477  struct niceNice {rec::Track recoTrk; simb::MCParticle simiTrk;};
478  std::vector<niceNice> niceTracks;
479  for ( auto const& track : (*TrackHandle) ) {
480 
481  /// Want to be able to know what you've matched back to at MCTruth
482  std::vector<std::pair<simb::MCParticle*,float>> MCsfromTrack;
483  gar::rec::Track* nonconst_track = const_cast<gar::rec::Track*>(&track);
484  MCsfromTrack = fBack->TrackToMCParticles(nonconst_track);
485  int nMCsfromTrack = MCsfromTrack.size();
486  if (nMCsfromTrack!=1) continue;
487 
488  simb::MCParticle theMCPart = *(MCsfromTrack[0].first);
489  TParticlePDG* particle = pdgInstance->GetParticle(theMCPart.PdgCode());
490  if (particle==NULL ) continue; // What causes this err? If anything.
491  if (particle->Charge()==0.0) continue;
492  if (particle->Stable()==0 ) continue;
493 
494  // Does theMCParticle go out to the ECAL?
495  int nTraj = theMCPart.NumberTrajectoryPoints();
496  TVector3 doink; bool whackThatECAL = false;
497  for (int iTraj=0; iTraj<nTraj; ++iTraj) {
498  doink.SetXYZ(theMCPart.Vx(iTraj),theMCPart.Vy(iTraj),theMCPart.Vz(iTraj));
499  if ( fGeo->PointInECALBarrel(doink) || fGeo->PointInECALEndcap(doink) ) {
500  whackThatECAL = true;
501  break;
502  }
503  }
504  if (!whackThatECAL) continue;
505 
506  // This track is nice
507  niceNice tmp = {track, theMCPart};
508  niceTracks.push_back(tmp);
509  }
510 
511 
512 
513  // Anti-stubbiness cut.
514  std::vector<niceNice>::iterator iNiceTrk=niceTracks.begin();
515  for (; iNiceTrk!=niceTracks.end(); ++iNiceTrk) {
516  simb::MCParticle theMCPart = iNiceTrk->simiTrk;
517  std::vector<art::Ptr<rec::Track>> tracksFromSameMCP =
518  fBack->MCParticleToTracks(&theMCPart,TrackGrabber);
519 
520  // Get ionization fraction for every track with contribution from this MCP
521  std::vector<float> ionzFromSameMCP; ionzFromSameMCP.resize(tracksFromSameMCP.size());
522  for (size_t iTrkFromSame=0; iTrkFromSame<tracksFromSameMCP.size(); ++iTrkFromSame) {
523  rec::Track tmpTrk = *(tracksFromSameMCP[iTrkFromSame]);
524  std::vector<art::Ptr<rec::Hit>> hitList = fBack->TrackToHits(&tmpTrk);
525  float thisTracksI = 0;
526  for (auto& ptrHit : hitList) thisTracksI += ptrHit->Signal();
527  ionzFromSameMCP[iTrkFromSame] = thisTracksI;
528  }
529  float ionzTotSameMCP = 0;
530  for (size_t iIonSame=0; iIonSame<ionzFromSameMCP.size(); ++iIonSame)
531  ionzTotSameMCP += ionzFromSameMCP[iIonSame];
532  for (size_t iIonSame=0; iIonSame<ionzFromSameMCP.size(); ++iIonSame) {
533  ionzFromSameMCP[iIonSame] /= ionzTotSameMCP;
534  if (fVerbosity>0) chargeFrac->Fill(ionzFromSameMCP[iIonSame]);
535  }
536 
537  // Cut on ion fraction in niceTracks
538  for (size_t iTrkFromSame=0; iTrkFromSame<tracksFromSameMCP.size(); ++iTrkFromSame) {
539  if ( *(tracksFromSameMCP[iTrkFromSame])==iNiceTrk->recoTrk
540  && ionzFromSameMCP[iTrkFromSame] <fMinIonFracCut) {
541  niceTracks.erase(iNiceTrk);
542  --iNiceTrk;
543  break;
544  }
545  }
546  }
547 
548 
549  iNiceTrk = niceTracks.begin();
550  std::vector<niceNice>::iterator jNiceTrk = iNiceTrk +1;
551  for (; iNiceTrk!=niceTracks.end(); ++iNiceTrk) {
552  for (; jNiceTrk!=niceTracks.end(); ++jNiceTrk) {
553  if ( iNiceTrk->simiTrk.TrackId() == jNiceTrk->simiTrk.TrackId() ){
554  niceTracks.erase(jNiceTrk);
555  --jNiceTrk;
556  }
557  }
558  }
559 
560 
561 
562  for (size_t iNiceTrk_local=0; iNiceTrk_local<niceTracks.size(); ++iNiceTrk_local) {
563  rec::Track track = niceTracks[iNiceTrk_local].recoTrk;
564  simb::MCParticle theMCPart = niceTracks[iNiceTrk_local].simiTrk;
565 
566 
567 
568  // Examine matched clusters on downstream ends of the track unless
569  // MC vertex in gas - don't test the matching quality then.
570  // Note: rec::TrackEndBeg is at the front of the deque here!
571  std::deque<rec::TrackEnd> endList = {rec::TrackEndBeg,rec::TrackEndEnd};
572 
573  TVector3 positionMCP = theMCPart.Position(0).Vect();
574  if (fGeo->PointInGArTPC(positionMCP)) {
575  // Pick the end where the particle ended.
576  // Don't include the drift distance in matching.
577  float distStart = std::hypot(track.Vertex()[1] -positionMCP[1],
578  track.Vertex()[2] -positionMCP[2]);
579  float distEnd = std::hypot(track.End()[1] -positionMCP[1],
580  track.End()[2] -positionMCP[2]);
581  if ( distStart < distEnd ) {
582  endList.pop_front();
583  } else {
584  endList.pop_back();
585  }
586  }
587 
588  // Having selected now the end we wil extrapolate,
589  std::deque<rec::TrackEnd>::iterator iEnd = endList.begin();
590  // Record info about the track at extrapolated end - need trackPar,
591  // TrackEnd later and they must be in MPD coordinates.
592  fTrackIDNumber.push_back(track.getIDNumber());
593  Float_t saveChi2;
594  float trackPar[5]; float trackEnd[3];
595 
596  if ( (*iEnd)==rec::TrackEndBeg ) {
597  for (size_t i=0; i<5; ++i) trackPar[i] = track.TrackParBeg()[i];
598  for (size_t i=0; i<3; ++i) trackEnd[i] = track.Vertex()[i];
599  fTrackX.push_back ( track.Vertex()[0] -ItsInTulsa[0] );
600  fTrackY.push_back ( track.Vertex()[1] -ItsInTulsa[1] );
601  fTrackZ.push_back ( track.Vertex()[2] -ItsInTulsa[2] );
602  fTrackPX.push_back (-track.Momentum_beg()*track.VtxDir()[0] );
603  fTrackPY.push_back (-track.Momentum_beg()*track.VtxDir()[1] );
604  fTrackPZ.push_back (-track.Momentum_beg()*track.VtxDir()[2] );
605  fTrackPmag.push_back( track.Momentum_beg() );
606  fTrackQ.push_back ( track.ChargeEnd() );
607  fTrackLen.push_back ( track.LengthBackward() );
608  saveChi2 = track.ChisqBackward();
609  fTrackChi2.push_back( saveChi2 );
610  } else {
611  for (size_t i=0; i<5; ++i) trackPar[i] = track.TrackParEnd()[i];
612  for (size_t i=0; i<3; ++i) trackEnd[i] = track.End()[i];
613  fTrackX.push_back ( track.End()[0] -ItsInTulsa[0] );
614  fTrackY.push_back ( track.End()[1] -ItsInTulsa[1] );
615  fTrackZ.push_back ( track.End()[2] -ItsInTulsa[2] );
616  fTrackPX.push_back (-track.Momentum_end()*track.EndDir()[0] );
617  fTrackPY.push_back (-track.Momentum_end()*track.EndDir()[1] );
618  fTrackPZ.push_back (-track.Momentum_end()*track.EndDir()[2] );
619  fTrackPmag.push_back( track.Momentum_end() );
620  fTrackQ.push_back ( track.ChargeBeg() );
621  fTrackLen.push_back ( track.LengthForward() );
622  saveChi2 = track.ChisqForward();
623  fTrackChi2.push_back( saveChi2);
624 
625  }
626 
627  // Apply the pVal cut
628  Int_t nHits = track.NHits();
629  fNTPCClustersOnTrack.push_back(nHits);
630  Float_t pVal = ROOT::Math::chisquared_cdf_c(saveChi2,nHits-5);
631  if (pVal <= fMinPvalCut) return false;
632  fTrackPval.push_back(pVal);
633  fTrackTime.push_back(track.Time());
634 
635  trackPar[0] -=ItsInTulsa[1]; trackPar[1] -=ItsInTulsa[2];
636  for (int i=0; i<3; ++i) trackEnd[i] -= ItsInTulsa[i];
637 
638  // Record some info about the matching MC
639  fMCPDG.push_back(theMCPart.PdgCode());
640  TrkId momTrkId = theMCPart.Mother();
641  int momPDG = 0;
642  if (momTrkId>0) {
643  int momIndex = TrackIdToIndex[momTrkId];
644  momPDG = (*MCPHandle).at(momIndex).PdgCode();
645  }
646  fMCPDGMother.push_back(momPDG);
647 
648  fMCPStartX.push_back(positionMCP.X());
649  fMCPStartY.push_back(positionMCP.Y());
650  fMCPStartZ.push_back(positionMCP.Z());
651  const TLorentzVector& momentumMCP = theMCPart.Momentum(0);
652  fMCPStartPX.push_back(momentumMCP.Px());
653  fMCPStartPY.push_back(momentumMCP.Py());
654  fMCPStartPZ.push_back(momentumMCP.Pz());
655  fMCPTime.push_back(theMCPart.T());
656 
657 
658 
659  // Now, look for the ECAL-track matching info
660  std::vector<rec::Cluster> clustersOnMCP;
661  for (rec::Cluster cluster : *ClusterHandle) {
662  if (fBack->MCParticleCreatedCluster(&theMCPart,&cluster)) {
663  clustersOnMCP.push_back(cluster);
664  }
665  if (fBack->ClusterCreatedMCParticle(&theMCPart,&cluster)) {
666  clustersOnMCP.push_back(cluster);
667  }
668  }
669 
670  // Because of how IsForebearOf works, the ionization in the cluster
671  // which is from theMCPart makes theMCPart both a parent and descendent
672  // of the MCParticles in the cluster. So we must remove duplicate
673  // clustersOnMCP, which means sorting them, which means we need a
674  // lambda function, etc.
675  std::sort(clustersOnMCP.begin(),clustersOnMCP.end(),
676  [](rec::Cluster a,rec::Cluster b){return a.getIDNumber() > b.getIDNumber();});
678  std::unique(clustersOnMCP.begin(),clustersOnMCP.end());
679  clustersOnMCP.resize(std::distance(clustersOnMCP.begin(),itr));
680 
681 
682 
683 
684  float eAssocNoInTruth = 0.0; int nAssocNoInTruth = 0;
685  float eUnassocInTruth = 0.0; int nUnassocInTruth = 0;
686  float eIsassocInTruth = 0.0; int nIsassocInTruth = 0;
687  size_t nCALedClusts = 0;
688  std::vector<rec::Cluster const*> clustersFromAssn;
689  std::vector<rec::TrackEnd const*> trackEndsFromAssn;
690 
691  // The art::FindMany object findManyTrackEndCAL is indexed over
692  // all the tracks in *TrackHandle (which is bigger than niceTracks).
693  size_t iTrack=0;
694  for (; iTrack<TrackHandle->size(); ++iTrack) {
695  if ( (*TrackHandle)[iTrack] == track ) break;
696  }
697 
698  // nCALedClusts.size() == trackEndsFromAssn.size() and is the same
699  // number regardless of std::deque<rec::TrackEnd>::iterator iEnd but
700  // the code reads better here
701  findManyTrackEndCAL->get(iTrack, clustersFromAssn,trackEndsFromAssn);
702  nCALedClusts = clustersFromAssn.size();
703 
704  for ( auto const& cluster : (*ClusterHandle) ) {
705 
706  // recompute the matching variables, similar to (if not exactly
707  // the same as) in Reco/TPCECALAssociation_module.cc They will be:
708  // inECALBarrel, distRadially, Over25, cutQuantity, dotSee
709  float radius = 1.0/trackPar[2];
710  float zCent = trackPar[1] - radius*sin(trackPar[3]);
711  float yCent = trackPar[0] + radius*cos(trackPar[3]);
712  float xClus = cluster.Position()[0] -ItsInTulsa[0];
713  float yClus = cluster.Position()[1] -ItsInTulsa[1];
714  float zClus = cluster.Position()[2] -ItsInTulsa[2];
715  float rClus = std::hypot(zClus,yClus);
716  bool inECALBarrel = fGeo->PointInECALBarrel(cluster.Position());
717 
718  float distRadially = std::hypot(zClus-zCent,yClus-yCent) -abs(radius);
719  distRadially = abs(distRadially);
720 
721  float retXYZ1[3]; float retXYZ2[3]; TVector3 trackXYZ;
722  float cutQuantity = -1.0; bool over25 = false;
723 
724  if (inECALBarrel) {
726  trackPar,trackEnd,rClus, 0.0, 0.0, retXYZ1,retXYZ2);
727  if ( errcode==0 ) {
728  float extrapXerr;
729  float transDist1 = std::hypot(retXYZ1[2]-zClus,retXYZ1[1]-yClus);
730  float transDist2 = std::hypot(retXYZ2[2]-zClus,retXYZ2[1]-yClus);
731  bool looneyExtrap;
732  if (transDist1<transDist2) {
733  trackXYZ.SetXYZ(retXYZ1[0],retXYZ1[1],retXYZ1[2]);
734  } else {
735  trackXYZ.SetXYZ(retXYZ2[0],retXYZ2[1],retXYZ2[2]);
736  }
737  trackXYZ += TVector3(ItsInTulsa);
738  looneyExtrap = !fGeo->PointInECALBarrel(trackXYZ)
739  && !fGeo->PointInECALEndcap(trackXYZ);
740  trackXYZ -= TVector3(ItsInTulsa);
741  if (!looneyExtrap) {
742  extrapXerr = trackXYZ.X() -xClus;
743  float expected_mean = 0;
744  if (trackEnd[0]<-25) {
745  expected_mean = +fMaxXdisplacement/2.0;
746  over25 = true;
747  }
748  if (trackEnd[0]>+25) {
749  expected_mean = -fMaxXdisplacement/2.0;
750  over25 = true;
751  }
752  cutQuantity = abs(extrapXerr -expected_mean);
753  }
754  }
755  } else {
756  // In an endcap. How many radians in a fMaxXdisplacement?
757  float radiansInDrift = trackPar[2]*fMaxXdisplacement
758  / tan(trackPar[4]);
759  if ( abs(radiansInDrift) >= 2.0*M_PI ) goto angleCut;
761  trackPar,trackEnd, xClus, retXYZ1);
762  if ( errcode==0 ) {
763  trackXYZ.SetXYZ(retXYZ1[0],retXYZ1[1],retXYZ1[2]);
764  trackXYZ += TVector3(ItsInTulsa);
765  bool looneyExtrap = !fGeo->PointInECALBarrel(trackXYZ)
766  && !fGeo->PointInECALEndcap(trackXYZ);
767  trackXYZ -= TVector3(ItsInTulsa);
768  if (!looneyExtrap) {
769 
770  float angClus = std::atan2(yClus-yCent,zClus-zCent);
771  float angXtrap = std::atan2(retXYZ1[1] -yCent,retXYZ1[2] -zCent) -angClus;
772  // angXtrap can indeed be outside of -PI to +PI
773  if (angXtrap > +M_PI) angXtrap -= 2.0*M_PI;
774  if (angXtrap < -M_PI) angXtrap += 2.0*M_PI;
775  cutQuantity = abs(radius*angXtrap);
776  }
777  }
778  }
779 
780  angleCut:
781  float trackDir[3];
782  float dotSee = -2.0;
783  int nCells = cluster.CalorimeterHits().size();
784  if (nCells >= fClusterDirNhitCut) {
785  float xEval = trackXYZ.x(); // Ya not the cluster X
786  int errcode = util::TrackPropagator::DirectionX(
787  trackPar,trackEnd, xEval,trackDir);
788  if (errcode==0) {
789  TVector3 clusterDir;
790  clusterDir.SetXYZ(cluster.EigenVectors()[0],
791  cluster.EigenVectors()[1],cluster.EigenVectors()[2]);
792  dotSee = clusterDir.Dot(trackDir);
793  }
794  }
795 
796  // Look at distance from extrapolated track to cluster.
797  float dist3dXtrap = std::hypot(
798  trackXYZ.x()-xClus, trackXYZ.y()-yClus, trackXYZ.z()-zClus);
799 
800 
801 
802  bool clusterOnTrack = false;
803  for (size_t iCALedClust=0; iCALedClust<nCALedClusts; ++iCALedClust) {
804  if (*trackEndsFromAssn[iCALedClust] != (*iEnd) ) continue;
805  if (*clustersFromAssn[iCALedClust] == cluster) {
806  clusterOnTrack = true;
807  break;
808  }
809  }
810 
811  bool clusterOnMCP = false;
812  for (size_t iClusOnMCP = 0; iClusOnMCP<clustersOnMCP.size(); ++iClusOnMCP) {
813  if ( clustersOnMCP[iClusOnMCP] == cluster ) {
814  clusterOnMCP = true;
815  break;
816  }
817  }
818 
819 
820 
821 
822  if (!clusterOnMCP ) {
823  fRadClusTrackFal.push_back(distRadially);
824  if (inECALBarrel) {
825  if (over25) {
826  fXClusTrackOver25Fal.push_back(cutQuantity);
827  } else {
828  fXClusTrackUnder25Fal.push_back(cutQuantity);
829  }
830  } else {
831  fRPhiClusTrackFal.push_back(cutQuantity);
832  }
833  fDotClustTrackFal.push_back(dotSee);
834  fDistClustTrackFal.push_back(dist3dXtrap);
835 
836  if ( clusterOnTrack ) {
837  eAssocNoInTruth += cluster.Energy();
838  nAssocNoInTruth += cluster.CalorimeterHits().size();
839  }
840  } else {
841  fRadClusTrackTru.push_back(distRadially);
842  if (inECALBarrel) {
843  if (over25) {
844  fXClusTrackOver25Tru.push_back(cutQuantity);
845  } else {
846  fXClusTrackUnder25Tru.push_back(cutQuantity);
847  }
848  } else {
849  fRPhiClusTrackTru.push_back(cutQuantity);
850  }
851  fDotClustTrackTru.push_back(dotSee);
852  fDistClustTrackTru.push_back(dist3dXtrap);
853 
854  if (!clusterOnTrack && clusterOnMCP ) {
855  eUnassocInTruth += cluster.Energy();
856  nUnassocInTruth += cluster.CalorimeterHits().size();
857  } else {
858  eIsassocInTruth += cluster.Energy();
859  nIsassocInTruth += cluster.CalorimeterHits().size();
860  }
861  }
862  }
863 
864  fEassocNoInTruth.push_back(eAssocNoInTruth);
865  fNassocNoInTruth.push_back(nAssocNoInTruth);
866  fEunassocInTruth.push_back(eUnassocInTruth);
867  fNunassocInTruth.push_back(nUnassocInTruth);
868  fEisassocInTruth.push_back(eIsassocInTruth);
869  fNisassocInTruth.push_back(nIsassocInTruth);
870 
871  } // end loop over TrackHandle
872 
873  return true;
874 } // end MatchingPerformance::FillVectors
875 
876 
void analyze(art::Event const &e) override
intermediate_table::iterator iterator
float const & Momentum_beg() const
Definition: Track.h:146
unsigned int NumberTrajectoryPoints() const
Definition: MCParticle.h:218
const TLorentzVector & Position(const int i=0) const
Definition: MCParticle.h:219
TH1F * chargeFrac
Fraction total ionization from theMCPart in any given track.
int PdgCode() const
Definition: MCParticle.h:212
std::vector< std::string > fMCPProc
std::vector< art::Ptr< rec::Track > > MCParticleToTracks(simb::MCParticle *const p, std::vector< art::Ptr< rec::Track >> const &tracks)
std::vector< Float_t > fXClusTrackOver25Tru
std::vector< art::Ptr< rec::Hit > > const TrackToHits(rec::Track *const t)
std::string fInstanceLabelECAL
Instance name for ECAL.
const float * TrackParBeg() const
Definition: Track.h:151
std::vector< Float_t > fXClusTrackUnder25Fal
std::vector< std::string > fMCPEndProc
std::string string
Definition: nybbler.cc:12
bool PointInECALEndcap(TVector3 const &point) const
std::vector< Float_t > fDotClustTrackFal
const detinfo::DetectorClocks * fClocks
int Mother() const
Definition: MCParticle.h:213
bool PointInGArTPC(TVector3 const &point) const
bool MCParticleCreatedCluster(simb::MCParticle *const p, rec::Cluster *const c)
float TPCXCent() const
Returns the X location of the center of the TPC in cm.
Definition: GeometryCore.h:778
Description of geometry of one entire detector.
Definition: GeometryCore.h:436
std::vector< Float_t > fEassocNoInTruth
float const & LengthBackward() const
Definition: Track.h:145
Cluster finding and building.
TrackEnd const TrackEndEnd
Definition: Track.h:33
MatchingPerformance & operator=(MatchingPerformance const &)=delete
EDAnalyzer(fhicl::ParameterSet const &pset)
Definition: EDAnalyzer.h:25
const detinfo::DetectorProperties * fDetProp
Particle class.
std::vector< Float_t > fDistClustTrackFal
float const & ChisqBackward() const
Definition: Track.h:149
std::enable_if_t< std::is_arithmetic_v< T >, T > hypot(T x, T y)
Definition: hypot.h:60
const float * VtxDir() const
Definition: Track.h:141
std::vector< Int_t > fNTPCClustersOnTrack
double const & Time() const
Definition: Track.h:155
virtual double Efield(unsigned int planegap=0) const =0
Returns the nominal electric field in the specified volume.
T abs(T value)
std::vector< Float_t > fRPhiClusTrackTru
float const & LengthForward() const
Definition: Track.h:144
const double e
const float * Vertex() const
Definition: Track.h:139
int ChargeEnd() const
Definition: Track.cxx:236
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
std::vector< ULong64_t > fTrackIDNumber
const double a
int ChargeBeg() const
Definition: Track.cxx:229
T get(std::string const &key) const
Definition: ParameterSet.h:271
float fMinIonFracCut
Do not analyse track fits with low ionization fraction.
static int PropagateToX(const float *trackpar, const float *Xpoint, const float x, float *retXYZ, const float Rmax=0.0)
double T(const int i=0) const
Definition: MCParticle.h:224
const gar::geo::GeometryCore * fGeo
gar::rec::IDNumber getIDNumber() const
Definition: Cluster.cxx:106
std::vector< Float_t > fRPhiClusTrackFal
p
Definition: test.py:223
const float * TrackParEnd() const
Definition: Track.h:152
float TPCZCent() const
Returns the Z location of the center of the TPC in cm.
Definition: GeometryCore.h:792
static int PropagateToCylinder(const float *trackpar, const float *Xpoint, const float rCyl, const float yCyl, const float zCyl, float *retXYZ1, float *retXYZ2, const float Xmax=0.0, const float epsilon=2.0e-5)
std::vector< Double_t > fTrackTime
string tmp
Definition: languages.py:63
bool PointInECALBarrel(TVector3 const &point) const
double distance(double x1, double y1, double z1, double x2, double y2, double z2)
std::vector< Float_t > fXClusTrackUnder25Tru
virtual double Temperature() const =0
float const & ChisqForward() const
Definition: Track.h:148
const float * End() const
Definition: Track.h:140
bool ClusterCreatedMCParticle(simb::MCParticle *const p, rec::Cluster *const c)
std::vector< Float_t > fXClusTrackOver25Fal
Interface to propagate a Track to the specific point.
#define M_PI
Definition: includeROOT.h:54
General GArSoft Utilities.
double Vx(const int i=0) const
Definition: MCParticle.h:221
float fMinPvalCut
Do not analyse track fits with this pVal or less.
TrackEnd const TrackEndBeg
Definition: Track.h:33
std::vector< Float_t > fDistClustTrackTru
float TPCYCent() const
Returns the Y location of the center of the TPC in cm.
Definition: GeometryCore.h:785
std::vector< std::pair< simb::MCParticle *, float > > TrackToMCParticles(rec::Track *const t)
static int DirectionX(const float *trackpar, const float *Xpoint, float &xEval, float *retXYZ)
const TLorentzVector & Momentum(const int i=0) const
Definition: MCParticle.h:220
double Vz(const int i=0) const
Definition: MCParticle.h:223
std::vector< Float_t > fEunassocInTruth
static bool * b
Definition: config.cpp:1043
float const & Momentum_end() const
Definition: Track.h:147
size_t const & NHits() const
Definition: Track.h:150
bool FillVectors(art::Event const &e)
MatchingPerformance(fhicl::ParameterSet const &p)
gar::rec::IDNumber getIDNumber() const
Definition: Track.cxx:42
std::vector< Float_t > fDotClustTrackTru
virtual double DriftVelocity(double efield=0., double temperature=0., bool cmPerns=true) const =0
std::vector< Float_t > fEisassocInTruth
art framework interface to geometry description
std::vector< Float_t > fRadClusTrackFal
Definition: fwd.h:31
double Vy(const int i=0) const
Definition: MCParticle.h:222
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
QTextStream & endl(QTextStream &s)
Event finding and building.
int fClusterDirNhitCut
Do not use cluster direction unless you have this many hits or more.
std::vector< Float_t > fRadClusTrackTru
const float * EndDir() const
Definition: Track.h:142