tpcpatrec2_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: tpcpatrec2
3 // Plugin Type: producer (art v3_00_00)
4 // File: tpcpatrec2_module.cc
5 //
6 // Generated at Tue Feb 5 08:57:00 2019 by Thomas Junk using cetskelgen
7 // from cetlib version v3_04_00.
8 ////////////////////////////////////////////////////////////////////////
9 
17 #include "fhiclcpp/ParameterSet.h"
20 #include "canvas/Persistency/Common/FindManyP.h"
21 
22 #include <memory>
23 #include <set>
24 
25 #include "TMath.h"
26 #include "TVector3.h"
27 
28 #include "Geant4/G4ThreeVector.hh"
29 #include "nutools/MagneticField/MagneticField.h"
30 
31 // GArSoft Includes
35 #include "Reco/TrackPar.h"
36 #include "Reco/tracker2algs.h"
37 
38 namespace gar {
39  namespace rec {
40 
41  class tpcpatrec2 : public art::EDProducer {
42  public:
43  explicit tpcpatrec2(fhicl::ParameterSet const& p);
44  // The compiler-generated destructor is fine for non-base
45  // classes without bare pointers or other resource use.
46 
47  // Plugins should not be copied or assigned.
48  tpcpatrec2(tpcpatrec2 const&) = delete;
49  tpcpatrec2(tpcpatrec2&&) = delete;
50  tpcpatrec2& operator=(tpcpatrec2 const&) = delete;
51  tpcpatrec2& operator=(tpcpatrec2&&) = delete;
52 
53  // Required functions.
54  void produce(art::Event& e) override;
55 
56  private:
57 
58  // Declare member data here.
59 
60  std::string fVecHitLabel; ///< label of module to get the vector hits and associations with hits
61  std::string fTPCClusterLabel; ///< label of module to get the TPC clusters
62  int fPrintLevel; ///< debug printout: 0: none, 1: selected, 2: all
63  float fVecHitMatchCos; ///< matching condition for pairs of vector hits cos angle between directions
64  float fVecHitMatchPos; ///< matching condition for pairs of vector hits -- 3D distance (cm)
65  float fVecHitMatchPEX; ///< matching condition for pairs of vector hits -- miss distance (cm)
66  float fVecHitMatchEta; ///< matching condition for pairs of vector hits -- eta match (cm)
67  float fVecHitMatchLambda; ///< matching condition for pairs of vector hits -- dLambda (radians)
68  unsigned int fInitialTPNTPCClusters; ///< number of hits to use for initial trackpar estimate, if present
69  size_t fMinNumTPCClusters; ///< minimum number of hits for a patrec track
70  float fSortTransWeight; ///< for use in the hit sorting algorithm -- transverse distance weight factor
71  float fSortDistBack; ///< for use in the hit sorting algorithm -- how far to go back before raising the distance figure of merit
72  float fCloseEtaUnmatch; ///< distance to look for vector hits that don't match in eta.
73 
74  bool fXBasedSecondPass; ///< switch to tell us to use the X-based second-pass of patrec
75  int fXBasedMinTPCClusters; ///< min number of TPC clusters to require on new tracks found with the second pass
76  size_t fPatRecLookBack1; ///< n hits to look backwards to make a linear extrapolation
77  size_t fPatRecLookBack2; ///< extrapolate from lookback1 to lookback2 and see how close the new hit is to the line
78  float fHitResolYZ; ///< resolution in cm of a hit in YZ (pad size)
79  float fHitResolX; ///< resolution in cm of a hit in X (drift direction)
80  float fSigmaRoad; ///< how many sigma away from a track a hit can be and still add it during patrec
81 
82  // criteria for associating vector hits together to form clusters
83  bool vhclusmatch(const std::vector<gar::rec::VecHit> &vechits, std::vector<size_t> &cluster, size_t vh);
84 
85  // rough estimate of track parameters
86  int makepatrectrack(std::vector<gar::rec::TPCCluster> &tpcclusters, gar::rec::TrackPar &trackpar);
87 
88  float calceta2d(gar::rec::VecHit &vhtest, gar::rec::VecHit &vh);
89 
90  // test to see if a cluster looks like a conversion and split it in two if it does. Returns true
91  // if the cluster is identified as a conversion.
92 
93  bool conversion_test_split(const std::vector<gar::rec::VecHit> &vechits,
94  std::vector<size_t> &cluster,
95  std::vector<size_t> &splitclus1,
96  std::vector<size_t> &splitclus2);
97 
98  };
99 
100 
102  {
103  fVecHitLabel = p.get<std::string>("VecHitLabel","vechit");
104  fTPCClusterLabel = p.get<std::string>("TPCClusterLabel","tpcclusterpass1");
105  fPrintLevel = p.get<int>("PrintLevel",0);
106  fVecHitMatchCos = p.get<float>("VecHitMatchCos",0.9);
107  fVecHitMatchPos = p.get<float>("VecHitMatchPos",20.0);
108  fVecHitMatchPEX = p.get<float>("VecHitMatchPEX",5.0);
109  fVecHitMatchEta = p.get<float>("VecHitMatchEta",1.0);
110  fVecHitMatchLambda = p.get<float>("VecHitMatchLambda",0.1);
111  fInitialTPNTPCClusters = p.get<unsigned int>("InitialTPNTPCClusters",100);
112  fMinNumTPCClusters = p.get<size_t>("MinNumTPCClusters",20);
113  fSortTransWeight = p.get<float>("SortTransWeight",0.1);
114  fSortDistBack = p.get<float>("SortDistBack",2.0);
115  fCloseEtaUnmatch = p.get<float>("CloseEtaUnmatch",20.0);
116  fXBasedSecondPass = p.get<bool>("XBasedSecondPass",true);
117  fXBasedMinTPCClusters = p.get<int>("XBasedMinTPCClusters",10);
118  fPatRecLookBack1 = p.get<size_t>("PatRecLookBack1",5);
119  fPatRecLookBack2 = p.get<size_t>("PatRecLookBack2",10);
120  if (fPatRecLookBack1 == fPatRecLookBack2)
121  {
122  throw cet::exception("tpcpatrec2_module: PatRecLookBack1 and PatRecLookBack2 are the same");
123  }
124  fHitResolYZ = p.get<float>("HitResolYZ",1.0); // TODO -- think about what this value is
125  fHitResolX = p.get<float>("HitResolX",0.5); // this is probably much better
126  fSigmaRoad = p.get<float>("SigmaRoad",5.0);
127 
128  art::InputTag vechitTag(fVecHitLabel);
129  consumes< std::vector<gar::rec::VecHit> >(vechitTag);
130  consumes< art::Assns<gar::rec::TPCCluster, gar::rec::VecHit> >(vechitTag);
131  produces< std::vector<gar::rec::Track> >();
132  produces< art::Assns<gar::rec::TPCCluster, gar::rec::Track> >();
133  produces< art::Assns<gar::rec::VecHit, gar::rec::Track> >();
134  }
135 
137  {
138  std::unique_ptr< std::vector<gar::rec::Track> > trkCol(new std::vector<gar::rec::Track>);
139  std::unique_ptr< art::Assns<gar::rec::VecHit,gar::rec::Track> > vhTrkAssns(new ::art::Assns<gar::rec::VecHit,gar::rec::Track>);
140  std::unique_ptr< art::Assns<gar::rec::TPCCluster,gar::rec::Track> > TPCClusterTrkAssns(new ::art::Assns<gar::rec::TPCCluster,gar::rec::Track>);
141 
142  auto vechitHandle = e.getValidHandle< std::vector<gar::rec::VecHit> >(fVecHitLabel);
143  auto const& vechits = *vechitHandle;
144 
145  auto TPCClusterHandle = e.getValidHandle< std::vector<gar::rec::TPCCluster> >(fTPCClusterLabel);
146  auto const& e_tpcclusters = *TPCClusterHandle; // TPC Clusters from the event
147 
148  auto const trackPtrMaker = art::PtrMaker<gar::rec::Track>(e);
149  auto const vhPtrMaker = art::PtrMaker<gar::rec::VecHit>(e, vechitHandle.id());
150  auto const clusPtrMaker = art::PtrMaker<gar::rec::TPCCluster>(e,TPCClusterHandle.id());
151 
152  const art::FindManyP<gar::rec::TPCCluster> TPCClustersFromVecHits(vechitHandle,e,fVecHitLabel);
153 
155  G4ThreeVector zerovec(0,0,0);
156  G4ThreeVector magfield = magFieldService->FieldAtPoint(zerovec);
157 
158  std::set<gar::rec::IDNumber> TPCClusNumerosUsedInFirstPass;
159 
160  // stitch together vector hits into tracks
161  // question -- do we need to iterate this, first looking for small-angle matches, and then
162  // loosening up? Also need to address tracks that get stitched across the primary vertex -- may need to split
163  // these after other tracks have been found.
164 
165  std::vector< std::vector< size_t > > vhclusters; // change this to use just indices of vh's
166 
167  for (size_t ivh = 0; ivh< vechits.size(); ++ ivh)
168  {
169  if (fPrintLevel>1)
170  {
171  std::cout << " vhprint " << vechits[ivh].Position()[0] << " " << vechits[ivh].Position()[1] << " " << vechits[ivh].Position()[2] << " " <<
172  vechits[ivh].Direction()[0] << " " << vechits[ivh].Direction()[1] << " " << vechits[ivh].Direction()[2] << " " << std::endl;
173  }
174 
175  std::vector<size_t> clusmatchlist;
176  for (size_t iclus=0; iclus<vhclusters.size(); ++iclus)
177  {
178  if (vhclusmatch(vechits,vhclusters[iclus],ivh))
179  {
180  clusmatchlist.push_back(iclus);
181  }
182  }
183  if (clusmatchlist.size() == 0)
184  {
185  std::vector<size_t> newclus;
186  newclus.push_back(ivh);
187  vhclusters.push_back(newclus);
188  }
189  else if (clusmatchlist.size() == 1)
190  {
191  vhclusters[clusmatchlist[0]].push_back(ivh);
192  }
193  else // multiple matches -- merge clusters togetehr
194  {
195  for (size_t icm=1; icm<clusmatchlist.size(); ++icm)
196  {
197  for (size_t ivh2=0; ivh2<vhclusters[clusmatchlist[icm]].size(); ++ivh2)
198  {
199  vhclusters[clusmatchlist[0]].push_back(vhclusters[clusmatchlist[icm]][ivh2]);
200  }
201  }
202  // remove the merged vh clusters, using the new indexes after removing earlier ones
203  for (size_t icm=1; icm<clusmatchlist.size(); ++icm)
204  {
205  vhclusters.erase(vhclusters.begin() + (clusmatchlist[icm]-icm+1));
206  }
207  }
208  }
209 
210  //std::cout << "Before conversion check, clusters: " << std::endl;
211  //for (size_t iclus=0; iclus<vhclusters.size(); ++iclus)
212  // {
213  // std::cout << "Cluster " << iclus << std::endl;
214  // for (size_t ivh = 0; ivh< vhclusters.at(iclus).size(); ++ ivh)
215  // {
216  // size_t i=vhclusters.at(iclus).at(ivh);
217  // std::cout << " " << ivh << " " <<
218  // vechits[i].Position()[0] << " " << vechits[i].Position()[1] << " " << vechits[i].Position()[2] << " " <<
219  // vechits[i].Direction()[0] << " " << vechits[i].Direction()[1] << " " << vechits[i].Direction()[2] << " " << std::endl;
220  // }
221  // }
222 
223  // look for conversions with two tracks that have been joined together and split them in two.
224 
225  std::vector<size_t> identified_conversions; // index into vhclusters of identified conversions
226  std::vector< std::vector< size_t > > splitclus1; // vhcluster for one leg after split
227  std::vector< std::vector< size_t > > splitclus2; // vhcluster for the other leg after split
228 
229  for (size_t iclus=0; iclus<vhclusters.size(); ++iclus)
230  {
231  std::vector<size_t> scc1;
232  std::vector<size_t> scc2;
233  if (conversion_test_split(vechits, vhclusters.at(iclus), scc1, scc2))
234  {
235  identified_conversions.push_back(iclus);
236  splitclus1.push_back(scc1);
237  splitclus2.push_back(scc2);
238  }
239  }
240 
241  // rearrange the cluster list -- put the two legs separately in the list, replacing the incorrectly-merged one
242 
243  for (size_t icc=0; icc<identified_conversions.size(); ++icc)
244  {
245  vhclusters.at(identified_conversions.at(icc)) = splitclus1.at(icc);
246  vhclusters.push_back(splitclus2.at(icc));
247  }
248 
249 
250  // make a local list of TPCClusters for each track and find initial track parameters
251  for (size_t iclus=0; iclus < vhclusters.size(); ++iclus)
252  {
253  std::vector<gar::rec::TPCCluster> TPCClusters;
254  std::vector<art::Ptr<gar::rec::TPCCluster> > TPCClusterptrs;
255  for (size_t ivh=0; ivh<vhclusters[iclus].size(); ++ivh)
256  {
257  for (size_t iTPCCluster=0; iTPCCluster<TPCClustersFromVecHits.at(vhclusters[iclus][ivh]).size(); ++iTPCCluster)
258  {
259  TPCClusterptrs.push_back(TPCClustersFromVecHits.at(vhclusters[iclus][ivh]).at(iTPCCluster));
260  TPCClusters.push_back(*TPCClusterptrs.back());
261  }
262  }
263 
264  if (TPCClusters.size() >= fMinNumTPCClusters)
265  {
266  gar::rec::TrackPar trackpar;
267  if ( makepatrectrack(TPCClusters,trackpar) == 0 )
268  {
269  trkCol->push_back(trackpar.CreateTrack());
270  auto const trackpointer = trackPtrMaker(trkCol->size()-1);
271  for (size_t iTPCCluster=0; iTPCCluster<TPCClusters.size(); ++iTPCCluster)
272  {
273  TPCClusNumerosUsedInFirstPass.insert(TPCClusters.at(iTPCCluster).getIDNumber());
274  TPCClusterTrkAssns->addSingle(TPCClusterptrs.at(iTPCCluster),trackpointer);
275  }
276  for (size_t ivh=0; ivh<vhclusters[iclus].size(); ++ivh)
277  {
278  auto const vhpointer = vhPtrMaker(ivh);
279  vhTrkAssns->addSingle(vhpointer,trackpointer);
280  }
281  }
282  }
283  }
284 
285  // to think about -- remove dodgy tracks so that the second pass may have a better chance at picking them up.
286  // any remaining misclassified conversions, for instance. Or just don't put them on the list in the
287  // first place.
288 
289  // Second pass patrec:
290  // go back and use the X-based pattern recognition on TPC clusters not included in tracks found above
291 
292  if (fXBasedSecondPass)
293  {
294  // first find unassociated TPC clusters and sort them by their X positions
295  // keep them in place, just make a vector of sorted indices
296 
297  std::vector<gar::rec::TPCCluster> tcc2pass;
298  std::vector<float> clusx;
299  std::vector<size_t> tcc2passidx;
300 
301  float roadsq = fSigmaRoad*fSigmaRoad;
302  float resolSq = fHitResolYZ*fHitResolYZ;
303 
304  for (size_t iclus=0; iclus < e_tpcclusters.size(); ++iclus)
305  {
306  if (TPCClusNumerosUsedInFirstPass.count(e_tpcclusters.at(iclus).getIDNumber()) == 0)
307  {
308  tcc2pass.push_back(e_tpcclusters.at(iclus));
309  tcc2passidx.push_back(iclus); // for use in making associations
310  clusx.push_back(tcc2pass.back().Position()[0]);
311  }
312  }
313 
314  if (tcc2pass.size()>0)
315  {
316  std::vector<int> csi(clusx.size());
317  TMath::Sort((int) clusx.size(),clusx.data(),csi.data());
318 
319  // do this twice, once going forwards through the tcc2pass, once backwards, and then collect hits
320  // in groups and split them when either the forwards or the backwards list says to split them.
321 
322  std::vector< std::vector<int> > cluslistf;
323  std::vector<int> trackf(tcc2pass.size());
324  for (size_t iclus=0; iclus<tcc2pass.size(); ++iclus)
325  {
326  const float *cpos = tcc2pass[csi[iclus]].Position();
327  TVector3 hpvec(cpos);
328 
329  float bestsignifs = -1;
330  int ibest = -1;
331  for (size_t itcand = 0; itcand < cluslistf.size(); ++itcand)
332  {
333  float signifs = 1E9;
334  //size_t clsiz = cluslistf[itcand].size();
335  //if (clsiz > fPatRecLookBack1 && clsiz > fPatRecLookBack2)
336  // {
337  // TVector3 pt1( tcc2pass[csi[cluslistf[itcand][clsiz-fPatRecLookBack1]]].Position() );
338  // TVector3 pt2( tcc2pass[csi[cluslistf[itcand][clsiz-fPatRecLookBack2]]].Position() );
339  // TVector3 uv = pt1-pt2;
340  // uv *= 1.0/uv.Mag();
341  // signifs = ((hpvec-pt1).Cross(uv)).Mag2()/resolSq;
342  // }
343  //else // not enough tcc2pass, just look how close we are to the last one
344  // {
345  const float *hpos = tcc2pass[csi[cluslistf[itcand].back()]].Position();
346  signifs = (TMath::Sq( (hpos[1]-cpos[1]) ) +
347  TMath::Sq( (hpos[2]-cpos[2]) ))/resolSq;
348  // }
349  if (bestsignifs < 0 || signifs < bestsignifs)
350  {
351  bestsignifs = signifs;
352  ibest = itcand;
353  }
354  }
355  if (ibest == -1 || bestsignifs > roadsq) // start a new track if we're not on the road, or if we had no tracks to begin with
356  {
357  ibest = cluslistf.size();
358  std::vector<int> vtmp;
359  cluslistf.push_back(vtmp);
360  }
361  cluslistf[ibest].push_back(iclus);
362  trackf[iclus] = ibest;
363  }
364 
365  std::vector< std::vector<int> > cluslistb;
366  std::vector<int> trackb(tcc2pass.size());
367  for (int iclus=tcc2pass.size()-1; iclus >= 0; --iclus)
368  {
369  const float *cpos = tcc2pass[csi[iclus]].Position();
370  TVector3 hpvec(cpos);
371 
372  float bestsignifs = -1;
373  int ibest = -1;
374  for (size_t itcand = 0; itcand < cluslistb.size(); ++itcand)
375  {
376  float signifs = 1E9;
377  //size_t clsiz = cluslistb[itcand].size();
378  //if (clsiz > fPatRecLookBack1 && clsiz > fPatRecLookBack2)
379  //{
380  // TVector3 pt1( tcc2pass[csi[cluslistb[itcand][clsiz-fPatRecLookBack1]]].Position() );
381  // TVector3 pt2( tcc2pass[csi[cluslistb[itcand][clsiz-fPatRecLookBack2]]].Position() );
382  // TVector3 uv = pt1-pt2;
383  // uv *= 1.0/uv.Mag();
384  // signifs = ((hpvec-pt1).Cross(uv)).Mag2()/resolSq;
385  // }
386  //else // not enough tcc2pass, just look how close we are to the last one
387  // {
388  const float *hpos = tcc2pass[csi[cluslistb[itcand].back()]].Position();
389  signifs = (TMath::Sq( (hpos[1]-cpos[1]) ) +
390  TMath::Sq( (hpos[2]-cpos[2]) ))/resolSq;
391  // }
392 
393  if (bestsignifs < 0 || signifs < bestsignifs)
394  {
395  bestsignifs = signifs;
396  ibest = itcand;
397  }
398  }
399  if (ibest == -1 || bestsignifs > roadsq) // start a new track if we're not on the road, or if we had no tracks to begin with
400  {
401  ibest = cluslistb.size();
402  std::vector<int> vtmp;
403  cluslistb.push_back(vtmp);
404  }
405  cluslistb[ibest].push_back(iclus);
406  trackb[iclus] = ibest;
407  }
408 
409  // make a list of tracks that is the set of disjoint subsets
410 
411  std::vector< std::vector<int> > cluslist;
412  for (size_t itrack=0; itrack<cluslistf.size(); ++itrack)
413  {
414  int itrackl = 0;
415  for (size_t iclus=0; iclus<cluslistf[itrack].size(); ++iclus)
416  {
417  int ihif = cluslistf[itrack][iclus];
418  if (iclus == 0 || (trackb[ihif] != itrackl))
419  {
420  std::vector<int> vtmp;
421  cluslist.push_back(vtmp);
422  itrackl = trackb[ihif];
423  }
424  cluslist.back().push_back(ihif);
425  }
426  }
427 
428  // now make patrec tracks out of these grouped TPC clusters
429 
430  for (size_t itrack=0; itrack<cluslist.size(); ++itrack)
431  {
432  if (cluslist.at(itrack).size() < (size_t) fXBasedMinTPCClusters) continue;
433  std::vector<gar::rec::TPCCluster> tcl;
434  for (size_t iclus=0; iclus<cluslist.at(itrack).size(); ++iclus)
435  {
436  tcl.push_back(tcc2pass.at(csi[cluslist[itrack].at(iclus)]));
437  }
438  gar::rec::TrackPar trackpar;
439  if (makepatrectrack(tcl,trackpar) == 0)
440  {
441  trkCol->push_back(trackpar.CreateTrack());
442  auto const trackptr = trackPtrMaker(trkCol->size()-1);
443  for (size_t iclus=0; iclus<tcl.size(); ++iclus)
444  {
445  auto const clusptr = clusPtrMaker(tcc2passidx.at(csi[cluslist[itrack][iclus]]));
446  TPCClusterTrkAssns->addSingle(clusptr,trackptr);
447  if (fPrintLevel>1)
448  {
449  std::cout << " second-pass track " << itrack << " clus: " << iclus << " : ";
450  TVector3 cp(tcc2pass[csi[cluslist[itrack][iclus]]].Position());
451  std::cout << cp.X() << " " << cp.Y() << " " << cp.Z() << std::endl;
452  }
453  }
454  }
455  }
456 
457  } // end check if we have any TPC clusters for pass 2
458  } // end check if we want to run pass 2 patrec
459 
460  e.put(std::move(trkCol));
461  e.put(std::move(vhTrkAssns));
462  e.put(std::move(TPCClusterTrkAssns));
463 
464  }
465 
466 
467  bool tpcpatrec2::vhclusmatch(const std::vector<gar::rec::VecHit> &vechits, std::vector<size_t> &cluster, size_t vhindex)
468  {
469  gar::rec::VecHit vh = vechits[vhindex];
470  TVector3 vhdir(vh.Direction());
471  TVector3 vhpos(vh.Position());
472 
473  bool foundmatch = false;
474  for (size_t ivh=0; ivh<cluster.size(); ++ivh)
475  {
476  gar::rec::VecHit vhtest = vechits[cluster[ivh]];
477  TVector3 vhtestdir(vhtest.Direction());
478  TVector3 vhtestpos(vhtest.Position());
479 
480  if (fPrintLevel > 1)
481  {
482  std::cout << "Testing vh " << ivh << " in a cluster of size: " << cluster.size() << std::endl;
483  }
484 
485  // require the two VH's directions to point along each other -- use dot product
486 
487  if (TMath::Abs((vhdir).Dot(vhtestdir)) < fVecHitMatchCos)
488  {
489  if (fPrintLevel > 1)
490  {
491  std::cout << " Dot failure: " << TMath::Abs((vhdir).Dot(vhtestdir)) << std::endl;
492  }
493  continue;
494  }
495 
496  // require the positions to be within fVecHitMatchPos of each other
497 
498  if ((vhpos-vhtestpos).Mag() > fVecHitMatchPos)
499  {
500  if (fPrintLevel > 1)
501  {
502  std::cout << " Pos failure: " << (vhpos-vhtestpos).Mag() << std::endl;
503  }
504  continue;
505  }
506 
507  // require the extrapolation of one VH's line to another VH's center to match up. Do for
508  // both VH's.
509 
510  if ( ((vhpos-vhtestpos).Cross(vhdir)).Mag() > fVecHitMatchPEX )
511  {
512  if (fPrintLevel > 1)
513  {
514  std::cout << "PEX failure: " << ((vhpos-vhtestpos).Cross(vhdir)).Mag() << std::endl;
515  }
516  continue;
517  }
518  if ( ((vhpos-vhtestpos).Cross(vhtestdir)).Mag() > fVecHitMatchPEX )
519  {
520  if (fPrintLevel > 1)
521  {
522  std::cout << "PEX failure: " << ((vhpos-vhtestpos).Cross(vhtestdir)).Mag() << std::endl;
523  }
524  continue;
525  }
526 
527  float eta = calceta2d(vhtest,vh);
528 
529  if ( eta > fVecHitMatchEta )
530  {
531  if (fPrintLevel > 1)
532  {
533  std::cout << "Eta failure: " << eta << std::endl;
534  }
535  continue;
536  }
537 
538 
539  //----------------
540  // lambda requirement
541 
542  float vhpd = TMath::Sqrt( TMath::Sq(vhdir.Y()) + TMath::Sq(vhdir.Z()) );
543  float vhxd = TMath::Abs( vhdir.X() );
544  float vhlambda = TMath::Pi()/2.0;
545  if (vhpd >0) vhlambda = TMath::ATan(vhxd/vhpd);
546 
547  float cvhpd = TMath::Sqrt( TMath::Sq(vhtestdir.Y()) + TMath::Sq(vhtestdir.Z()) );
548  float cvhxd = TMath::Abs( vhtestdir.X() );
549  float cvhlambda = TMath::Pi()/2.0;
550  if (cvhpd >0) cvhlambda = TMath::ATan(cvhxd/cvhpd);
551 
552  if ( TMath::Abs(vhlambda - cvhlambda) > fVecHitMatchLambda )
553  {
554  if (fPrintLevel > 1)
555  {
556  std::cout << "dlambda failure: " << vhlambda << " " << cvhlambda << std::endl;
557  }
558  continue;
559  }
560 
561  if ( vhdir.Dot(vhtestdir) * vhdir.X() * vhtestdir.X() < 0 &&
562  TMath::Abs(vhdir.X()) > 0.01 && TMath::Abs(vhtestdir.X()) > 0.01)
563  {
564  if (fPrintLevel > 1)
565  {
566  std::cout << "lambda sign failure" << std::endl;
567  }
568  continue;
569  }
570 
571  if (fPrintLevel > 1)
572  {
573  std::cout << " vh cluster match " << std::endl;
574  }
575  foundmatch = true;
576  }
577  if (!foundmatch)
578  {
579  return false;
580  }
581  else
582  {
583  // we have a match, but let's check it to see if we should discard it because there's a
584  // close-by mismatch, which happens when a photon converts
585  // the above loop stops when we find a match, but this time we want to go through
586  // all the VH's in the cluster and check them, so new loop.
587 
588  // for (size_t ivh=0; ivh<cluster.size(); ++ivh)
589  // {
590  // gar::rec::VecHit vhtest = vechits[cluster[ivh]];
591  // TVector3 vhtestpos(vhtest.Position());
592 
593  // // look for close-by VH's with an eta mismatch
594  // if ((vhpos-vhtestpos).Mag() < fCloseEtaUnmatch)
595  // {
596  // float eta = calceta2d(vhtest,vh);
597  // if ( eta > fVecHitMatchEta )
598  // {
599  // return false;
600  // }
601  // }
602  // }
603 
604  }
605  return true;
606  }
607 
608  // rough estimate of track parameters -- both ends
609 
610  int tpcpatrec2::makepatrectrack(std::vector<gar::rec::TPCCluster> &trackTPCClusters, gar::rec::TrackPar &trackpar)
611  {
612  // track parameters: x is the independent variable
613  // 0: y
614  // 1: z
615  // 2: curvature
616  // 3: phi
617  // 4: lambda = angle from the cathode plane
618  // 5: x /// added on to the end
619 
620 
621  float lengthforwards = 0;
622  std::vector<int> hlf;
623  float lengthbackwards = 0;
624  std::vector<int> hlb;
625 
626  gar::rec::sort_TPCClusters_along_track(trackTPCClusters,hlf,hlb,fPrintLevel,lengthforwards,lengthbackwards,fSortTransWeight,fSortDistBack);
627 
628  std::vector<float> tparbeg(6,0);
629  float xother = 0;
630  if ( gar::rec::initial_trackpar_estimate(trackTPCClusters, hlf, tparbeg[2], tparbeg[4],
631  tparbeg[3], tparbeg[5], tparbeg[0], tparbeg[1], xother, fInitialTPNTPCClusters, fPrintLevel) != 0)
632  {
633  return 1;
634  }
635 
636  std::vector<float> tparend(6,0);
637  if ( gar::rec::initial_trackpar_estimate(trackTPCClusters, hlb, tparend[2], tparend[4],
638  tparend[3], tparend[5], tparend[0], tparend[1], xother, fInitialTPNTPCClusters, fPrintLevel) != 0)
639  {
640  return 1;
641  }
642 
643  // no chisquare or covariance in patrec tracks
644  float covmatbeg[25];
645  float covmatend[25];
646  for (size_t i=0; i<25; ++i) // no covmat in patrec tracks
647  {
648  covmatend[i] = 0;
649  covmatbeg[i] = 0;
650  }
651 
652  trackpar.setNTPCClusters(trackTPCClusters.size());
653  trackpar.setTime(0);
654  trackpar.setChisqForwards(0);
655  trackpar.setChisqBackwards(0);
656  trackpar.setLengthForwards(lengthforwards);
657  trackpar.setLengthBackwards(lengthbackwards);
658  trackpar.setCovMatBeg(covmatbeg);
659  trackpar.setCovMatEnd(covmatend);
660  trackpar.setTrackParametersBegin(tparbeg.data());
661  trackpar.setXBeg(tparbeg[5]);
662  trackpar.setTrackParametersEnd(tparend.data());
663  trackpar.setXEnd(tparend[5]);
664 
665  return 0;
666  }
667 
668 
669  // compute a 2D eta
670 
672  {
673  // normalized direction vector for the VH under test, just the components
674  // perpendicular to X
675 
676  TVector3 vhtestdir(vhtest.Direction());
677  TVector3 vhtestpos(vhtest.Position());
678  TVector3 vhdir(vh.Direction());
679  TVector3 vhpos(vh.Position());
680 
681  TVector3 vhdp(vhdir);
682  vhdp.SetX(0);
683  float norm = vhdp.Mag();
684  if (norm > 0) vhdp *= (1.0/norm);
685 
686  // same for the VH in the cluster under test
687 
688  TVector3 vhcp(vhtestdir);
689  vhcp.SetX(0);
690  norm = vhcp.Mag();
691  if (norm > 0) vhcp *= (1.0/norm);
692 
693  float relsign = 1.0;
694  if (vhdp.Dot(vhcp) < 0) relsign = -1;
695 
696  TVector3 dcent = vhpos-vhtestpos;
697  dcent.SetX(0);
698 
699  TVector3 avgdir1 = 0.5*(vhdp + relsign*vhcp);
700  float amag = avgdir1.Mag();
701  if (amag != 0) avgdir1 *= 1.0/amag;
702  float eta = (dcent.Cross(avgdir1)).Mag();
703  return eta;
704 
705  }
706 
707  // test to see if a cluster looks like a conversion and split it in two if it does. Returns true
708  // if the cluster is identified as a conversion.
709 
710  bool tpcpatrec2::conversion_test_split(const std::vector<gar::rec::VecHit> &vechits,
711  std::vector<size_t> &cluster,
712  std::vector<size_t> &splitclus1,
713  std::vector<size_t> &splitclus2)
714  {
715 
716  splitclus1.clear();
717  splitclus2.clear();
718 
719  // find the VH the farthest away from all the others as an approximation of the end of one of the legs of the
720  // conversion candidate.
721 
722  double dsummax=0;
723  size_t ivhend=0;
724  for (size_t ivh=0; ivh<cluster.size(); ++ivh)
725  {
726  TVector3 vhpos(vechits.at(cluster.at(ivh)).Position());
727  double dsum = 0;
728  for (size_t jvh=0; jvh<cluster.size(); ++jvh)
729  {
730  if (ivh == jvh) continue;
731  TVector3 vhpos2(vechits.at(cluster.at(jvh)).Position());
732  gar::rec::VecHit vh1 = vechits.at(cluster.at(jvh));
733  gar::rec::VecHit vh2 = vechits.at(cluster.at(ivh));
734  dsum += calceta2d(vh1,vh2);
735  dsum += (vhpos-vhpos2).Mag();
736  }
737  //std::cout << "Looking for end: " << cluster.at(ivh) << " " << vhpos.X() << " " << vhpos.Y() << " " << vhpos.Z() << " " << dsum << std::endl;
738  if (dsum > dsummax)
739  {
740  ivhend = ivh; // this is an index into cluster
741  dsummax = dsum;
742  //std::cout << "This is the new max" << std::endl;
743  }
744  }
745  if (dsummax == 0) return(false);
746 
747  // step along the cluster, looking for the closest vh not on the list yet, and identify places where we turn around
748  // and backtrack.
749 
750  std::vector<size_t> already; // already looked at vh list
751  std::set<size_t> yet; // set of vector hits yet to look at.
752 
753  size_t ivhlast = 0; // the last one looked at -- index into vechits
754 
755  for(size_t ivh=0; ivh<cluster.size(); ++ivh)
756  {
757  if (ivh == ivhend)
758  {
759  ivhlast = cluster.at(ivh);
760  already.push_back(ivhlast);
761  //std::cout << " pushed " << ivhlast << " to already" << std::endl;
762  }
763  else
764  {
765  yet.insert(cluster.at(ivh));
766  }
767  }
768 
769  TVector3 lastpdir(0,0,0); // direction in which we're going. Don't know yet, and the VH's
770  //have a two-fold ambiguity as to what that means
771 
772  TVector3 lastpos(vechits.at(ivhlast).Position()); // position of ivhlast
773  gar::rec::VecHit lastvhdp = vechits.at(ivhlast); // save for calculating eta
774 
775  while(yet.size() > 0)
776  {
777 
778  // find which VH in the yet-to-be-looked-at pile that is most likely the "next" one.
779  // choose the closest vechit that satisfies all the matching criteria.
780 
781  float dmin = 0;
782  bool foundmin = false;
783  size_t inext=0;
784  for (auto iyet : yet)
785  {
786  TVector3 testpos(vechits.at(iyet).Position());
787  TVector3 testdir(vechits.at(iyet).Direction());
788  gar::rec::VecHit testvhdp = vechits.at(iyet);
789  float dtest = (lastpos - testpos).Mag() + calceta2d(lastvhdp,testvhdp);
790  if (dtest < dmin || !foundmin)
791  {
792  foundmin = true;
793  dmin = dtest;
794  inext = iyet;
795  }
796  }
797  if (!foundmin) return(false);
798  TVector3 nextpos(vechits.at(inext).Position());
799  TVector3 nextdir(vechits.at(inext).Direction());
800  if (lastpdir.Mag() > 1E-3)
801  {
802  TVector3 testpdir = nextpos - lastpos;
803  if (testpdir.Angle(lastpdir) > 3)
804  {
805  // we turned around -- found a conversion.
806  splitclus1 = already;
807  for (auto iyet : yet)
808  {
809  splitclus2.push_back(iyet);
810  }
811  //std::cout << "Found a conversion" << std::endl;
812  return(true);
813  }
814  }
815  lastpdir = nextpos - lastpos;
816  already.push_back(inext);
817  //std::cout << " pushed " << inext << " to already" << std::endl;
818  yet.erase(inext);
819  lastpos = nextpos;
820  lastvhdp = vechits.at(inext);
821  //std::cout << "conv hunting: " << lastpos.X() << " " << lastpos.Y() << " " << lastpos.Z() << std::endl;
822  }
823  return(false);
824  }
825 
827 
828 
829  } // namespace rec
830 } // namespace gar
void setNTPCClusters(const size_t nTPCClusters)
Definition: TrackPar.cxx:214
size_t fMinNumTPCClusters
minimum number of hits for a patrec track
void setLengthForwards(const float lengthforwards)
Definition: TrackPar.cxx:251
rec
Definition: tracks.py:88
int fPrintLevel
debug printout: 0: none, 1: selected, 2: all
const float * Position() const
Definition: VecHit.h:47
void setCovMatBeg(const float *covmatbeg)
Definition: TrackPar.cxx:235
std::string string
Definition: nybbler.cc:12
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.h:20
tpcpatrec2(fhicl::ParameterSet const &p)
void setLengthBackwards(const float lengthbackwards)
Definition: TrackPar.cxx:256
Cluster finding and building.
const float * Direction() const
Definition: VecHit.h:48
std::string fVecHitLabel
label of module to get the vector hits and associations with hits
size_t fPatRecLookBack2
extrapolate from lookback1 to lookback2 and see how close the new hit is to the line ...
void setTrackParametersBegin(const float *tparbeg)
Definition: TrackPar.cxx:219
const double e
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
def move(depos, offset)
Definition: depos.py:107
bool vhclusmatch(const std::vector< gar::rec::VecHit > &vechits, std::vector< size_t > &cluster, size_t vh)
void setXEnd(const float xend)
Definition: TrackPar.cxx:276
void setTrackParametersEnd(const float *tparend)
Definition: TrackPar.cxx:227
float calceta2d(gar::rec::VecHit &vhtest, gar::rec::VecHit &vh)
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
Definition: DataViewImpl.h:441
p
Definition: test.py:223
float fVecHitMatchEta
matching condition for pairs of vector hits – eta match (cm)
unsigned int fInitialTPNTPCClusters
number of hits to use for initial trackpar estimate, if present
void setChisqBackwards(const float chisqbackwards)
Definition: TrackPar.cxx:266
std::string fTPCClusterLabel
label of module to get the TPC clusters
float fHitResolYZ
resolution in cm of a hit in YZ (pad size)
gar::rec::Track CreateTrack()
Definition: TrackPar.cxx:292
size_t fPatRecLookBack1
n hits to look backwards to make a linear extrapolation
auto norm(Vector const &v)
Return norm of the specified vector.
bool conversion_test_split(const std::vector< gar::rec::VecHit > &vechits, std::vector< size_t > &cluster, std::vector< size_t > &splitclus1, std::vector< size_t > &splitclus2)
float fHitResolX
resolution in cm of a hit in X (drift direction)
float fCloseEtaUnmatch
distance to look for vector hits that don&#39;t match in eta.
General GArSoft Utilities.
int makepatrectrack(std::vector< gar::rec::TPCCluster > &tpcclusters, gar::rec::TrackPar &trackpar)
void setCovMatEnd(const float *covmatend)
Definition: TrackPar.cxx:243
void sort_TPCClusters_along_track(const std::vector< gar::rec::TPCCluster > &TPCClusters, std::vector< int > &hlf, std::vector< int > &hlb, int printlevel, float &lengthforwards, float &lengthbackwards, float sorttransweight, float sortdistback)
void setXBeg(const float xbeg)
Definition: TrackPar.cxx:271
float fVecHitMatchLambda
matching condition for pairs of vector hits – dLambda (radians)
int fXBasedMinTPCClusters
min number of TPC clusters to require on new tracks found with the second pass
float fSortTransWeight
for use in the hit sorting algorithm – transverse distance weight factor
tpcpatrec2 & operator=(tpcpatrec2 const &)=delete
void setChisqForwards(const float chisqforwards)
Definition: TrackPar.cxx:261
bool fXBasedSecondPass
switch to tell us to use the X-based second-pass of patrec
float fVecHitMatchPEX
matching condition for pairs of vector hits – miss distance (cm)
float fVecHitMatchCos
matching condition for pairs of vector hits cos angle between directions
float fSortDistBack
for use in the hit sorting algorithm – how far to go back before raising the distance figure of meri...
float fVecHitMatchPos
matching condition for pairs of vector hits – 3D distance (cm)
static struct @2 tcl
float fSigmaRoad
how many sigma away from a track a hit can be and still add it during patrec
void setTime(const double time)
Definition: TrackPar.cxx:281
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
QTextStream & endl(QTextStream &s)
void produce(art::Event &e) override
int initial_trackpar_estimate(const std::vector< gar::rec::TPCCluster > &TPCClusters, std::vector< int > &TPCClusterlist, float &curvature_init, float &lambda_init, float &phi_init, float &xpos, float &ypos, float &zpos, float &x_other_end, unsigned int initialtpnTPCClusters, int printlevel)
Definition: tracker2algs.cxx:8