LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
ProjectionMatchingAlg.cxx
Go to the documentation of this file.
1 // Class: ProjectionMatchingAlg
3 // Author: D.Stefan (Dorota.Stefan@ncbj.gov.pl) and R.Sulej (Robert.Sulej@cern.ch), May 2015
5 
7 
8 #include "larcore/CoreUtils/ServiceUtil.h" // lar::providerFrom<>()
10 
11 #include "larevt/CalibrationDBI/Interface/ChannelStatusService.h"
12 #include "larevt/CalibrationDBI/Interface/ChannelStatusProvider.h"
13 #include "larcorealg/CoreUtils/NumericUtils.h" // util::absDiff()
14 
16 
18  fGeom( &*(art::ServiceHandle<geo::Geometry>()) ),
19  fDetProp(lar::providerFrom<detinfo::DetectorPropertiesService>())
20 {
22  fFineTuningEps = config.FineTuningEps();
23 
26 
28 
30 
34 
35  fDetProp = lar::providerFrom<detinfo::DetectorPropertiesService>();
36 }
37 // ------------------------------------------------------
38 
40  const pma::Track3D& trk, const img::DataProviderAlg & adcImage, float thr) const
41 {
42  unsigned int nAll = 0, nPassed = 0;
43  unsigned int testPlane = adcImage.Plane();
44 
45  std::vector< unsigned int > trkTPCs = trk.TPCs();
46  std::vector< unsigned int > trkCryos = trk.Cryos();
47 
48  unsigned int tpc, cryo;
49 
50  auto const & channelStatus = art::ServiceHandle< lariov::ChannelStatusService >()->GetProvider();
51 
52  double step = 0.3;
53  // check how pixels with a high signal are distributed along the track
54  // namely: are there track sections crossing empty spaces, except dead wires?
55  pma::Vector3D p(trk.front()->Point3D().X(), trk.front()->Point3D().Y(), trk.front()->Point3D().Z());
56  for (auto const * seg : trk.Segments())
57  {
58  if (seg->TPC() < 0) // skip segments between tpc's, look only at those contained in tpc
59  {
60  p = seg->End(); continue;
61  }
62  pma::Vector3D p0 = seg->Start();
63  pma::Vector3D p1 = seg->End();
64 
65  pma::Node3D* node = static_cast<pma::Node3D*>(seg->Prev());
66 
67  tpc = seg->TPC(); cryo = seg->Cryo();
68 
69  pma::Vector3D dc = step * seg->GetDirection3D();
70 
71  double f = pma::GetSegmentProjVector(p, p0, p1);
72  while ((f < 1.0) && node->SameTPC(p))
73  {
74  pma::Vector2D p2d(fGeom->WireCoordinate(p.Y(), p.Z(), testPlane, tpc, cryo), p.X());
75  geo::WireID wireID(cryo, tpc, testPlane, (int)p2d.X());
76 
77  int widx = (int)p2d.X();
78  int didx = (int)fDetProp->ConvertXToTicks(p2d.Y(), testPlane, tpc, cryo);
79 
80  if (fGeom->HasWire(wireID))
81  {
83  if (channelStatus.IsGood(ch))
84  {
85  float max_adc = adcImage.poolMax(widx, didx, 2); // +/- 2 wires, can be parameterized
86  if (max_adc > thr) nPassed++;
87 
88  nAll++;
89  }
90  //else mf::LogVerbatim("ProjectionMatchingAlg")
91  // << "crossing BAD CHANNEL (wire #" << (int)p2d.X() << ")" << std::endl;
92  }
93 
94  p += dc; f = pma::GetSegmentProjVector(p, p0, p1);
95  }
96 
97  p = seg->End(); // need to have it at the end due to the p in the first iter set to the hit position, not segment start
98  }
99 
100  if (nAll > 0)
101  {
102  double v = nPassed / (double)nAll;
103  mf::LogVerbatim("ProjectionMatchingAlg") << " trk fraction ok: " << v;
104  return v;
105  }
106  else return 1.0;
107 }
108 // ------------------------------------------------------
109 
111  const img::DataProviderAlg & adcImage,
113  TH1F * histoPassing, TH1F * histoRejected) const
114 {
115  double max_d = fTrkValidationDist2D;
116  double d2, max_d2 = max_d * max_d;
117  unsigned int nAll = 0, nPassed = 0;
118  unsigned int testPlane = adcImage.Plane();
119 
120  std::vector< unsigned int > trkTPCs = trk.TPCs();
121  std::vector< unsigned int > trkCryos = trk.Cryos();
122  std::map< std::pair< unsigned int, unsigned int >, std::pair< TVector2, TVector2 > > ranges;
123  std::map< std::pair< unsigned int, unsigned int >, double > wirePitch;
124  for (auto c : trkCryos)
125  for (auto t : trkTPCs)
126  {
127  ranges[std::pair< unsigned int, unsigned int >(t, c)] = trk.WireDriftRange(testPlane, t, c);
128  wirePitch[std::pair< unsigned int, unsigned int >(t, c)] = fGeom->TPC(t, c).Plane(testPlane).WirePitch();
129  }
130 
131  unsigned int tpc, cryo;
132  std::map< std::pair< unsigned int, unsigned int >, std::vector< pma::Vector2D > > all_close_points;
133 
134  for (const auto h : hits)
135  if (h->WireID().Plane == testPlane)
136  {
137  tpc = h->WireID().TPC;
138  cryo = h->WireID().Cryostat;
139  std::pair< unsigned int, unsigned int > tpc_cryo(tpc, cryo);
140  std::pair< TVector2, TVector2 > rect = ranges[tpc_cryo];
141 
142  if ((h->WireID().Wire > rect.first.X() - 10) && // chceck only hits in the rectangle around
143  (h->WireID().Wire < rect.second.X() + 10) && // the track projection, it is faster than
144  (h->PeakTime() > rect.first.Y() - 100) && // calculation of trk.Dist2(p2d, testPlane)
145  (h->PeakTime() < rect.second.Y() + 100))
146  {
147  TVector2 p2d(wirePitch[tpc_cryo] * h->WireID().Wire, fDetProp->ConvertTicksToX(h->PeakTime(), testPlane, tpc, cryo));
148 
149  d2 = trk.Dist2(p2d, testPlane, tpc, cryo);
150 
151  if (d2 < max_d2) { all_close_points[tpc_cryo].emplace_back(p2d.X(), p2d.Y()); }
152  }
153  }
154 
155  auto const & channelStatus = art::ServiceHandle< lariov::ChannelStatusService >()->GetProvider();
156 
157  double step = 0.3;
158  // then check how points-close-to-the-track-projection are distributed along the
159  // track, namely: are there track sections crossing empty spaces, except dead wires?
160  pma::Vector3D p(trk.front()->Point3D().X(), trk.front()->Point3D().Y(), trk.front()->Point3D().Z());
161  for (auto const * seg : trk.Segments())
162  {
163  if (seg->TPC() < 0) // skip segments between tpc's, look only at those contained in tpc
164  {
165  p = seg->End(); continue;
166  }
167  pma::Vector3D p0 = seg->Start();
168  pma::Vector3D p1 = seg->End();
169 
170  pma::Node3D* node = static_cast<pma::Node3D*>(seg->Prev());
171 
172  tpc = seg->TPC(); cryo = seg->Cryo();
173 
174  pma::Vector3D dc = step * seg->GetDirection3D();
175 
176  auto const & points = all_close_points[std::pair< unsigned int, unsigned int >(tpc, cryo)];
177 
178  double f = pma::GetSegmentProjVector(p, p0, p1);
179 
180  double wirepitch = fGeom->TPC(tpc, cryo).Plane(testPlane).WirePitch();
181  while ((f < 1.0) && node->SameTPC(p))
182  {
183  pma::Vector2D p2d(fGeom->WireCoordinate(p.Y(), p.Z(), testPlane, tpc, cryo), p.X());
184  geo::WireID wireID(cryo, tpc, testPlane, (int)p2d.X());
185 
186  int widx = (int)p2d.X();
187  int didx = (int)fDetProp->ConvertXToTicks(p2d.Y(), testPlane, tpc, cryo);
188 
189  if (fGeom->HasWire(wireID))
190  {
192  if (channelStatus.IsGood(ch))
193  {
194  bool is_close = false;
195  float max_adc = adcImage.poolMax(widx, didx, 2);
196 
197  if (points.size())
198  {
199  p2d.SetX(wirepitch * p2d.X());
200  for (const auto & h : points)
201  {
202  d2 = pma::Dist2(p2d, h);
203  if (d2 < max_d2) { is_close = true; nPassed++; break; }
204  }
205  }
206  nAll++;
207 
208  // now fill the calibration histograms
209  if (is_close) { if (histoPassing) histoPassing->Fill(max_adc); }
210  else { if (histoRejected) histoRejected->Fill(max_adc); }
211  }
212  //else mf::LogVerbatim("ProjectionMatchingAlg")
213  // << "crossing BAD CHANNEL (wire #" << (int)p2d.X() << ")" << std::endl;
214  }
215 
216  p += dc; f = pma::GetSegmentProjVector(p, p0, p1);
217  }
218  p = seg->End();
219  }
220 
221  if (nAll > 0)
222  {
223  double v = nPassed / (double)nAll;
224  mf::LogVerbatim("ProjectionMatchingAlg") << " trk fraction ok: " << v;
225  return v;
226  }
227  else return 1.0;
228 }
229 // ------------------------------------------------------
230 
232  const std::vector< art::Ptr<recob::Hit> >& hits) const
233 {
234  if (hits.empty()) { return 0; }
235 
236  double max_d = fTrkValidationDist2D;
237  double d2, max_d2 = max_d * max_d;
238  unsigned int nAll = 0, nPassed = 0;
239  unsigned int testPlane = hits.front()->WireID().Plane;
240 
241  std::vector< unsigned int > trkTPCs = trk.TPCs();
242  std::vector< unsigned int > trkCryos = trk.Cryos();
243  std::map< std::pair< unsigned int, unsigned int >, std::pair< TVector2, TVector2 > > ranges;
244  std::map< std::pair< unsigned int, unsigned int >, double > wirePitch;
245  for (auto c : trkCryos)
246  for (auto t : trkTPCs)
247  {
248  ranges[std::pair< unsigned int, unsigned int >(t, c)] = trk.WireDriftRange(testPlane, t, c);
249  wirePitch[std::pair< unsigned int, unsigned int >(t, c)] = fGeom->TPC(t, c).Plane(testPlane).WirePitch();
250  }
251 
252  unsigned int tpc, cryo;
253  std::map< std::pair< unsigned int, unsigned int >, std::vector< pma::Vector2D > > all_close_points;
254 
255  for (const auto h : hits)
256  if (h->WireID().Plane == testPlane)
257  {
258  tpc = h->WireID().TPC;
259  cryo = h->WireID().Cryostat;
260  std::pair< unsigned int, unsigned int > tpc_cryo(tpc, cryo);
261  std::pair< TVector2, TVector2 > rect = ranges[tpc_cryo];
262 
263  if ((h->WireID().Wire > rect.first.X() - 10) && // chceck only hits in the rectangle around
264  (h->WireID().Wire < rect.second.X() + 10) && // the track projection, it is faster than
265  (h->PeakTime() > rect.first.Y() - 100) && // calculation of trk.Dist2(p2d, testPlane)
266  (h->PeakTime() < rect.second.Y() + 100))
267  {
268  TVector2 p2d(wirePitch[tpc_cryo] * h->WireID().Wire, fDetProp->ConvertTicksToX(h->PeakTime(), testPlane, tpc, cryo));
269 
270  d2 = trk.Dist2(p2d, testPlane, tpc, cryo);
271 
272  if (d2 < max_d2) all_close_points[tpc_cryo].emplace_back(p2d.X(), p2d.Y());
273  }
274  }
275 
276  auto const & channelStatus = art::ServiceHandle< lariov::ChannelStatusService >()->GetProvider();
277 
278  double step = 0.3;
279  // then check how points-close-to-the-track-projection are distributed along the
280  // track, namely: are there track sections crossing empty spaces, except dead wires?
281  pma::Vector3D p(trk.front()->Point3D().X(), trk.front()->Point3D().Y(), trk.front()->Point3D().Z());
282  for (auto const * seg : trk.Segments())
283  {
284  if (seg->TPC() < 0) // skip segments between tpc's, look only at those contained in tpc
285  {
286  p = seg->End(); continue;
287  }
288  pma::Vector3D p0 = seg->Start();
289  pma::Vector3D p1 = seg->End();
290 
291  pma::Node3D* node = static_cast<pma::Node3D*>(seg->Prev());
292 
293  tpc = seg->TPC(); cryo = seg->Cryo();
294 
295  pma::Vector3D dc = step * seg->GetDirection3D();
296 
297  auto const & points = all_close_points[std::pair< unsigned int, unsigned int >(tpc, cryo)];
298 
299  double f = pma::GetSegmentProjVector(p, p0, p1);
300 
301  double wirepitch = fGeom->TPC(tpc, cryo).Plane(testPlane).WirePitch();
302  while ((f < 1.0) && node->SameTPC(p))
303  {
304  pma::Vector2D p2d(fGeom->WireCoordinate(p.Y(), p.Z(), testPlane, tpc, cryo), p.X());
305  geo::WireID wireID(cryo, tpc, testPlane, (int)p2d.X());
306  if (fGeom->HasWire(wireID))
307  {
309  if (channelStatus.IsGood(ch))
310  {
311  if (points.size())
312  {
313  p2d.SetX(wirepitch * p2d.X());
314  for (const auto & h : points)
315  {
316  d2 = pma::Dist2(p2d, h);
317  if (d2 < max_d2) { nPassed++; break; }
318  }
319  }
320  nAll++;
321  }
322  //else mf::LogVerbatim("ProjectionMatchingAlg")
323  // << "crossing BAD CHANNEL (wire #" << (int)p2d.X() << ")" << std::endl;
324  }
325 
326  p += dc; f = pma::GetSegmentProjVector(p, p0, p1);
327  }
328  p = seg->End();
329  }
330 
331  if (nAll > 0)
332  {
333  double v = nPassed / (double)nAll;
334  mf::LogVerbatim("ProjectionMatchingAlg") << " trk fraction ok: " << v;
335  return v;
336  }
337  else return 1.0;
338 }
339 // ------------------------------------------------------
340 
342  const TVector3& p0, const TVector3& p1,
344  unsigned int testPlane, unsigned int tpc, unsigned int cryo) const
345 {
346  double step = 0.3;
347  double max_d = fTrkValidationDist2D;
348  double d2, max_d2 = max_d * max_d;
349  unsigned int nAll = 0, nPassed = 0;
350 
351  TVector3 p(p0);
352  TVector3 dc(p1); dc -= p;
353  dc *= step / dc.Mag();
354 
355  auto const & channelStatus = art::ServiceHandle< lariov::ChannelStatusService >()->GetProvider();
356 
357  double f = pma::GetSegmentProjVector(p, p0, p1);
358  double wirepitch = fGeom->TPC(tpc, cryo).Plane(testPlane).WirePitch();
359  while (f < 1.0)
360  {
361  TVector2 p2d(fGeom->WireCoordinate(p.Y(), p.Z(), testPlane, tpc, cryo), p.X());
362  geo::WireID wireID(cryo, tpc, testPlane, (int)p2d.X());
363  if (fGeom->HasWire(wireID))
364  {
366  if (channelStatus.IsGood(ch))
367  {
368  p2d.Set(wirepitch * p2d.X(), p2d.Y());
369  for (const auto & h : hits)
370  if ((h->WireID().Plane == testPlane) &&
371  (h->WireID().TPC == tpc) &&
372  (h->WireID().Cryostat == cryo))
373  {
374  d2 = pma::Dist2(p2d, pma::WireDriftToCm(h->WireID().Wire, h->PeakTime(), testPlane, tpc, cryo));
375  if (d2 < max_d2) { nPassed++; break; }
376  }
377  nAll++;
378  }
379  //else mf::LogVerbatim("ProjectionMatchingAlg")
380  // << "crossing BAD CHANNEL (wire #" << (int)p2d.X() << ")" << std::endl;
381  }
382 
383  p += dc; f = pma::GetSegmentProjVector(p, p0, p1);
384  }
385 
386  if (nAll > 3) // validate actually only if 2D projection in testPlane has some minimum length
387  {
388  double v = nPassed / (double)nAll;
389  mf::LogVerbatim("ProjectionMatchingAlg") << " segment fraction ok: " << v;
390  return v;
391  }
392  else return 1.0;
393 }
394 // ------------------------------------------------------
395 
397 {
398  trk.SelectHits();
399  trk.DisableSingleViewEnds();
400 
401  size_t idx = 0;
402  while ((idx < trk.size() - 1) && !trk[idx]->IsEnabled()) idx++;
403  double l0 = trk.Length(0, idx + 1);
404 
405  idx = trk.size() - 1;
406  while ((idx > 1) && !trk[idx]->IsEnabled()) idx--;
407  double l1 = trk.Length(idx - 1, trk.size() - 1);
408 
409  trk.SelectHits();
410 
411  return 1.0 - (l0 + l1) / trk.Length();
412 }
413 // ------------------------------------------------------
414 
416 {
417  int nSegments = (int)( 0.8 * trk_size / sqrt(trk_size) );
418 
419  if (nSegments > 1) return (size_t)nSegments;
420  else return 1;
421 }
422 // ------------------------------------------------------
423 
425  const std::vector< art::Ptr<recob::Hit> >& hits_1,
426  const std::vector< art::Ptr<recob::Hit> >& hits_2) const
427 {
428  pma::Track3D* trk = new pma::Track3D(); // track candidate
429  trk->AddHits(hits_1);
430  trk->AddHits(hits_2);
431 
432  mf::LogVerbatim("ProjectionMatchingAlg") << "track size: " << trk->size();
433  std::vector< unsigned int > tpcs = trk->TPCs();
434  for (size_t t = 0; t < tpcs.size(); ++t)
435  {
436  mf::LogVerbatim("ProjectionMatchingAlg") << " tpc:" << tpcs[t];
437  }
438  mf::LogVerbatim("ProjectionMatchingAlg")
439  << " #coll:" << trk->NHits(geo::kZ)
440  << " #ind2:" << trk->NHits(geo::kV)
441  << " #ind1:" << trk->NHits(geo::kU);
442 
443  size_t nSegments = getSegCount(trk->size());
444  size_t nNodes = (size_t)( nSegments - 1 ); // n nodes to add
445 
446  mf::LogVerbatim("ProjectionMatchingAlg") << " initialize trk";
447  if (!trk->Initialize())
448  {
449  mf::LogWarning("ProjectionMatchingAlg") << " initialization failed, delete trk";
450  delete trk;
451  return 0;
452  }
453 
454  double f = twoViewFraction(*trk);
455  if (f > fMinTwoViewFraction)
456  {
457  double g = 0.0;
458  mf::LogVerbatim("ProjectionMatchingAlg") << " optimize trk (" << nSegments << " seg)";
459  if (nNodes)
460  {
461  g = trk->Optimize(nNodes, fOptimizationEps, false, true, 25, 10); // build nodes
462  mf::LogVerbatim("ProjectionMatchingAlg") << " nodes done, g = " << g;
463  trk->SelectAllHits();
464  }
465  g = trk->Optimize(0, fFineTuningEps); // final tuning
466  mf::LogVerbatim("ProjectionMatchingAlg") << " tune done, g = " << g;
467 
468  trk->SortHits();
469  // trk->ShiftEndsToHits(); // not sure if useful already here
470  return trk;
471  }
472  else
473  {
474  mf::LogVerbatim("ProjectionMatchingAlg") << " clusters do not match, f = " << f;
475  delete trk;
476  return 0;
477  }
478 }
479 // ------------------------------------------------------
480 
482  const std::vector< art::Ptr<recob::Hit> >& hits) const
483 {
484  std::map< unsigned int, std::vector< art::Ptr<recob::Hit> > > hits_by_tpc;
485  for (auto const & h : hits)
486  {
487  hits_by_tpc[h->WireID().TPC].push_back(h);
488  }
489 
490  std::vector< pma::Track3D* > tracks;
491  for(auto const & hsel : hits_by_tpc)
492  {
493  //pma::Track3D* trk = buildTrack(hsel.second);
494  pma::Track3D* trk = buildSegment(hsel.second);
495  if (trk) tracks.push_back(trk);
496  }
497 
498  bool need_reopt = false;
499  while (tracks.size() > 1)
500  {
501  need_reopt = true;
502 
503  pma::Track3D* first = tracks.front();
504  pma::Track3D* best = 0;
505  double d, dmin = 1.0e12;
506  size_t t_best = 0, cfg = 0;
507  for (size_t t = 1; t < tracks.size(); ++t)
508  {
509  pma::Track3D* second = tracks[t];
510 
511  d = pma::Dist2(first->front()->Point3D(), second->front()->Point3D());
512  if (d < dmin) { dmin = d; best = second; t_best = t; cfg = 0; }
513 
514  d = pma::Dist2(first->front()->Point3D(), second->back()->Point3D());
515  if (d < dmin) { dmin = d; best = second; t_best = t; cfg = 1; }
516 
517  d = pma::Dist2(first->back()->Point3D(), second->front()->Point3D());
518  if (d < dmin) { dmin = d; best = second; t_best = t; cfg = 2; }
519 
520  d = pma::Dist2(first->back()->Point3D(), second->back()->Point3D());
521  if (d < dmin) { dmin = d; best = second; t_best = t; cfg = 3; }
522  }
523  if (best)
524  {
525  switch (cfg)
526  {
527  default:
528  case 0:
529  case 1:
530  mergeTracks(*best, *first, false);
531  tracks[0] = best; delete first; break;
532 
533  case 2:
534  case 3:
535  mergeTracks(*first, *best, false);
536  delete best; break;
537  }
538  tracks.erase(tracks.begin() + t_best);
539  }
540  else break; // should not happen
541  }
542 
543  pma::Track3D* trk = 0;
544  if (!tracks.empty())
545  {
546  trk = tracks.front();
547  if (need_reopt)
548  {
549  double g = trk->Optimize(0, fOptimizationEps);
550  mf::LogVerbatim("ProjectionMatchingAlg") << " reopt after merging initial tpc segments: done, g = " << g;
551  }
552 
553  int nSegments = getSegCount(trk->size()) - trk->Segments().size() + 1;
554  if (nSegments > 0) // need to add segments
555  {
556  double g = 0.0;
557  size_t nNodes = (size_t)( nSegments - 1 ); // n nodes to add
558  if (nNodes)
559  {
560  mf::LogVerbatim("ProjectionMatchingAlg") << " optimize trk (add " << nSegments << " seg)";
561 
562  g = trk->Optimize(nNodes, fOptimizationEps, false, true, 25, 10); // build nodes
563  mf::LogVerbatim("ProjectionMatchingAlg") << " nodes done, g = " << g;
564  trk->SelectAllHits();
565  }
566  g = trk->Optimize(0, fFineTuningEps); // final tuning
567  mf::LogVerbatim("ProjectionMatchingAlg") << " tune done, g = " << g;
568  }
569  trk->SortHits();
570  }
571  return trk;
572 }
573 
574 // ------------------------------------------------------
575 
578  const pma::Vector3D & vtx) const
579 {
580  double vtxarray[3] {vtx.X(), vtx.Y(), vtx.Z()};
581 
582  if (!fGeom->HasTPC(fGeom->FindTPCAtPosition(vtxarray))) return 0;
583 
584  TVector3 vtxv3(vtx.X(), vtx.Y(), vtx.Z());
585 
586  const size_t tpc = fGeom->FindTPCAtPosition(vtxarray).TPC;
587  const size_t cryo = fGeom->FindCryostatAtPosition(vtxarray);
588  const geo::TPCGeo& tpcgeom = fGeom->Cryostat(cryo).TPC(tpc);
589 
590  // use only hits from tpc where the vtx is
591  std::vector<art::Ptr<recob::Hit> > hitstpc;
592  for (size_t h = 0; h < hits.size(); ++h)
593  if (hits[h]->WireID().TPC == tpc)
594  hitstpc.push_back(hits[h]);
595 
596  if (!hitstpc.size()) return 0;
597 
598  std::vector<art::Ptr<recob::Hit> > hitstrk;
599  size_t view = 0; size_t countviews = 0;
600  while (view < 3)
601  {
602  mf::LogVerbatim("ProjectionMatchinAlg") << "collecting hits from view: " << view;
603  if (!tpcgeom.HasPlane(view)) {++view; continue;}
604 
605  // select hits only for a single view
606  std::vector<art::Ptr<recob::Hit> > hitsview;
607  for (size_t h = 0; h < hitstpc.size(); ++h)
608  if (hitstpc[h]->WireID().Plane == view)
609  hitsview.push_back(hitstpc[h]);
610  if (!hitsview.size()) {++view; continue;}
611 
612  // filter our small groups of hits, far from main shower
613  std::vector<art::Ptr<recob::Hit> > hitsfilter;
614  TVector2 proj_pr = pma::GetProjectionToPlane(vtxv3, view, tpc, cryo);
615 
616  mf::LogVerbatim("ProjectionMatchinAlg") << "start filter out: ";
617  FilterOutSmallParts(2.0, hitsview, hitsfilter, proj_pr);
618  mf::LogVerbatim("ProjectionMatchingAlg") << "after filter out";
619 
620  for (size_t h = 0; h < hitsfilter.size(); ++h)
621  hitstrk.push_back(hitsfilter[h]);
622 
623  if (hitsfilter.size() >= 5) countviews++;
624 
625  ++view;
626  }
627 
628  if (!hitstrk.size() || (countviews < 2))
629  {
630  mf::LogWarning("ProjectionMatchinAlg") << "too few hits, segment not built";
631  return 0;
632  }
633 
634  // hits are prepared, finally segment is built
635 
636  pma::Track3D* trk = new pma::Track3D();
637  trk = buildSegment(hitstrk, vtxv3);
638 
639  // make shorter segment to estimate direction more precise
640  ShortenSeg(*trk, tpcgeom);
641 
642  if (trk->size() < 10)
643  {
644  mf::LogWarning("ProjectionMatchingAlg") << "too short segment, delete segment";
645  delete trk;
646  return 0;
647  }
648 
649  return trk;
650 }
651 
652 // ------------------------------------------------------
653 
655  double r2d,
656  const std::vector< art::Ptr<recob::Hit> >& hits_in,
657  std::vector< art::Ptr<recob::Hit> >& hits_out,
658  const TVector2& vtx2d) const
659 {
660  size_t min_size = hits_in.size() / 5;
661  if (min_size < 3) min_size = 3;
662 
663  std::vector<size_t> used;
664  std::vector< std::vector< art::Ptr<recob::Hit> > > sub_groups;
665  std::vector< art::Ptr<recob::Hit> > close_hits;
666 
667  float mindist2 = 99999.99; size_t id_sub_groups_save = 0; size_t id = 0;
668  while (GetCloseHits(r2d, hits_in, used, close_hits))
669  {
670 
671  sub_groups.emplace_back(close_hits);
672 
673  for (size_t h = 0; h < close_hits.size(); ++h)
674  {
675  TVector2 hi_cm = pma::WireDriftToCm(close_hits[h]->WireID().Wire,
676  close_hits[h]->PeakTime(),
677  close_hits[h]->WireID().Plane,
678  close_hits[h]->WireID().TPC,
679  close_hits[h]->WireID().Cryostat);
680 
681  float dist2 = pma::Dist2(hi_cm, vtx2d);
682  if (dist2 < mindist2)
683  {
684  id_sub_groups_save = id;
685  mindist2 = dist2;
686  }
687  }
688 
689  id++;
690  }
691 
692  for (size_t i = 0; i < sub_groups.size(); ++i)
693  {
694  if (i == id_sub_groups_save)
695  {
696  for (auto h : sub_groups[i]) hits_out.push_back(h);
697  }
698  }
699 
700  for (size_t i = 0; i < sub_groups.size(); ++i)
701  {
702  if ((i != id_sub_groups_save) && (hits_out.size() < 10) && (sub_groups[i].size() > min_size))
703  for (auto h : sub_groups[i]) hits_out.push_back(h);
704  }
705 }
706 
707 // ------------------------------------------------------
708 
710  double r2d,
711  const std::vector< art::Ptr<recob::Hit> >& hits_in,
712  std::vector<size_t>& used,
713  std::vector< art::Ptr<recob::Hit> >& hits_out) const
714 {
715  hits_out.clear();
716 
717  const double gapMargin = 5.0; // can be changed to f(id_tpc1, id_tpc2)
718  size_t idx = 0;
719 
720  while ((idx < hits_in.size()) && Has(used, idx)) idx++;
721 
722  if (idx < hits_in.size())
723  {
724  hits_out.push_back(hits_in[idx]);
725  used.push_back(idx);
726 
727  unsigned int tpc = hits_in[idx]->WireID().TPC;
728  unsigned int cryo = hits_in[idx]->WireID().Cryostat;
729  unsigned int view = hits_in[idx]->WireID().Plane;
730  double wirePitch = fGeom->TPC(tpc, cryo).Plane(view).WirePitch();
731  double driftPitch = fDetProp->GetXTicksCoefficient(tpc, cryo);
732 
733  double r2d2 = r2d*r2d;
734  double gapMargin2 = sqrt(2 * gapMargin*gapMargin);
735  gapMargin2 = (gapMargin2 + r2d)*(gapMargin2 + r2d);
736 
737  bool collect = true;
738  while (collect)
739  {
740  collect = false;
741  for (size_t i = 0; i < hits_in.size(); i++)
742  if (!Has(used, i))
743  {
744  art::Ptr<recob::Hit> const & hi = hits_in[i];
745  TVector2 hi_cm(wirePitch * hi->WireID().Wire, driftPitch * hi->PeakTime());
746 
747  bool accept = false;
748 
749  for (auto const & ho : hits_out)
750  {
751 
752  TVector2 ho_cm(wirePitch * ho->WireID().Wire, driftPitch * ho->PeakTime());
753  double d2 = pma::Dist2(hi_cm, ho_cm);
754 
755  if (d2 < r2d2) { accept = true; break; }
756  }
757  if (accept)
758  {
759  collect = true;
760  hits_out.push_back(hi);
761  used.push_back(i);
762  }
763  }
764  }
765  return true;
766  }
767  else return false;
768 }
769 
770 // ------------------------------------------------------
771 
773 {
774  double mse = trk.GetMse();
775  mf::LogWarning("ProjectionMatchingAlg") << "initial value of mse: " << mse;
776  while ((mse > 0.5) && TestTrk(trk, tpcgeom))
777  {
778  mse = trk.GetMse();
779  for (size_t h = 0; h < trk.size(); ++h)
780  if (std::sqrt(pma::Dist2(trk[h]->Point3D(), trk.front()->Point3D()))
781  > 0.8*trk.Length()) trk[h]->SetEnabled(false);
782 
784 
785  // trk.Optimize(0.0001, false); // BUG: first argument missing; tentatively:
786  trk.Optimize(0, 0.0001, false);
787  trk.SortHits();
788 
789  mf::LogWarning("ProjectionMatchingAlg") << " mse: " << mse;
790  if (mse == trk.GetMse()) break;
791  else mse = trk.GetMse();
792  }
793 
795 }
796 
797 // ------------------------------------------------------
798 
800 {
801  bool test = false;
802 
803  if (tpcgeom.HasPlane(0) && tpcgeom.HasPlane(1))
804  {
805  if ((trk.NEnabledHits(0) > 5) && (trk.NEnabledHits(1) > 5))
806  test = true;
807  }
808  else if (tpcgeom.HasPlane(0) && tpcgeom.HasPlane(2))
809  {
810  if ((trk.NEnabledHits(0) > 5) && (trk.NEnabledHits(2) > 5))
811  test = true;
812  }
813  else if (tpcgeom.HasPlane(1) && tpcgeom.HasPlane(2))
814  {
815  if ((trk.NEnabledHits(1) > 5) && (trk.NEnabledHits(2) > 5))
816  test = true;
817  }
818 
819  double length = 0.0;
820  for (size_t h = 0; h < trk.size(); ++h)
821  {
822  if (!trk[h]->IsEnabled()) break;
823  length = std::sqrt(pma::Dist2(trk.front()->Point3D(), trk[h]->Point3D()));
824  }
825 
826  mf::LogWarning("ProjectionMatchingAlg") << "length of segment: " << length;
827  if (length < 3.0) test = false; // cm
828 
829  return test;
830 }
831 
832 // ------------------------------------------------------
833 
834 bool pma::ProjectionMatchingAlg::Has(const std::vector<size_t>& v, size_t idx) const
835 {
836  for (auto c : v) if (c == idx) return true;
837  return false;
838 }
839 
840 // ------------------------------------------------------
841 
843 {
844  size_t h = 0;
845  while (h < trk.size())
846  {
847  if (trk[h]->IsEnabled()) ++h;
848  else (trk.release_at(h));
849  }
850 }
851 
852 // ------------------------------------------------------
853 
855  const std::vector< art::Ptr<recob::Hit> >& hits_1,
856  const std::vector< art::Ptr<recob::Hit> >& hits_2) const
857 {
858  pma::Track3D* trk = new pma::Track3D();
859  trk->SetEndSegWeight(0.001F);
860  trk->AddHits(hits_1);
861  trk->AddHits(hits_2);
862 
863  if (trk->HasTwoViews() &&
864  (trk->TPCs().size() == 1)) // now only in single tpc
865  {
866  if (!trk->Initialize(0.001F))
867  {
868  mf::LogWarning("ProjectionMatchingAlg") << "initialization failed, delete segment";
869  delete trk;
870  return 0;
871  }
872  trk->Optimize(0, fFineTuningEps);
873 
874  trk->SortHits();
875  return trk;
876  }
877  else
878  {
879  mf::LogWarning("ProjectionMatchingAlg") << "need at least two views in single tpc";
880  delete trk;
881  return 0;
882  }
883 }
884 // ------------------------------------------------------
885 
887  const std::vector< art::Ptr<recob::Hit> >& hits_1,
888  const std::vector< art::Ptr<recob::Hit> >& hits_2,
889  const TVector3& point) const
890 {
891  pma::Track3D* trk = buildSegment(hits_1, hits_2);
892 
893  if (trk)
894  {
895  double dfront = pma::Dist2(trk->front()->Point3D(), point);
896  double dback = pma::Dist2(trk->back()->Point3D(), point);
897  if (dfront > dback) trk->Flip();
898 
899  trk->Nodes().front()->SetPoint3D(point);
900  trk->Nodes().front()->SetFrozen(true);
901  trk->Optimize(0, fFineTuningEps);
902 
903  trk->SortHits();
904  }
905  return trk;
906 }
907 // ------------------------------------------------------
908 
911  const TVector3& point) const
912 {
914 
915  if (trk)
916  {
917  double dfront = pma::Dist2(trk->front()->Point3D(), point);
918  double dback = pma::Dist2(trk->back()->Point3D(), point);
919  if (dfront > dback) trk->Flip();
920 
921  trk->Nodes().front()->SetPoint3D(point);
922  trk->Nodes().front()->SetFrozen(true);
923  trk->Optimize(0, fFineTuningEps);
924 
925  trk->SortHits();
926  }
927  return trk;
928 }
929 // ------------------------------------------------------
930 
932  const pma::Track3D& trk,
934  bool add_nodes) const
935 {
936  pma::Track3D* copy = new pma::Track3D(trk);
937  copy->AddHits(hits);
938 
939  mf::LogVerbatim("ProjectionMatchingAlg") << "ext. track size: " << copy->size()
940  << " #coll:" << copy->NHits(geo::kZ)
941  << " #ind2:" << copy->NHits(geo::kV)
942  << " #ind1:" << copy->NHits(geo::kU);
943 
944  if (add_nodes)
945  {
946  size_t nSegments = getSegCount(copy->size());
947  int nNodes = nSegments - copy->Nodes().size() + 1; // n nodes to add
948  if (nNodes < 0) nNodes = 0;
949 
950  if (nNodes)
951  {
952  mf::LogVerbatim("ProjectionMatchingAlg") << " add " << nNodes << " nodes";
953  copy->Optimize(nNodes, fOptimizationEps);
954  }
955  }
956  double g = copy->Optimize(0, fFineTuningEps);
957  mf::LogVerbatim("ProjectionMatchingAlg") << " reopt done, g = " << g;
958 
959  return copy;
960 }
961 // ------------------------------------------------------
962 
964  int wire, int wdir, double drift_x, int view,
965  unsigned int tpc, unsigned int cryo,
966  const pma::Track3D& trk,
967  const std::vector< art::Ptr<recob::Hit> >& hits) const
968 {
969  size_t nCloseHits = 0;
970  int forwWires = 3, backWires = -1;
971  double xMargin = 0.4;
972  for (auto h : hits)
973  if ((view == (int)h->WireID().Plane) &&
974  (tpc == h->WireID().TPC) &&
975  (cryo == h->WireID().Cryostat))
976  {
977  bool found = false;
978  for (size_t ht = 0; ht < trk.size(); ht++)
979  if (trk[ht]->Hit2DPtr().key() == h.key())
980  {
981  found = true; break;
982  }
983  if (found) continue;
984 
985  int dw = wdir * (h->WireID().Wire - wire);
986  if ((dw <= forwWires) && (dw >= backWires))
987  {
988  double x = fDetProp->ConvertTicksToX(h->PeakTime(), view, tpc, cryo);
989  if (fabs(x - drift_x) < xMargin) nCloseHits++;
990  }
991  }
992  if (nCloseHits > 1) return false;
993  else return true;
994 }
995 
997  const std::map< unsigned int, std::vector< art::Ptr<recob::Hit> > >& hits,
998  std::pair<int, int> const * wires, double const * xPos,
999  unsigned int tpc, unsigned int cryo) const
1000 {
1001  double x = 0.0, y = 0.0, z = 0.0;
1002  std::vector< std::pair<int, unsigned int> > wire_view;
1003  for (unsigned int i = 0; i < 3; i++)
1004  if (wires[i].first >= 0)
1005  {
1006  const auto hiter = hits.find(i);
1007  if (hiter != hits.end())
1008  {
1009  if (chkEndpointHits(wires[i].first, wires[i].second, xPos[i], i, tpc, cryo, trk, hiter->second))
1010  {
1011  x += xPos[i];
1012  wire_view.push_back(std::pair<int, unsigned int>(wires[i].first, i));
1013  }
1014  }
1015  }
1016  if (wire_view.size() > 1)
1017  {
1018  x /= wire_view.size();
1020  wire_view[0].first, wire_view[1].first,
1021  wire_view[0].second, wire_view[1].second,
1022  cryo, tpc, y, z);
1023  trk.AddRefPoint(x, y, z);
1024  mf::LogVerbatim("ProjectionMatchingAlg") << "trk tpc:" << tpc << " size:" << trk.size()
1025  << " add ref.point (" << x << "; " << y << "; " << z << ")";
1026  return true;
1027  }
1028  else
1029  {
1030  mf::LogVerbatim("ProjectionMatchingAlg") << "trk tpc:" << tpc << " size:" << trk.size()
1031  << " wire-plane-parallel track, but need two clean views of endpoint";
1032  return false;
1033  }
1034 }
1035 
1037  pma::Track3D& trk, const std::map< unsigned int, std::vector< art::Ptr<recob::Hit> > >& hits) const
1038 {
1039  unsigned int tpc = trk.FrontTPC(), cryo = trk.FrontCryo();
1040  if ((tpc != trk.BackTPC()) || (cryo != trk.BackCryo()))
1041  {
1042  mf::LogWarning("ProjectionMatchingAlg") << "Please, apply before TPC stitching.";
1043  return;
1044  }
1045 
1046  const double maxCosXZ = 0.992546; // 7 deg
1047 
1048  pma::Segment3D* segFront = trk.Segments().front();
1049  if (trk.Segments().size() > 2)
1050  {
1051  pma::Segment3D* segFront1 = trk.Segments()[1];
1052  if ((segFront->Length() < 0.8) && (segFront1->Length() > 5.0))
1053  segFront = segFront1;
1054  }
1055  pma::Vector3D dirFront = segFront->GetDirection3D();
1056  pma::Vector3D dirFrontXZ(dirFront.X(), 0., dirFront.Z());
1057  dirFrontXZ *= 1.0 / dirFrontXZ.R();
1058 
1059  pma::Segment3D* segBack = trk.Segments().back();
1060  if (trk.Segments().size() > 2)
1061  {
1062  pma::Segment3D* segBack1 = trk.Segments()[trk.Segments().size() - 2];
1063  if ((segBack->Length() < 0.8) && (segBack1->Length() > 5.0))
1064  segBack = segBack1;
1065  }
1066  pma::Vector3D dirBack = segBack->GetDirection3D();
1067  pma::Vector3D dirBackXZ(dirBack.X(), 0., dirBack.Z());
1068  dirBackXZ *= 1.0 / dirBackXZ.R();
1069 
1070  if ((fabs(dirFrontXZ.Z()) < maxCosXZ) && (fabs(dirBackXZ.Z()) < maxCosXZ))
1071  {
1072  return; // front & back are not parallel to wire planes => exit
1073  }
1074 
1075  unsigned int nPlanesFront = 0, nPlanesBack = 0;
1076  std::pair<int, int> wiresFront[3], wiresBack[3]; // wire index; index direction
1077  double xFront[3], xBack[3];
1078 
1079  for (unsigned int i = 0; i < 3; i++)
1080  {
1081  bool frontPresent = false, backPresent = false;
1082  if (fGeom->TPC(tpc, cryo).HasPlane(i))
1083  {
1084  int idxFront0 = trk.NextHit(-1, i);
1085  int idxBack0 = trk.PrevHit(trk.size(), i);
1086  if ((idxFront0 >= 0) && (idxFront0 < (int)trk.size()) &&
1087  (idxBack0 >= 0) && (idxBack0 < (int)trk.size()))
1088  {
1089  int idxFront1 = trk.NextHit(idxFront0, i);
1090  int idxBack1 = trk.PrevHit(idxBack0, i);
1091  if ((idxFront1 >= 0) && (idxFront1 < (int)trk.size()) &&
1092  (idxBack1 >= 0) && (idxBack1 < (int)trk.size()))
1093  {
1094  int wFront0 = trk[idxFront0]->Wire();
1095  int wBack0 = trk[idxBack0]->Wire();
1096 
1097  int wFront1 = trk[idxFront1]->Wire();
1098  int wBack1 = trk[idxBack1]->Wire();
1099 
1100  wiresFront[i].first = wFront0;
1101  wiresFront[i].second = wFront0 - wFront1;
1102  xFront[i] = fDetProp->ConvertTicksToX(trk[idxFront0]->PeakTime(), i, tpc, cryo);
1103 
1104  wiresBack[i].first = wBack0;
1105  wiresBack[i].second = wBack0 - wBack1;
1106  xBack[i] = fDetProp->ConvertTicksToX(trk[idxBack0]->PeakTime(), i, tpc, cryo);
1107 
1108  if (wiresFront[i].second)
1109  {
1110  if (wiresFront[i].second > 0) wiresFront[i].second = 1;
1111  else wiresFront[i].second = -1;
1112 
1113  frontPresent = true;
1114  nPlanesFront++;
1115  }
1116 
1117  if (wiresBack[i].second)
1118  {
1119  if (wiresBack[i].second > 0) wiresBack[i].second = 1;
1120  else wiresBack[i].second = -1;
1121 
1122  backPresent = true;
1123  nPlanesBack++;
1124  }
1125  }
1126  }
1127  }
1128  if (!frontPresent) { wiresFront[i].first = -1; }
1129  if (!backPresent) { wiresBack[i].first = -1; }
1130  }
1131 
1132  bool refAdded = false;
1133  if ((nPlanesFront > 1) && (fabs(dirFrontXZ.Z()) >= maxCosXZ))
1134  {
1135  refAdded |= addEndpointRef(trk, hits, wiresFront, xFront, tpc, cryo);
1136  }
1137 
1138  if ((nPlanesBack > 1) && (fabs(dirBackXZ.Z()) >= maxCosXZ))
1139  {
1140  refAdded |= addEndpointRef(trk, hits, wiresBack, xBack, tpc, cryo);
1141  }
1142  if (refAdded)
1143  {
1144  mf::LogVerbatim("ProjectionMatchingAlg") << "guide wire-plane-parallel track endpoints";
1145  double g = trk.Optimize(0, 0.1 * fFineTuningEps);
1146  mf::LogVerbatim("ProjectionMatchingAlg") << " done, g = " << g;
1147  }
1148 }
1149 // ------------------------------------------------------
1150 
1153  const std::map< unsigned int, std::vector< art::Ptr<recob::Hit> > >& hits) const
1154 {
1155  const double maxCosXZ = 0.992546; // 7 deg
1156 
1157  unsigned int tpc, cryo;
1158  pma::Segment3D* seg0 = 0;
1159  pma::Segment3D* seg1 = 0;
1160 
1161  if (endpoint == pma::Track3D::kBegin)
1162  {
1163  tpc = trk.FrontTPC(), cryo = trk.FrontCryo();
1164  seg0 = trk.Segments().front();
1165  if (trk.Segments().size() > 2)
1166  {
1167  seg1 = trk.Segments()[1];
1168  }
1169  }
1170  else
1171  {
1172  tpc = trk.BackTPC(), cryo = trk.BackCryo();
1173  seg0 = trk.Segments().back();
1174  if (trk.Segments().size() > 2)
1175  {
1176  seg1 = trk.Segments()[trk.Segments().size() - 2];
1177  }
1178  }
1179  if (seg1 && (seg0->Length() < 0.8) && (seg1->Length() > 5.0))
1180  {
1181  seg0 = seg1;
1182  }
1183  pma::Vector3D dir0 = seg0->GetDirection3D();
1184  pma::Vector3D dir0XZ(dir0.X(), 0., dir0.Z());
1185  dir0XZ *= 1.0 / dir0XZ.R();
1186 
1187  if (fabs(dir0XZ.Z()) < maxCosXZ) { return; } // not parallel to wire planes => exit
1188 
1189  unsigned int nPlanes = 0;
1190  std::pair<int, int> wires[3]; // wire index; index direction
1191  double x0[3];
1192 
1193  for (unsigned int i = 0; i < 3; i++)
1194  {
1195  bool present = false;
1196  if (fGeom->TPC(tpc, cryo).HasPlane(i))
1197  {
1198  int idx0 = -1, idx1 = -1;
1199  if (endpoint == pma::Track3D::kBegin)
1200  {
1201  idx0 = trk.NextHit(-1, i);
1202  }
1203  else
1204  {
1205  idx0 = trk.PrevHit(trk.size(), i);
1206  }
1207 
1208  if ((idx0 >= 0) && (idx0 < (int)trk.size()) &&
1209  (trk[idx0]->TPC() == tpc) && (trk[idx0]->Cryo() == cryo))
1210  {
1211  if (endpoint == pma::Track3D::kBegin)
1212  {
1213  idx1 = trk.NextHit(idx0, i);
1214  }
1215  else
1216  {
1217  idx1 = trk.PrevHit(idx0, i);
1218  }
1219 
1220  if ((idx1 >= 0) && (idx1 < (int)trk.size()) &&
1221  (trk[idx1]->TPC() == tpc) && (trk[idx1]->Cryo() == cryo))
1222  {
1223  int w0 = trk[idx0]->Wire();
1224  int w1 = trk[idx1]->Wire();
1225 
1226  wires[i].first = w0;
1227  wires[i].second = w0 - w1;
1228  x0[i] = fDetProp->ConvertTicksToX(trk[idx0]->PeakTime(), i, tpc, cryo);
1229 
1230  if (wires[i].second)
1231  {
1232  if (wires[i].second > 0) wires[i].second = 1;
1233  else wires[i].second = -1;
1234 
1235  present = true;
1236  nPlanes++;
1237  }
1238  }
1239  }
1240  }
1241  if (!present) { wires[i].first = -1; }
1242  }
1243 
1244  if ((nPlanes > 1) && (fabs(dir0XZ.Z()) >= maxCosXZ) &&
1245  addEndpointRef(trk, hits, wires, x0, tpc, cryo))
1246  {
1247  mf::LogVerbatim("ProjectionMatchingAlg") << "guide wire-plane-parallel track endpoint";
1248  double g = trk.Optimize(0, 0.1 * fFineTuningEps);
1249  mf::LogVerbatim("ProjectionMatchingAlg") << " done, g = " << g;
1250  }
1251 }
1252 // ------------------------------------------------------
1253 
1255  pma::Track3D& trk, TVector3 p0, TVector3 p1) const
1256 {
1257  std::vector< pma::Hit3D* > trimmedHits;
1258 
1259 
1260 
1261  return trimmedHits;
1262 }
1263 // ------------------------------------------------------
1264 
1266 {
1267  unsigned int k = 0;
1268  double distFF = pma::Dist2(first.front()->Point3D(), second.front()->Point3D());
1269  double dist = distFF;
1270 
1271  double distFB = pma::Dist2(first.front()->Point3D(), second.back()->Point3D());
1272  if (distFB < dist) { k = 1; dist = distFB; }
1273 
1274  double distBF = pma::Dist2(first.back()->Point3D(), second.front()->Point3D());
1275  if (distBF < dist) { k = 2; dist = distBF; }
1276 
1277  double distBB = pma::Dist2(first.back()->Point3D(), second.back()->Point3D());
1278  if (distBB < dist) { k = 3; dist = distBB; }
1279 
1280  switch (k) // flip to get dst end before src start, do not merge if track's order reversed
1281  {
1282  case 0: first.Flip(); break;
1283  case 1: mf::LogError("PMAlgTrackMaker") << "Tracks in reversed order."; return false;
1284  case 2: break;
1285  case 3: second.Flip(); break;
1286  default: throw cet::exception("pma::ProjectionMatchingAlg") << "alignTracks: should never happen." << std::endl;
1287  }
1288  return true;
1289 }
1290 
1292 {
1293  if (!alignTracks(dst, src)) return;
1294 
1295  unsigned int tpc = src.FrontTPC();
1296  unsigned int cryo = src.FrontCryo();
1297  double lmean = dst.Length() / (dst.Nodes().size() - 1);
1298  if ((pma::Dist2(
1299  dst.Nodes().back()->Point3D(),
1300  src.Nodes().front()->Point3D()) > 0.5 * lmean) ||
1301  (tpc != dst.BackTPC()) || (cryo != dst.BackCryo()))
1302  {
1303  dst.AddNode(src.Nodes().front()->Point3D(), tpc, cryo);
1304  if (src.Nodes().front()->IsFrozen())
1305  dst.Nodes().back()->SetFrozen(true);
1306  }
1307  for (size_t n = 1; n < src.Nodes().size(); n++)
1308  {
1309  pma::Node3D* node = src.Nodes()[n];
1310 
1311  dst.AddNode(src.Nodes()[n]->Point3D(),
1312  node->TPC(), node->Cryo());
1313 
1314  if (node->IsFrozen())
1315  dst.Nodes().back()->SetFrozen(true);
1316  }
1317  for (size_t h = 0; h < src.size(); h++)
1318  {
1319  dst.push_back(src[h]->Hit2DPtr());
1320  }
1321  if (reopt)
1322  {
1323  double g = dst.Optimize(0, fFineTuningEps);
1324  mf::LogVerbatim("ProjectionMatchingAlg") << " reopt after merging done, g = " << g;
1325  }
1326  else
1327  {
1328  dst.MakeProjection();
1329  }
1330 
1331  dst.SortHits();
1332  dst.ShiftEndsToHits();
1333 
1334  dst.MakeProjection();
1335  dst.SortHits();
1336 }
1337 // ------------------------------------------------------
1338 
1339 double pma::ProjectionMatchingAlg::selectInitialHits(pma::Track3D& trk, unsigned int view, unsigned int* nused) const
1340 {
1341  for (size_t i = 0; i < trk.size(); i++)
1342  {
1343  pma::Hit3D* hit = trk[i];
1344  if (hit->View2D() == view)
1345  {
1346  if ((hit->GetDistToProj() > 0.5) || // more than 0.5cm away away from the segment
1347  (hit->GetSegFraction() < -1.0)) // projects before segment start (to check!!!)
1348  hit->TagOutlier(true);
1349  else hit->TagOutlier(false);
1350  }
1351  }
1352 
1353  unsigned int nhits = 0;
1354  double last_x, dx = 0.0, last_q, dq = 0.0, dqdx = 0.0;
1355  int ih = trk.NextHit(-1, view);
1356 
1357  pma::Hit3D* hit = trk[ih];
1358  pma::Hit3D* lastHit = hit;
1359 
1360  if ((ih >= 0) && (ih < (int)trk.size()))
1361  {
1362  hit->TagOutlier(true);
1363 
1364  ih = trk.NextHit(ih, view);
1365  while ((dx < 2.5) && (ih >= 0) && (ih < (int)trk.size()))
1366  {
1367  hit = trk[ih];
1368 
1369  if (util::absDiff(hit->Wire(), lastHit->Wire()) > 2)
1370  break; // break on gap in wire direction
1371 
1372  last_x = trk.HitDxByView(ih, view);
1373  last_q = hit->SummedADC();
1374  if (dx + last_x < 3.0)
1375  {
1376  dq += last_q;
1377  dx += last_x;
1378  nhits++;
1379  }
1380  else break;
1381 
1382  lastHit = hit;
1383  ih = trk.NextHit(ih, view);
1384  }
1385  while ((ih >= 0) && (ih < (int)trk.size()))
1386  {
1387  hit = trk[ih];
1388  hit->TagOutlier(true);
1389  ih = trk.NextHit(ih, view);
1390  }
1391  }
1392  else { mf::LogError("ProjectionMatchingAlg") << "Initial part selection failed."; }
1393 
1394  if (!nhits) { mf::LogError("ProjectionMatchingAlg") << "Initial part too short to select useful hits."; }
1395 
1396  if (dx > 0.0) dqdx = dq / dx;
1397 
1398  if (nused) (*nused) = nhits;
1399 
1400  //std::cout << "nhits=" << nhits << ", dq=" << dq << ", dx=" << dx << std::endl;
1401  return dqdx;
1402 }
1403 // ------------------------------------------------------
1404 
Float_t x
Definition: compare.C:6
geo::Length_t WireCoordinate(double YPos, double ZPos, geo::PlaneID const &planeid) const
Returns the index of the nearest wire to the specified position.
bool SelectHits(float fraction=1.0F)
pma::Track3D * buildShowerSeg(const std::vector< art::Ptr< recob::Hit > > &hits, const pma::Vector3D &vtx) const
Build a shower segment from sets of hits and attached to the provided vertex.
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
bool HasPlane(unsigned int iplane) const
Returns whether a plane with index iplane is present in this TPC.
Definition: TPCGeo.h:155
std::vector< unsigned int > TPCs(void) const
Definition: PmaTrack3D.cxx:437
Functions to help with numbers.
detinfo::DetectorProperties const * fDetProp
double GetDistToProj(void) const
Definition: PmaHit3D.h:69
Utilities related to art service access.
double GetMse(unsigned int view=geo::kUnknown) const
MSE of hits weighted with hit amplidudes and wire plane coefficients.
double Dist2(const TVector2 &p2d, unsigned int view, unsigned int tpc, unsigned int cryo) const
void guideEndpoints(pma::Track3D &trk, const std::map< unsigned int, std::vector< art::Ptr< recob::Hit > > > &hits) const
Add 3D reference points to clean endpoints of a track (both need to be in the same TPC)...
unsigned int View2D(void) const
Definition: PmaHit3D.h:58
double Dist2(const TVector2 &v1, const TVector2 &v2)
Definition: Utilities.cxx:19
unsigned int FrontTPC(void) const
Definition: PmaTrack3D.h:104
unsigned int BackTPC(void) const
Definition: PmaTrack3D.h:107
int PrevHit(int index, unsigned int view=geo::kZ, bool inclDisabled=false) const
Definition: PmaTrack3D.cxx:877
bool Flip(std::vector< pma::Track3D * > &allTracks)
Definition: PmaTrack3D.cxx:499
static void SetOptFactor(unsigned int view, float value)
Definition: PmaElement3D.h:104
bool addEndpointRef(pma::Track3D &trk, const std::map< unsigned int, std::vector< art::Ptr< recob::Hit > > > &hits, std::pair< int, int > const *wires, double const *xPos, unsigned int tpc, unsigned int cryo) const
T::provider_type const * providerFrom()
Returns a constant pointer to the provider of specified service.
Definition: ServiceUtil.h:77
geo::GeometryCore const * fGeom
Planes which measure V.
Definition: geo_types.h:77
geo::WireID WireID() const
Initial tdc tick for hit.
Definition: Hit.h:234
Float_t y
Definition: compare.C:6
::fhicl::TupleAs< Point(::geo::Length_t,::geo::Length_t,::geo::Length_t)> Point3D
Atom object for reading a 3D point or vector (centimeters).
Double_t z
Definition: plot.C:279
Geometry information for a single TPC.
Definition: TPCGeo.h:37
std::vector< pma::Node3D * > const & Nodes(void) const
Definition: PmaTrack3D.h:232
Planes which measure Z direction.
Definition: geo_types.h:79
bool GetCloseHits(double r2d, const std::vector< art::Ptr< recob::Hit > > &hits_in, std::vector< size_t > &used, std::vector< art::Ptr< recob::Hit > > &hits_out) const
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:313
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
static void SetMargin(double m)
Set allowed node position margin around TPC.
Definition: PmaNode3D.h:105
std::vector< pma::Segment3D * > const & Segments(void) const
Definition: PmaTrack3D.h:227
unsigned int Wire(void) const
Definition: PmaHit3D.h:59
recob::tracking::Vector_t Vector3D
Definition: Utilities.h:29
pma::Track3D * buildMultiTPCTrack(const std::vector< art::Ptr< recob::Hit > > &hits) const
as far as hits origin from at least two wire planes.
virtual double ConvertXToTicks(double X, int p, int t, int c) const =0
void AddRefPoint(const TVector3 &p)
Definition: PmaTrack3D.h:189
unsigned int NEnabledHits(unsigned int view=geo::kUnknown) const
Definition: PmaTrack3D.cxx:416
int TPC(void) const
TPC index or -1 if out of any TPC.
Definition: PmaElement3D.h:31
bool ShiftEndsToHits(void)
TFile f
Definition: plotHisto.C:6
geo::TPCID FindTPCAtPosition(double const worldLoc[3]) const
Returns the ID of the TPC at specified location.
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
std::pair< TVector2, TVector2 > WireDriftRange(unsigned int view, unsigned int tpc, unsigned int cryo) const
Definition: PmaTrack3D.cxx:469
Planes which measure U.
Definition: geo_types.h:76
double selectInitialHits(pma::Track3D &trk, unsigned int view=geo::kZ, unsigned int *nused=0) const
float GetSegFraction() const
Definition: PmaHit3D.h:72
void hits()
Definition: readHits.C:15
void AddNode(pma::Node3D *node)
pma::Hit3D * release_at(size_t index)
Definition: PmaTrack3D.cxx:340
unsigned int NHits(unsigned int view) const
Definition: PmaTrack3D.cxx:406
bool alignTracks(pma::Track3D &first, pma::Track3D &second) const
virtual double GetXTicksCoefficient(int t, int c) const =0
unsigned int BackCryo(void) const
Definition: PmaTrack3D.h:108
pma::Track3D * buildSegment(const std::vector< art::Ptr< recob::Hit > > &hits_1, const std::vector< art::Ptr< recob::Hit > > &hits_2=std::vector< art::Ptr< recob::Hit > >()) const
bool chkEndpointHits(int wire, int wdir, double drift_x, int view, unsigned int tpc, unsigned int cryo, const pma::Track3D &trk, const std::vector< art::Ptr< recob::Hit > > &hits) const
void SetEndSegWeight(float value)
Definition: PmaTrack3D.h:271
pma::Track3D * buildTrack(const std::vector< art::Ptr< recob::Hit > > &hits_1, const std::vector< art::Ptr< recob::Hit > > &hits_2=std::vector< art::Ptr< recob::Hit > >()) const
wire planes; number of segments used to create the track depends on the number of hits...
pma::Hit3D *& back()
Definition: PmaTrack3D.h:74
Float_t d
Definition: plot.C:237
ROOT::Math::DisplacementVector2D< ROOT::Math::Cartesian2D< double > > Vector2D
Definition: Utilities.h:28
CryostatGeo const & Cryostat(geo::CryostatID const &cryoid) const
Returns the specified cryostat.
double Optimize(int nNodes=-1, double eps=0.01, bool selAllHits=true, bool setAllNodes=true, size_t selSegHits=0, size_t selVtxHits=0)
Main optimization method.
bool SameTPC(const TVector3 &p3d, float margin=0.0F) const
Check if p3d is in the same TPC as the node.
Definition: PmaNode3D.cxx:83
float SummedADC(void) const
Definition: PmaHit3D.h:62
General LArSoft Utilities.
unsigned int Plane(void) const
bool IntersectionPoint(geo::WireID const &wid1, geo::WireID const &wid2, double &y, double &z) const
Returns the intersection point of two wires.
void ShortenSeg(pma::Track3D &trk, const geo::TPCGeo &tpcgeom) const
unsigned int FrontCryo(void) const
Definition: PmaTrack3D.h:105
std::vector< unsigned int > Cryos(void) const
Definition: PmaTrack3D.cxx:453
Detector simulation of raw signals on wires.
constexpr auto absDiff(A const &a, B const &b)
Returns the absolute value of the difference between two values.
Definition: NumericUtils.h:43
unsigned int DisableSingleViewEnds(void)
bool Has(const std::vector< size_t > &v, size_t idx) const
void push_back(pma::Hit3D *hit)
Definition: PmaTrack3D.h:66
double validate_on_adc_test(const pma::Track3D &trk, const img::DataProviderAlg &adcImage, const std::vector< art::Ptr< recob::Hit > > &hits, TH1F *histoPassing, TH1F *histoRejected) const
bool HasTPC(geo::TPCID const &tpcid) const
Returns whether we have the specified TPC.
virtual double ConvertTicksToX(double ticks, int p, int t, int c) const =0
TVector3 const & Point3D(void) const
Definition: PmaHit3D.h:48
double validate_on_adc(const pma::Track3D &trk, const img::DataProviderAlg &adcImage, float thr) const
bool HasTwoViews(size_t nmin=1) const
Definition: PmaTrack3D.cxx:428
int Cryo(void) const
Cryostat index or -1 if out of any cryostat.
Definition: PmaElement3D.h:33
raw::ChannelID_t PlaneWireToChannel(WireID const &wireid) const
Returns the ID of the TPC channel connected to the specified wire.
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:219
double Length(size_t step=1) const
Definition: PmaTrack3D.h:81
static size_t getSegCount(size_t trk_size)
bool IsFrozen(void) const
Check if the vertex 3D position is fixed.
Definition: PmaElement3D.h:96
virtual void TagOutlier(bool state)
Definition: PmaHit3D.h:86
LArSoft-specific namespace.
void FilterOutSmallParts(double r2d, const std::vector< art::Ptr< recob::Hit > > &hits_in, std::vector< art::Ptr< recob::Hit > > &hits_out, const TVector2 &vtx2d) const
const TPCGeo & TPC(unsigned int itpc) const
Return the itpc&#39;th TPC in the cryostat.
double GetSegmentProjVector(const TVector2 &p, const TVector2 &p0, const TVector2 &p1)
Definition: Utilities.cxx:100
pma::Vector3D GetDirection3D(void) const override
Get 3D direction cosines of this segment.
TVector2 WireDriftToCm(unsigned int wire, float drift, unsigned int plane, unsigned int tpc, unsigned int cryo)
Definition: Utilities.cxx:296
bool Initialize(float initEndSegW=0.05F)
Definition: PmaTrack3D.cxx:84
TVector2 GetProjectionToPlane(const TVector3 &p, unsigned int plane, unsigned int tpc, unsigned int cryo)
Definition: Utilities.cxx:280
pma::Track3D * extendTrack(const pma::Track3D &trk, const std::vector< art::Ptr< recob::Hit > > &hits, bool add_nodes) const
Add more hits to an existing track, reoptimize, optionally add more nodes.
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
ProjectionMatchingAlg(const Config &config)
int NextHit(int index, unsigned int view=geo::kZ, bool inclDisabled=false) const
Definition: PmaTrack3D.cxx:861
void MakeProjection(void)
std::vector< pma::Hit3D * > trimTrackToVolume(pma::Track3D &trk, TVector3 p0, TVector3 p1) const
HLT enums.
double HitDxByView(size_t index, unsigned int view) const
Definition: PmaTrack3D.cxx:952
Char_t n[5]
TPCGeo const & TPC(unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified TPC.
PlaneGeo const & Plane(geo::View_t view) const
Return the plane in the tpc with View_t view.
Definition: TPCGeo.cxx:299
void SortHits(void)
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:27
float poolMax(int wire, int drift, size_t r=0) const
Pool max value in a patch around the wire/drift pixel.
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:203
size_t size() const
Definition: PmaTrack3D.h:76
recob::tracking::Plane Plane
Definition: TrackState.h:17
void RemoveNotEnabledHits(pma::Track3D &trk) const
Namespace collecting geometry-related classes utilities.
double twoViewFraction(pma::Track3D &trk) const
geo::CryostatID::CryostatID_t FindCryostatAtPosition(geo::Point_t const &worldLoc) const
Returns the index of the cryostat at specified location.
ProductStatus present()
Definition: ProductStatus.h:16
pma::Hit3D *& front()
Definition: PmaTrack3D.h:72
double validate(const pma::Track3D &trk, const std::vector< art::Ptr< recob::Hit > > &hits) const
bool TestTrk(pma::Track3D &trk, const geo::TPCGeo &tpcgeom) const
double Length(void) const
Definition: PmaElement3D.h:49
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
double WirePitch() const
Return the wire pitch (in centimeters). It is assumed constant.
Definition: PlaneGeo.h:367
bool SelectAllHits(void)
bool HasWire(geo::WireID const &wireid) const
Returns whether we have the specified wire.
void mergeTracks(pma::Track3D &dst, pma::Track3D &src, bool reopt) const
void AddHits(const std::vector< art::Ptr< recob::Hit > > &hits)
Definition: PmaTrack3D.cxx:393