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