tracker1_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: tracker1
3 // Plugin Type: producer (art v2_11_02)
4 // File: tracker1_module.cc
5 //
6 // Generated at Thu Jun 14 15:47:04 2018 by Thomas Junk using cetskelgen
7 // from cetlib version v3_03_01.
8 // Sort hits in X and add nearby hits.
9 ////////////////////////////////////////////////////////////////////////
10 
18 #include "fhiclcpp/ParameterSet.h"
20 #include "cetlib_except/exception.h"
22 
23 #include <memory>
24 #include <set>
25 
26 #include "TVectorF.h"
27 #include "TMatrix.h"
28 #include "TMath.h"
29 #include "Fit/Fitter.h"
30 #include "Math/Functor.h"
31 #include "TVector3.h"
32 
33 #include "Geant4/G4ThreeVector.hh"
34 
36 #include "nutools/MagneticField/MagneticField.h"
37 
38 // GArSoft Includes
41 #include "Reco/TrackPar.h"
42 #include "Geometry/GeometryGAr.h"
43 
44 namespace gar {
45  namespace rec {
46 
47  class tracker1 : public art::EDProducer {
48  public:
49  explicit tracker1(fhicl::ParameterSet const & p);
50  // The compiler-generated destructor is fine for non-base
51  // classes without bare pointers or other resource use.
52 
53  // Plugins should not be copied or assigned.
54  tracker1(tracker1 const &) = delete;
55  tracker1(tracker1 &&) = delete;
56  tracker1 & operator = (tracker1 const &) = delete;
57  tracker1 & operator = (tracker1 &&) = delete;
58 
59  // Required functions.
60  void produce(art::Event & e) override;
61 
62  private:
63 
64  float fHitRCut; ///< only take hits within rcut of the center of the detector
65  size_t fPatRecAlg; ///< 1: x-sorted patrec. 2: vector-hit patrec
66  size_t fPatRecLookBack1; ///< n hits to look backwards to make a linear extrapolation
67  size_t fPatRecLookBack2; ///< extrapolate from lookback1 to lookback2 and see how close the new hit is to the line
68  float fHitResolYZ; ///< resolution in cm of a hit in YZ (pad size)
69  float fHitResolX; ///< resolution in cm of a hit in X (drift direction)
70  float fSigmaRoad; ///< how many sigma away from a track a hit can be and still add it during patrec
71 
72  float fMaxVecHitLen; ///< maximum vector hit length in patrec alg 2, in cm
73  float fVecHitRoad; ///< max dist from a vector hit to a hit to assign it. for patrec alg 2. in cm.
74  float fVecHitMatchCos; ///< matching condition for pairs of vector hits cos angle between directions
75  float fVecHitMatchPos; ///< matching condition for pairs of vector hits -- 3D distance (cm)
76  float fVecHitMatchPEX; ///< matching condition for pairs of vector hits -- miss distance (cm)
77  float fVecHitMatchEta; ///< matching condition for pairs of vector hits -- eta match (cm)
78  float fVecHitMatchLambda; ///< matching condition for pairs of vector hits -- dLambda (radians)
79  unsigned int fVecHitMinHits; ///< minimum number of hits on a vector hit for it to be considered
80 
81  float fKalCurvStepUncSq; ///< constant uncertainty term on each step of the Kalman fit -- squared, for curvature
82  float fKalPhiStepUncSq; ///< constant uncertainty term on each step of the Kalman fit -- squared, for phi
83  float fKalLambdaStepUncSq; ///< constant uncertainty term on each step of the Kalman fit -- squared, for lambda
84 
85  //float fXGapToEndTrack; ///< how big a gap must be before we end a track and start a new one (unused for now)
86  unsigned int fMinNumHits; ///< minimum number of hits to define a track
87  unsigned int fInitialTPNHits; ///< number of hits to use for initial trackpar estimate, if present
88  std::string fHitLabel; ///< label of module creating hits
89  int fPrintLevel; ///< debug printout: 0: none, 1: just track parameters and residuals, 2: all
90  int fTrackPass; ///< which pass of the tracking to save as the tracks in the event
91  int fDumpTracks; ///< 0: do not print out tracks, 1: print out tracks
92 
93  std::string fSortOrder; ///< switch to tell what way to sort hits before presenting them to the fitter
94 
95  float fHitResolYZinFit; ///< Hit resolution parameter to use in fit
96  float fRoadYZinFit; ///< cut in cm for dropping hits from tracks in fit
97 
98  std::string fFirstPassFitType; ///< helix or Kalman -- which fitter to call for first-pass tracks
99  std::string fSecondPassFitType; ///< helix or Kalman -- which fitter to call for second-pass tracks
100 
101  int initial_trackpar_estimate(art::ValidHandle<std::vector<Hit> > &hitHandle,
102  std::vector<std::vector<int> > &hitlist,
103  std::vector<int> &hsi,
104  int itrack,
105  bool isForwards,
106  float &curvature_init,
107  float &lambda_init,
108  float &phi_init,
109  float &xpos,
110  float &ypos,
111  float &zpos,
112  float &x_other_end);
113 
114  int KalmanFit( art::ValidHandle<std::vector<Hit> > &hitHandle,
115  std::vector<std::vector<int> > &hitlist,
116  std::vector<int> &hsi,
117  int itrack,
118  bool isForwards,
119  std::vector<float> &trackparatend,
120  float &chisquared,
121  float &length,
122  float *covmat, // 5x5 covariance matrix
123  std::set<int> &unused_hits);
124 
125  int KalmanFitBothWays(art::ValidHandle<std::vector<Hit> > &hitHandle,
126  std::vector<std::vector<int> > &hitlist,
127  std::vector<int> &hsi,
128  int itrack,
129  std::set<int> &unused_hits,
130  TrackPar &trackpar
131  );
132 
133  int FitHelix(art::ValidHandle<std::vector<Hit> > &hitHandle,
134  std::vector<std::vector<int> > &hitlist,
135  std::vector<int> &hsi,
136  int itrack,
137  bool isForwards,
138  std::set<int> &unused_hits,
139  TrackPar &trackpar
140  );
141 
142  size_t ifob(size_t ihit, size_t nhits, bool isForwards);
143 
144  float capprox(float x1,float y1,
145  float x2,float y2,
146  float x3,float y3,
147  float &xc, float &yc); ///< initial guess of curvature calculator -- from ALICE. Also returns circle center
148 
149  float capprox2(float y0, float z0, float y1, float z1, float y2, float z2); // -- returns abs value of curvature
150 
151  typedef struct{
152  TVector3 pos;
153  TVector3 dir;
154  std::vector<size_t> hitindex;
155  } vechit_t;
156 
157  bool vh_hitmatch(TVector3 &hpvec, int ihit, vechit_t &vechit, const std::vector<gar::rec::Hit> &hits, std::vector<int> &hsi);
158  void fitlinesdir(std::vector<TVector3> &hlist, TVector3 &pos, TVector3 &dir);
159  void fitline(std::vector<double> &x, std::vector<double> &y, double &lambda, double &intercept);
160  bool vhclusmatch(std::vector<vechit_t> &cluster, vechit_t &vh);
161 
162  };
163 
164  // constructor
165 
167  {
168 
169  fHitRCut = p.get<float>("HitRCut",240);
170  fPatRecAlg = p.get<size_t>("PatRecAlg",2);
171  fPatRecLookBack1 = p.get<size_t>("PatRecLookBack1",5);
172  fPatRecLookBack2 = p.get<size_t>("PatRecLookBack2",10);
173  if (fPatRecLookBack1 == fPatRecLookBack2)
174  {
175  throw cet::exception("tracker1_module: PatRecLookBack1 and PatRecLookBack2 are the same");
176  }
177  fHitResolYZ = p.get<float>("HitResolYZ",1.0); // TODO -- think about what this value is
178  fHitResolX = p.get<float>("HitResolX",0.5); // this is probably much better
179  fSigmaRoad = p.get<float>("SigmaRoad",5.0);
180  fMinNumHits = p.get<unsigned int>("MinNumHits",20);
181  fHitLabel = p.get<std::string>("HitLabel","hit");
182  fPrintLevel = p.get<int>("PrintLevel",0);
183  fTrackPass = p.get<int>("TrackPass",2);
184  fDumpTracks = p.get<int>("DumpTracks",2);
185  fHitResolYZinFit = p.get<float>("HitResolYZinFit",4.0);
186  fRoadYZinFit = p.get<float>("RoadYZinFit",1.0);
187  fFirstPassFitType = p.get<std::string>("FirstPassFitType","helix");
188  fSecondPassFitType = p.get<std::string>("SecondPassFitType","Kalman");
189  fMaxVecHitLen = p.get<float>("MaxVecHitLen",10.0);
190  fVecHitRoad = p.get<float>("VecHitRoad",5.0);
191  fVecHitMatchCos = p.get<float>("VecHitMatchCos",0.9);
192  fVecHitMatchPos = p.get<float>("VecHitMatchPos",20.0);
193  fVecHitMatchPEX = p.get<float>("VecHitMatchPEX",5.0);
194  fVecHitMatchEta = p.get<float>("VecHitMatchEta",1.0);
195  fVecHitMatchLambda = p.get<float>("VecHitMatchLambda",0.1);
196  fVecHitMinHits = p.get<unsigned int>("VecHitMinHits",3);
197 
198  fSortOrder = p.get<std::string>("SortOrder","AlongLength");
199  fInitialTPNHits = p.get<int>("InitialTPNHits",100);
200 
201  fKalCurvStepUncSq = p.get<float>("KalCurvStepUncSq",1.0E-9);
202  fKalPhiStepUncSq = p.get<float>("KalPhiStepUncSq",1.0E-9);
203  fKalLambdaStepUncSq = p.get<float>("KalLambdaStepUncSq",1.0E-9);
204 
205  art::InputTag itag(fHitLabel);
206  consumes< std::vector<gar::rec::Hit> >(itag);
207  produces< std::vector<gar::rec::Track> >();
208  produces< art::Assns<gar::rec::Hit, gar::rec::Track> >();
209  }
210 
212  {
213  std::unique_ptr< std::vector<gar::rec::Track> > trkCol(new std::vector<gar::rec::Track>);
214  std::unique_ptr< art::Assns<gar::rec::Hit,gar::rec::Track> > hitTrkAssns(new ::art::Assns<gar::rec::Hit,gar::rec::Track>);
215 
216  auto hitHandle = e.getValidHandle< std::vector<Hit> >(fHitLabel);
217  auto const& hits = *hitHandle;
218 
219  auto const trackPtrMaker = art::PtrMaker<gar::rec::Track>(e);
220  auto const hitPtrMaker = art::PtrMaker<gar::rec::Hit>(e, hitHandle.id());
221 
223  G4ThreeVector zerovec(0,0,0);
224  G4ThreeVector magfield = magFieldService->FieldAtPoint(zerovec);
225 
227  double xtpccent = geo->TPCXCent();
228  double ytpccent = geo->TPCYCent();
229  double ztpccent = geo->TPCZCent();
230  TVector3 tpccent(xtpccent,ytpccent,ztpccent);
231  TVector3 xhat(1,0,0);
232 
233  // make an array of hit indices sorted by hit X position
234  std::vector<float> hitx;
235  for (size_t i=0; i<hits.size(); ++i)
236  {
237  hitx.push_back(hits[i].Position()[0]);
238  }
239  std::vector<int> hsi(hitx.size());
240  TMath::Sort((int) hitx.size(),hitx.data(),hsi.data());
241 
242  float roadsq = fSigmaRoad*fSigmaRoad;
243 
244  // record which hits we have assigned to which tracks. Make a forwards and a backwards hit list
245  // as the sorting is different
246 
247  std::vector< std::vector<int> > hitlist;
248 
249  float resolSq = fHitResolYZ*fHitResolYZ;
250 
251  // initial patrec algorithm -- sort hits in x and look for clusters in y and z
252 
253  if (fPatRecAlg == 1)
254  {
255 
256  // do this twice, once going forwards through the hits, once backwards, and then collect hits
257  // in groups and split them when either the forwards or the backwards list says to split them.
258 
259  std::vector< std::vector<int> > hitlistf;
260  std::vector<int> trackf(hits.size());
261  for (size_t ihit=0; ihit<hits.size(); ++ihit)
262  {
263  const float *hpos = hits[hsi[ihit]].Position();
264  TVector3 hpvec(hpos);
265  if ( ((hpos - tpccent).Cross(xhat)).Mag() > fHitRCut ) continue; // skip hits if they are too far away from center as the
266  // last few pad rows may have distorted hits
267 
268  float bestsignifs = -1;
269  int ibest = -1;
270  for (size_t itcand = 0; itcand < hitlistf.size(); ++itcand)
271  {
272  float signifs = 1E9;
273  size_t hlsiz = hitlistf[itcand].size();
274  if (hlsiz > fPatRecLookBack1 && hlsiz > fPatRecLookBack2)
275  {
276  TVector3 pt1( hits[hsi[hitlistf[itcand][hlsiz-fPatRecLookBack1]]].Position() );
277  TVector3 pt2( hits[hsi[hitlistf[itcand][hlsiz-fPatRecLookBack2]]].Position() );
278  TVector3 uv = pt1-pt2;
279  uv *= 1.0/uv.Mag();
280  signifs = ((hpvec-pt1).Cross(uv)).Mag2()/resolSq;
281  }
282  else // not enough hits, just look how close we are to the last one
283  {
284  const float *cpos = hits[hsi[hitlistf[itcand].back()]].Position();
285  signifs = (TMath::Sq( (hpos[1]-cpos[1]) ) +
286  TMath::Sq( (hpos[2]-cpos[2]) ))/resolSq;
287  }
288  if (bestsignifs < 0 || signifs < bestsignifs)
289  {
290  bestsignifs = signifs;
291  ibest = itcand;
292  }
293  }
294  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
295  {
296  ibest = hitlistf.size();
297  std::vector<int> vtmp;
298  hitlistf.push_back(vtmp);
299  }
300  hitlistf[ibest].push_back(ihit);
301  trackf[ihit] = ibest;
302  }
303 
304  std::vector< std::vector<int> > hitlistb;
305  std::vector<int> trackb(hits.size());
306  for (int ihit=hits.size()-1; ihit >= 0; --ihit)
307  {
308  const float *hpos = hits[hsi[ihit]].Position();
309  TVector3 hpvec(hpos);
310  if ( ((hpos - tpccent).Cross(xhat)).Mag() > fHitRCut ) continue; // skip hits if they are too far away from center as the
311  // last few pad rows may have distorted hits
312 
313  float bestsignifs = -1;
314  int ibest = -1;
315  for (size_t itcand = 0; itcand < hitlistb.size(); ++itcand)
316  {
317  float signifs = 1E9;
318  size_t hlsiz = hitlistb[itcand].size();
319  if (hlsiz > fPatRecLookBack1 && hlsiz > fPatRecLookBack2)
320  {
321  TVector3 pt1( hits[hsi[hitlistb[itcand][hlsiz-fPatRecLookBack1]]].Position() );
322  TVector3 pt2( hits[hsi[hitlistb[itcand][hlsiz-fPatRecLookBack2]]].Position() );
323  TVector3 uv = pt1-pt2;
324  uv *= 1.0/uv.Mag();
325  signifs = ((hpvec-pt1).Cross(uv)).Mag2()/resolSq;
326  }
327  else // not enough hits, just look how close we are to the last one
328  {
329  const float *cpos = hits[hsi[hitlistb[itcand].back()]].Position();
330  signifs = (TMath::Sq( (hpos[1]-cpos[1]) ) +
331  TMath::Sq( (hpos[2]-cpos[2]) ))/resolSq;
332  }
333 
334  if (bestsignifs < 0 || signifs < bestsignifs)
335  {
336  bestsignifs = signifs;
337  ibest = itcand;
338  }
339  }
340  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
341  {
342  ibest = hitlistb.size();
343  std::vector<int> vtmp;
344  hitlistb.push_back(vtmp);
345  }
346  hitlistb[ibest].push_back(ihit);
347  trackb[ihit] = ibest;
348  }
349 
350  // make a list of tracks that is the set of disjoint subsets
351 
352  for (size_t itrack=0; itrack<hitlistf.size(); ++itrack)
353  {
354  int itrackl = 0;
355  for (size_t ihit=0; ihit<hitlistf[itrack].size(); ++ihit)
356  {
357  int ihif = hitlistf[itrack][ihit];
358  if (ihit == 0 || (trackb[ihif] != itrackl))
359  {
360  std::vector<int> vtmp;
361  hitlist.push_back(vtmp);
362  itrackl = trackb[ihif];
363  }
364  hitlist.back().push_back(ihif);
365  }
366  }
367 
368  }
369 
370  // second try at a patrec algorithm -- find "vector hits"
371  // start with hits sorted in x. At least that limits how far through the list we must search
372  // make a vector of vector hits, and then piece them together to form track candidates.
373 
374  else if (fPatRecAlg == 2)
375  {
376  std::vector<vechit_t> vechits;
377  std::vector<vechit_t> vhtmp;
378 
379  for (size_t ihit=0; ihit<hits.size(); ++ihit)
380  {
381  const float *hpos = hits[hsi[ihit]].Position();
382  TVector3 hpvec(hpos);
383  if ( ((hpos - tpccent).Cross(xhat)).Mag() > fHitRCut ) continue; // skip hits if they are too far away from center as the
384  // last few pad rows may have distorted hits
385 
386  bool matched=false;
387  for (size_t ivh=0; ivh<vhtmp.size(); ++ivh)
388  {
389  //std::cout << "testing hit: " << ihit << " with vector hit " << ivh << std::endl;
390  if (vh_hitmatch(hpvec, ihit, vhtmp[ivh], hits, hsi )) // updates vechit with this hit if matched
391  {
392  matched = true;
393  break;
394  }
395  }
396  if (!matched) // make a new vechit if we haven't found one yet
397  {
398  vechit_t vh;
399  vh.pos.SetXYZ(hpos[0],hpos[1],hpos[2]);
400  vh.dir.SetXYZ(0,0,0); // new vechit with just one hit; don't know the direction yet
401  vh.hitindex.push_back(ihit);
402  vhtmp.push_back(vh);
403  //std::cout << "Created a new vector hit with one hit: " << hpos[0] << " " << hpos[1] << " " << hpos[2] << std::endl;
404  }
405  }
406 
407  // trim the list of vechits down to only those with more than two hits
408 
409  for (size_t ivh=0; ivh<vhtmp.size(); ++ivh)
410  {
411  if (vhtmp[ivh].hitindex.size() >= (size_t)fVecHitMinHits)
412  {
413  vechits.push_back(vhtmp[ivh]);
414  }
415  }
416 
417  // stitch together vector hits into tracks
418  // question -- do we need to iterate this, first looking for small-angle matches, and then
419  // loosening up? Also need to address tracks that get stitched across the primary vertex -- may need to split
420  // these after other tracks have been found.
421 
422  std::vector< std::vector< vechit_t > > vhclusters;
423 
424  for (size_t ivh = 0; ivh< vechits.size(); ++ ivh)
425  {
426  //std::cout << " vhprint " << vechits[ivh].pos.X() << " " << vechits[ivh].pos.Y() << " " << vechits[ivh].pos.Z() << " " <<
427  //vechits[ivh].dir.X() << " " << vechits[ivh].dir.Y() << " " << vechits[ivh].dir.Z() << " " << vechits[ivh].hitindex.size() << std::endl;
428 
429  std::vector<size_t> clusmatchlist;
430  for (size_t iclus=0; iclus<vhclusters.size(); ++iclus)
431  {
432  if (vhclusmatch(vhclusters[iclus],vechits[ivh]))
433  {
434  clusmatchlist.push_back(iclus);
435  }
436  }
437  if (clusmatchlist.size() == 0)
438  {
439  std::vector<vechit_t> newclus;
440  newclus.push_back(vechits[ivh]);
441  vhclusters.push_back(newclus);
442  }
443  else if (clusmatchlist.size() == 1)
444  {
445  vhclusters[clusmatchlist[0]].push_back(vechits[ivh]);
446  }
447  else // multiple matches -- merge clusters togetehr
448  {
449  for (size_t icm=1; icm<clusmatchlist.size(); ++icm)
450  {
451  for (size_t ivh=0; ivh<vhclusters[clusmatchlist[icm]].size(); ++ivh)
452  {
453  vhclusters[clusmatchlist[0]].push_back(vhclusters[clusmatchlist[icm]][ivh]);
454  }
455  }
456  // remove the merged vh clusters, using the new indexes after removing earlier ones
457  for (size_t icm=1; icm<clusmatchlist.size(); ++icm)
458  {
459  vhclusters.erase(vhclusters.begin() + (clusmatchlist[icm]-icm+1));
460  }
461  }
462  }
463 
464 
465  // populate the hit list with hits from the vector hits in clusters.
466 
467  for (size_t iclus=0; iclus < vhclusters.size(); ++iclus)
468  {
469  std::vector<int> vtmp;
470  hitlist.push_back(vtmp);
471  for (size_t ivh=0; ivh < vhclusters[iclus].size(); ++ ivh)
472  {
473  for (size_t ihit=0; ihit < vhclusters[iclus][ivh].hitindex.size(); ++ihit)
474  {
475  hitlist.back().push_back(vhclusters[iclus][ivh].hitindex[ihit]);
476  //std::cout << "Added a hit " << hitlist.back().size() << " to track: " << iclus << std::endl;
477  }
478  }
479  // re-sort the hitlist in x
480 
481  std::sort(hitlist[iclus].begin(), hitlist[iclus].end(),
482  [&hsi](int a, int b ) { return (hsi[a] > hsi[b]);});
483  }
484  }
485 
486  else
487  {
488  throw cet::exception("tracker1_module.cc: ununderstood PatRecAlg: ") << fPatRecAlg;
489  }
490 
491  size_t ntracks = hitlist.size();
492 
493  // do a first pass of fitting the tracks
494 
495  std::vector<TrackPar> firstpass_tracks;
496  std::vector<int> firstpass_tid;
497  std::vector<TrackPar> secondpass_tracks;
498  std::vector<int> secondpass_tid;
499 
500  if (fDumpTracks > 0)
501  {
502  int ntracktmp = 0;
503  for (size_t itrack=0;itrack<ntracks;++itrack)
504  {
505  if (hitlist[itrack].size() >= fMinNumHits) ntracktmp++;
506  }
507  std::cout << "Trkdump: " << ntracktmp << std::endl;
508  }
509 
510  std::vector<int> whichtrack(hits.size(),-1);
511 
512  for (size_t itrack=0; itrack<ntracks; ++itrack)
513  {
514  size_t nhits = hitlist[itrack].size();
515  if ( nhits >= fMinNumHits)
516  {
517  for (size_t ihit=0; ihit<nhits; ++ihit)
518  {
519  whichtrack[hitlist[itrack][ihit]] = itrack; // fill this here so we only get the ones passing the nhits cut
520  }
521 
522  if (fPrintLevel)
523  {
524  std::cout << "Starting a new Pass1 track: " << itrack << " Number of hits: " << nhits << std::endl;
525  }
526 
527  TrackPar trackparams;
528  std::set<int> unused_hits;
529 
530  int retcode=0;
531  if (fFirstPassFitType == "helix")
532  {
533  retcode = FitHelix(hitHandle,hitlist,hsi,itrack,true,unused_hits,trackparams);
534  }
535  else if (fFirstPassFitType == "Kalman")
536  {
537  retcode = KalmanFitBothWays(hitHandle,hitlist,hsi,itrack,unused_hits,trackparams);
538  }
539  else
540  {
541  throw cet::exception("Tracker1") << "Invalid first-pass fit type: " << fFirstPassFitType;
542  }
543  if (retcode != 0) continue;
544 
545  firstpass_tracks.push_back(trackparams);
546  firstpass_tid.push_back(itrack);
547 
548  if (fDumpTracks > 0)
549  {
550  std::cout << "Trkdump: " << itrack << std::endl;
551  std::cout << "Trkdump: " << trackparams.getTrackParametersBegin()[5] << std::endl;
552  for (int i=0; i<5;++i) std::cout << "Trkdump: " << trackparams.getTrackParametersBegin()[i] << std::endl;
553  std::cout << "Trkdump: " << trackparams.getTrackParametersEnd()[5] << std::endl;
554  for (int i=0; i<5;++i) std::cout << "Trkdump: " << trackparams.getTrackParametersEnd()[i] << std::endl;
555  std::cout << "Trkdump: " << nhits << std::endl;
556  for (size_t ihit=0;ihit<nhits;++ihit)
557  {
558  std::cout << "Trkdump: " << hits[hsi[hitlist[itrack][ihit]]].Position()[0] << std::endl;
559  std::cout << "Trkdump: " << hits[hsi[hitlist[itrack][ihit]]].Position()[1] << std::endl;
560  std::cout << "Trkdump: " << hits[hsi[hitlist[itrack][ihit]]].Position()[2] << std::endl;
561  }
562  }
563  }
564  }
565 
566  // Rearrange the hit lists -- ask ourselves which track each hit is best assigned to. Make a new hit list, hitlist2
567  // start only with hits that were assigned to tracks in pass1 (i.e. don't try to add new hits that made short, faraway tracks)
568  // todo -- change this last requirement to an absolute distance cut. Debug the track parameter extrapolation first.
569 
570  std::vector< std::vector<int> > hitlist2(firstpass_tracks.size());
571  if (firstpass_tracks.size() > 0 && fTrackPass > 1)
572  {
573  for (size_t ihit=0; ihit< hits.size(); ++ihit)
574  {
575  if (whichtrack[ihit] < 0) continue;
576  const float *hpos = hits[hsi[ihit]].Position();
577  float mindist = 0;
578  size_t ibest = 0;
579  for (size_t itrack=0; itrack<firstpass_tracks.size(); ++itrack)
580  {
581  float dist = firstpass_tracks[itrack].DistXYZ(hpos);
582  if (itrack == 0 || dist < mindist)
583  {
584  mindist = dist;
585  ibest = itrack;
586  }
587  }
588  hitlist2[ibest].push_back(ihit);
589  }
590 
591  size_t ntracks2 = hitlist2.size();
592  for (size_t itrack=0; itrack<ntracks2; ++itrack)
593  {
594  size_t nhits = hitlist2[itrack].size();
595  if ( nhits >= fMinNumHits)
596  {
597  if (fPrintLevel)
598  {
599  std::cout << "Starting a new Pass2 track: " << itrack << " Number of hits: " << nhits << std::endl;
600  }
601 
602  TrackPar trackparams;
603  std::set<int> unused_hits;
604 
605  int retcode=0;
606  if (fFirstPassFitType == "helix")
607  {
608  retcode = FitHelix(hitHandle,hitlist2,hsi,itrack,true,unused_hits,trackparams);
609  }
610  else if (fFirstPassFitType == "Kalman")
611  {
612  retcode = KalmanFitBothWays(hitHandle,hitlist2,hsi,itrack,unused_hits,trackparams);
613  }
614  else
615  {
616  throw cet::exception("Tracker1") << "Invalid first-pass fit type: " << fFirstPassFitType;
617  }
618  if (retcode != 0) continue;
619 
620  secondpass_tracks.push_back(trackparams);
621  secondpass_tid.push_back(itrack);
622  }
623  }
624  }
625  // Remove stray hits. Dig through unassociated hits and try to make extra tracks out of them.
626  // May need to wait until vertex finding is done so we know where to concentrate the effort
627 
628  // currently -- put second-pass tracks and associations with hits in the event
629 
630  if (fTrackPass == 1)
631  {
632  for (size_t itrack=0; itrack<firstpass_tracks.size(); ++itrack)
633  {
634  trkCol->push_back(firstpass_tracks[itrack].CreateTrack());
635  auto const trackpointer = trackPtrMaker(itrack);
636  for (size_t ihit=0; ihit<hitlist[firstpass_tid[itrack]].size(); ++ ihit)
637  {
638  auto const hitpointer = hitPtrMaker(hsi[hitlist[firstpass_tid[itrack]][ihit]]);
639  hitTrkAssns->addSingle(hitpointer,trackpointer);
640  }
641  }
642  }
643  else if (fTrackPass == 2)
644  {
645  for (size_t itrack=0; itrack<secondpass_tracks.size(); ++itrack)
646  {
647  trkCol->push_back(secondpass_tracks[itrack].CreateTrack());
648  auto const trackpointer = trackPtrMaker(itrack);
649  for (size_t ihit=0; ihit<hitlist2[secondpass_tid[itrack]].size(); ++ ihit)
650  {
651  auto const hitpointer = hitPtrMaker(hsi[hitlist2[secondpass_tid[itrack]][ihit]]);
652  hitTrkAssns->addSingle(hitpointer,trackpointer);
653  }
654  }
655  }
656  else
657  {
658  throw cet::exception("Tracker1") << "Invalid track pass number requested: " << fTrackPass;
659  }
660 
661  e.put(std::move(trkCol));
662  e.put(std::move(hitTrkAssns));
663  }
664 
665  //_____________________________________________________________________________
666  float tracker1::capprox(float x1,float y1,
667  float x2,float y2,
668  float x3,float y3,
669  float &xc, float &yc)
670  {
671  //-----------------------------------------------------------------
672  // Initial approximation of the track curvature -- copied from ALICE
673  // here x is y and y is z for us
674  //-----------------------------------------------------------------
675  x3 -=x1;
676  x2 -=x1;
677  y3 -=y1;
678  y2 -=y1;
679  //
680  float det = x3*y2-x2*y3;
681  if (TMath::Abs(det)<1e-10){
682  return 100;
683  }
684  //
685  float u = 0.5* (x2*(x2-x3)+y2*(y2-y3))/det;
686  float x0 = x3*0.5-y3*u;
687  float y0 = y3*0.5+x3*u;
688  float c2 = 1/TMath::Sqrt(x0*x0+y0*y0);
689  xc = x0 + x1;
690  yc = y0 + y1;
691  if (det<0) c2*=-1;
692  return c2;
693  }
694 
695  // redo this using y and z as coordinates, and also return a positive value. The caller needs to decide the
696  // screw orientation of the helix -- not enough to go on with just y and z coordinates
697 
698  float tracker1::capprox2(float y0, float z0, float y1, float z1, float y2, float z2)
699  {
700  float A = y1*(z2 - z0) - z1*(y2 - y0) + (y2*z0 - z2*y0);
701 
702  float B = -( (y1*y1 + z1*z1)*(z2 - z0)
703  -z1*( (y2*y2 + z2*z2) - (y0*y0 + z0*z0) )
704  + ( (y2*y2 + z2*z2)*z0 - z2*(y0*y0 + z0*z0) ) );
705 
706  float C = (y1*y1 + z1*z1)*(y2 - y0)
707  -y1*( (y2*y2 + z2*z2) - (y0*y0 + z0*z0))
708  + ( (y2*y2 + z2*z2)*y0 - y2*(y0*y0 + z0*z0) );
709 
710  float D = - ( (y1*y1 + z1*z1)*(y2*z0 - z2*y0)
711  - y1*( (y2*y2 + z2*z2)*z0 - z2*(y0*y0 + z0*z0) )
712  + z1*( (y2*y2 + z2*z2)*y0 - y2*(y0*y0 + z0*z0) ));
713 
714  if (TMath::Abs(A) < 1E-10)
715  { return 0;}
716 
717  float yc = -B/(2.0*A);
718  float zc = -C/(2.0*A);
719  float rs = yc*yc + zc*zc -D/A;
720 
721  if (fPrintLevel > 1)
722  {
723  std::cout << " In capprox2, A, B, C, D, rs: " << A << " " << B << " " << C << " " << D << " " << rs << std::endl;
724  }
725  if (rs <= 0)
726  { throw cet::exception("tracker1capprox2: negative input to sqrt"); }
727  float curv = 1.0/TMath::Sqrt(rs);
728  return curv;
729  }
730 
731 
732  int tracker1::KalmanFitBothWays(art::ValidHandle<std::vector<Hit> > &hitHandle,
733  std::vector<std::vector<int> > &hitlist,
734  std::vector<int> &hsi,
735  int itrack,
736  std::set<int> &unused_hits,
737  TrackPar &trackpar
738  )
739 
740  {
741  // variables: x is the independent variable
742  // 0: y
743  // 1: z
744  // 2: curvature
745  // 3: phi
746  // 4: lambda = angle from the cathode plane
747  // 5: x /// added on to the end
748 
749  // the "forward" fit is just in increasing x. Track parameters are at the end of the fit
750 
751 
752  // re-sort hits before giving them to the fitter. Sorting in X may scramble the hit order if the track is in the Y,Z plane
753  // start calling them tracks here.
754 
755  std::vector<std::vector<int> > hlf;
756  std::vector<std::vector<int> > hlb;
757 
758  if (fSortOrder == "AlongLength")
759  {
760 
761  hlf = hitlist; // only sort the track we're working on but pass the whole hitlist to the Kalman filter for historical reasons
762  hlb = hitlist;
763 
764  auto const& hits = *hitHandle;
765 
766  float cmin[3]; // min x, y, and z coordinates over all hits
767  float cmax[3]; // max x, y, and z coordinates over all hits
768  size_t ihex[6]; // index of hit which gave the min or max ("extreme") 0-2: (min xyz) 3-5 (max xyz)
769 
770  for (size_t ihit=0; ihit<hitlist[itrack].size(); ++ihit)
771  {
772  for (int i=0; i<3; ++i)
773  {
774  float c = hits[hsi[hitlist[itrack][ihit]]].Position()[i];
775  if (ihit==0)
776  {
777  cmin[i] = c;
778  cmax[i] = c;
779  ihex[i] = 0;
780  ihex[i+3] = 0;
781  }
782  else
783  {
784  if (c<cmin[i])
785  {
786  cmin[i] = c;
787  ihex[i] = ihit;
788  }
789  if (c>cmax[i])
790  {
791  cmax[i] = c;
792  ihex[i+3] = ihit;
793  }
794  }
795  }
796  }
797  // now we have six hits that have the min and max x, y, and z values. Find out which of these six
798  // hits has the biggest sum of distances to all the other hits (the most extreme)
799  float sumdmax = 0;
800  size_t imax = 0;
801  for (size_t i=0; i<6; ++i)
802  {
803  float sumd = 0;
804  TVector3 poshc(hits[hsi[hitlist[itrack][ihex[i]]]].Position());
805  for (size_t ihit=0; ihit<hitlist[itrack].size(); ++ihit)
806  {
807  TVector3 hp(hits[hsi[hitlist[itrack][ihit]]].Position());
808  sumd += (poshc - hp).Mag();
809  }
810  if (sumd > sumdmax)
811  {
812  sumdmax = sumd;
813  imax = i;
814  }
815  }
816 
817  // Use this hit as a starting point -- find the closest hit to the last
818  // and add it to the newly sorted list hls. Change -- sort hits in order of how
819  // far they are from the first hit. Prevents oscillations in position on sort order.
820  // This can be optimized to just sort an arry of distances using TMath::Sort.
821 
822  std::vector<int> hls;
823  hls.push_back(hitlist[itrack][ihex[imax]]);
824  TVector3 lpos(hits[hsi[hls[0]]].Position());
825  for (size_t inh=1;inh<hitlist[itrack].size();++inh)
826  {
827  float dmin=0;
828  float jmin=-1;
829  for (size_t jh=0;jh<hitlist[itrack].size();++jh)
830  {
831  bool found = false;
832  for (size_t kh=0;kh<hls.size();++kh)
833  {
834  if (hls[kh] == hitlist[itrack][jh])
835  {
836  found = true;
837  break;
838  }
839  }
840  if (found) continue; // skip if we've already assigned this hit on this track
841  TVector3 hpos(hits[hsi[hitlist[itrack][jh]]].Position());
842  float d=(hpos-lpos).Mag();
843  if (jmin == -1)
844  {
845  jmin = jh;
846  dmin = d;
847  }
848  else
849  {
850  if (d<dmin)
851  {
852  jmin = jh;
853  dmin = d;
854  }
855  }
856  }
857  // std::cout << "dmin: " << dmin << std::endl;
858  hls.push_back(hitlist[itrack][jmin]);
859  }
860  // replace our hit list with our newly sorted hit list.
861 
862  if (fPrintLevel>2)
863  {
864  std::cout << "Itrack: " << itrack << std::endl;
865  for (size_t ihit=0; ihit<hitlist[itrack].size(); ++ihit)
866  {
867  printf("Sort compare: %5d %10.3f %10.3f %10.3f %5d %10.3f %10.3f %10.3f\n",
868  hitlist[itrack][ihit],
869  hits[hsi[hitlist[itrack][ihit]]].Position()[0],
870  hits[hsi[hitlist[itrack][ihit]]].Position()[1],
871  hits[hsi[hitlist[itrack][ihit]]].Position()[2],
872  hls[ihit],
873  hits[hsi[hls[ihit]]].Position()[0],
874  hits[hsi[hls[ihit]]].Position()[1],
875  hits[hsi[hls[ihit]]].Position()[2]);
876  }
877  }
878  hlf[itrack] = hls;
879 
880  // now go backwards -- start at the end hit and use that as a starting point
881 
882  hls.clear();
883  hls.push_back(hlf[itrack].back());
884  TVector3 lpos2(hits[hsi[hls[0]]].Position());
885  for (size_t inh=1;inh<hitlist[itrack].size();++inh)
886  {
887  float dmin=0;
888  float jmin=-1;
889  for (size_t jh=0;jh<hitlist[itrack].size();++jh)
890  {
891  bool found = false;
892  for (size_t kh=0;kh<hls.size();++kh)
893  {
894  if (hls[kh] == hitlist[itrack][jh])
895  {
896  found = true;
897  break;
898  }
899  }
900  if (found) continue; // skip if we've already assigned this hit on this track
901  TVector3 hpos(hits[hsi[hitlist[itrack][jh]]].Position());
902  float d=(hpos-lpos2).Mag();
903  if (jmin == -1)
904  {
905  jmin = jh;
906  dmin = d;
907  }
908  else
909  {
910  if (d<dmin)
911  {
912  jmin = jh;
913  dmin = d;
914  }
915  }
916  }
917  // std::cout << "dmin: " << dmin << std::endl;
918  hls.push_back(hitlist[itrack][jmin]);
919  }
920  // replace our hit list with our newly sorted hit list.
921 
922  if (fPrintLevel>2)
923  {
924  std::cout << "Itrack: " << itrack << std::endl;
925  for (size_t ihit=0; ihit<hitlist[itrack].size(); ++ihit)
926  {
927  printf("Sort compare: %5d %10.3f %10.3f %10.3f %5d %10.3f %10.3f %10.3f\n",
928  hitlist[itrack][ihit],
929  hits[hsi[hitlist[itrack][ihit]]].Position()[0],
930  hits[hsi[hitlist[itrack][ihit]]].Position()[1],
931  hits[hsi[hitlist[itrack][ihit]]].Position()[2],
932  hls[ihit],
933  hits[hsi[hls[ihit]]].Position()[0],
934  hits[hsi[hls[ihit]]].Position()[1],
935  hits[hsi[hls[ihit]]].Position()[2]);
936  }
937  }
938  hlb[itrack] = hls;
939 
940  }
941  else if (fSortOrder == "X")
942  {
943  hlf = hitlist;
944  std::sort(hlf[itrack].begin(), hlf[itrack].end(),
945  [&hsi](int a, int b ) { return (hsi[a] > hsi[b]);});
946  hlb = hitlist;
947  std::sort(hlb[itrack].begin(), hlb[itrack].end(),
948  [&hsi](int a, int b ) { return (hsi[a] < hsi[b]);});
949  }
950 
951  std::vector<float> tparend(6);
952  float covmatend[25];
953  float chisqforwards = 0;
954  float lengthforwards = 0;
955  int retcode = KalmanFit(hitHandle,hlf,hsi,itrack,true,tparend,chisqforwards,lengthforwards,covmatend,unused_hits);
956  if (retcode != 0) return 1;
957 
958  // the "backwards" fit is in decreasing x. Track paramters are at the end of the fit, the other end of the track
959 
960  std::vector<float> tparbeg(6);
961  float covmatbeg[25];
962  float chisqbackwards = 0;
963  float lengthbackwards = 0;
964 
965  retcode = KalmanFit(hitHandle,hlb,hsi,itrack,false,tparbeg,chisqbackwards,lengthbackwards,covmatbeg,unused_hits);
966  if (retcode != 0) return 1;
967 
968  size_t nhits=0;
969  if (hitlist[itrack].size()>unused_hits.size())
970  { nhits = hitlist[itrack].size()-unused_hits.size(); }
971  trackpar.setNHits(nhits);
972  trackpar.setTime(0);
973  trackpar.setChisqForwards(chisqforwards);
974  trackpar.setChisqBackwards(chisqbackwards);
975  trackpar.setLengthForwards(lengthforwards);
976  trackpar.setLengthBackwards(lengthbackwards);
977  trackpar.setCovMatBeg(covmatbeg);
978  trackpar.setCovMatEnd(covmatend);
979  trackpar.setTrackParametersBegin(tparbeg.data());
980  trackpar.setXBeg(tparbeg[5]);
981  trackpar.setTrackParametersEnd(tparend.data());
982  trackpar.setXEnd(tparend[5]);
983 
984  return 0;
985  }
986 
987  //--------------------------------------------------------------------------------------------------------------
988  //--------------------------------------------------------------------------------------------------------------
989 
990  // KalmanFit does a forwards or backwards Kalman fit using the sorted hit list
991  // variables: x is the independent variable
992  // 0: y
993  // 1: z
994  // 2: curvature
995  // 3: phi
996  // 4: lambda
997 
998  int tracker1::KalmanFit( art::ValidHandle<std::vector<Hit> > &hitHandle,
999  std::vector<std::vector<int> > &hitlist,
1000  std::vector<int> &hsi,
1001  int itrack,
1002  bool isForwards,
1003  std::vector<float> &trackparatend,
1004  float &chisquared,
1005  float &length,
1006  float *covmat, // 5x5 covariance matrix
1007  std::set<int> &unused_hits)
1008  {
1009 
1010  // set some default values in case we return early
1011 
1012  auto const& hits = *hitHandle;
1013  size_t nhits = hitlist[itrack].size();
1014  chisquared = 0;
1015  length = 0;
1016  for (size_t i=0; i<5; ++i) trackparatend[i] = 0;
1017  for (size_t i=0; i<25; ++i) covmat[i] = 0;
1018 
1019  float roadsq = fRoadYZinFit*fRoadYZinFit;
1020 
1021  // estimate curvature, lambda, phi, xpos from the initial track parameters
1022  float curvature_init=0.1;
1023  float phi_init = 0;
1024  float lambda_init = 0;
1025  float xpos_init=0;
1026  float ypos_init=0;
1027  float zpos_init=0;
1028  float x_other_end = 0;
1029  if ( initial_trackpar_estimate(hitHandle,
1030  hitlist,
1031  hsi,
1032  itrack,
1033  isForwards,
1034  curvature_init,
1035  lambda_init,
1036  phi_init,
1037  xpos_init,
1038  ypos_init,
1039  zpos_init,
1040  x_other_end) != 0)
1041  {
1042  //std::cout << "kalman fit failed on initial trackpar estimate" << std::endl;
1043  return 1;
1044  }
1045 
1046  // Kalman fitter variables
1047 
1048  float xpos = xpos_init;
1049 
1050  TMatrixF P(5,5); // covariance matrix of parameters
1051  // fill in initial guesses -- generous uncertainties on first value.
1052  P.Zero();
1053  P[0][0] = TMath::Sq(1); // initial position uncertainties -- y
1054  P[1][1] = TMath::Sq(1); // and z
1055  P[2][2] = TMath::Sq(.5); // curvature of zero gets us to infinite momentum, and curvature of 2 is curled up tighter than the pads
1056  P[3][3] = TMath::Sq(.5); // phi uncertainty
1057  P[4][4] = TMath::Sq(.5); // lambda uncertainty
1058 
1059  TMatrixF PPred(5,5);
1060 
1061  // per-step additions to the covariance matrix
1062  TMatrixF Q(5,5);
1063  Q.Zero();
1064  Q[2][2] = fKalCurvStepUncSq; // allow for some curvature uncertainty between points
1065  Q[3][3] = fKalPhiStepUncSq; // phi
1066  Q[4][4] = fKalLambdaStepUncSq; // lambda
1067 
1068  // uncertainties on the measured points (big for now)
1069  TMatrixF R(2,2);
1070  R.Zero();
1071  R[0][0] = TMath::Sq(fHitResolYZinFit); // in cm^2
1072  R[1][1] = TMath::Sq(fHitResolYZinFit); // in cm^2
1073 
1074  // add the hits and update the track parameters and uncertainties. Put in additional terms to keep uncertainties from shrinking when
1075  // scattering and energy loss can change the track parameters along the way.
1076 
1077  // F = partial(updatefunc)/partial(parvec). Update functions are in the comments below.
1078  TMatrixF F(5,5);
1079  TMatrixF FT(5,5);
1080  TVectorF parvec(5);
1081  parvec[0] = ypos_init;
1082  parvec[1] = zpos_init;
1083  parvec[2] = curvature_init;
1084  parvec[3] = phi_init;
1085  parvec[4] = lambda_init;
1086  TVectorF predstep(5);
1087 
1088  TMatrixF H(2,5); // partial(obs)/partial(params)
1089  H.Zero();
1090  H[0][0] = 1; // y
1091  H[1][1] = 1; // z
1092  TMatrixF HT(5,2);
1093 
1094  TVectorF z(2);
1095  TVectorF ytilde(2);
1096  TVectorF hx(2);
1097  TMatrixF S(2,2);
1098  TMatrixF K(5,2);
1099 
1100  TMatrixF I(5,5);
1101  I.Zero();
1102  for (int i=0;i<5;++i) I[i][i] = 1;
1103 
1104  for (size_t ihit=1; ihit<nhits; ++ihit)
1105  {
1106 
1107  size_t ihf = ifob(ihit,nhits,isForwards);
1108  float xh = hits[hsi[hitlist[itrack][ihf]]].Position()[0];
1109  float yh = hits[hsi[hitlist[itrack][ihf]]].Position()[1];
1110  float zh = hits[hsi[hitlist[itrack][ihf]]].Position()[2];
1111 
1112  if (fPrintLevel > 0)
1113  {
1114  std::cout << std::endl;
1115  std::cout << "Adding a new hit: " << xh << " " << yh << " " << zh << std::endl;
1116  }
1117 
1118  // for readability
1119 
1120  float curvature = parvec[2];
1121  float phi = parvec[3];
1122  float lambda = parvec[4];
1123 
1124  // update prediction to the plane containing x. Maybe we need to find the closest point on the helix to the hit we are adding,
1125  // and not necessarily force it to be at this x
1126 
1127  F.Zero();
1128 
1129  // y = yold + slope*dx*Sin(phi). F[0][i] = dy/dtrackpar[i], where f is the update function slope*dx*Sin(phi)
1130 
1131  float slope = TMath::Tan(lambda);
1132  if (slope != 0)
1133  {
1134  slope = 1.0/slope;
1135  }
1136  else
1137  {
1138  slope = 1E9;
1139  }
1140 
1141  // relocate dx to be the location along the helix of the closest point. Linearize for now near xpos.
1142  // old calc
1143 
1144  float dx = xh - xpos;
1145 
1146  float dxdenom = slope*slope/(fHitResolYZ*fHitResolYZ) + 1.0/(fHitResolX*fHitResolX);
1147  float dxnum = (slope/(fHitResolYZ*fHitResolYZ))*( (yh - parvec[0])*TMath::Sin(phi) + (zh - parvec[1])*TMath::Cos(phi) )
1148  + (xh - xpos)/(fHitResolX*fHitResolX);
1149  dx = dxnum/dxdenom;
1150  if (dx == 0) dx = 1E-3;
1151  //std::cout << "dxdenom, dxnum: " << dxdenom << " " << dxnum << std::endl;
1152  //std::cout << "Track pos: " << xpos << " " << parvec[0] << " " << parvec[1] << " " << " Hit pos: " << xh << " " << yh << " " << zh << std::endl;
1153  //std::cout << "dx old and new: " << xh - xpos << " " << dx << std::endl;
1154 
1155 
1156  //TODO check this -- are these the derivatives?
1157 
1158  // y = yold + dx*slope*TMath::Sin(phi)
1159  // slope = cot(lambda), so dslope/dlambda = -csc^2(lambda) = -1 - slope^2
1160  F[0][0] = 1.;
1161  F[0][3] = dx*slope*TMath::Cos(phi);
1162  F[0][4] = dx*TMath::Sin(phi)*(-1.0-slope*slope);
1163 
1164  // z = zold + slope*dx*Cos(phi)
1165  F[1][1] = 1.;
1166  F[1][3] = -dx*slope*TMath::Sin(phi);
1167  F[1][4] = dx*TMath::Cos(phi)*(-1.0-slope*slope);
1168 
1169  // curvature = old curvature -- doesn't change but put in an uncertainty
1170  F[2][2] = 1.;
1171 
1172  // phi = old phi + curvature*slope*dx
1173  // need to take the derivative of a product here
1174  F[3][2] = dx*slope;
1175  F[3][3] = 1.;
1176  F[3][4] = dx*curvature*(-1.0-slope*slope);
1177 
1178  // lambda -- same -- but put in an uncertainty in case it changes
1179  F[4][4] = 1.;
1180 
1181  // predicted step
1182 
1183  if (fPrintLevel > 1)
1184  {
1185  std::cout << "F Matrix: " << std::endl;
1186  F.Print();
1187  std::cout << "P Matrix: " << std::endl;
1188  P.Print();
1189  }
1190  if (fPrintLevel > 0)
1191  {
1192  std::cout << "x: " << xpos << " dx: " << dx << std::endl;
1193  std::cout << " Parvec: y " << parvec[0] << " z " << parvec[1] << " c " << parvec[2] << " phi " << parvec[3] << " lambda " << parvec[4] << std::endl;
1194  }
1195 
1196  predstep = parvec;
1197  predstep[0] += slope*dx*TMath::Sin(phi); // update y
1198  predstep[1] += slope*dx*TMath::Cos(phi); // update z
1199  predstep[3] += slope*dx*curvature; // update phi
1200 
1201  if (fPrintLevel > 1)
1202  {
1203  std::cout << " Predstep: y " << predstep[0] << " z " << predstep[1] << " c " << predstep[2] << " phi " << predstep[3] << " lambda " << predstep[4] << std::endl;
1204  }
1205  // equations from the extended Kalman filter
1206  FT.Transpose(F);
1207  PPred = F*P*FT + Q;
1208  if (fPrintLevel > 1)
1209  {
1210  std::cout << "PPred Matrix: " << std::endl;
1211  PPred.Print();
1212  }
1213 
1214  ytilde[0] = yh - predstep[0];
1215  ytilde[1] = zh - predstep[1];
1216  float ydistsq = ytilde.Norm2Sqr();
1217  if (ydistsq > roadsq)
1218  {
1219  unused_hits.insert(ihf);
1220  continue;
1221  }
1222  chisquared += ytilde.Norm2Sqr()/TMath::Sq(fHitResolYZ);
1223  if (fPrintLevel > 0)
1224  {
1225  std::cout << "ytilde (residuals): " << std::endl;
1226  ytilde.Print();
1227  }
1228  if (fPrintLevel > 1)
1229  {
1230  std::cout << "H Matrix: " << std::endl;
1231  H.Print();
1232  }
1233 
1234  HT.Transpose(H);
1235  S = H*PPred*HT + R;
1236  if (fPrintLevel > 1)
1237  {
1238  std::cout << "S Matrix: " << std::endl;
1239  S.Print();
1240  }
1241 
1242  S.Invert();
1243  if (fPrintLevel > 1)
1244  {
1245  std::cout << "Inverted S Matrix: " << std::endl;
1246  S.Print();
1247  }
1248 
1249  K = PPred*HT*S;
1250  if (fPrintLevel > 1)
1251  {
1252  std::cout << "K Matrix: " << std::endl;
1253  K.Print();
1254  }
1255 
1256  float yprev = parvec[0];
1257  float zprev = parvec[1];
1258  parvec = predstep + K*ytilde;
1259  P = (I-K*H)*PPred;
1260  xpos = xpos + dx;
1261  //std::cout << " Updated xpos: " << xpos << " " << dx << std::endl;
1262 
1263  length += TMath::Sqrt( dx*dx + TMath::Sq(parvec[0]-yprev) + TMath::Sq(parvec[1]-zprev) );
1264  }
1265 
1266  for (size_t i=0; i<5; ++i)
1267  {
1268  trackparatend[i] = parvec[i];
1269  }
1270  trackparatend[5] = xpos; // tack this on so we can specify where the track endpoint is
1271  if (fPrintLevel > 1)
1272  {
1273  std::cout << "Track params at end (y, z, curv, phi, lambda) " << trackparatend[0] << " " << trackparatend[1] << " " <<
1274  trackparatend[2] << " " << trackparatend[3] <<" " << trackparatend[4] << std::endl;
1275  S.Print();
1276  }
1277 
1278  // just for visualization of the initial track parameter guesses. Comment out when fitting tracks
1279 
1280  //trackparatend[0] = ypos_init;
1281  //trackparatend[1] = zpos_init;
1282  //trackparatend[2] = curvature_init;
1283  //trackparatend[3] = phi_init;
1284  //trackparatend[4] = lambda_init;
1285  //trackparatend[5] = xpos_init;
1286 
1287 
1288  size_t icov=0;
1289  for (size_t i=0; i<5; ++i)
1290  {
1291  for (size_t j=0; j<5; ++j)
1292  {
1293  covmat[icov] = P[i][j];
1294  }
1295  }
1296 
1297  return 0;
1298  }
1299 
1300  //--------------------------------------------------------------------------------------------------------------
1301 
1302 
1303  size_t tracker1::ifob(size_t ihit, size_t nhits, bool isForwards)
1304  {
1305 
1306  return ihit; // disable ifob -- hit list now encodes track direction
1307 
1308  //if (ihit >= nhits)
1309  // {
1310  // throw cet::exception("Tracker1") << "Invalid hit index in ifob: " << ihit << " nhits: " << nhits;
1311  // }
1312  //if (isForwards)
1313  //{
1314  // return ihit;
1315  //}
1316  //else
1317  //{
1318  // return (nhits - ihit - 1);
1319  // }
1320  }
1321 
1322 
1323  //--------------------------------------------------------------------------------------------------------------
1324 
1325  int tracker1::initial_trackpar_estimate(art::ValidHandle<std::vector<Hit> > &hitHandle,
1326  std::vector<std::vector<int> > &hitlist,
1327  std::vector<int> &hsi,
1328  int itrack,
1329  bool isForwards,
1330  float &curvature_init,
1331  float &lambda_init,
1332  float &phi_init,
1333  float &xpos,
1334  float &ypos,
1335  float &zpos,
1336  float &x_other_end)
1337  {
1338  // form a rough guess of track parameters
1339 
1340  auto const& hits = *hitHandle;
1341  size_t nhits = hitlist[itrack].size();
1342 
1343  size_t farhit_index = TMath::Min(nhits-1, (size_t) fInitialTPNHits);
1344  size_t inthit_index = farhit_index/2;
1345 
1346  size_t firsthit = ifob(0,nhits,isForwards);
1347  //size_t inthit = ifob(fMinNumHits/2,nhits,isForwards);
1348  //size_t farhit = ifob(fMinNumHits-1,nhits,isForwards);
1349  size_t inthit = ifob(inthit_index,nhits,isForwards);
1350  size_t farhit = ifob(farhit_index,nhits,isForwards);
1351  size_t lasthit = ifob(nhits-1,nhits,isForwards);
1352 
1353  float trackbeg[3] = {hits[hsi[hitlist[itrack][firsthit]]].Position()[0],
1354  hits[hsi[hitlist[itrack][firsthit]]].Position()[1],
1355  hits[hsi[hitlist[itrack][firsthit]]].Position()[2]};
1356 
1357  float tp1[3] = {hits[hsi[hitlist[itrack][inthit]]].Position()[0],
1358  hits[hsi[hitlist[itrack][inthit]]].Position()[1],
1359  hits[hsi[hitlist[itrack][inthit]]].Position()[2]};
1360 
1361  float tp2[3] = {hits[hsi[hitlist[itrack][farhit]]].Position()[0],
1362  hits[hsi[hitlist[itrack][farhit]]].Position()[1],
1363  hits[hsi[hitlist[itrack][farhit]]].Position()[2]};
1364 
1365  if (fPrintLevel>1)
1366  {
1367  std::cout << "Hit Dump in initial_trackpar_estimate: " << std::endl;
1368  for (size_t i=0;i<nhits;++i)
1369  {
1370  size_t ihf = ifob(i,nhits,isForwards);
1371  std::cout << i << " : " <<
1372  hits[hsi[hitlist[itrack][ihf]]].Position()[0] << " " <<
1373  hits[hsi[hitlist[itrack][ihf]]].Position()[1] << " " <<
1374  hits[hsi[hitlist[itrack][ihf]]].Position()[2] << std::endl;
1375  }
1376  }
1377  if (fPrintLevel>0)
1378  {
1379  std::cout << "isForwards: " << isForwards << std::endl;
1380  std::cout << "first hit: " << firsthit << ", inter hit: " << inthit << " " << " far hit: " << farhit << std::endl;
1381  std::cout << "in the hit list: " << hsi[hitlist[itrack][firsthit]] << " " << hsi[hitlist[itrack][inthit]] << " " << hsi[hitlist[itrack][farhit]] << std::endl;
1382  std::cout << "First hit x, y, z: " << trackbeg[0] << " " << trackbeg[1] << " " << trackbeg[2] << std::endl;
1383  std::cout << "Inter hit x, y, z: " << tp1[0] << " " << tp1[1] << " " << tp1[2] << std::endl;
1384  std::cout << "Far hit x, y, z: " << tp2[0] << " " << tp2[1] << " " << tp2[2] << std::endl;
1385  }
1386 
1387  xpos = trackbeg[0];
1388  ypos = trackbeg[1];
1389  zpos = trackbeg[2];
1390  x_other_end = hits[hsi[hitlist[itrack][lasthit]]].Position()[0];
1391 
1392 
1393  float ycc=0;
1394  float zcc=0;
1395  curvature_init = capprox(trackbeg[1],trackbeg[2],tp1[1],tp1[2],tp2[1],tp2[2],ycc,zcc);
1396  //std::cout << " inputs to trackpar circ fit (y,z): " << trackbeg[1] << " " << trackbeg[2] << " : "
1397  // << tp1[1] << " " << tp1[2] << " : " << tp2[1] << " " << tp2[2] << std::endl;
1398  //std::cout << "curvature output: " << curvature_init << std::endl;
1399 
1400  phi_init = TMath::ATan2( trackbeg[2] - zcc, ycc - trackbeg[1] );
1401  float phi2 = phi_init;
1402  if (curvature_init<0) phi_init += TMath::Pi();
1403  float radius_init = 10000;
1404  if (curvature_init != 0) radius_init = 1.0/curvature_init;
1405 
1406  float dx1 = tp2[0] - xpos;
1407  if (dx1 != 0)
1408  {
1409  float dphi2 = TMath::ATan2(tp2[2]-zcc,ycc-tp2[1])-phi2;
1410  if (dphi2 > TMath::Pi()) dphi2 -= 2.0*TMath::Pi();
1411  if (dphi2 < -TMath::Pi()) dphi2 += 2.0*TMath::Pi();
1412  lambda_init = TMath::ATan(1.0/((radius_init/dx1)*dphi2));
1413  }
1414  else
1415  {
1416  //std::cout << "initial track par estimate failure" << std::endl;
1417  lambda_init = 0;
1418  return 1;
1419  } // got fMinNumHits all at exactly the same value of x (they were sorted). Reject track.
1420 
1421  if (fPrintLevel>0)
1422  {
1423  std::cout << "phi calc: dz, dy " << tp2[2]-trackbeg[2] << " " << tp2[1]-trackbeg[1] << std::endl;
1424  std::cout << "initial curvature, phi, lambda: " << curvature_init << " " << phi_init << " " << lambda_init << std::endl;
1425  }
1426  return 0;
1427  }
1428 
1429  //--------------------------------------------------------------
1430  // the isForwards switch is only used to select which end to use to estimate the initial track parameters. Since this is a single helix
1431  // fit, the track parameters are the same, except for an evaluation of x, y, and z at the beginning and the end.
1432  // to do -- drop some hits if they have bad chisquared
1433 
1434  int tracker1::FitHelix(art::ValidHandle<std::vector<Hit> > &hitHandle,
1435  std::vector<std::vector<int> > &hitlist,
1436  std::vector<int> &hsi,
1437  int itrack,
1438  bool isForwards,
1439  std::set<int> &unused_hits,
1440  TrackPar &trackpar
1441  )
1442  {
1443  auto const& hits = *hitHandle;
1444  size_t nhits = hitlist[itrack].size();
1445  if (nhits < fMinNumHits) return 1;
1446 
1447  // estimate curvature, lambda, phi, xpos from the initial track parameters
1448  float curvature_init=0.1;
1449  float phi_init = 0;
1450  float lambda_init = 0;
1451  float xpos_init=0;
1452  float ypos_init=0;
1453  float zpos_init=0;
1454  float x_other_end=0;
1455  if ( initial_trackpar_estimate(hitHandle,
1456  hitlist,
1457  hsi,
1458  itrack,
1459  isForwards,
1460  curvature_init,
1461  lambda_init,
1462  phi_init,
1463  xpos_init,
1464  ypos_init,
1465  zpos_init,
1466  x_other_end) != 0)
1467  {
1468  return 1;
1469  }
1470 
1471  float tpi[5] = {ypos_init, zpos_init, curvature_init, phi_init, lambda_init};
1472  float covmat[25] = {0};
1473 
1474  // syntax from $ROOTSYS/tutorials/fit/fitCircle.C
1475 
1476  auto chi2Function = [&](const Double_t *par) {
1477  //minimisation function computing the sum of squares of residuals
1478  // looping at the graph points
1479 
1480  float tpl[5] = { (float) par[0], (float) par[1], (float) par[2], (float) par[3], (float) par[4] };
1481 
1482  // only need this to compute chisquared, so set the track parameters the same at the beginning and end,
1483  // and no covmat is needed (defined outside to be zero)
1484 
1485  TrackPar tpar(0,0,nhits,xpos_init,tpl,covmat,0,xpos_init,tpl,covmat,0,0);
1486 
1487  float c2sum = 0;
1488  for (size_t ihit=0; ihit<nhits; ++ihit)
1489  {
1490  TVector3 hitpos(hits[hsi[hitlist[itrack][ihit]]].Position()[0],
1491  hits[hsi[hitlist[itrack][ihit]]].Position()[1],
1492  hits[hsi[hitlist[itrack][ihit]]].Position()[2]);
1493  TVector3 helixpos = tpar.getPosAtX(hitpos.X(),isForwards);
1494  //std::cout << hitpos.X() << " " << hitpos.Y() << " " << hitpos.Z() << " " << helixpos.X() << " " << helixpos.Y() << " " << helixpos.Z() << std::endl;
1495  c2sum += (hitpos-helixpos).Mag2();
1496  }
1497  double dc2sum = c2sum;
1498  return dc2sum;
1499  };
1500 
1501  // wrap chi2 funciton in a function object for the fit
1502  // 5 is the number of fit parameters (size of array par)
1503  ROOT::Math::Functor fcn(chi2Function,5);
1504  ROOT::Fit::Fitter fitter;
1505 
1506  double pStart[5];
1507  for (size_t i=0; i<5; ++i) pStart[i] = tpi[i];
1508  fitter.SetFCN(fcn, pStart);
1509  fitter.Config().ParSettings(0).SetName("y0");
1510  fitter.Config().ParSettings(1).SetName("z0");
1511  fitter.Config().ParSettings(2).SetName("curvature");
1512  fitter.Config().ParSettings(3).SetName("phi0");
1513  fitter.Config().ParSettings(4).SetName("lambda");
1514 
1515  // do the fit
1516  bool ok = fitter.FitFCN();
1517  if (!ok) {
1518  LOG_WARNING("gar::rec::tracker1") << "Helix Fit failed";
1519  return(1);
1520  }
1521 
1522  const ROOT::Fit::FitResult & result = fitter.Result();
1523  //result.Print(std::cout);
1524  float fity0 = result.Value(0);
1525  float fitz0 = result.Value(1);
1526  float fitcurvature = result.Value(2);
1527  float fitphi0 = result.Value(3);
1528  float fitlambda = result.Value(4);
1529  float tpfit[5] = {fity0,fitz0,fitcurvature,fitphi0,fitlambda};
1530  float chisqmin = result.MinFcnValue();
1531 
1532  float stmp = TMath::Tan(fitlambda);
1533  //float stmp = TMath::Tan(fTrackParametersBegin[4]);
1534  if (stmp != 0)
1535  {
1536  stmp = 1.0/stmp;
1537  }
1538  else
1539  {
1540  stmp = 1E9;
1541  }
1542 
1543  float tracklength = TMath::Abs(xpos_init - x_other_end) * TMath::Sqrt( 1.0 + stmp*stmp );
1544  float covmatfit[25];
1545  for (size_t i=0; i<5; ++i)
1546  {
1547  for (size_t j=0; j<5; ++j)
1548  {
1549  covmatfit[5*i + j] = result.CovMatrix(i,j);
1550  }
1551  }
1552 
1553  trackpar.setNHits(nhits);
1554  trackpar.setTime(0);
1555  trackpar.setChisqForwards(chisqmin);
1556  trackpar.setChisqBackwards(chisqmin);
1557  trackpar.setLengthForwards(tracklength);
1558  trackpar.setLengthBackwards(tracklength);
1559  trackpar.setCovMatBeg(covmatfit); // todo -- put in covariance matrices at both ends properly.
1560  trackpar.setCovMatEnd(covmatfit);
1561  if (isForwards)
1562  {
1563  trackpar.setTrackParametersBegin(tpfit);
1564  trackpar.setXBeg(xpos_init);
1565  trackpar.setXEnd(x_other_end);
1566  TVector3 xyzend = trackpar.getPosAtX(x_other_end,true);
1567  float yend = xyzend[1];
1568  float zend = xyzend[2];
1569  float tp_other_end[5] = {yend,zend,fitcurvature,fitphi0,fitlambda};
1570  trackpar.setTrackParametersEnd(tp_other_end);
1571  }
1572  else
1573  {
1574  trackpar.setTrackParametersEnd(tpfit);
1575  trackpar.setXEnd(xpos_init);
1576  trackpar.setXBeg(x_other_end);
1577  TVector3 xyzend = trackpar.getPosAtX(x_other_end,true);
1578  float yend = xyzend[1];
1579  float zend = xyzend[2];
1580  float tp_other_end[5] = {yend,zend,fitcurvature,fitphi0,fitlambda};
1581  trackpar.setTrackParametersBegin(tp_other_end);
1582  }
1583 
1584  return 0;
1585  }
1586 
1587  // see if a hit is consistent with a vector hit and add it if it is.
1588  // fit lines in y vs x and z vs x
1589 
1590  bool tracker1::vh_hitmatch(TVector3 &hpvec, int ihit, tracker1::vechit_t &vechit, const std::vector<gar::rec::Hit> &hits, std::vector<int> &hsi)
1591  {
1592  bool retval = false;
1593 
1594  float dist = 1E6;
1595  for (size_t iht=0; iht<vechit.hitindex.size(); ++iht)
1596  {
1597  TVector3 ht(hits[hsi[vechit.hitindex[iht]]].Position());
1598  float d = (hpvec - ht).Mag();
1599  if (d>fMaxVecHitLen) return retval;
1600  dist = TMath::Min(dist,d);
1601  }
1602 
1603  if (vechit.hitindex.size() > 1)
1604  {
1605  dist = ((hpvec - vechit.pos).Cross(vechit.dir)).Mag();
1606  //std::cout << " Distance cross comparison: " << dist << std::endl;
1607  }
1608 
1609  if (dist < fVecHitRoad) // add hit to vector hit if we have a match
1610  {
1611  //std::cout << "matched a hit to a vh" << std::endl;
1612  std::vector<TVector3> hplist;
1613  for (size_t i=0; i< vechit.hitindex.size(); ++i)
1614  {
1615  hplist.emplace_back(hits[hsi[vechit.hitindex[i]]].Position());
1616  }
1617  hplist.push_back(hpvec);
1618  fitlinesdir(hplist,vechit.pos,vechit.dir);
1619  vechit.hitindex.push_back(ihit);
1620  //std::cout << "vechit now has " << hplist.size() << " hits" << std::endl;
1621  //std::cout << vechit.pos.X() << " " << vechit.pos.Y() << " " << vechit.pos.Z() << std::endl;
1622  //std::cout << vechit.dir.X() << " " << vechit.dir.Y() << " " << vechit.dir.Z() << std::endl;
1623  retval = true;
1624  }
1625  return retval;
1626  }
1627 
1628  void tracker1::fitlinesdir(std::vector<TVector3> &hlist, TVector3 &pos, TVector3 &dir)
1629  {
1630  std::vector<double> x;
1631  std::vector<double> y;
1632  std::vector<double> z;
1633  for (size_t i=0; i<hlist.size();++i)
1634  {
1635  x.push_back(hlist[i].X());
1636  y.push_back(hlist[i].Y());
1637  z.push_back(hlist[i].Z());
1638  }
1639  double slope_yx=0;
1640  double slope_zx=0;
1641  double intercept_yx=0;
1642  double intercept_zx=0;
1643 
1644  double slope_yz=0;
1645  double slope_xz=0;
1646  double intercept_yz=0;
1647  double intercept_xz=0;
1648 
1649  double slope_xy=0;
1650  double slope_zy=0;
1651  double intercept_xy=0;
1652  double intercept_zy=0;
1653 
1654  fitline(x,y,slope_xy,intercept_xy);
1655  fitline(x,z,slope_xz,intercept_xz);
1656 
1657  fitline(y,z,slope_yz,intercept_yz);
1658  fitline(y,x,slope_yx,intercept_yx);
1659 
1660  fitline(z,y,slope_zy,intercept_zy);
1661  fitline(z,x,slope_zx,intercept_zx);
1662 
1663  // pick the direction with the smallest sum of the absolute values of slopes to use to determine the line direction
1664  // in three-dimensional space
1665 
1666  double slopesumx = TMath::Abs(slope_xy) + TMath::Abs(slope_xz);
1667  double slopesumy = TMath::Abs(slope_yz) + TMath::Abs(slope_yx);
1668  double slopesumz = TMath::Abs(slope_zx) + TMath::Abs(slope_zy);
1669 
1670  if (slopesumx < slopesumy && slopesumx < slopesumz)
1671  {
1672  dir.SetXYZ(1.0,slope_xy,slope_xz);
1673  double avgx = 0;
1674  for (size_t i=0; i<x.size(); ++i)
1675  {
1676  avgx += x[i];
1677  }
1678  avgx /= x.size();
1679  pos.SetXYZ(avgx, avgx*slope_xy + intercept_xy, avgx*slope_xz + intercept_xz);
1680  }
1681  else if (slopesumy < slopesumx && slopesumy < slopesumz)
1682  {
1683  dir.SetXYZ(slope_yx,1.0,slope_yz);
1684  double avgy = 0;
1685  for (size_t i=0; i<y.size(); ++i)
1686  {
1687  avgy += y[i];
1688  }
1689  avgy /= y.size();
1690  pos.SetXYZ(avgy*slope_yx + intercept_yx, avgy, avgy*slope_yz + intercept_yz);
1691  }
1692  else
1693  {
1694  dir.SetXYZ(slope_zx,slope_zy,1.0);
1695  double avgz = 0;
1696  for (size_t i=0; i<z.size(); ++i)
1697  {
1698  avgz += z[i];
1699  }
1700  avgz /= z.size();
1701  pos.SetXYZ(avgz*slope_zx + intercept_zx, avgz*slope_zy + intercept_zy, avgz);
1702  }
1703  dir *= 1.0/dir.Mag();
1704 
1705  // put in fit values for y and z
1706  }
1707 
1708  // fit with same weights on all points -- to think about: what are the uncertainties?
1709 
1710  void tracker1::fitline(std::vector<double> &x, std::vector<double> &y, double &slope, double &intercept)
1711  {
1712  size_t n = x.size();
1713  if (n < 2)
1714  {
1715  throw cet::exception("tracker1: too few hits to fit a line in linefit");
1716  }
1717  double sumx = 0;
1718  double sumy = 0;
1719  double sumxx = 0;
1720  double sumxy = 0;
1721 
1722  for (size_t i=0; i<n; ++i)
1723  {
1724  sumx += x[i];
1725  sumy += y[i];
1726  sumxx += TMath::Sq(x[i]);
1727  sumxy += x[i]*y[i];
1728  }
1729  double denom = (n*sumxx) - TMath::Sq(sumx);
1730  if (denom == 0)
1731  {
1732  slope = 1E6; // is this right?
1733  intercept = 0;
1734  }
1735  else
1736  {
1737  slope = (n*sumxy - sumx*sumy)/denom;
1738  intercept = (sumxx*sumy - sumx*sumxy)/denom;
1739  }
1740  }
1741 
1742  bool tracker1::vhclusmatch(std::vector<tracker1::vechit_t> &cluster, vechit_t &vh)
1743  {
1744  for (size_t ivh=0; ivh<cluster.size(); ++ivh)
1745  {
1746  //std::cout << "Testing vh " << ivh << " in a cluster of size: " << cluster.size() << std::endl;
1747 
1748  // require the two VH's directions to point along each other -- use dot product
1749 
1750  if (TMath::Abs((vh.dir).Dot(cluster[ivh].dir)) < fVecHitMatchCos)
1751  {
1752  // std::cout << " Dot failure: " << TMath::Abs((vh.dir).Dot(cluster[ivh].dir)) << std::endl;
1753  continue;
1754  }
1755 
1756  // require the positions to be within fVecHitMatchPos of each other
1757 
1758  if ((vh.pos-cluster[ivh].pos).Mag() > fVecHitMatchPos)
1759  {
1760  //std::cout << " Pos failure: " << (vh.pos-cluster[ivh].pos).Mag() << std::endl;
1761  continue;
1762  }
1763 
1764  // require the extrapolation of one VH's line to another VH's center to match up. Do for
1765  // both VH's.
1766 
1767  if ( ((vh.pos-cluster[ivh].pos).Cross(vh.dir)).Mag() > fVecHitMatchPEX )
1768  {
1769  //std::cout << "PEX failure: " << ((vh.pos-cluster[ivh].pos).Cross(vh.dir)).Mag() << std::endl;
1770  continue;
1771  }
1772  if ( ((vh.pos-cluster[ivh].pos).Cross(cluster[ivh].dir)).Mag() > fVecHitMatchPEX )
1773  {
1774  //std::cout << "PEX failure: " << ((vh.pos-cluster[ivh].pos).Cross(cluster[ivh].dir)).Mag() << std::endl;
1775  continue;
1776  }
1777 
1778  //--------------------------
1779  // compute a 2D eta
1780 
1781  // normalized direction vector for the VH under test, just the components
1782  // perpendicular to X
1783 
1784  TVector3 vhdp(vh.dir);
1785  vhdp.SetX(0);
1786  float norm = vhdp.Mag();
1787  if (norm > 0) vhdp *= (1.0/norm);
1788 
1789  // same for the VH in the cluster under test
1790 
1791  TVector3 vhcp(cluster[ivh].dir);
1792  vhcp.SetX(0);
1793  norm = vhcp.Mag();
1794  if (norm > 0) vhcp *= (1.0/norm);
1795 
1796  float relsign = 1.0;
1797  if (vhdp.Dot(vhcp) < 0) relsign = -1;
1798 
1799  TVector3 dcent = vh.pos-cluster[ivh].pos;
1800  dcent.SetX(0);
1801 
1802  TVector3 avgdir1 = 0.5*(vhdp + relsign*vhcp);
1803  float amag = avgdir1.Mag();
1804  if (amag != 0) avgdir1 *= 1.0/amag;
1805  float eta = (dcent.Cross(avgdir1)).Mag();
1806 
1807  if ( eta > fVecHitMatchEta )
1808  {
1809  //std::cout << "Eta failure: " << eta1 << " " << eta2 << std::endl;
1810  continue;
1811  }
1812 
1813  //----------------
1814  // lambda requirement
1815 
1816  float vhpd = TMath::Sqrt( TMath::Sq(vh.dir.Y()) + TMath::Sq(vh.dir.Z()) );
1817  float vhxd = TMath::Abs( vh.dir.X() );
1818  float vhlambda = TMath::Pi()/2.0;
1819  if (vhpd >0) vhlambda = TMath::ATan(vhxd/vhpd);
1820 
1821  float cvhpd = TMath::Sqrt( TMath::Sq(cluster[ivh].dir.Y()) + TMath::Sq(cluster[ivh].dir.Z()) );
1822  float cvhxd = TMath::Abs( cluster[ivh].dir.X() );
1823  float cvhlambda = TMath::Pi()/2.0;
1824  if (cvhpd >0) cvhlambda = TMath::ATan(cvhxd/cvhpd);
1825 
1826  if ( TMath::Abs(vhlambda - cvhlambda) > fVecHitMatchLambda )
1827  {
1828  //std::cout << "dlambda failure: " << vhlambda << " " << cvhlambda << std::endl;
1829  continue;
1830  }
1831 
1832  if ( vh.dir.Dot(cluster[ivh].dir) * vh.dir.X() * cluster[ivh].dir.X() < 0 &&
1833  TMath::Abs(vh.dir.X()) > 0.01 && TMath::Abs(cluster[ivh].dir.X()) > 0.01)
1834  {
1835  //std::cout << "lambda sign failure" << std::endl;
1836  continue;
1837  }
1838 
1839  //std::cout << " vh cluster match " << std::endl;
1840  return true;
1841  }
1842  return false;
1843  }
1844 
1846 
1847  } // namespace rec
1848 } // namespace gar
end
while True: pbar.update(maxval-len(onlies[E][S])) #print iS, "/", len(onlies[E][S]) found = False for...
void setLengthForwards(const float lengthforwards)
Definition: TrackPar.cxx:251
rec
Definition: tracks.py:88
float fKalLambdaStepUncSq
constant uncertainty term on each step of the Kalman fit – squared, for lambda
size_t fPatRecLookBack1
n hits to look backwards to make a linear extrapolation
int ntracks
Definition: tracks.py:246
static QCString result
TH3F * xpos
Definition: doAna.cpp:29
float fVecHitMatchPos
matching condition for pairs of vector hits – 3D distance (cm)
void fitlinesdir(std::vector< TVector3 > &hlist, TVector3 &pos, TVector3 &dir)
void setCovMatBeg(const float *covmatbeg)
Definition: TrackPar.cxx:235
std::string string
Definition: nybbler.cc:12
std::string fSecondPassFitType
helix or Kalman – which fitter to call for second-pass tracks
float fKalCurvStepUncSq
constant uncertainty term on each step of the Kalman fit – squared, for curvature ...
const float * getTrackParametersEnd() const
Definition: TrackPar.cxx:126
bool vh_hitmatch(TVector3 &hpvec, int ihit, vechit_t &vechit, const std::vector< gar::rec::Hit > &hits, std::vector< int > &hsi)
struct vector vector
float fVecHitMatchPEX
matching condition for pairs of vector hits – miss distance (cm)
std::pair< float, std::string > P
void setLengthBackwards(const float lengthbackwards)
Definition: TrackPar.cxx:256
string dir
Cluster finding and building.
int fPrintLevel
debug printout: 0: none, 1: just track parameters and residuals, 2: all
unsigned int fMinNumHits
minimum number of hits to define a track
Particle class.
std::string fFirstPassFitType
helix or Kalman – which fitter to call for first-pass tracks
float capprox2(float y0, float z0, float y1, float z1, float y2, float z2)
TH3F * ypos
Definition: doAna.cpp:30
float fHitRCut
only take hits within rcut of the center of the detector
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
std::string fSortOrder
switch to tell what way to sort hits before presenting them to the fitter
void setTrackParametersBegin(const float *tparbeg)
Definition: TrackPar.cxx:219
int fTrackPass
which pass of the tracking to save as the tracks in the event
std::vector< size_t > hitindex
TH3F * zpos
Definition: doAna.cpp:31
const double e
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
tracker1(fhicl::ParameterSet const &p)
std::void_t< T > n
const double a
def move(depos, offset)
Definition: depos.py:107
T get(std::string const &key) const
Definition: ParameterSet.h:271
void setXEnd(const float xend)
Definition: TrackPar.cxx:276
void setTrackParametersEnd(const float *tparend)
Definition: TrackPar.cxx:227
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
Definition: DataViewImpl.h:441
bool vhclusmatch(std::vector< vechit_t > &cluster, vechit_t &vh)
p
Definition: test.py:223
void setChisqBackwards(const float chisqbackwards)
Definition: TrackPar.cxx:266
unsigned int fVecHitMinHits
minimum number of hits on a vector hit for it to be considered
float fVecHitRoad
max dist from a vector hit to a hit to assign it. for patrec alg 2. in cm.
float fVecHitMatchCos
matching condition for pairs of vector hits cos angle between directions
int KalmanFit(art::ValidHandle< std::vector< Hit > > &hitHandle, std::vector< std::vector< int > > &hitlist, std::vector< int > &hsi, int itrack, bool isForwards, std::vector< float > &trackparatend, float &chisquared, float &length, float *covmat, std::set< int > &unused_hits)
float fRoadYZinFit
cut in cm for dropping hits from tracks in fit
float capprox(float x1, float y1, float x2, float y2, float x3, float y3, float &xc, float &yc)
initial guess of curvature calculator – from ALICE. Also returns circle center
auto norm(Vector const &v)
Return norm of the specified vector.
float fHitResolX
resolution in cm of a hit in X (drift direction)
int initial_trackpar_estimate(art::ValidHandle< std::vector< Hit > > &hitHandle, std::vector< std::vector< int > > &hitlist, std::vector< int > &hsi, int itrack, bool isForwards, float &curvature_init, float &lambda_init, float &phi_init, float &xpos, float &ypos, float &zpos, float &x_other_end)
General GArSoft Utilities.
float fVecHitMatchLambda
matching condition for pairs of vector hits – dLambda (radians)
int imax
Definition: tracks.py:195
void setCovMatEnd(const float *covmatend)
Definition: TrackPar.cxx:243
constexpr double dist(const TReal *x, const TReal *y, const unsigned int dimension)
void setXBeg(const float xbeg)
Definition: TrackPar.cxx:271
int fDumpTracks
0: do not print out tracks, 1: print out tracks
float fSigmaRoad
how many sigma away from a track a hit can be and still add it during patrec
unsigned int fInitialTPNHits
number of hits to use for initial trackpar estimate, if present
void produce(art::Event &e) override
#define A
Definition: memgrp.cpp:38
static bool * b
Definition: config.cpp:1043
list x
Definition: train.py:276
float fMaxVecHitLen
maximum vector hit length in patrec alg 2, in cm
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:72
const float * getTrackParametersBegin() const
Definition: TrackPar.cxx:121
int FitHelix(art::ValidHandle< std::vector< Hit > > &hitHandle, std::vector< std::vector< int > > &hitlist, std::vector< int > &hsi, int itrack, bool isForwards, std::set< int > &unused_hits, TrackPar &trackpar)
void setChisqForwards(const float chisqforwards)
Definition: TrackPar.cxx:261
float fHitResolYZinFit
Hit resolution parameter to use in fit.
int KalmanFitBothWays(art::ValidHandle< std::vector< Hit > > &hitHandle, std::vector< std::vector< int > > &hitlist, std::vector< int > &hsi, int itrack, std::set< int > &unused_hits, TrackPar &trackpar)
tracker1 & operator=(tracker1 const &)=delete
size_t fPatRecAlg
1: x-sorted patrec. 2: vector-hit patrec
float fVecHitMatchEta
matching condition for pairs of vector hits – eta match (cm)
LArSoft geometry interface.
Definition: ChannelGeo.h:16
art framework interface to geometry description
float fHitResolYZ
resolution in cm of a hit in YZ (pad size)
void setTime(const double time)
Definition: TrackPar.cxx:281
std::string fHitLabel
label of module creating hits
size_t fPatRecLookBack2
extrapolate from lookback1 to lookback2 and see how close the new hit is to the line ...
void fitline(std::vector< double > &x, std::vector< double > &y, double &lambda, double &intercept)
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
QTextStream & endl(QTextStream &s)
size_t ifob(size_t ihit, size_t nhits, bool isForwards)
float fKalPhiStepUncSq
constant uncertainty term on each step of the Kalman fit – squared, for phi