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