TPCECALAssociation_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: TPCECALAssociation
3 // Plugin Type: producer (art v2_11_02)
4 // File: TPCECALAssociation_module.cc
5 //
6 ////////////////////////////////////////////////////////////////////////
7 
15 
18 #include "fhiclcpp/ParameterSet.h"
20 
21 #include "Geometry/GeometryGAr.h"
24 
28 
29 #include "art_root_io/TFileService.h"
30 #include "TH2D.h"
31 
32 
33 
34 namespace gar {
35  namespace rec {
36 
37 
38 
40  public:
41  explicit TPCECALAssociation(fhicl::ParameterSet const & p);
42  // The compiler-generated destructor is fine for non-base
43  // classes without bare pointers or other resource use.
44 
45  // Plugins should not be copied or assigned.
46  TPCECALAssociation(TPCECALAssociation const &) = delete;
50 
51  // Required functions.
52  void beginJob() override;
53  void produce(art::Event & e) override;
54 
55  private:
56 
57  // Declare member data here.
58  std::string fTrackLabel; ///< label to find the reco tracks
59  std::string fClusterLabel; ///< label to find the right reco caloclusters
62  float fTrackEndXCut; ///< Extrapolate only track ends outside central drift
63  float fTrackEndRCut; ///< Extrapolate only track ends outside central region
64  float fPerpRCut; ///< Max dist cluster center to circle of track (z,y) only
65  float fBarrelXCut; ///< Max dist cluster center (drift time compensated) track in x
66  float fEndcapRphiCut; ///< Max dist cluster center (drift time compensated) track in r*phi
67  float fClusterDirNhitCut; ///< Do not cut on cluster direction unless you have this many hits or more
68  float fClusterDirCut; ///< Min cos angle between extrapolated track and cluster direction
69 
70  const detinfo::DetectorProperties* fDetProp; ///< detector properties
71  const detinfo::DetectorClocks* fClocks; ///< detector clock information
72  const geo::GeometryCore* fGeo; ///< pointer to the geometry
74 
75  // Position of TPC from geometry service; 1 S Boston Ave.
76  float ItsInTulsa[3];
77 
78  TH1F* radClusTrack; ///< Cluster to track in transverse plane
79  TH2F* xClusTrack; ///< Cluster to track in barrel, x only, vs x of trackend
80  TH1F* phiClusTrack; ///< Cluster to track in endcap
82  TH2F* dotClustTrack; ///< cos(cluster axis to extrapolated track)
83  TH1F* nEntryVsCut; ///< Number passing each cut
84  };
85 
86 
87 
89 
90  fTrackLabel = p.get<std::string>("TrackLabel", "track");
91  fClusterLabel = p.get<std::string>("ClusterLabel","calocluster");
92  fInstanceName = p.get<std::string>("InstanceName","");
93  fVerbosity = p.get<int>("Verbosity", 0);
94  // Needs to be computed in produce; so will be 0.0 to do that
95  // otherwise of course the fcl file value appears
96  fTrackEndXCut = p.get<float>("TrackEndXCut", 215.0);
97  fTrackEndRCut = p.get<float>("TrackEndRCut", 230.0);
98  fPerpRCut = p.get<float>("PerpRCut", 10.0);
99  fBarrelXCut = p.get<float>("BarrelXCut", 10.0);
100  fEndcapRphiCut = p.get<float>("EndXCut", 10.0);
101  fClusterDirNhitCut = p.get<int> ("ClusterDirNhitCut", 5);
102  fClusterDirCut = p.get<float>("ClusterDirCut", 0.40);
103  fDetProp = gar::providerFrom<detinfo::DetectorPropertiesService>();
104  fClocks = gar::providerFrom<detinfo::DetectorClocksServiceGAr>();
105  fGeo = gar::providerFrom<geo::GeometryGAr>();
106 
107  produces< art::Assns<gar::rec::Cluster, gar::rec::Track, gar::rec::TrackEnd > >(fInstanceName);
108  }
109 
110 
111 
113 
114  ItsInTulsa[0] = fGeo->TPCXCent();
115  ItsInTulsa[1] = fGeo->TPCYCent();
116  ItsInTulsa[2] = fGeo->TPCZCent();
117 
118  if (fVerbosity>0) {
120  radClusTrack = tfs->make<TH1F>("radClusTrack",
121  "(z,y) distance from cluster to track", 100, 0.0,60.0);
122  xClusTrack = tfs->make<TH2F>("xClusTrack",
123  "x of track minus x of cluster vs x position of track end in barrel",
124  100,-250.0,+250.0, 100,-200.0,+200.0);
125  phiClusTrack = tfs->make<TH1F>("phiClusTrack",
126  "angular distance from cluster to track in endcap", 90,-M_PI,+M_PI);
127  rPhiClusTrack = tfs->make<TH1F>("rPhiClusTrack",
128  "distance from cluster to track in endcap", 100,-100.0,+100.0);
129  dotClustTrack = tfs->make<TH2F>("dotClustTrack",
130  "No hits in cluster vs dot product of cluster axis to extrapolated track direction",
131  100,-1.0,+1.0, 100,0.5,100.5);
132  nEntryVsCut = tfs->make<TH1F>("nEntryVsCut",
133  "Number track end & cluster combos vs sequentially applied cut", 36, -0.5, 35.5);
134  }
135  }
136 
137 
138 
140 
141  // Get tracks and clusters. If either is missing, just skip this event
142  // processing. That's not an exception
143 
145  auto ClusterHandle = e.getHandle< std::vector<gar::rec::Cluster> >(itag);
146  if (!ClusterHandle) return;
147 
148  auto TrackHandle = e.getHandle< std::vector<gar::rec::Track> >(fTrackLabel);
149  if (!TrackHandle) return;
150 
151  // fClocks service provides this info on event-by-event basis not at beginJob.
153  *fClocks->SpillLength();
154 
155  // Here are the associations
156  std::unique_ptr<art::Assns<gar::rec::Cluster, gar::rec::Track, gar::rec::TrackEnd>>
158  auto const clusterPtrMaker = art::PtrMaker<rec::Cluster>(e, ClusterHandle.id());
159  auto const trackPtrMaker = art::PtrMaker<rec::Track> (e, TrackHandle.id());
160  // Here are some intermediate info needed because both ends of a track might
161  // be associated to a cluster and that ain't rite!
162  std::vector<art::Ptr<gar::rec::Track>> candTrack;
163  std::vector<gar::rec::TrackEnd> candEnd;
164  std::vector<float> candDist;
165 
166 
167  for (size_t iCluster=0; iCluster<ClusterHandle->size(); ++iCluster) {
168  gar::rec::Cluster cluster = (*ClusterHandle)[iCluster];
169  TVector3 clusterCenter(cluster.Position());
170  bool inECALBarrel = fGeo->PointInECALBarrel(clusterCenter);
171  // fGeo uses one coordinate system, this code uses another.
172  clusterCenter -=ItsInTulsa;
173  float yClus = clusterCenter[1];
174  float zClus = clusterCenter[2];
175  float rClus = std::hypot(zClus,yClus);
176  float xClus = clusterCenter[0];
177 
178  for (size_t iTrack=0; iTrack<TrackHandle->size(); ++iTrack) {
179  gar::rec::Track track = (*TrackHandle)[iTrack];
180 
181  // Which if any ends of the track are near the outer edges of the TPC?
182  bool outside[2]; outside[0] = outside[1] = false;
183  candTrack.clear(); candEnd.clear(); candDist.clear();
184 
185  if ( abs(track.Vertex()[0] -ItsInTulsa[0]) > fTrackEndXCut ||
186  std::hypot(track.Vertex()[1] -ItsInTulsa[1],
187  track.Vertex()[2] -ItsInTulsa[2]) > fTrackEndRCut ) {
188  outside[TrackEndBeg] = true;
189  }
190  if ( abs(track.End()[0] -ItsInTulsa[0]) > fTrackEndXCut ||
191  std::hypot(track.End()[1] -ItsInTulsa[1],
192  track.End()[2] -ItsInTulsa[2]) > fTrackEndRCut ) {
193  outside[TrackEndEnd] = true;
194  }
195 
196  // Plot and cut on the distance of cluster to helix in transverse plane.
197  for (gar::rec::TrackEnd iEnd = TrackEndBeg; iEnd >= TrackEndEnd; --iEnd) {
198  if (fVerbosity>0) nEntryVsCut->Fill(0);
199 
200  if (outside[iEnd]) {
201  if (fVerbosity>0) nEntryVsCut->Fill(1);
202 
203  float trackPar[5]; float trackEnd[3];
204  if (iEnd==TrackEndBeg) {
205  for (int i=0; i<5; ++i) trackPar[i] = track.TrackParBeg()[i];
206  for (int i=0; i<3; ++i) trackEnd[i] = track.Vertex()[i];
207  } else {
208  for (int i=0; i<5; ++i) trackPar[i] = track.TrackParEnd()[i];
209  for (int i=0; i<3; ++i) trackEnd[i] = track.End()[i];
210  }
211  // Translate to the center-of-MPD coordinate system
212  trackPar[0] -=ItsInTulsa[1]; trackPar[1] -=ItsInTulsa[2];
213  for (int i=0; i<3; ++i) trackEnd[i] -= ItsInTulsa[i];
214  float radius = 1.0/trackPar[2];
215  float zCent = trackPar[1] - radius*sin(trackPar[3]);
216  float yCent = trackPar[0] + radius*cos(trackPar[3]);
217 
218  float distRadially = std::hypot(zClus-zCent,yClus-yCent) -abs(radius);
219  distRadially = abs(distRadially);
220  if (fVerbosity>0) radClusTrack->Fill( distRadially );
221 
222  if ( distRadially > fPerpRCut ) {
223  // This track-cluster match fails
224  continue;
225  }
226  if (fVerbosity>0) nEntryVsCut->Fill(2);
227 
228  // Require plausible extrapolation in x as well
229  float retXYZ1[3]; float retXYZ2[3];
230  TVector3 trackXYZ;
231  if (inECALBarrel) {
232  if (fVerbosity>0) nEntryVsCut->Fill(10);
233 
234  // Extrapolate track to that radius. Using MPD center coords.
236  trackPar,trackEnd,rClus, 0.0, 0.0, retXYZ1,retXYZ2);
237  if ( errcode!=0 ) {
238  // This track-cluster match fails. Error code 1, there is
239  // no intersection at all, is possible
240  continue;
241  }
242  if (fVerbosity>0) nEntryVsCut->Fill(11);
243  float extrapXerr;
244  float transDist1 = std::hypot(retXYZ1[2]-zClus,retXYZ1[1]-yClus);
245  float transDist2 = std::hypot(retXYZ2[2]-zClus,retXYZ2[1]-yClus);
246  bool looneyExtrap;
247  if (transDist1<transDist2) {
248  trackXYZ.SetXYZ(retXYZ1[0],retXYZ1[1],retXYZ1[2]);
249  } else {
250  trackXYZ.SetXYZ(retXYZ2[0],retXYZ2[1],retXYZ2[2]);
251  }
252  trackXYZ += TVector3(ItsInTulsa);
253  looneyExtrap = !fGeo->PointInECALBarrel(trackXYZ)
254  && !fGeo->PointInECALEndcap(trackXYZ);
255  if (looneyExtrap) continue;
256  if (fVerbosity>0) nEntryVsCut->Fill(12);
257  trackXYZ -= TVector3(ItsInTulsa);
258 
259  extrapXerr = trackXYZ.X() -xClus;
260  if (fVerbosity>0) xClusTrack->Fill(trackEnd[0], extrapXerr);
261  // extrapXerr is roughly maxXdisplacement/2 for trackend at
262  // x < -25cm and -maxXdisplacement/2 for trackend at x > 25cm.
263  float expected_mean = 0;
264  if (trackEnd[0]<-25) expected_mean = +maxXdisplacement/2.0;
265  if (trackEnd[0]>+25) expected_mean = -maxXdisplacement/2.0;
266  float cutQuantity = extrapXerr -expected_mean;
267  if ( abs(cutQuantity) > maxXdisplacement/2.0+fBarrelXCut ) {
268  continue;
269  }
270  if (fVerbosity>0) nEntryVsCut->Fill(13);
271 
272  } else {
273  if (fVerbosity>0) nEntryVsCut->Fill(20);
274 
275  // In an endcap. How many radians in a maxXdisplacement?
276  float radiansInDrift = trackPar[2]*maxXdisplacement
277  / tan(trackPar[4]);
278  if ( abs(radiansInDrift) >= 2.0*M_PI ) {
279  // Drat! No distinguishing power here. So we
280  // count it as associated
281  goto angleCut;
282  }
283  if (fVerbosity>0) nEntryVsCut->Fill(21);
284 
286  trackPar,trackEnd, xClus, retXYZ1);
287  if ( errcode!=0 ) {
288  // This track-cluster match fails.
289  continue;
290  }
291  if (fVerbosity>0) nEntryVsCut->Fill(22);
292  trackXYZ.SetXYZ(retXYZ1[0],retXYZ1[1],retXYZ1[2]);
293  trackXYZ += TVector3(ItsInTulsa);
294  bool looneyExtrap = !fGeo->PointInECALBarrel(trackXYZ)
295  && !fGeo->PointInECALEndcap(trackXYZ);
296  if (looneyExtrap) continue;
297  if (fVerbosity>0) nEntryVsCut->Fill(23);
298  trackXYZ -= TVector3(ItsInTulsa);
299 
300  // Find how many radians the closest point on the propagated
301  // track is from the cluster along the helix, projected onto
302  // to the perpendicular plane. (bound to -pi,+pi range)
303  float angClus = std::atan2(yClus-yCent,zClus-zCent);
304  float angXtrap = std::atan2(retXYZ1[1] -yCent,retXYZ1[2] -zCent) -angClus;
305  // angXtrap can indeed be outside of -PI to +PI
306  if (angXtrap > +M_PI) angXtrap -= 2.0*M_PI;
307  if (angXtrap < -M_PI) angXtrap += 2.0*M_PI;
308  if (fVerbosity>0) phiClusTrack->Fill(angXtrap);
309  float extrapRphiErr = abs(radius)*angXtrap;
310  if (fVerbosity>0) rPhiClusTrack->Fill(extrapRphiErr);
311  if (abs(extrapRphiErr) > fEndcapRphiCut) {
312  continue;
313  }
314  if (fVerbosity>0) nEntryVsCut->Fill(24);
315  }
316 
317  angleCut:
318  float trackDir[3];
319  float xEval = trackXYZ.x(); // Ya not the cluster X
320  int errcode = util::TrackPropagator::DirectionX(
321  trackPar,trackEnd, xEval,trackDir);
322  if (fVerbosity>0) nEntryVsCut->Fill(30);
323  if (errcode!=0) {
324  // Unlikely but possible condition
325  continue;
326  }
327  if (fVerbosity>0) nEntryVsCut->Fill(31);
328  TVector3 clusterDir;
329  clusterDir.SetXYZ(cluster.EigenVectors()[0],
330  cluster.EigenVectors()[1],cluster.EigenVectors()[2]);
331  float dotSee = clusterDir.Dot(trackDir);
332  int nCells = cluster.CalorimeterHits().size();
333  dotClustTrack->Fill(dotSee,nCells);
334  if (nCells>=fClusterDirNhitCut && dotSee<fClusterDirCut) continue;
335  if (fVerbosity>0) nEntryVsCut->Fill(32);
336 
337 
338 
339  // Save the cluster-track association candidate
340  art::Ptr<gar::rec::Track> const trackPtr = trackPtrMaker(iTrack);
341  candTrack.push_back(trackPtr);
342  candEnd.push_back(iEnd);
343  float howFar = std::hypot(trackXYZ.x() -xClus, trackXYZ.y() -yClus, trackXYZ.z() -zClus);
344  candDist.push_back(howFar);
345  }
346  } // end loop over 2 ends of track
347 
348  // Pick which, if either, end of the track to match
349  if (candEnd.size()==0) continue;
350  art::Ptr<gar::rec::Track> trackPtrBest = candTrack[0];
351  gar::rec::TrackEnd candEndBest = candEnd[0];
352  if (candEnd.size()==2) {
353  if (candDist[0]>candDist[1]) {
354  trackPtrBest = candTrack[1];
355  candEndBest = candEnd[1];
356  }
357  }
358  art::Ptr<gar::rec::Cluster> const clusterPtr = clusterPtrMaker(iCluster);
359  ClusterTrackAssns->addSingle(clusterPtr,trackPtrBest,candEndBest);
360  }
361  } // end loop over clusters
362 
363  e.put(std::move(ClusterTrackAssns), fInstanceName);
364  return;
365  }
366 
367 
368 
370 
371  } // namespace rec
372 } // namespace gar
rec
Definition: tracks.py:88
TH2F * xClusTrack
Cluster to track in barrel, x only, vs x of trackend.
int TrackEnd
Definition: Track.h:32
const float * TrackParBeg() const
Definition: Track.h:151
const detinfo::DetectorProperties * fDetProp
detector properties
Handle< PROD > getHandle(SelectorBase const &) const
Definition: DataViewImpl.h:382
std::string string
Definition: nybbler.cc:12
bool PointInECALEndcap(TVector3 const &point) const
virtual double SpillLength() const =0
Duration of spill [ns].
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.h:20
float fTrackEndRCut
Extrapolate only track ends outside central region.
TH1F * nEntryVsCut
Number passing each cut.
float TPCXCent() const
Returns the X location of the center of the TPC in cm.
Definition: GeometryCore.h:778
TH1F * radClusTrack
Cluster to track in transverse plane.
const detinfo::DetectorClocks * fClocks
detector clock information
float fBarrelXCut
Max dist cluster center (drift time compensated) track in x.
Description of geometry of one entire detector.
Definition: GeometryCore.h:436
Cluster finding and building.
TrackEnd const TrackEndEnd
Definition: Track.h:33
const geo::GeometryCore * fGeo
pointer to the geometry
TH1F * phiClusTrack
Cluster to track in endcap.
std::enable_if_t< std::is_arithmetic_v< T >, T > hypot(T x, T y)
Definition: hypot.h:60
virtual double Efield(unsigned int planegap=0) const =0
Returns the nominal electric field in the specified volume.
T abs(T value)
float fEndcapRphiCut
Max dist cluster center (drift time compensated) track in r*phi.
TPCECALAssociation & operator=(TPCECALAssociation const &)=delete
const double e
float fPerpRCut
Max dist cluster center to circle of track (z,y) only.
const float * Vertex() const
Definition: Track.h:139
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
def move(depos, offset)
Definition: depos.py:107
const std::vector< gar::rec::CaloHit * > & CalorimeterHits() const
Definition: Cluster.h:103
static int PropagateToX(const float *trackpar, const float *Xpoint, const float x, float *retXYZ, const float Rmax=0.0)
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)
bool PointInECALBarrel(TVector3 const &point) const
const float * EigenVectors() const
Definition: Cluster.h:99
std::string fClusterLabel
label to find the right reco caloclusters
virtual double Temperature() const =0
const float * End() const
Definition: Track.h:140
TH2F * dotClustTrack
cos(cluster axis to extrapolated track)
std::string fTrackLabel
label to find the reco tracks
Interface to propagate a Track to the specific point.
const float * Position() const
Definition: Cluster.h:96
#define M_PI
Definition: includeROOT.h:54
General GArSoft Utilities.
TrackEnd const TrackEndBeg
Definition: Track.h:33
float TPCYCent() const
Returns the Y location of the center of the TPC in cm.
Definition: GeometryCore.h:785
static int DirectionX(const float *trackpar, const float *Xpoint, float &xEval, float *retXYZ)
void produce(art::Event &e) override
float fTrackEndXCut
Extrapolate only track ends outside central drift.
TPCECALAssociation(fhicl::ParameterSet const &p)
float fClusterDirCut
Min cos angle between extrapolated track and cluster direction.
virtual double DriftVelocity(double efield=0., double temperature=0., bool cmPerns=true) const =0
art framework interface to geometry description
float fClusterDirNhitCut
Do not cut on cluster direction unless you have this many hits or more.