All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
larreco/larreco/RecoAlg/PMAlg/Utilities.cxx
Go to the documentation of this file.
1 /**
2  * @file Utilities.h
3  *
4  * @author D.Stefan and R.Sulej
5  *
6  * @brief Implementation of the Projection Matching Algorithm
7  *
8  * Some geometrical functions and sorting helpers.
9  * See PmaTrack3D.h file for details.
10  */
11 
13 
14 #include "art/Framework/Services/Registry/ServiceHandle.h"
15 #include "cetlib/pow.h"
16 #include "messagefacility/MessageLogger/MessageLogger.h"
17 
18 #include "TMatrixT.h"
19 #include "TVector2.h"
20 #include "TVector3.h"
21 #include "TVectorT.h"
22 
23 #include <cmath>
24 #include <utility>
25 #include <vector>
26 
34 
35 #include "range/v3/algorithm.hpp"
36 #include "range/v3/numeric.hpp"
37 #include "range/v3/view.hpp"
38 
39 double
40 pma::Dist2(const TVector2& v1, const TVector2& v2)
41 {
42  double const dx = v1.X() - v2.X(), dy = v1.Y() - v2.Y();
43  return cet::sum_of_squares(dx, dy);
44 }
45 double
46 pma::Dist2(const Vector2D& v1, const Vector2D& v2)
47 {
48  double const dx = v1.X() - v2.X(), dy = v1.Y() - v2.Y();
49  return cet::sum_of_squares(dx, dy);
50 }
51 
52 size_t
53 pma::GetHitsCount(const std::vector<pma::Hit3D*>& hits, unsigned int view)
54 {
55  if (view == geo::kUnknown) { return hits.size(); }
56  return ranges::count_if(hits, [view](auto hit) { return view == hit->View2D(); });
57 }
58 
59 double
60 pma::GetSummedADC(const std::vector<pma::Hit3D*>& hits, unsigned int view)
61 {
62  using namespace ranges;
63  auto to_summed_adc = [](auto hit) { return hit->SummedADC(); };
64  if (view == geo::kUnknown) { return accumulate(hits | views::transform(to_summed_adc), 0.); }
65  return accumulate(hits | views::filter([view](auto hit) { return view == hit->View2D(); }) |
66  views::transform(to_summed_adc),
67  0.);
68 }
69 
70 double
71 pma::GetSummedAmpl(const std::vector<pma::Hit3D*>& hits, unsigned int view)
72 {
73  using namespace ranges;
74  auto to_amplitude = [](auto hit) { return hit->GetAmplitude(); };
75  if (view == geo::kUnknown) { return accumulate(hits | views::transform(to_amplitude), 0.); }
76  return accumulate(hits | views::filter([view](auto hit) { return view == hit->View2D(); }) |
77  views::transform(to_amplitude),
78  0.);
79 }
80 
81 double
82 pma::GetHitsRadius3D(const std::vector<pma::Hit3D*>& hits, bool exact)
83 {
84  if (hits.empty()) return 0.0;
85 
86  if (!exact && (hits.size() < 5)) return 0.0;
87 
88  using namespace ranges;
89  auto to_3d_point = [](auto hit) -> decltype(auto) { return hit->Point3D(); };
90  auto const mean_point =
91  accumulate(hits | views::transform(to_3d_point), TVector3{}) * (1. / hits.size());
92 
93  auto to_dist2_from_mean = [&mean_point](auto hit) {
94  return pma::Dist2(hit->Point3D(), mean_point);
95  };
96  auto const max_r2 = max(hits | views::transform(to_dist2_from_mean));
97  return sqrt(max_r2);
98 }
99 
100 double
101 pma::GetHitsRadius2D(const std::vector<pma::Hit3D*>& hits, bool exact)
102 {
103  if (hits.empty()) return 0.0;
104 
105  if (!exact && (hits.size() < 5)) return 0.0;
106 
107  using namespace ranges;
108  auto to_2d_point = [](auto hit) -> decltype(auto) { return hit->Point2D(); };
109  auto const mean_point =
110  accumulate(hits | views::transform(to_2d_point), TVector2{}) * (1. / hits.size());
111 
112  auto to_dist2_from_mean = [&mean_point](auto hit) {
113  return pma::Dist2(hit->Point2D(), mean_point);
114  };
115  auto const max_r2 = max(hits | views::transform(to_dist2_from_mean));
116  return sqrt(max_r2);
117 }
118 
119 double
120 pma::GetSegmentProjVector(const TVector2& p, const TVector2& p0, const TVector2& p1)
121 {
122  TVector2 const v0(p - p0);
123  TVector2 const v1(p1 - p0);
124  return v0 * v1 / v1.Mod2();
125 }
126 
127 double
129 {
130  pma::Vector2D const v0(p - p0);
131  pma::Vector2D const v1(p1 - p0);
132  return v0.Dot(v1) / v1.Mag2();
133 }
134 
135 double
136 pma::GetSegmentProjVector(const TVector3& p, const TVector3& p0, const TVector3& p1)
137 {
138  TVector3 const v0(p - p0);
139  TVector3 const v1(p1 - p0);
140  return v0.Dot(v1) / v1.Mag2();
141 }
142 
143 double
145 {
146  pma::Vector3D const v0(p - p0);
147  pma::Vector3D const v1(p1 - p0);
148  return v0.Dot(v1) / v1.Mag2();
149 }
150 
151 TVector2
152 pma::GetProjectionToSegment(const TVector2& p, const TVector2& p0, const TVector2& p1)
153 {
154  TVector2 const v1(p1 - p0);
155  double const b = GetSegmentProjVector(p, p0, p1);
156  return p0 + v1 * b;
157 }
158 
159 TVector3
160 pma::GetProjectionToSegment(const TVector3& p, const TVector3& p0, const TVector3& p1)
161 {
162  TVector3 const v1(p1 - p0);
163  double const b = GetSegmentProjVector(p, p0, p1);
164  return p0 + v1 * b;
165 }
166 
167 double
168 pma::SolveLeastSquares3D(const std::vector<std::pair<TVector3, TVector3>>& lines, TVector3& result)
169 {
170  // RS: please, ask me if you need examples/explanation of formulas as they
171  // are not easy to derive from the code solely; I have Mathcad sources that
172  // were used to test the solving method, weighting, etc.
173 
174  result.SetXYZ(0., 0., 0.);
175  if (lines.size() < 2) {
176  mf::LogError("pma::SolveLeastSquares3D") << "Need min. two lines.";
177  return -1.0;
178  }
179 
180  double m;
181  std::vector<TVectorT<double>> U, P;
182  for (size_t v = 0; v < lines.size(); v++) {
183  TVector3 point = lines[v].first;
184  TVector3 dir = lines[v].second;
185  dir -= point;
186  m = dir.Mag();
187  if (m > 0.0) {
188  dir *= 1.0 / m;
189 
190  P.push_back(TVectorT<double>(3));
191  P.back()[0] = point.X();
192  P.back()[1] = point.Y();
193  P.back()[2] = point.Z();
194 
195  U.push_back(TVectorT<double>(3));
196  U.back()[0] = dir.X();
197  U.back()[1] = dir.Y();
198  U.back()[2] = dir.Z();
199  }
200  else
201  mf::LogWarning("pma::SolveLeastSquares3D") << "Line undefined.";
202  }
203  if (P.size() < 2) {
204  mf::LogError("pma::SolveLeastSquares3D") << "Need min. two lines.";
205  return -1.0;
206  }
207 
208  TVectorT<double> x(3), y(3), w(3);
209  TMatrixT<double> A(3, 3);
210  double ur, uc, pc;
211  double s_uc2[3], s_ur_uc[3];
212  double s_p_uc2[3], s_p_ur_uc[3];
213 
214  w[0] = 1.0;
215  w[1] = 1.0;
216  w[2] = 1.0;
217  for (size_t r = 0; r < 3; r++) {
218  y[r] = 0.0;
219  for (size_t c = 0; c < 3; c++) {
220  s_uc2[c] = 0.0;
221  s_ur_uc[c] = 0.0;
222  s_p_uc2[c] = 0.0;
223  s_p_ur_uc[c] = 0.0;
224 
225  for (size_t v = 0; v < P.size(); v++) {
226  //w[1] = fWeights[v]; // to remember that individual coordinates can be supressed...
227  //w[2] = fWeights[v];
228 
229  ur = U[v][r];
230  uc = U[v][c];
231  pc = P[v][c];
232 
233  s_uc2[c] += w[r] * w[c] * (1 - uc * uc);
234  s_p_uc2[c] += w[r] * w[r] * pc * (1 - uc * uc);
235 
236  s_ur_uc[c] += w[r] * w[c] * ur * uc;
237  s_p_ur_uc[c] += w[r] * w[r] * pc * ur * uc;
238  }
239 
240  if (r == c) {
241  y[r] += s_p_uc2[c];
242  A(r, c) = s_uc2[c];
243  }
244  else {
245  y[r] -= s_p_ur_uc[c];
246  A(r, c) = -s_ur_uc[c];
247  }
248  }
249  }
250  try {
251  x = A.InvertFast() * y;
252  }
253  catch (...) {
254  result.SetXYZ(0., 0., 0.);
255  return 1.0e12;
256  }
257 
258  result.SetXYZ(x[0], x[1], x[2]);
259 
260  double mse = 0.0;
261  for (size_t v = 0; v < lines.size(); v++) {
262  TVector3 const pproj = pma::GetProjectionToSegment(result, lines[v].first, lines[v].second);
263 
264  double const dx = result.X() - pproj.X(); // dx, dy, dz and the result point can be weighted
265  double const dy = result.Y() - pproj.Y(); // here (linearly) by each line uncertainty
266  double const dz = result.Z() - pproj.Z();
267  mse += cet::sum_of_squares(dx, dy, dz);
268  }
269  return mse / lines.size();
270 }
271 
272 TVector2
273 pma::GetProjectionToPlane(const TVector3& p,
274  unsigned int plane,
275  unsigned int tpc,
276  unsigned int cryo)
277 {
278  art::ServiceHandle<geo::Geometry const> geom;
279 
280  return TVector2(geom->TPC(tpc, cryo).Plane(plane).PlaneCoordinate(p), p.X());
281 }
282 
283 TVector2
285  unsigned int plane,
286  unsigned int tpc,
287  unsigned int cryo)
288 {
289  TVector3 v0_3d(0., 0., 0.);
290  TVector2 v0_2d = GetProjectionToPlane(v0_3d, plane, tpc, cryo);
291  TVector2 v1_2d = GetProjectionToPlane(v, plane, tpc, cryo);
292 
293  return v1_2d - v0_2d;
294 }
295 
296 TVector2
298  unsigned int wire,
299  float drift,
300  unsigned int plane,
301  unsigned int tpc,
302  unsigned int cryo)
303 {
304  art::ServiceHandle<geo::Geometry const> geom;
305  return TVector2(geom->TPC(tpc, cryo).Plane(plane).WirePitch() * wire,
306  detProp.ConvertTicksToX(drift, plane, tpc, cryo));
307 }
308 
309 TVector2
311  float xw,
312  float yd,
313  unsigned int plane,
314  unsigned int tpc,
315  unsigned int cryo)
316 {
317  art::ServiceHandle<geo::Geometry const> geom;
318  return TVector2(xw / geom->TPC(tpc, cryo).Plane(plane).WirePitch(),
319  detProp.ConvertXToTicks(yd, plane, tpc, cryo));
320 }
321 
322 bool
324 {
325  if (h1 && h2)
326  return h1->fSegFraction < h2->fSegFraction;
327  else
328  return false;
329 }
330 
331 bool
333 {
334  if (h1 && h2)
335  return h1->GetDist2ToProj() < h2->GetDist2ToProj();
336  else
337  return false;
338 }
339 
340 bool
342 {
343  pma::Track3D* trk1 = t1.Track();
344  pma::Track3D* trk2 = t2.Track();
345  if (trk1 && trk2) {
346  double l1 = pma::Dist2(trk1->front()->Point3D(), trk1->back()->Point3D());
347  double l2 = pma::Dist2(trk2->front()->Point3D(), trk2->back()->Point3D());
348  return l1 > l2;
349  }
350  else
351  return false;
352 }
353 
354 pma::bSegmentProjLess::bSegmentProjLess(const TVector3& s0, const TVector3& s1)
355  : segStart(s0), segStop(s1)
356 {
357  if (s0 == s1) mf::LogError("pma::bSegmentProjLess") << "Vectors equal!";
358 }
double SolveLeastSquares3D(const std::vector< std::pair< TVector3, TVector3 >> &lines, TVector3 &result)
double GetSummedAmpl(const std::vector< pma::Hit3D * > &hits, unsigned int view=geo::kUnknown)
double GetHitsRadius2D(const std::vector< pma::Hit3D * > &hits, bool exact=false)
static constexpr Sample_t transform(Sample_t sample)
Implementation of the Projection Matching Algorithm.
process_name opflash particleana ie x
double Dist2(const TVector2 &v1, const TVector2 &v2)
Unknown view.
Definition: geo_types.h:136
pma::Hit3D const * front() const
Definition: PmaTrack3D.h:101
pdgs p
Definition: selectors.fcl:22
float fSegFraction
Definition: PmaHit3D.h:191
TVector3 const & Point3D() const
Definition: PmaHit3D.h:55
TVector2 WireDriftToCm(detinfo::DetectorPropertiesData const &detProp, unsigned int wire, float drift, unsigned int plane, unsigned int tpc, unsigned int cryo)
bool operator()(pma::Hit3D *h1, pma::Hit3D *h2)
process_name hit
Definition: cheaterreco.fcl:51
double GetHitsRadius3D(const std::vector< pma::Hit3D * > &hits, bool exact=false)
recob::tracking::Vector_t Vector3D
tuple m
now if test mode generate materials, CRT shell, world, gdml header else just generate CRT shell for u...
double GetDist2ToProj() const
Definition: PmaHit3D.cxx:110
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
bSegmentProjLess(const TVector3 &s0, const TVector3 &s1)
process_name opflash particleana ie ie y
size_t GetHitsCount(const std::vector< pma::Hit3D * > &hits, unsigned int view)
TVector2 GetProjectionToSegment(const TVector2 &p, const TVector2 &p0, const TVector2 &p1)
double ConvertXToTicks(double X, int p, int t, int c) const
Implementation of the Projection Matching Algorithm.
TVector2 GetVectorProjectionToPlane(const TVector3 &v, unsigned int plane, unsigned int tpc, unsigned int cryo)
tuple dir
Definition: dropbox.py:28
double ConvertTicksToX(double ticks, int p, int t, int c) const
Track finding helper for the Projection Matching Algorithm.
physics filters filter
Encapsulate the construction of a single detector plane.
bool operator()(pma::Hit3D *h1, pma::Hit3D *h2)
double GetSegmentProjVector(const TVector2 &p, const TVector2 &p0, const TVector2 &p1)
TVector2 GetProjectionToPlane(const TVector3 &p, unsigned int plane, unsigned int tpc, unsigned int cryo)
ROOT::Math::DisplacementVector2D< ROOT::Math::Cartesian2D< double > > Vector2D
pma::Hit3D const * back() const
Definition: PmaTrack3D.h:106
TVector2 CmToWireDrift(detinfo::DetectorPropertiesData const &detProp, float xw, float yd, unsigned int plane, unsigned int tpc, unsigned int cryo)
double GetSummedADC(const std::vector< pma::Hit3D * > &hits, unsigned int view=geo::kUnknown)
float A
Definition: dedx.py:137
pma::Track3D * Track() const
esac echo uname r
bool operator()(const pma::TrkCandidate &t1, const pma::TrkCandidate &t2)
physics associatedGroupsWithLeft p1
art framework interface to geometry description
auto const detProp
Encapsulate the construction of a single detector plane.