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 
15 #include "cetlib/pow.h"
17 
18 #include "TMatrixT.h"
19 #include "TVectorT.h"
20 #include <math.h>
21 
31 
32 #include "range/v3/algorithm.hpp"
33 #include "range/v3/numeric.hpp"
34 #include "range/v3/view.hpp"
35 
36 double
37 pma::Dist2(const TVector2& v1, const TVector2& v2)
38 {
39  double const dx = v1.X() - v2.X(), dy = v1.Y() - v2.Y();
40  return cet::sum_of_squares(dx, dy);
41 }
42 double
43 pma::Dist2(const Vector2D& v1, const Vector2D& v2)
44 {
45  double const dx = v1.X() - v2.X(), dy = v1.Y() - v2.Y();
46  return cet::sum_of_squares(dx, dy);
47 }
48 
49 size_t
50 pma::GetHitsCount(const std::vector<pma::Hit3D*>& hits, unsigned int view)
51 {
52  if (view == geo::kUnknown) { return hits.size(); }
53  return ranges::count_if(hits, [view](auto hit) { return view == hit->View2D(); });
54 }
55 
56 double
57 pma::GetSummedADC(const std::vector<pma::Hit3D*>& hits, unsigned int view)
58 {
59  using namespace ranges;
60  auto to_summed_adc = [](auto hit) { return hit->SummedADC(); };
61  if (view == geo::kUnknown) { return accumulate(hits | views::transform(to_summed_adc), 0.); }
62  return accumulate(hits | views::filter([view](auto hit) { return view == hit->View2D(); }) |
63  views::transform(to_summed_adc),
64  0.);
65 }
66 
67 double
68 pma::GetSummedAmpl(const std::vector<pma::Hit3D*>& hits, unsigned int view)
69 {
70  using namespace ranges;
71  auto to_amplitude = [](auto hit) { return hit->GetAmplitude(); };
72  if (view == geo::kUnknown) { return accumulate(hits | views::transform(to_amplitude), 0.); }
73  return accumulate(hits | views::filter([view](auto hit) { return view == hit->View2D(); }) |
74  views::transform(to_amplitude),
75  0.);
76 }
77 
78 double
79 pma::GetHitsRadius3D(const std::vector<pma::Hit3D*>& hits, bool exact)
80 {
81  if (hits.empty()) return 0.0;
82 
83  if (!exact && (hits.size() < 5)) return 0.0;
84 
85  using namespace ranges;
86  auto to_3d_point = [](auto hit) -> decltype(auto) { return hit->Point3D(); };
87  auto const mean_point =
88  accumulate(hits | views::transform(to_3d_point), TVector3{}) * (1. / hits.size());
89 
90  auto to_dist2_from_mean = [&mean_point](auto hit) {
91  return pma::Dist2(hit->Point3D(), mean_point);
92  };
93  auto const max_r2 = max(hits | views::transform(to_dist2_from_mean));
94  return sqrt(max_r2);
95 }
96 
97 double
98 pma::GetHitsRadius2D(const std::vector<pma::Hit3D*>& hits, bool exact)
99 {
100  if (hits.empty()) return 0.0;
101 
102  if (!exact && (hits.size() < 5)) return 0.0;
103 
104  using namespace ranges;
105  auto to_2d_point = [](auto hit) -> decltype(auto) { return hit->Point2D(); };
106  auto const mean_point =
107  accumulate(hits | views::transform(to_2d_point), TVector2{}) * (1. / hits.size());
108 
109  auto to_dist2_from_mean = [&mean_point](auto hit) {
110  return pma::Dist2(hit->Point2D(), mean_point);
111  };
112  auto const max_r2 = max(hits | views::transform(to_dist2_from_mean));
113  return sqrt(max_r2);
114 }
115 
116 double
117 pma::GetSegmentProjVector(const TVector2& p, const TVector2& p0, const TVector2& p1)
118 {
119  TVector2 const v0(p - p0);
120  TVector2 const v1(p1 - p0);
121  return v0 * v1 / v1.Mod2();
122 }
123 
124 double
126 {
127  pma::Vector2D const v0(p - p0);
128  pma::Vector2D const v1(p1 - p0);
129  return v0.Dot(v1) / v1.Mag2();
130 }
131 
132 double
133 pma::GetSegmentProjVector(const TVector3& p, const TVector3& p0, const TVector3& p1)
134 {
135  TVector3 const v0(p - p0);
136  TVector3 const v1(p1 - p0);
137  return v0.Dot(v1) / v1.Mag2();
138 }
139 
140 double
142 {
143  pma::Vector3D const v0(p - p0);
144  pma::Vector3D const v1(p1 - p0);
145  return v0.Dot(v1) / v1.Mag2();
146 }
147 
148 TVector2
149 pma::GetProjectionToSegment(const TVector2& p, const TVector2& p0, const TVector2& p1)
150 {
151  TVector2 const v1(p1 - p0);
152  double const b = GetSegmentProjVector(p, p0, p1);
153  return p0 + v1 * b;
154 }
155 
156 TVector3
157 pma::GetProjectionToSegment(const TVector3& p, const TVector3& p0, const TVector3& p1)
158 {
159  TVector3 const v1(p1 - p0);
160  double const b = GetSegmentProjVector(p, p0, p1);
161  return p0 + v1 * b;
162 }
163 
164 double
165 pma::SolveLeastSquares3D(const std::vector<std::pair<TVector3, TVector3>>& lines, TVector3& result)
166 {
167  // RS: please, ask me if you need examples/explanation of formulas as they
168  // are not easy to derive from the code solely; I have Mathcad sources that
169  // were used to test the solving method, weighting, etc.
170 
171  result.SetXYZ(0., 0., 0.);
172  if (lines.size() < 2) {
173  mf::LogError("pma::SolveLeastSquares3D") << "Need min. two lines.";
174  return -1.0;
175  }
176 
177  double m;
178  std::vector<TVectorT<double>> U, P;
179  for (size_t v = 0; v < lines.size(); v++) {
180  TVector3 point = lines[v].first;
181  TVector3 dir = lines[v].second;
182  dir -= point;
183  m = dir.Mag();
184  if (m > 0.0) {
185  dir *= 1.0 / m;
186 
187  P.push_back(TVectorT<double>(3));
188  P.back()[0] = point.X();
189  P.back()[1] = point.Y();
190  P.back()[2] = point.Z();
191 
192  U.push_back(TVectorT<double>(3));
193  U.back()[0] = dir.X();
194  U.back()[1] = dir.Y();
195  U.back()[2] = dir.Z();
196  }
197  else
198  mf::LogWarning("pma::SolveLeastSquares3D") << "Line undefined.";
199  }
200  if (P.size() < 2) {
201  mf::LogError("pma::SolveLeastSquares3D") << "Need min. two lines.";
202  return -1.0;
203  }
204 
205  TVectorT<double> x(3), y(3), w(3);
206  TMatrixT<double> A(3, 3);
207  double ur, uc, pc;
208  double s_uc2[3], s_ur_uc[3];
209  double s_p_uc2[3], s_p_ur_uc[3];
210 
211  w[0] = 1.0;
212  w[1] = 1.0;
213  w[2] = 1.0;
214  for (size_t r = 0; r < 3; r++) {
215  y[r] = 0.0;
216  for (size_t c = 0; c < 3; c++) {
217  s_uc2[c] = 0.0;
218  s_ur_uc[c] = 0.0;
219  s_p_uc2[c] = 0.0;
220  s_p_ur_uc[c] = 0.0;
221 
222  for (size_t v = 0; v < P.size(); v++) {
223  //w[1] = fWeights[v]; // to remember that individual coordinates can be supressed...
224  //w[2] = fWeights[v];
225 
226  ur = U[v][r];
227  uc = U[v][c];
228  pc = P[v][c];
229 
230  s_uc2[c] += w[r] * w[c] * (1 - uc * uc);
231  s_p_uc2[c] += w[r] * w[r] * pc * (1 - uc * uc);
232 
233  s_ur_uc[c] += w[r] * w[c] * ur * uc;
234  s_p_ur_uc[c] += w[r] * w[r] * pc * ur * uc;
235  }
236 
237  if (r == c) {
238  y[r] += s_p_uc2[c];
239  A(r, c) = s_uc2[c];
240  }
241  else {
242  y[r] -= s_p_ur_uc[c];
243  A(r, c) = -s_ur_uc[c];
244  }
245  }
246  }
247  try {
248  x = A.InvertFast() * y;
249  }
250  catch (...) {
251  result.SetXYZ(0., 0., 0.);
252  return 1.0e12;
253  }
254 
255  result.SetXYZ(x[0], x[1], x[2]);
256 
257  double mse = 0.0;
258  for (size_t v = 0; v < lines.size(); v++) {
259  TVector3 const pproj = pma::GetProjectionToSegment(result, lines[v].first, lines[v].second);
260 
261  double const dx = result.X() - pproj.X(); // dx, dy, dz and the result point can be weighted
262  double const dy = result.Y() - pproj.Y(); // here (linearly) by each line uncertainty
263  double const dz = result.Z() - pproj.Z();
264  mse += cet::sum_of_squares(dx, dy, dz);
265  }
266  return mse / lines.size();
267 }
268 
269 TVector2
270 pma::GetProjectionToPlane(const TVector3& p,
271  unsigned int plane,
272  unsigned int tpc,
273  unsigned int cryo)
274 {
276 
277  return TVector2(geom->TPC(tpc, cryo).Plane(plane).PlaneCoordinate(p), p.X());
278 }
279 
280 TVector2
282  unsigned int plane,
283  unsigned int tpc,
284  unsigned int cryo)
285 {
286  TVector3 v0_3d(0., 0., 0.);
287  TVector2 v0_2d = GetProjectionToPlane(v0_3d, plane, tpc, cryo);
288  TVector2 v1_2d = GetProjectionToPlane(v, plane, tpc, cryo);
289 
290  return v1_2d - v0_2d;
291 }
292 
293 TVector2
295  unsigned int wire,
296  float drift,
297  unsigned int plane,
298  unsigned int tpc,
299  unsigned int cryo)
300 {
302  return TVector2(geom->TPC(tpc, cryo).Plane(plane).WirePitch() * wire,
303  detProp.ConvertTicksToX(drift, plane, tpc, cryo));
304 }
305 
306 TVector2
308  float xw,
309  float yd,
310  unsigned int plane,
311  unsigned int tpc,
312  unsigned int cryo)
313 {
315  return TVector2(xw / geom->TPC(tpc, cryo).Plane(plane).WirePitch(),
316  detProp.ConvertXToTicks(yd, plane, tpc, cryo));
317 }
318 
319 bool
321 {
322  if (h1 && h2)
323  return h1->fSegFraction < h2->fSegFraction;
324  else
325  return false;
326 }
327 
328 bool
330 {
331  if (h1 && h2)
332  return h1->GetDist2ToProj() < h2->GetDist2ToProj();
333  else
334  return false;
335 }
336 
337 bool
339 {
340  pma::Track3D* trk1 = t1.Track();
341  pma::Track3D* trk2 = t2.Track();
342  if (trk1 && trk2) {
343  double l1 = pma::Dist2(trk1->front()->Point3D(), trk1->back()->Point3D());
344  double l2 = pma::Dist2(trk2->front()->Point3D(), trk2->back()->Point3D());
345  return l1 > l2;
346  }
347  else
348  return false;
349 }
350 
351 pma::bSegmentProjLess::bSegmentProjLess(const TVector3& s0, const TVector3& s1)
352  : segStart(s0), segStop(s1)
353 {
354  if (s0 == s1) mf::LogError("pma::bSegmentProjLess") << "Vectors equal!";
355 }
double SolveLeastSquares3D(const std::vector< std::pair< TVector3, TVector3 >> &lines, TVector3 &result)
Definition: Utilities.cxx:165
double GetSummedAmpl(const std::vector< pma::Hit3D * > &hits, unsigned int view=geo::kUnknown)
Definition: Utilities.cxx:68
double GetHitsRadius2D(const std::vector< pma::Hit3D * > &hits, bool exact=false)
Definition: Utilities.cxx:98
static QCString result
Implementation of the Projection Matching Algorithm.
double Dist2(const TVector2 &v1, const TVector2 &v2)
Definition: Utilities.cxx:37
Unknown view.
Definition: geo_types.h:136
pma::Hit3D const * front() const
Definition: PmaTrack3D.h:98
constexpr T sum_of_squares(T x, T y)
Definition: pow.h:139
float fSegFraction
Definition: PmaHit3D.h:191
struct vector vector
TVector3 const & Point3D() const
Definition: PmaHit3D.h:55
std::pair< float, std::string > P
TVector2 WireDriftToCm(detinfo::DetectorPropertiesData const &detProp, unsigned int wire, float drift, unsigned int plane, unsigned int tpc, unsigned int cryo)
Definition: Utilities.cxx:294
bool operator()(pma::Hit3D *h1, pma::Hit3D *h2)
Definition: Utilities.cxx:329
string dir
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
double GetHitsRadius3D(const std::vector< pma::Hit3D * > &hits, bool exact=false)
Definition: Utilities.cxx:79
recob::tracking::Vector_t Vector3D
Definition: Utilities.h:31
double GetDist2ToProj() const
Definition: PmaHit3D.cxx:110
art framework interface to geometry description
bSegmentProjLess(const TVector3 &s0, const TVector3 &s1)
Definition: Utilities.cxx:351
size_t GetHitsCount(const std::vector< pma::Hit3D * > &hits, unsigned int view)
Definition: Utilities.cxx:50
TVector2 GetProjectionToSegment(const TVector2 &p, const TVector2 &p0, const TVector2 &p1)
Definition: Utilities.cxx:149
p
Definition: test.py:223
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)
Definition: Utilities.cxx:281
static int max(int a, int b)
Detector simulation of raw signals on wires.
double ConvertTicksToX(double ticks, int p, int t, int c) const
Track finding helper for the Projection Matching Algorithm.
Implementation of the Projection Matching Algorithm.
Encapsulate the construction of a single detector plane.
bool operator()(pma::Hit3D *h1, pma::Hit3D *h2)
Definition: Utilities.cxx:320
double GetSegmentProjVector(const TVector2 &p, const TVector2 &p0, const TVector2 &p1)
Definition: Utilities.cxx:117
TVector2 GetProjectionToPlane(const TVector3 &p, unsigned int plane, unsigned int tpc, unsigned int cryo)
Definition: Utilities.cxx:270
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
ROOT::Math::DisplacementVector2D< ROOT::Math::Cartesian2D< double > > Vector2D
Definition: Utilities.h:30
pma::Hit3D const * back() const
Definition: PmaTrack3D.h:103
#define A
Definition: memgrp.cpp:38
static bool * b
Definition: config.cpp:1043
TVector2 CmToWireDrift(detinfo::DetectorPropertiesData const &detProp, float xw, float yd, unsigned int plane, unsigned int tpc, unsigned int cryo)
Definition: Utilities.cxx:307
list x
Definition: train.py:276
TPCGeo const & TPC(unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified TPC.
double GetSummedADC(const std::vector< pma::Hit3D * > &hits, unsigned int view=geo::kUnknown)
Definition: Utilities.cxx:57
static unsigned filter(unsigned char *out, const unsigned char *in, unsigned w, unsigned h, const LodePNG_InfoColor *info)
Definition: lodepng.cpp:3576
PlaneGeo const & Plane(geo::View_t view) const
Return the plane in the tpc with View_t view.
Definition: TPCGeo.cxx:263
second_as<> second
Type of time stored in seconds, in double precision.
Definition: spacetime.h:85
pma::Track3D * Track() const
double PlaneCoordinate(geo::Point_t const &point) const
Returns the coordinate of the point on the plane.
Definition: PlaneGeo.h:861
bool operator()(const pma::TrkCandidate &t1, const pma::TrkCandidate &t2)
Definition: Utilities.cxx:338
double WirePitch() const
Return the wire pitch (in centimeters). It is assumed constant.
Definition: PlaneGeo.h:411
Encapsulate the construction of a single detector plane.