SeedFinderAlgorithm.cxx
Go to the documentation of this file.
1 //
2 // Name: SeedFinderAlgorithm.cxx
3 //
4 // Purpose: Implementation file for module SeedFinderAlgorithm.
5 //
6 // Ben Jones, MIT
7 //
8 
9 #include <stdint.h>
10 
15 
23 
24 namespace trkf {
25 
26  //----------------------------------------------------------------------------
28 
29  //----------------------------------------------------------------------------
30  void
32  {
33 
34  fSptalg = new trkf::SpacePointAlg(pset.get<fhicl::ParameterSet>("SpacePointAlg"));
35 
36  fInitSeedLength = pset.get<double>("InitSeedLength");
37  fMinPointsInSeed = pset.get<int>("MinPointsInSeed");
38 
39  fRefits = pset.get<double>("Refits");
40 
41  fHitResolution = pset.get<double>("HitResolution");
42 
43  fOccupancyCut = pset.get<double>("OccupancyCut");
44  fLengthCut = pset.get<double>("LengthCut");
45  fExtendSeeds = pset.get<bool>("ExtendSeeds");
46 
47  fAllow2DSeeds = pset.get<bool>("Allow2DSeeds", false);
48 
49  fMaxViewRMS.resize(3);
50  fMaxViewRMS = pset.get<std::vector<double>>("MaxViewRMS");
51 
53  }
54 
55  //------------------------------------------------------------
56  // Given a set of spacepoints, find seeds, and catalogue
57  // spacepoints by the seeds they formed
58  //
59  std::vector<recob::Seed>
61  detinfo::DetectorPropertiesData const& detProp,
62  art::PtrVector<recob::Hit> const& HitsFlat,
63  std::vector<art::PtrVector<recob::Hit>>& CataloguedHits,
64  unsigned int StopAfter) const
65  {
66  // Vector of seeds found to return
67  std::vector<recob::Seed> ReturnVector;
68 
69  // First check if there is any overlap
70  std::vector<recob::SpacePoint> spts;
71 
73  fSptalg->makeSpacePoints(clockData, detProp, HitsFlat, spts);
74 
75  if (int(spts.size()) < fMinPointsInSeed) { return std::vector<recob::Seed>(); }
76 
77  // If we got here, we have enough spacepoints to potentially make seeds from these hits.
78 
79  // This is table will let us quickly look up which hits are in a given view / channel.
80  // structure is OrgHits[View][Channel] = {index1,index2...}
81  // where the indices are of HitsFlat[index].
82 
83  std::vector<std::vector<std::vector<int>>> OrgHits(3);
84  for (size_t n = 0; n != 3; ++n)
85  OrgHits[n].resize(fNChannels);
86 
87  // These two tables contain the hit to spacepoint mappings
88 
89  std::vector<std::vector<int>> SpacePointsPerHit(HitsFlat.size(), std::vector<int>());
90  std::vector<std::vector<int>> HitsPerSpacePoint(spts.size(), std::vector<int>());
91 
92  // This vector records the status of each hit.
93  // The possible values are:
94  // 0. hit unused
95  // 1. hit used in a seed
96  // Initially none are used.
97 
98  std::vector<char> HitStatus(HitsFlat.size(), 0);
99 
100  // Fill the organizing map
101 
102  for (size_t i = 0; i != HitsFlat.size(); ++i) {
103  OrgHits[HitsFlat.at(i)->View()][HitsFlat.at(i)->Channel()].push_back(i);
104  }
105 
106  // Fill the spacepoint / hit lookups
107 
108  for (size_t iSP = 0; iSP != spts.size(); ++iSP) {
109  art::PtrVector<recob::Hit> HitsThisSP = fSptalg->getAssociatedHits(spts.at(iSP));
110 
111  for (size_t iH = 0; iH != HitsThisSP.size(); ++iH) {
112  geo::View_t ThisView = HitsThisSP.at(iH)->View();
113  uint32_t ThisChannel = HitsThisSP.at(iH)->Channel();
114  float ThisTime = HitsThisSP.at(iH)->PeakTime();
115  float eta = 0.001;
116 
117  for (size_t iOrg = 0; iOrg != OrgHits[ThisView][ThisChannel].size(); ++iOrg) {
118  if (fabs(ThisTime - HitsFlat.at(OrgHits[ThisView][ThisChannel][iOrg])->PeakTime()) <
119  eta) {
120  SpacePointsPerHit.at(OrgHits[ThisView][ThisChannel][iOrg]).push_back(iSP);
121  HitsPerSpacePoint.at(iSP).push_back(OrgHits[ThisView][ThisChannel][iOrg]);
122  }
123  }
124  }
125  }
126 
127  // The general idea will be:
128  // A. Make spacepoints from remaining hits
129  // B. Look for 1 seed in that vector
130  // C. Discard used hits
131  // D. Repeat
132 
133  // This vector keeps track of the status of each space point.
134  // The key is the position in the AllSpacePoints vector.
135  // The value is
136  // 0: point unused
137  // 1: point used in seed
138  // 2: point thrown but unused
139  // 3: flag to terminate seed finding
140 
141  std::vector<char> PointStatus(spts.size(), 0);
142 
143  std::vector<std::map<geo::View_t, std::vector<int>>> WhichHitsPerSeed;
144 
145  bool KeepChopping = true;
146 
147  while (KeepChopping) {
148  // This vector keeps a list of the points used in this seed
149  std::vector<int> PointsUsed;
150 
151  // Find exactly one seed, starting at high Z
152  recob::Seed TheSeed =
153  FindSeedAtEnd(detProp, spts, PointStatus, PointsUsed, HitsFlat, OrgHits);
154 
155  // If it was a good seed, collect up the relevant spacepoints
156  // and add the seed to the return vector
157 
158  if (TheSeed.IsValid()) {
159 
160  for (size_t iP = 0; iP != PointsUsed.size(); ++iP) {
161  for (size_t iH = 0; iH != HitsPerSpacePoint.at(PointsUsed.at(iP)).size(); ++iH) {
162  int UsedHitID = HitsPerSpacePoint.at(PointsUsed.at(iP)).at(iH);
163  HitStatus[UsedHitID] = 2;
164  }
165  }
166  PointStatus[PointsUsed.at(0)] = 1;
167  ConsolidateSeed(detProp, TheSeed, HitsFlat, HitStatus, OrgHits, false);
168  }
169 
170  if (TheSeed.IsValid()) {
171  if (fRefits > 0) {
172  std::vector<char> HitStatusGood;
173  recob::Seed SeedGood;
174  for (size_t r = 0; r != (unsigned int)fRefits; ++r) {
175  double PrevLength = TheSeed.GetLength();
176 
177  SeedGood = TheSeed;
178  HitStatusGood = HitStatus;
179 
180  std::vector<int> PresentHitList;
181  for (size_t iH = 0; iH != HitStatus.size(); ++iH) {
182  if (HitStatus[iH] == 2) { PresentHitList.push_back(iH); }
183  }
184  double pt[3], dir[3], err[3];
185 
186  TheSeed.GetPoint(pt, err);
187  TheSeed.GetDirection(dir, err);
188 
189  TVector3 Center, Direction;
190  std::vector<double> ViewRMS;
191  std::vector<int> HitsPerView;
193  detProp, HitsFlat, PresentHitList, Center, Direction, ViewRMS, HitsPerView);
194 
195  Direction = Direction.Unit() * TheSeed.GetLength();
196 
197  int nViewsWithHits(0);
198  for (size_t n = 0; n != 3; ++n) {
199  pt[n] = Center[n];
200  dir[n] = Direction[n];
201 
202  TheSeed.SetPoint(pt, err);
203  TheSeed.SetDirection(dir, err);
204 
205  if (HitsPerView[n] > 0) nViewsWithHits++;
206  }
207 
208  if (nViewsWithHits < 2) TheSeed.SetValidity(false);
209 
210  if (TheSeed.IsValid())
211  ConsolidateSeed(detProp, TheSeed, HitsFlat, HitStatus, OrgHits, fExtendSeeds);
212 
213  // if we accidentally invalidated the seed, go back to the old one and escape
214  else {
215  // If we invalidated the seed, go back one interaction
216  // and kill the loop
217  HitStatus = HitStatusGood;
218  TheSeed = SeedGood;
219  break;
220  }
221  if ((r > 0) && (fabs(PrevLength - TheSeed.GetLength()) < fPitches.at(0))) {
222  // If we didn't change much, kill the loop
223  break;
224  }
225  }
226  }
227  }
228 
229  if (TheSeed.IsValid()) {
230  WhichHitsPerSeed.push_back(std::map<geo::View_t, std::vector<int>>());
231 
232  art::PtrVector<recob::Hit> HitsWithThisSeed;
233  for (size_t iH = 0; iH != HitStatus.size(); ++iH) {
234  if (HitStatus.at(iH) == 2) {
235  WhichHitsPerSeed.at(WhichHitsPerSeed.size() - 1)[HitsFlat[iH]->View()].push_back(iH);
236  HitsWithThisSeed.push_back(HitsFlat.at(iH));
237  HitStatus.at(iH) = 1;
238 
239  for (size_t iSP = 0; iSP != SpacePointsPerHit.at(iH).size(); ++iSP) {
240  PointStatus[SpacePointsPerHit.at(iH).at(iSP)] = 1;
241  }
242  }
243  }
244 
245  // Record that we used this set of hits with this seed in the return catalogue
246  ReturnVector.push_back(TheSeed);
247  CataloguedHits.push_back(HitsWithThisSeed);
248 
249  // Tidy up
250  HitsWithThisSeed.clear();
251  }
252  else {
253  // If it was not a good seed, throw out the top SP and try again
254  PointStatus.at(PointsUsed.at(0)) = 2;
255  }
256 
257  int TotalSPsUsed = 0;
258  for (size_t i = 0; i != PointStatus.size(); ++i) {
259  if (PointStatus[i] != 0) TotalSPsUsed++;
260  }
261 
262  if ((int(spts.size()) - TotalSPsUsed) < fMinPointsInSeed) KeepChopping = false;
263 
264  if ((PointStatus[0] == 3) || (PointStatus.size() == 0)) KeepChopping = false;
265 
266  PointsUsed.clear();
267 
268  if ((ReturnVector.size() >= StopAfter) && (StopAfter > 0)) break;
269 
270  } // end spt-level loop
271 
272  // If we didn't find any seeds, we can make one last ditch attempt. See
273  // if the whole collection is colinear enough to make one megaseed
274  // (good for patching up high angle tracks)
275 
276  if (ReturnVector.size() == 0) {
277  std::vector<int> ListAllHits;
278  for (size_t i = 0; i != HitsFlat.size(); ++i) {
279  ListAllHits.push_back(i);
280  HitStatus[i] = 2;
281  }
282  TVector3 SeedCenter(0, 0, 0);
283  TVector3 SeedDirection(0, 0, 0);
284 
285  std::vector<double> ViewRMS;
286  std::vector<int> HitsPerView;
287 
288  std::vector<art::PtrVector<recob::Hit>> HitsInThisCollection(3);
289 
291  detProp, HitsFlat, ListAllHits, SeedCenter, SeedDirection, ViewRMS, HitsPerView);
292 
293  bool ThrowOutSeed = false;
294 
295  double PtArray[3], DirArray[3];
296  int nViewsWithHits(0);
297  for (size_t n = 0; n != 3; ++n) {
298  PtArray[n] = SeedCenter[n];
299  DirArray[n] = SeedDirection[n];
300  if (HitsPerView[n] > 0) nViewsWithHits++;
301  }
302  recob::Seed TheSeed(PtArray, DirArray);
303 
304  if (nViewsWithHits < 2 || (nViewsWithHits < 3 && !fAllow2DSeeds)) ThrowOutSeed = true;
305 
306  if (!ThrowOutSeed) {
307  ConsolidateSeed(detProp, TheSeed, HitsFlat, HitStatus, OrgHits, false);
308 
309  // Now we have consolidated, grab the right
310  // hits to find the RMS and refitted direction
311  ListAllHits.clear();
312  for (size_t i = 0; i != HitStatus.size(); ++i) {
313  if (HitStatus.at(i) == 2) ListAllHits.push_back(i);
314  }
315  std::vector<int> HitsPerView;
317  detProp, HitsFlat, ListAllHits, SeedCenter, SeedDirection, ViewRMS, HitsPerView);
318 
319  int nViewsWithHits(0);
320  for (size_t n = 0; n != 3; ++n) {
321  PtArray[n] = SeedCenter[n];
322  DirArray[n] = SeedDirection[n];
323  // ThrowOutSeed = true;
324  if (HitsPerView[n] > 0) nViewsWithHits++;
325  }
326 
327  if (nViewsWithHits < 2 || (nViewsWithHits < 3 && !fAllow2DSeeds)) ThrowOutSeed = true;
328 
329  TheSeed = recob::Seed(PtArray, DirArray);
330 
331  if (fMaxViewRMS.at(0) > 0) {
332  for (size_t j = 0; j != fMaxViewRMS.size(); j++) {
333  if (fMaxViewRMS.at(j) < ViewRMS.at(j)) { ThrowOutSeed = true; }
334  }
335  }
336  }
337 
338  if ((!ThrowOutSeed) && (TheSeed.IsValid())) {
339  ReturnVector.push_back(TheSeed);
340  art::PtrVector<recob::Hit> HitsThisSeed;
341  for (size_t i = 0; i != ListAllHits.size(); ++i) {
342  HitsThisSeed.push_back(HitsFlat.at(ListAllHits.at(i)));
343  }
344  CataloguedHits.push_back(HitsThisSeed);
345  }
346  }
347 
348  // Tidy up
349  SpacePointsPerHit.clear();
350  HitsPerSpacePoint.clear();
351  PointStatus.clear();
352  OrgHits.clear();
353  HitStatus.clear();
354 
355  for (size_t i = 0; i != ReturnVector.size(); ++i) {
356  double CrazyValue = 1000000;
357  double Length = ReturnVector.at(i).GetLength();
358  if (!((Length > fLengthCut) && (Length < CrazyValue))) {
359  ReturnVector.erase(ReturnVector.begin() + i);
360  CataloguedHits.erase(CataloguedHits.begin() + i);
361  --i;
362  }
363  }
364 
365  return ReturnVector;
366  }
367 
368  //------------------------------------------------------------
369  // Latest extendseed method
370  //
371 
372  void
374  recob::Seed& TheSeed,
375  art::PtrVector<recob::Hit> const& HitsFlat,
376  std::vector<char>& HitStatus,
377  std::vector<std::vector<std::vector<int>>>& OrgHits,
378  bool Extend) const
379  {
380 
381  bool ThrowOutSeed = false;
382 
383  // This will keep track of what hits are in this seed
384  std::map<geo::View_t, std::map<uint32_t, std::vector<int>>> HitsInThisSeed;
385 
386  int NHitsThisSeed = 0;
387 
388  double MinS = 1000, MaxS = -1000;
389  for (size_t i = 0; i != HitStatus.size(); ++i) {
390  if (HitStatus.at(i) == 2) {
391  double disp, s;
392  GetHitDistAndProj(detProp, TheSeed, HitsFlat.at(i), disp, s);
393  if (fabs(s) > 1.2) {
394  // This hit is not rightfully part of this seed, toss it.
395  HitStatus[i] = 0;
396  }
397  else {
398  NHitsThisSeed++;
399 
400  if (s < MinS) MinS = s;
401  if (s > MaxS) MaxS = s;
402  HitsInThisSeed[HitsFlat.at(i)->View()][HitsFlat.at(i)->Channel()].push_back(i);
403  }
404  }
405  }
406 
407  double LengthRescale = (MaxS - MinS) / 2.;
408  double PositionShift = (MaxS + MinS) / 2.;
409 
410  double pt[3], dir[3], err[3];
411  TheSeed.GetPoint(pt, err);
412  TheSeed.GetDirection(dir, err);
413 
414  for (size_t n = 0; n != 3; ++n) {
415  pt[n] += dir[n] * PositionShift;
416  dir[n] *= LengthRescale;
417  }
418 
419  TheSeed.SetPoint(pt, err);
420  TheSeed.SetDirection(dir, err);
421 
422  // Run through checking if we missed any hits
423  for (auto itP = HitsInThisSeed.begin(); itP != HitsInThisSeed.end(); ++itP) {
424  double dist, s;
425  geo::View_t View = itP->first;
426  uint32_t LowestChan = itP->second.begin()->first;
427  uint32_t HighestChan = itP->second.rbegin()->first;
428  for (uint32_t c = LowestChan; c != HighestChan; ++c) {
429  for (size_t h = 0; h != OrgHits[View][c].size(); ++h) {
430  if (HitStatus[OrgHits[View][c].at(h)] == 0) {
431  GetHitDistAndProj(detProp, TheSeed, HitsFlat[OrgHits[View][c].at(h)], dist, s);
432  if (dist < fHitResolution) {
433  NHitsThisSeed++;
434 
435  HitStatus[OrgHits[View][c].at(h)] = 2;
436 
437  HitsInThisSeed[View][c].push_back(OrgHits[View][c].at(h));
438  }
439  else
440  HitStatus[OrgHits[View][c].at(h)] = 0;
441  }
442  }
443  }
444  }
445 
446  if (NHitsThisSeed == 0) ThrowOutSeed = true;
447 
448  // Check seed occupancy
449 
450  uint32_t LowestChanInSeed[3], HighestChanInSeed[3];
451  double Occupancy[] = {0., 0., 0.};
452  int nHitsPerView[] = {0, 0, 0};
453 
454  for (auto itP = HitsInThisSeed.begin(); itP != HitsInThisSeed.end(); ++itP) {
455 
456  geo::View_t View = itP->first;
457 
458  LowestChanInSeed[View] = itP->second.begin()->first;
459  HighestChanInSeed[View] = itP->second.rbegin()->first;
460 
461  nHitsPerView[View]++;
462 
463  int FilledChanCount = 0;
464 
465  for (size_t c = LowestChanInSeed[View]; c != HighestChanInSeed[View]; ++c) {
466  if (itP->second[c].size() > 0) ++FilledChanCount;
467  }
468 
469  Occupancy[View] =
470  float(FilledChanCount) / float(HighestChanInSeed[View] - LowestChanInSeed[View]);
471  }
472 
473  int nBelowCut(0);
474  int nViewsWithHits(0);
475  for (size_t n = 0; n != 3; ++n) {
476  if (Occupancy[n] < fOccupancyCut) nBelowCut++;
477  if (nHitsPerView[n] > 0) nViewsWithHits++;
478  }
479 
480  int belowCut(0);
481 
482  if (fAllow2DSeeds && nViewsWithHits < 3) belowCut = 1;
483 
484  if (nBelowCut > belowCut) ThrowOutSeed = true;
485 
486  if ((Extend) && (!ThrowOutSeed)) {
487  std::vector<std::vector<double>> ToAddNegativeS(3, std::vector<double>());
488  std::vector<std::vector<double>> ToAddPositiveS(3, std::vector<double>());
489  std::vector<std::vector<int>> ToAddNegativeH(3, std::vector<int>());
490  std::vector<std::vector<int>> ToAddPositiveH(3, std::vector<int>());
491 
492  for (auto itP = HitsInThisSeed.begin(); itP != HitsInThisSeed.end(); ++itP) {
493  double dist, s;
494 
495  geo::View_t View = itP->first;
496 
497  if (LowestChanInSeed[View] > 0) {
498  for (uint32_t c = LowestChanInSeed[View] - 1; c != 0; --c) {
499  bool GotOneThisChannel = false;
500  for (size_t h = 0; h != OrgHits[View][c].size(); ++h) {
501  if (HitStatus[OrgHits[View][c][h]] == 0) {
502  GetHitDistAndProj(detProp, TheSeed, HitsFlat[OrgHits[View][c].at(h)], dist, s);
503  if (dist < fHitResolution) {
504  GotOneThisChannel = true;
505  if (s < 0) {
506  ToAddNegativeS[View].push_back(s);
507  ToAddNegativeH[View].push_back(OrgHits[View][c].at(h));
508  }
509  else {
510  ToAddPositiveS[View].push_back(s);
511  ToAddPositiveH[View].push_back(OrgHits[View][c].at(h));
512  }
513  }
514  }
515  }
516  if (GotOneThisChannel == false) break;
517  }
518  }
519  if (HighestChanInSeed[View] < fNChannels)
520 
521  for (uint32_t c = HighestChanInSeed[View] + 1; c != fNChannels; ++c) {
522  bool GotOneThisChannel = false;
523  for (size_t h = 0; h != OrgHits[View][c].size(); ++h) {
524  if (HitStatus[OrgHits[View][c][h]] == 0) {
525  GetHitDistAndProj(detProp, TheSeed, HitsFlat[OrgHits[View][c].at(h)], dist, s);
526  if (dist < fHitResolution) {
527  GotOneThisChannel = true;
528  if (s < 0) {
529 
530  ToAddNegativeS[View].push_back(s);
531  ToAddNegativeH[View].push_back(OrgHits[View][c].at(h));
532  }
533  else {
534  ToAddPositiveS[View].push_back(s);
535  ToAddPositiveH[View].push_back(OrgHits[View][c].at(h));
536  }
537  }
538  }
539  }
540  if (GotOneThisChannel == false) break;
541  }
542  }
543 
544  double ExtendPositiveS = 0, ExtendNegativeS = 0;
545 
546  if ((ToAddPositiveS[0].size() > 0) && (ToAddPositiveS[1].size() > 0) &&
547  (ToAddPositiveS[2].size() > 0)) {
548  for (size_t n = 0; n != 3; ++n) {
549  int n1 = (n + 1) % 3;
550  int n2 = (n + 2) % 3;
551 
552  if ((ToAddPositiveS[n].back() <= ToAddPositiveS[n1].back()) &&
553  (ToAddPositiveS[n].back() <= ToAddPositiveS[n2].back())) {
554  ExtendPositiveS = ToAddPositiveS[n].back();
555  }
556  }
557  }
558 
559  if ((ToAddNegativeS[0].size() > 0) && (ToAddNegativeS[1].size() > 0) &&
560  (ToAddNegativeS[2].size() > 0)) {
561  for (size_t n = 0; n != 3; ++n) {
562  int n1 = (n + 1) % 3;
563  int n2 = (n + 2) % 3;
564  if ((ToAddNegativeS[n].back() >= ToAddNegativeS[n1].back()) &&
565  (ToAddNegativeS[n].back() >= ToAddNegativeS[n2].back())) {
566  ExtendNegativeS = ToAddNegativeS[n].back();
567  }
568  }
569  }
570 
571  if (fabs(ExtendNegativeS) < 1.) ExtendNegativeS = -1.;
572  if (fabs(ExtendPositiveS) < 1.) ExtendPositiveS = 1.;
573 
574  LengthRescale = (ExtendPositiveS - ExtendNegativeS) / 2.;
575  PositionShift = (ExtendPositiveS + ExtendNegativeS) / 2.;
576 
577  for (size_t n = 0; n != 3; ++n) {
578  pt[n] += dir[n] * PositionShift;
579  dir[n] *= LengthRescale;
580 
581  for (size_t i = 0; i != ToAddPositiveS[n].size(); ++i) {
582  if (ToAddPositiveS[n].at(i) < ExtendPositiveS)
583  HitStatus[ToAddPositiveH[n].at(i)] = 2;
584  else
585  HitStatus[ToAddPositiveH[n].at(i)] = 0;
586  }
587 
588  for (size_t i = 0; i != ToAddNegativeS[n].size(); ++i) {
589  if (ToAddNegativeS[n].at(i) > ExtendNegativeS)
590  HitStatus[ToAddNegativeH[n].at(i)] = 2;
591  else
592  HitStatus[ToAddNegativeH[n].at(i)] = 0;
593  }
594  }
595 
596  TheSeed.SetPoint(pt, err);
597  TheSeed.SetDirection(dir, err);
598  }
599 
600  if (ThrowOutSeed) TheSeed.SetValidity(false);
601  }
602 
603  //------------------------------------------------------------
604 
605  void
607  recob::Seed const& ASeed,
608  art::Ptr<recob::Hit> const& AHit,
609  double& disp,
610  double& s) const
611  {
613 
614  double xyzStart[3], xyzEnd[3];
615 
616  geom->WireEndPoints(0, 0, AHit->WireID().Plane, AHit->WireID().Wire, xyzStart, xyzEnd);
617 
618  double HitX = detProp.ConvertTicksToX(AHit->PeakTime(), AHit->WireID().Plane, 0, 0);
619 
620  double HitXHigh = detProp.ConvertTicksToX(AHit->PeakTimePlusRMS(), AHit->WireID().Plane, 0, 0);
621  double HitXLow = detProp.ConvertTicksToX(AHit->PeakTimeMinusRMS(), AHit->WireID().Plane, 0, 0);
622 
623  double HitWidth = HitXHigh - HitXLow;
624 
625  double pt[3], dir[3], err[3];
626 
627  ASeed.GetDirection(dir, err);
628  ASeed.GetPoint(pt, err);
629 
630  TVector3 sPt(pt[0], pt[1], pt[2]);
631  TVector3 sDir(dir[0], dir[1], dir[2]);
632  TVector3 hPt(HitX, xyzStart[1], xyzStart[2]);
633  TVector3 hDir(0, xyzStart[1] - xyzEnd[1], xyzStart[2] - xyzEnd[2]);
634 
635  s = (sPt - hPt).Dot(hDir * (hDir.Dot(sDir)) - sDir * (hDir.Dot(hDir))) /
636  (hDir.Dot(hDir) * sDir.Dot(sDir) - pow(hDir.Dot(sDir), 2));
637 
638  disp = fabs((sPt - hPt).Dot(sDir.Cross(hDir)) / (sDir.Cross(hDir)).Mag()) / HitWidth;
639  }
640 
641  //------------------------------------------------------------
642  // Try to find one seed at the high Z end of a set of spacepoints
643  //
644 
647  std::vector<recob::SpacePoint> const& Points,
648  std::vector<char>& PointStatus,
649  std::vector<int>& PointsInRange,
650  art::PtrVector<recob::Hit> const& HitsFlat,
651  std::vector<std::vector<std::vector<int>>>& OrgHits) const
652  {
653  // This pointer will be returned later
654  recob::Seed ReturnSeed;
655 
656  // Keep track of spacepoints we used, not just their IDs
657  std::vector<recob::SpacePoint> PointsUsed;
658 
659  // Clear output vector
660  PointsInRange.clear();
661 
662  // Loop through hits looking for highest Z seedable point
663  TVector3 HighestZPoint;
664  bool NoPointFound = true;
665  int counter = Points.size() - 1;
666  while ((NoPointFound == true) && (counter >= 0)) {
667  if (PointStatus[counter] == 0) {
668  HighestZPoint = TVector3(
669  Points.at(counter).XYZ()[0], Points.at(counter).XYZ()[1], Points.at(counter).XYZ()[2]);
670  NoPointFound = false;
671  }
672  else
673  counter--;
674  }
675  if (NoPointFound) {
676  // We didn't find a high point at all
677  // - let the algorithm know to give up.
678  PointStatus[0] = 3;
679  }
680 
681  // Now we have the high Z point, loop through collecting
682  // near enough hits. We look 2 seed lengths away, since
683  // the seed is bidirectional from the central point
684 
685  double TwiceLength = 2.0 * fInitSeedLength;
686 
687  for (int index = Points.size() - 1; index != -1; --index) {
688  if (PointStatus[index] == 0) {
689  // first check z, then check total distance
690  // (much faster, since most will be out of range in z anyway)
691  if ((HighestZPoint[2] - Points.at(index).XYZ()[2]) < TwiceLength) {
692  double DistanceToHighZ = pow(pow(HighestZPoint[1] - Points.at(index).XYZ()[1], 2) +
693  pow(HighestZPoint[2] - Points.at(index).XYZ()[2], 2),
694  0.5);
695  if (DistanceToHighZ < TwiceLength) {
696  PointsInRange.push_back(index);
697  PointsUsed.push_back(Points.at(index));
698  }
699  }
700  else
701  break;
702  }
703  }
704 
705  TVector3 SeedCenter(0, 0, 0);
706  TVector3 SeedDirection(0, 0, 0);
707 
708  // Check we have enough points in here to form a seed,
709  // otherwise return a dud
710  int NPoints = PointsInRange.size();
711 
712  if (NPoints < fMinPointsInSeed) return recob::Seed();
713 
714  std::map<int, bool> HitMap;
715  std::vector<int> HitList;
716 
717  for (unsigned int i = 0; i != PointsInRange.size(); i++) {
718  std::vector<art::PtrVector<recob::Hit>> HitsInThisCollection(3);
719 
720  art::PtrVector<recob::Hit> HitsThisSP =
721  fSptalg->getAssociatedHits((Points.at(PointsInRange.at(i))));
722  for (art::PtrVector<recob::Hit>::const_iterator itHit = HitsThisSP.begin();
723  itHit != HitsThisSP.end();
724  ++itHit) {
725  uint32_t Channel = (*itHit)->Channel();
726  geo::View_t View = (*itHit)->View();
727 
728  double eta = 0.01;
729  for (size_t iH = 0; iH != OrgHits[View][Channel].size(); ++iH) {
730  if (fabs(HitsFlat[OrgHits[View][Channel][iH]]->PeakTime() - (*itHit)->PeakTime()) < eta) {
731  HitMap[OrgHits[View][Channel][iH]] = true;
732  }
733  }
734  }
735  }
736 
737  for (auto itH = HitMap.begin(); itH != HitMap.end(); ++itH) {
738  HitList.push_back(itH->first);
739  }
740 
741  std::vector<double> ViewRMS;
742  std::vector<int> HitsPerView;
743 
745  detProp, HitsFlat, HitList, SeedCenter, SeedDirection, ViewRMS, HitsPerView);
746 
747  HitMap.clear();
748  HitList.clear();
749 
750  // See if seed points have some linearity
751 
752  bool ThrowOutSeed = false;
753 
754  double PtArray[3], DirArray[3];
755  double AngleFactor =
756  pow(pow(SeedDirection.Y(), 2) + pow(SeedDirection.Z(), 2), 0.5) / SeedDirection.Mag();
757 
758  int nViewsWithHits(0);
759 
760  for (size_t n = 0; n != 3; ++n) {
761  DirArray[n] = SeedDirection[n] * fInitSeedLength / AngleFactor;
762  PtArray[n] = SeedCenter[n];
763  if (HitsPerView[n] > 0) nViewsWithHits++;
764  }
765 
766  if (nViewsWithHits < 2 || (nViewsWithHits < 3 && !fAllow2DSeeds)) ThrowOutSeed = true;
767 
768  ReturnSeed = recob::Seed(PtArray, DirArray);
769 
770  if (fMaxViewRMS.at(0) > 0) {
771 
772  for (size_t j = 0; j != fMaxViewRMS.size(); j++) {
773  if (fMaxViewRMS.at(j) < ViewRMS.at(j)) { ThrowOutSeed = true; }
774  // mf::LogVerbatim("SeedFinderAlgorithm") << RMS.at(j);
775  }
776  }
777 
778  // If the seed is marked as bad, return a dud, otherwise
779  // return the ReturnSeed pointer
780  if (!ThrowOutSeed)
781  return ReturnSeed;
782  else
783  return recob::Seed();
784  }
785 
786  //-----------------------------------------------------------
787 
788  void
790  art::PtrVector<recob::Hit> const& HitsFlat,
791  std::vector<int>& HitsToUse,
792  TVector3& Center,
793  TVector3& Direction,
794  std::vector<double>& ViewRMS,
795  std::vector<int>& N) const
796  {
797  N.resize(3);
798 
799  std::map<uint32_t, bool> HitsClaimed;
800 
801  // We'll store hit coordinates in each view into this vector
802 
803  std::vector<std::vector<double>> HitTimes(3);
804  std::vector<std::vector<double>> HitWires(3);
805  std::vector<std::vector<double>> HitWidths(3);
806  std::vector<double> MeanWireCoord(3, 0);
807  std::vector<double> MeanTimeCoord(3, 0);
808 
809  // Run through the collection getting hit info for these spacepoints
810 
811  std::vector<double> x(3, 0), y(3, 0), xx(3, 0), xy(3, 0), yy(3, 0), sig(3, 0);
812 
813  for (size_t i = 0; i != HitsToUse.size(); ++i) {
814  auto itHit = HitsFlat.begin() + HitsToUse[i];
815 
816  size_t ViewIndex;
817 
818  auto const hitView = (*itHit)->View();
819  if (hitView == geo::kU)
820  ViewIndex = 0;
821  else if (hitView == geo::kV)
822  ViewIndex = 1;
823  else if (hitView == geo::kW)
824  ViewIndex = 2;
825  else {
827  << "SpacePointAlg does not support view " << geo::PlaneGeo::ViewName(hitView) << " (#"
828  << hitView << ")\n";
829  }
830  double WireCoord = (*itHit)->WireID().Wire * fPitches.at(ViewIndex);
831  double TimeCoord = detProp.ConvertTicksToX((*itHit)->PeakTime(), ViewIndex, 0, 0);
832  double TimeUpper = detProp.ConvertTicksToX((*itHit)->PeakTimePlusRMS(), ViewIndex, 0, 0);
833  double TimeLower = detProp.ConvertTicksToX((*itHit)->PeakTimeMinusRMS(), ViewIndex, 0, 0);
834  double Width = fabs(0.5 * (TimeUpper - TimeLower));
835  double Width2 = pow(Width, 2);
836 
837  HitWires.at(ViewIndex).push_back(WireCoord);
838  HitTimes.at(ViewIndex).push_back(TimeCoord);
839  HitWidths.at(ViewIndex).push_back(fabs(0.5 * (TimeUpper - TimeLower)));
840 
841  MeanWireCoord.at(ViewIndex) += WireCoord;
842  MeanTimeCoord.at(ViewIndex) += TimeCoord;
843 
844  // Elements for LS
845  x.at(ViewIndex) += WireCoord / Width2;
846  y.at(ViewIndex) += TimeCoord / Width2;
847  xy.at(ViewIndex) += (TimeCoord * WireCoord) / Width2;
848  xx.at(ViewIndex) += (WireCoord * WireCoord) / Width2;
849  yy.at(ViewIndex) += (TimeCoord * TimeCoord) / Width2;
850  sig.at(ViewIndex) += 1. / Width2;
851  N.at(ViewIndex)++;
852  }
853 
854  ViewRMS.clear();
855  ViewRMS.resize(3);
856  std::vector<double> ViewGrad(3);
857  std::vector<double> ViewOffset(3);
858 
859  for (size_t n = 0; n != 3; ++n) {
860  MeanWireCoord[n] /= N[n];
861  MeanTimeCoord[n] /= N[n];
862 
863  double BigN = 1000000;
864  double SmallN = 1. / BigN;
865 
866  if (N[n] > 2) {
867  double Numerator = (y[n] / sig[n] - xy[n] / x[n]);
868  double Denominator = (x[n] / sig[n] - xx[n] / x[n]);
869  if (fabs(Denominator) > SmallN)
870  ViewGrad.at(n) = Numerator / Denominator;
871  else
872  ViewGrad[n] = BigN;
873  }
874  else if (N[n] == 2)
875  ViewGrad[n] = xy[n] / xx[n];
876  else
877  ViewGrad[n] = BigN;
878 
879  ViewOffset.at(n) = (y[n] - ViewGrad[n] * x[n]) / sig[n];
880  ViewRMS.at(n) = pow((yy[n] + pow(ViewGrad[n], 2) * xx[n] + pow(ViewOffset[n], 2) * sig[n] -
881  2 * ViewGrad[n] * xy[n] - 2 * ViewOffset[n] * y[n] +
882  2 * ViewGrad[n] * ViewOffset[n] * x[n]) /
883  N[n],
884  0.5);
885  // Make RMS rotation perp to track
886  if (ViewGrad.at(n) != 0) ViewRMS[n] *= sin(atan(1. / ViewGrad.at(n)));
887  }
888 
889  for (size_t n = 0; n != 3; ++n) {
890  size_t n1 = (n + 1) % 3;
891  size_t n2 = (n + 2) % 3;
892  if ((N[n] <= N[n1]) && (N[n] <= N[n2])) {
893 
894  if (N[n1] < N[n2]) { std::swap(n1, n2); }
895  if ((N[n1] == 0) || (N[n2] == 0)) continue;
896 
897  Direction =
898  (fXDir + fPitchDir[n1] * (1. / ViewGrad[n1]) +
899  fWireDir[n1] *
900  (((1. / ViewGrad[n2]) - fPitchDir[n1].Dot(fPitchDir[n2]) * (1. / ViewGrad[n1])) /
901  fWireDir[n1].Dot(fPitchDir[n2])))
902  .Unit();
903 
904  /*
905  Center2D[n] =
906  fXDir * 0.5 * (MeanTimeCoord[n1]+MeanTimeCoord[n2])
907  + fPitchDir[n1] * (MeanWireCoord[n1] + fWireZeroOffset[n1])
908  + fWireDir[n1] * ( ((MeanWireCoord[n2] + fWireZeroOffset[n2]) - ( MeanWireCoord[n1] + fWireZeroOffset[n1] )*fPitchDir[n1].Dot(fPitchDir[n2]))/(fPitchDir[n2].Dot(fWireDir[n1])) );
909  */
910 
911  double TimeCoord = 0.5 * (MeanTimeCoord[n1] + MeanTimeCoord[n2]);
912  double WireCoordIn1 = (TimeCoord - ViewOffset[n1]) / ViewGrad[n1] + fWireZeroOffset[n1];
913  double WireCoordIn2 = (TimeCoord - ViewOffset[n2]) / ViewGrad[n2] + fWireZeroOffset[n2];
914 
915  Center = fXDir * TimeCoord + fPitchDir[n1] * WireCoordIn1 +
916  fWireDir[n1] * ((WireCoordIn2 - WireCoordIn1 * fPitchDir[n1].Dot(fPitchDir[n2])) /
917  (fPitchDir[n2].Dot(fWireDir[n1])));
918 
919  ViewRMS[n] = -fabs(ViewRMS[n]);
920  ViewRMS[n1] = fabs(ViewRMS[n1]);
921  ViewRMS[n2] = fabs(ViewRMS[n2]);
922 
923  break;
924  }
925  }
926  }
927 
928  //-----------------------------------------------
929  void
931  {
933 
934  // Total number of channels in the detector
935  fNChannels = geom->Nchannels();
936 
937  // Find pitch of each wireplane
938  fPitches.resize(3);
939  fPitches.at(0) = fabs(geom->WirePitch(geo::kU));
940  fPitches.at(1) = fabs(geom->WirePitch(geo::kV));
941  fPitches.at(2) = fabs(geom->WirePitch(geo::kW));
942 
943  // Setup basis vectors
944  fXDir = TVector3(1, 0, 0);
945  fYDir = TVector3(0, 1, 0);
946  fZDir = TVector3(0, 0, 1);
947 
948  fWireDir.resize(3);
949  fPitchDir.resize(3);
950  fWireZeroOffset.resize(3);
951 
952  double xyzStart1[3], xyzStart2[3];
953  double xyzEnd1[3], xyzEnd2[3];
954 
955  // Calculate wire coordinate systems
956  for (size_t n = 0; n != 3; ++n) {
957  geom->WireEndPoints(0, 0, n, 0, xyzStart1, xyzEnd1);
958  geom->WireEndPoints(0, 0, n, 1, xyzStart2, xyzEnd2);
959  fWireDir[n] =
960  TVector3(xyzEnd1[0] - xyzStart1[0], xyzEnd1[1] - xyzStart1[1], xyzEnd1[2] - xyzStart1[2])
961  .Unit();
962  fPitchDir[n] = fWireDir[n].Cross(fXDir).Unit();
963  if (fPitchDir[n].Dot(TVector3(
964  xyzEnd2[0] - xyzEnd1[0], xyzEnd2[1] - xyzEnd1[1], xyzEnd2[2] - xyzEnd1[2])) < 0)
965  fPitchDir[n] = -fPitchDir[n];
966 
967  fWireZeroOffset[n] =
968  xyzEnd1[0] * fPitchDir[n][0] + xyzEnd1[1] * fPitchDir[n][1] + xyzEnd1[2] * fPitchDir[n][2];
969  }
970  }
971 
972  //-----------------------------------------------
973 
974  std::vector<recob::Seed>
976  detinfo::DetectorClocksData const& clockData,
977  detinfo::DetectorPropertiesData const& detProp,
980  unsigned int StopAfter) const
981  {
982  std::vector<recob::Seed> ReturnVec;
983  return FindSeeds(clockData, detProp, Hits, HitCatalogue, StopAfter);
984  }
985 
986  //---------------------------------------------
987 
988  std::vector<std::vector<recob::Seed>>
990  detinfo::DetectorClocksData const& clockData,
991  detinfo::DetectorPropertiesData const& detProp,
994  unsigned int StopAfter) const
995  {
996 
997  std::vector<std::vector<recob::Seed>> ReturnVec;
998 
999  // This piece of code looks detector specific, but its not -
1000  // it also works for 2 planes, but one vector is empty.
1001 
1002  if (!(fSptalg->enableU() && fSptalg->enableV() && fSptalg->enableW()))
1003  mf::LogWarning("BezierTrackerModule")
1004  << "Warning: SpacePointAlg is does not have three views enabled. This may cause unexpected "
1005  "behaviour in the bezier tracker.";
1006 
1007  try {
1009  SortedHits.at(geo::kU).begin();
1010  itU != SortedHits.at(geo::kU).end();
1011  ++itU)
1013  SortedHits.at(geo::kV).begin();
1014  itV != SortedHits.at(geo::kV).end();
1015  ++itV)
1017  SortedHits.at(geo::kW).begin();
1018  itW != SortedHits.at(geo::kW).end();
1019  ++itW) {
1020  art::PtrVector<recob::Hit> HitsThisComboFlat;
1021 
1022  if (fSptalg->enableU())
1023  for (size_t i = 0; i != itU->size(); ++i)
1024  HitsThisComboFlat.push_back(itU->at(i));
1025 
1026  if (fSptalg->enableV())
1027  for (size_t i = 0; i != itV->size(); ++i)
1028  HitsThisComboFlat.push_back(itV->at(i));
1029 
1030  if (fSptalg->enableW())
1031  for (size_t i = 0; i != itW->size(); ++i)
1032  HitsThisComboFlat.push_back(itW->at(i));
1033 
1034  std::vector<art::PtrVector<recob::Hit>> CataloguedHits;
1035 
1036  std::vector<recob::Seed> Seeds =
1037  FindSeeds(clockData, detProp, HitsThisComboFlat, CataloguedHits, StopAfter);
1038 
1039  // Add this harvest to return vectors
1040  HitsPerSeed.push_back(CataloguedHits);
1041  ReturnVec.push_back(Seeds);
1042 
1043  // Tidy up
1044  CataloguedHits.clear();
1045  Seeds.clear();
1046  }
1047  }
1048  catch (...) {
1049  mf::LogWarning("SeedFinderTrackerModule")
1050  << " bailed during hit map lookup - have you enabled all 3 planes?";
1051  ReturnVec.push_back(std::vector<recob::Seed>());
1052  }
1053 
1054  return ReturnVec;
1055  }
1056 
1057 }
std::vector< double > fPitches
float Length(const PFPStruct &pfp)
Definition: PFPUtils.cxx:3303
SeedFinderAlgorithm(const fhicl::ParameterSet &pset)
bool enableW() const noexcept
bool enableV() const noexcept
static std::string ViewName(geo::View_t view)
Returns the name of the specified view.
Definition: PlaneGeo.cxx:763
AdcChannelData::View View
bool IsValid() const
Definition: Seed.cxx:70
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
Planes which measure V.
Definition: geo_types.h:130
geo::WireID WireID() const
Definition: Hit.h:233
iterator begin()
Definition: PtrVector.h:217
void GetPoint(double *Pt, double *Err) const
Definition: Seed.cxx:108
constexpr T pow(T x)
Definition: pow.h:72
struct vector vector
void GetHitDistAndProj(detinfo::DetectorPropertiesData const &detProp, recob::Seed const &ASeed, art::Ptr< recob::Hit > const &AHit, double &disp, double &s) const
void reconfigure(fhicl::ParameterSet const &pset)
double Width(Resonance_t res)
resonance width (GeV)
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:580
string dir
void resize(Vector< T > &vec1, Index n1, const V &val)
recob::Seed FindSeedAtEnd(detinfo::DetectorPropertiesData const &detProp, std::vector< recob::SpacePoint > const &, std::vector< char > &, std::vector< int > &, art::PtrVector< recob::Hit > const &HitsFlat, std::vector< std::vector< std::vector< int >>> &OrgHits) const
geo::Length_t WirePitch(geo::PlaneID const &planeid) const
Returns the distance between two consecutive wires.
const art::PtrVector< recob::Hit > & getAssociatedHits(const recob::SpacePoint &spt) const
art framework interface to geometry description
void ConsolidateSeed(detinfo::DetectorPropertiesData const &detProp, recob::Seed &TheSeed, art::PtrVector< recob::Hit > const &, std::vector< char > &HitStatus, std::vector< std::vector< std::vector< int >>> &OrgHits, bool Extend) const
std::map< int, art::Ptr< recob::Hit > > HitMap
unsigned int Nchannels() const
Returns the number of TPC readout channels in the detector.
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
Planes which measure U.
Definition: geo_types.h:129
typename data_t::const_iterator const_iterator
Definition: PtrVector.h:55
void SetPoint(double *Pt, double *Err)
Definition: Seed.cxx:144
void push_back(Ptr< U > const &p)
Definition: PtrVector.h:435
void swap(Handle< T > &a, Handle< T > &b)
std::void_t< T > n
void makeSpacePoints(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, const art::PtrVector< recob::Hit > &hits, std::vector< recob::SpacePoint > &spts) const
T get(std::string const &key) const
Definition: ParameterSet.h:271
iterator end()
Definition: PtrVector.h:231
void GetCenterAndDirection(detinfo::DetectorPropertiesData const &detProp, art::PtrVector< recob::Hit > const &HitsFlat, std::vector< int > &HitsToUse, TVector3 &Center, TVector3 &Direction, std::vector< double > &ViewRMS, std::vector< int > &HitsPerView) const
reference at(size_type n)
Definition: PtrVector.h:359
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:493
std::vector< recob::Seed > FindSeeds(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, art::PtrVector< recob::Hit > const &HitsFlat, std::vector< art::PtrVector< recob::Hit >> &CataloguedHits, unsigned int StopAfter) const
float PeakTimeMinusRMS(float sigmas=+1.) const
Definition: Hit.h:239
void err(const char *fmt,...)
Definition: message.cpp:226
size_type size() const
Definition: PtrVector.h:302
std::vector< recob::Seed > GetSeedsFromUnSortedHits(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, art::PtrVector< recob::Hit > const &, std::vector< art::PtrVector< recob::Hit >> &, unsigned int StopAfter=0) const
double ConvertTicksToX(double ticks, int p, int t, int c) const
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
void clearHitMap() const
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:218
Declaration of signal hit object.
Encapsulate the construction of a single detector plane.
Contains all timing reference information for the detector.
constexpr double dist(const TReal *x, const TReal *y, const unsigned int dimension)
bool enableU() const noexcept
std::vector< TVector3 > fWireDir
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
void WireEndPoints(geo::WireID const &wireid, double *xyzStart, double *xyzEnd) const
Fills two arrays with the coordinates of the wire end points.
list x
Definition: train.py:276
Direction
Definition: AssnsIter.h:13
std::vector< TVector3 > fPitchDir
Planes which measure W (third view for Bo, MicroBooNE, etc).
Definition: geo_types.h:131
float PeakTimePlusRMS(float sigmas=+1.) const
Returns a time sigmas RMS away from the peak time.
Definition: Hit.h:236
std::set< art::Ptr< recob::Hit > > HitList
void clear()
Definition: PtrVector.h:533
void SetValidity(bool Validity)
Definition: Seed.cxx:90
std::vector< std::vector< recob::Seed > > GetSeedsFromSortedHits(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, std::vector< std::vector< art::PtrVector< recob::Hit >>> const &SortedHits, std::vector< std::vector< art::PtrVector< recob::Hit >>> &HitsPerSeed, unsigned int StopAfter=0) const
void GetDirection(double *Dir, double *Err) const
Definition: Seed.cxx:98
std::vector< double > fWireZeroOffset
static QCString * s
Definition: config.cpp:1042
double GetLength() const
Definition: Seed.cxx:155
void SetDirection(double *Dir, double *Err)
Definition: Seed.cxx:133
std::vector< double > fMaxViewRMS