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