LArSoft  v10_04_05
Liquid Argon Software toolkit - https://larsoft.org/
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
GeometryUtilities.cxx
Go to the documentation of this file.
1 // \file GeometryUtilities.cxx
3 //
4 // \brief Functions to calculate distances and angles in 3D and 2D
5 //
6 // andrzej.szelc@yale.edu
7 //
9 
19 
20 #include "cetlib/pow.h"
21 
22 #include <cmath>
23 
24 namespace util {
25 
27  geo::WireReadoutGeom const& wireReadoutGeom,
28  detinfo::DetectorClocksData const& clockData,
29  detinfo::DetectorPropertiesData const& propData)
30  : fGeom{geom}, fWireReadoutGeom{wireReadoutGeom}, fClocks{clockData}, fDetProp{propData}
31  {
32  fNPlanes = wireReadoutGeom.Nplanes();
33  vertangle.resize(fNPlanes);
34  for (unsigned int ip = 0; ip < fNPlanes; ip++) {
35  geo::WireID const wid{0, 0, ip, 0};
36  vertangle[ip] = wireReadoutGeom.Wire(wid).ThetaZ(false) - TMath::Pi() / 2.; // wire angle
37  }
38 
39  fWirePitch = fWireReadoutGeom.Plane({0, 0, 0}).WirePitch();
40  fTimeTick = sampling_rate(fClocks) / 1000.;
42 
46  }
47 
48  //-----------------------------------------------------------------------------
49  // omega0 and omega1 (calculated by CPAN in degrees):
50  // angle based on distances in wires and time - rescaled to cm.
51  // tan(angle)*fMean_wire_pitch/(fTimeTick*fDriftVelocity);
52  // as those calculated with Get2Dangle
53  // writes phi and theta in degrees.
56  int iplane1,
57  double omega0,
58  double omega1,
59  double& phi,
60  double& theta) const
61  {
62  // y, z, x coordinates
63  double ln(0), mn(0), nn(0);
64  double phis(0), thetan(0);
65 
66  // Pretend collection and induction planes.
67  // "Collection" is the plane with the vertical angle equal to zero.
68  // If both are non-zero, collection is the one with the negative angle.
69  unsigned int Cplane = 0, Iplane = 1;
70 
71  // angleC and angleI are the respective angles to vertical in C/I
72  // planes and slopeC, slopeI are the tangents of the track.
73  double angleC, angleI, slopeC, slopeI, omegaC, omegaI;
74  omegaC = kINVALID_DOUBLE;
75  omegaI = kINVALID_DOUBLE;
76 
77  // Don't know how to reconstruct these yet, so exit with error.
78  // In
79  if (omega0 == 0 || omega1 == 0) {
80  phi = 0;
81  theta = -999;
82  return -1;
83  }
84 
86 
87  // check if backwards going track
88  double alt_backwards = 0;
89 
90  if (std::fabs(omega0) > (TMath::Pi() / 2.0) || std::fabs(omega1) > (TMath::Pi() / 2.0)) {
91  alt_backwards = 1;
92  }
93 
94  if (vertangle[iplane0] == 0) {
95  // first plane is at 0 degrees
96  Cplane = iplane0;
97  Iplane = iplane1;
98  omegaC = omega0;
99  omegaI = omega1;
100  }
101  else if (vertangle[iplane1] == 0) {
102  // second plane is at 0 degrees
103  Cplane = iplane1;
104  Iplane = iplane0;
105  omegaC = omega1;
106  omegaI = omega0;
107  }
108  else if (vertangle[iplane0] != 0 && vertangle[iplane1] != 0) {
109  // both planes are at non zero degree - find the one with deg<0
110  if (vertangle[iplane1] < vertangle[iplane0]) {
111  Cplane = iplane1;
112  Iplane = iplane0;
113  omegaC = omega1;
114  omegaI = omega0;
115  }
116  else if (vertangle[iplane1] > vertangle[iplane0]) {
117  Cplane = iplane0;
118  Iplane = iplane1;
119  omegaC = omega0;
120  omegaI = omega1;
121  }
122  else {
123  // throw error - same plane.
124  return -1;
125  }
126  }
127 
128  slopeC = std::tan(omegaC);
129  slopeI = std::tan(omegaI);
130  angleC = vertangle[Cplane];
131  angleI = vertangle[Iplane];
132 
133  // 0 -1 factor depending on if one of the planes is vertical.
134  bool nfact = !(vertangle[Cplane]);
135 
136  // ln represents y, omega is 2d angle -- in first 2 quadrants y is positive.
137  if (omegaC < TMath::Pi() && omegaC > 0)
138  ln = 1;
139  else
140  ln = -1;
141 
142  // calculate x and z using y ( ln )
143  mn = (ln / (2 * std::sin(angleI))) *
144  ((std::cos(angleI) / (slopeC * std::cos(angleC))) - (1 / slopeI) +
145  nfact * (std::cos(angleI) / (std::cos(angleC) * slopeC) - 1 / slopeI));
146 
147  nn = (ln / (2 * std::cos(angleC))) *
148  ((1 / slopeC) + (1 / slopeI) + nfact * ((1 / slopeC) - (1 / slopeI)));
149 
150  // Direction angles
151  if (std::fabs(omegaC) > 0.01) // catch numeric error values
152  {
153  // phi=std::atan(ln/nn);
154  phis = std::asin(ln / TMath::Sqrt(ln * ln + nn * nn));
155 
156  if (std::fabs(slopeC + slopeI) < 0.001)
157  phis = 0;
158  else if (std::fabs(omegaI) > 0.01 &&
159  (omegaI / std::fabs(omegaI) == -omegaC / std::fabs(omegaC)) &&
160  (std::fabs(omegaC) < 1 * TMath::Pi() / 180 ||
161  std::fabs(omegaC) > 179 * TMath::Pi() / 180)) // angles have
162  phis = (std::fabs(omegaC) > TMath::Pi() / 2) ? TMath::Pi() : 0; // angles are
163 
164  if (nn < 0 && phis > 0 &&
165  !(!alt_backwards &&
166  std::fabs(phis) <
167  TMath::Pi() / 4)) // do not go back if track looks forward and phi is forward
168  phis = (TMath::Pi()) - phis;
169  else if (nn < 0 && phis < 0 && !(!alt_backwards && std::fabs(phis) < TMath::Pi() / 4))
170  phis = (-TMath::Pi()) - phis;
171 
172  phi = phis * 180 / TMath::Pi();
173  }
174  // If plane2 (collection), phi = 2d angle (omegaC in this case)
175  else {
176  phis = omegaC;
177  phi = omegaC;
178  }
179 
180  thetan = -std::asin(mn / std::hypot(ln, mn, nn));
181  theta = thetan * 180 / TMath::Pi();
182 
183  return 0;
184  }
185 
187  // Calculate theta in case phi~0
188  // returns theta in angles
191  int iplane1,
192  double dw0,
193  double dw1) const
194  {
195 
196  double splane, lplane; // plane in which the track is shorter and longer.
197  double sdw, ldw;
198 
199  if (dw0 == 0 && dw1 == 0) return -1;
200 
201  if (dw0 >= dw1) {
202  lplane = iplane0;
203  splane = iplane1;
204  ldw = dw0;
205  sdw = dw1;
206  }
207  else {
208  lplane = iplane1;
209  splane = iplane0;
210  ldw = dw1;
211  sdw = dw0;
212  }
213 
214  double top = (std::cos(vertangle[splane]) - std::cos(vertangle[lplane]) * sdw / ldw);
215  double bottom = std::tan(vertangle[lplane] * std::cos(vertangle[splane]));
216  bottom -= std::tan(vertangle[splane] * std::cos(vertangle[lplane])) * sdw / ldw;
217 
218  double tantheta = top / bottom;
219 
220  return std::atan(tantheta) * vertangle[lplane] / std::abs(vertangle[lplane]) * 180. /
221  TMath::Pi();
222  }
223 
225  // Calculate 3D pitch in beam coordinates
226  //
228  double GeometryUtilities::CalculatePitch(unsigned int iplane, double phi, double theta) const
229  {
230  auto const& plane = fWireReadoutGeom.Plane({0, 0, iplane});
231  if (plane.View() == geo::kUnknown || plane.View() == geo::k3D) {
232  mf::LogError(Form("Warning : no Pitch foreseen for view %d", plane.View()));
233  return -1.;
234  }
235 
236  double const pi = TMath::Pi();
237  double const fTheta = pi / 2 - theta;
238  double const fPhi = -(phi + pi / 2);
239 
240  double wirePitch = plane.WirePitch();
241  double angleToVert =
242  0.5 * TMath::Pi() - fWireReadoutGeom.WireAngleToVertical(plane.View(), plane.ID());
243  double cosgamma = std::abs(std::sin(angleToVert) * std::cos(fTheta) +
244  std::cos(angleToVert) * std::sin(fTheta) * std::sin(fPhi));
245 
246  return cosgamma > 0 ? wirePitch / cosgamma : -1.;
247  }
248 
250  // Calculate 3D pitch in polar coordinates
251  //
253  double GeometryUtilities::CalculatePitchPolar(unsigned int iplane, double phi, double theta) const
254  {
255  auto const& plane = fWireReadoutGeom.Plane({0, 0, iplane});
256  if (plane.View() == geo::kUnknown || plane.View() == geo::k3D) {
257  mf::LogError(Form("Warning : no Pitch foreseen for view %d", plane.View()));
258  return -1.;
259  }
260 
261  double const fTheta = theta; // KJK: Are these two variables necessary?
262  double const fPhi = phi;
263 
264  double wirePitch = plane.WirePitch();
265  double angleToVert =
266  0.5 * TMath::Pi() - fWireReadoutGeom.WireAngleToVertical(plane.View(), plane.ID());
267  double cosgamma = std::abs(std::sin(angleToVert) * std::cos(fTheta) +
268  std::cos(angleToVert) * std::sin(fTheta) * std::sin(fPhi));
269 
270  return cosgamma > 0 ? wirePitch / cosgamma : -1.;
271  }
272 
274  // Calculate 2D slope
275  // in "cm" "cm" coordinates
277  double GeometryUtilities::Get2Dslope(double wireend,
278  double wirestart,
279  double timeend,
280  double timestart) const
281  {
282 
283  return GeometryUtilities::Get2Dslope((wireend - wirestart) * fWiretoCm,
284  (timeend - timestart) * fTimetoCm);
285  }
286 
288  // Calculate 2D slope
289  // in "cm" "cm" coordinates
291  double GeometryUtilities::Get2Dslope(const PxPoint* endpoint, const PxPoint* startpoint) const
292  {
293  return Get2Dslope(endpoint->w - startpoint->w, endpoint->t - startpoint->t);
294  }
295 
297  // Calculate 2D slope
298  // in wire time coordinates coordinates
299  //
301  double GeometryUtilities::Get2Dslope(double dwire, double dtime) const
302  {
303  return std::tan(Get2Dangle(dwire, dtime)) / fWireTimetoCmCm;
304  }
305 
307  // Calculate 2D angle
308  // in "cm" "cm" coordinates
310  double GeometryUtilities::Get2Dangle(double wireend,
311  double wirestart,
312  double timeend,
313  double timestart) const
314  {
315  return Get2Dangle((wireend - wirestart) * fWiretoCm, (timeend - timestart) * fTimetoCm);
316  }
317 
319  // Calculate 2D angle
320  // in "cm" "cm" coordinates, endpoint and startpoint are assumed to be in
321  // cm/cm space
323  double GeometryUtilities::Get2Dangle(const PxPoint* endpoint, const PxPoint* startpoint) const
324  {
325  return Get2Dangle(endpoint->w - startpoint->w, endpoint->t - startpoint->t);
326  }
327 
329  // Calculate 2D angle
330  // in "cm" "cm" coordinates
332  double GeometryUtilities::Get2Dangle(double dwire, double dtime) const
333  {
334  double BC, AC;
335  double omega;
336 
337  BC = ((double)dwire); // in cm
338  AC = ((double)dtime); // in cm
339  omega = std::asin(AC / std::hypot(AC, BC));
340  if (BC < 0) // for the time being. Will check if it works for AC<0
341  {
342  if (AC > 0) {
343  omega = TMath::Pi() - std::abs(omega); //
344  }
345  else if (AC < 0) {
346  omega = -TMath::Pi() + std::abs(omega);
347  }
348  else {
349  omega = TMath::Pi();
350  }
351  }
352  return omega;
353  }
354 
355  // accepting phi and theta in degrees
356  // returning in radians.
357 
358  double GeometryUtilities::Get2DangleFrom3D(unsigned int plane, double phi, double theta) const
359  {
360  TVector3 dummyvector(std::cos(theta * TMath::Pi() / 180.) * std::sin(phi * TMath::Pi() / 180.),
361  std::sin(theta * TMath::Pi() / 180.),
362  std::cos(theta * TMath::Pi() / 180.) * std::cos(phi * TMath::Pi() / 180.));
363  return Get2DangleFrom3D(plane, dummyvector);
364  }
365 
366  // accepting TVector3
367  // returning in radians as is customary,
368 
369  double GeometryUtilities::Get2DangleFrom3D(unsigned int plane, TVector3 dir_vector) const
370  {
371  geo::PlaneID const planeid{0, 0, plane};
372  double alpha = 0.5 * TMath::Pi() - fWireReadoutGeom.WireAngleToVertical(
373  fWireReadoutGeom.Plane(planeid).View(), planeid);
374  // create dummy xyz point in middle of detector and another one in unit
375  // length. calculate correspoding points in wire-time space and use the differnces
376  // between those to return 2D a angle
377 
378  auto const& tpc = fGeom.TPC(planeid.parentID());
379  TVector3 start(tpc.HalfWidth(), 0., tpc.Length() / 2.);
380  TVector3 end = start + dir_vector;
381 
382  // the wire coordinate is already in cm. The time needs to be converted.
383  PxPoint startp(plane,
384  (tpc.HalfHeight() * std::sin(std::fabs(alpha)) + start[2] * std::cos(alpha) -
385  start[1] * std::sin(alpha)),
386  start[0]);
387 
388  PxPoint endp(plane,
389  (tpc.HalfHeight() * std::sin(std::fabs(alpha)) + end[2] * std::cos(alpha) -
390  end[1] * std::sin(alpha)),
391  end[0]);
392 
393  double angle = Get2Dangle(&endp, &startp);
394 
395  return angle;
396  }
397 
399  // Calculate 2D distance in "cm" "cm" coordinates
401  double GeometryUtilities::Get2DDistance(double wire1,
402  double time1,
403  double wire2,
404  double time2) const
405  {
406  return std::hypot((wire1 - wire2) * fWiretoCm, (time1 - time2) * fTimetoCm);
407  }
408 
409  double GeometryUtilities::Get2DDistance(const PxPoint* point1, const PxPoint* point2) const
410  {
411  return std::hypot(point1->w - point2->w, point1->t - point2->t);
412  }
413 
415  // Calculate 2D distance, using 2D angle in "cm" "cm" coordinates
417  double GeometryUtilities::Get2DPitchDistance(double angle, double inwire, double wire) const
418  {
419  double radangle = TMath::Pi() * angle / 180;
420  if (std::cos(radangle) == 0) return 9999;
421  return std::abs((wire - inwire) / std::cos(radangle)) * fWiretoCm;
422  }
423 
424  //----------------------------------------------------------------------------
425  double GeometryUtilities::Get2DPitchDistanceWSlope(double slope, double inwire, double wire) const
426  {
427 
428  return std::abs(wire - inwire) * TMath::Sqrt(1 + slope * slope) * fWiretoCm;
429  }
430 
432  // Calculate wire,time coordinates of the Hit projection onto a line
435  double intercept,
436  double wire1,
437  double time1,
438  double& wireout,
439  double& timeout) const
440  {
441  double invslope = 0;
442 
443  if (slope) { invslope = -1. / slope; }
444 
445  double ort_intercept = time1 - invslope * (double)wire1;
446 
447  if ((slope - invslope) != 0)
448  wireout = (ort_intercept - intercept) / (slope - invslope);
449  else
450  wireout = wire1;
451  timeout = slope * wireout + intercept;
452 
453  return 0;
454  }
455 
457  // Calculate wire,time coordinates of the Hit projection onto a line all points are
458  // assumed to be in cm/cm space.
461  const PxPoint* startpoint,
462  const PxPoint* point1,
463  PxPoint& pointout) const
464  {
465 
466  double intercept = startpoint->t - slope * startpoint->w;
467 
468  return GetPointOnLine(slope, intercept, point1, pointout);
469  }
470 
472  // Calculate wire,time coordinates of the Hit projection onto a line all points assumed
473  // to be in cm/cm space.
476  double intercept,
477  const PxPoint* point1,
478  PxPoint& pointout) const
479  {
480  double invslope = 0;
481 
482  if (slope) { invslope = -1. / slope; }
483 
484  double ort_intercept = point1->t - invslope * point1->w;
485 
486  if ((slope - invslope) != 0)
487  pointout.w = (ort_intercept - intercept) / (slope - invslope);
488  else
489  pointout.w = point1->w;
490 
491  pointout.t = slope * pointout.w + intercept;
492 
493  return 0;
494  }
495 
497  // Calculate wire,time coordinates of the Hit projection onto a line
500  double wirestart,
501  double timestart,
502  double wire1,
503  double time1,
504  double& wireout,
505  double& timeout) const
506  {
507  double intercept = timestart - slope * (double)wirestart;
508 
509  return GetPointOnLine(slope, intercept, wire1, time1, wireout, timeout);
510  }
511 
513  // Calculate wire,time coordinates of the Hit projection onto a line
516  double intercept,
517  double ort_intercept,
518  double& wireout,
519  double& timeout) const
520  {
521  double invslope = 0;
522 
523  if (slope) { invslope = -1. / slope; }
524 
525  invslope *= fWireTimetoCmCm * fWireTimetoCmCm;
526 
527  wireout = (ort_intercept - intercept) / (slope - invslope);
528  timeout = slope * wireout + intercept;
529 
530  wireout /= fWiretoCm;
531  timeout /= fTimetoCm;
532 
533  return 0;
534  }
535 
537  // Calculate wire,time coordinates of the Hit projection onto a line slope should be in
538  // cm/cm space. PxPoint should be in cm/cm space.
541  double intercept,
542  double ort_intercept,
543  PxPoint& pointonline) const
544  {
545  double invslope = 0;
546 
547  if (slope) invslope = -1. / slope;
548 
549  pointonline.w = (ort_intercept - intercept) / (slope - invslope);
550  pointonline.t = slope * pointonline.w + intercept;
551  return 0;
552  }
553 
555  int GeometryUtilities::GetProjectedPoint(const PxPoint* p0, const PxPoint* p1, PxPoint& pN) const
556  {
557  // determine third plane number
558  for (unsigned int i = 0; i < fNPlanes; ++i) {
559  if (i == p0->plane || i == p1->plane) continue;
560  pN.plane = i;
561  }
562 
563  // Assuming there is no problem ( and we found the best pair that comes close in time
564  // ) we try to get the Y and Z coordinates for the start of the shower.
565  unsigned int chan1 = fWireReadoutGeom.PlaneWireToChannel(geo::WireID(0, 0, p0->plane, p0->w));
566  unsigned int chan2 = fWireReadoutGeom.PlaneWireToChannel(geo::WireID(0, 0, p1->plane, p1->w));
569  double x = (p0->t - trigger_offset(fClocks)) * fTimetoCm + pos.X();
570 
571  auto const intersection = fWireReadoutGeom.ChannelsIntersect(chan1, chan2);
572  if (!intersection) return -1;
573 
574  pos.SetCoordinates(x, intersection->y, intersection->z);
575 
576  pN = Get2DPointProjection(pos, {0, 0, pN.plane});
577 
578  return 0;
579  }
580 
582  int GeometryUtilities::GetYZ(const PxPoint* p0, const PxPoint* p1, double* yz) const
583  {
584  assert(p0 && p1);
585  geo::TPCID const tpcid{0, 0};
586  geo::PlaneID const plane_0{tpcid, p0->plane};
587  geo::PlaneID const plane_1{tpcid, p1->plane};
588 
589  // Force to the closest wires if not in the range
590  int z0 = p0->w / fWiretoCm;
591  int z1 = p1->w / fWiretoCm;
592  if (z0 < 0) {
593  std::cout << "\033[93mWarning\033[00m "
594  "\033[95m<<GeometryUtilities::GetYZ>>\033[00m"
595  << std::endl
596  << " 2D wire position " << p0->w << " [cm] corresponds to negative wire number."
597  << std::endl
598  << " Forcing it to wire=0..." << std::endl
599  << "\033[93mWarning ends...\033[00m" << std::endl;
600  z0 = 0;
601  }
602  else if (z0 >= (int)(fWireReadoutGeom.Nwires(plane_0))) {
603  std::cout << "\033[93mWarning\033[00m "
604  "\033[95m<<GeometryUtilities::GetYZ>>\033[00m"
605  << std::endl
606  << " 2D wire position " << p0->w << " [cm] exceeds max wire number "
607  << (fWireReadoutGeom.Nwires(plane_0) - 1) << std::endl
608  << " Forcing it to the max wire number..." << std::endl
609  << "\033[93mWarning ends...\033[00m" << std::endl;
610  z0 = fWireReadoutGeom.Nwires(plane_0) - 1;
611  }
612  if (z1 < 0) {
613  std::cout << "\033[93mWarning\033[00m "
614  "\033[95m<<GeometryUtilities::GetYZ>>\033[00m"
615  << std::endl
616  << " 2D wire position " << p1->w << " [cm] corresponds to negative wire number."
617  << std::endl
618  << " Forcing it to wire=0..." << std::endl
619  << "\033[93mWarning ends...\033[00m" << std::endl;
620  z1 = 0;
621  }
622  if (z1 >= (int)(fWireReadoutGeom.Nwires(plane_1))) {
623  std::cout << "\033[93mWarning\033[00m "
624  "\033[95m<<GeometryUtilities::GetYZ>>\033[00m"
625  << std::endl
626  << " 2D wire position " << p1->w << " [cm] exceeds max wire number "
627  << (fWireReadoutGeom.Nwires(plane_1) - 1) << std::endl
628  << " Forcing it to the max wire number..." << std::endl
629  << "\033[93mWarning ends...\033[00m" << std::endl;
630  z1 = fWireReadoutGeom.Nwires(plane_1) - 1;
631  }
632 
633  unsigned int chan1 = fWireReadoutGeom.PlaneWireToChannel(geo::WireID(plane_0, z0));
634  unsigned int chan2 = fWireReadoutGeom.PlaneWireToChannel(geo::WireID(plane_1, z1));
635 
636  auto const intersection = fWireReadoutGeom.ChannelsIntersect(chan1, chan2);
637  if (!intersection) return -1;
638 
639  yz[0] = intersection->y;
640  yz[1] = intersection->z;
641 
642  return 0;
643  }
644 
646  int GeometryUtilities::GetXYZ(const PxPoint* p0, const PxPoint* p1, double* xyz) const
647  {
649  auto const pos = fWireReadoutGeom.Plane(geo::PlaneID{0, 0, p0->plane}).toWorldCoords(origin);
650  double x = (p0->t) - trigger_offset(fClocks) * fTimetoCm + pos.X();
651  double yz[2];
652 
653  GetYZ(p0, p1, yz);
654 
655  xyz[0] = x;
656  xyz[1] = yz[0];
657  xyz[2] = yz[1];
658 
659  return 0;
660  }
661 
663 
665  geo::PlaneID const& planeID) const
666  {
668  auto pos = fWireReadoutGeom.Plane(planeID).toWorldCoords(origin);
669  double drifttick = (xyz.X() / fDriftVelocity) * (1. / fTimeTick);
670 
671  pos.SetY(xyz.Y());
672  pos.SetZ(xyz.Z());
673 
674  PxPoint pN(0, 0, 0);
675  pN.w = fWireReadoutGeom.Plane(planeID).NearestWireID(pos).Wire;
676  pN.t = drifttick - (pos.X() / fDriftVelocity) * (1. / fTimeTick) + trigger_offset(fClocks);
677  pN.plane = planeID.Plane;
678 
679  return pN;
680  }
681 
683  // for now this returns the vlause in CM/CM space.
684  // this will become the default, but don't want to break the code that depends
685  // on the previous version. A.S. 03/26/14
687 
689  geo::PlaneID const& planeID) const
690  {
691  auto const x = point.X();
692  point.SetX(0);
693  return {
694  planeID.Plane, fWireReadoutGeom.Plane(planeID).NearestWireID(point).Wire * fWiretoCm, x};
695  }
696 
697  double GeometryUtilities::GetTimeTicks(double x, unsigned int plane) const
698  {
700  auto const pos = fWireReadoutGeom.Plane(geo::PlaneID{0, 0, plane}).toWorldCoords(origin);
701  double drifttick = (x / fDriftVelocity) * (1. / fTimeTick);
702 
703  return drifttick - (pos.X() / fDriftVelocity) * (1. / fTimeTick) + trigger_offset(fClocks);
704  }
705 
706  //----------------------------------------------------------------------
707  // provide projected wire pitch for the view // copied from track.cxx and
708  // modified
709  double GeometryUtilities::PitchInView(unsigned int plane, double phi, double theta) const
710  {
711  double dirs[3] = {0.};
712  GetDirectionCosines(phi, theta, dirs);
713 
716  double wirePitch = 0.;
717  double angleToVert = 0.;
718 
719  auto const& planegeom = fWireReadoutGeom.Plane({0, 0, plane});
720  wirePitch = planegeom.WirePitch();
721  angleToVert =
722  fWireReadoutGeom.WireAngleToVertical(planegeom.View(), planegeom.ID()) - 0.5 * TMath::Pi();
723 
724  //(sin(angleToVert),std::cos(angleToVert)) is the direction perpendiculaOBr to
725  // wire fDir.front() is the direction of the track at the beginning of its
726  // trajectory
727  double cosgamma = std::abs(std::sin(angleToVert) * dirs[1] + std::cos(angleToVert) * dirs[2]);
728 
729  if (cosgamma < 1.e-5)
730  // throw UtilException("cosgamma is basically 0, that can't be right");
731  {
732  std::cout << " returning 100" << std::endl;
733  return 100;
734  }
735 
736  return wirePitch / cosgamma;
737  }
738 
740  void GeometryUtilities::GetDirectionCosines(double phi, double theta, double* dirs) const
741  {
742  theta *= (TMath::Pi() / 180);
743  phi *= (TMath::Pi() / 180); // working on copies, it's ok.
744  dirs[0] = std::cos(theta) * std::sin(phi);
745  dirs[1] = std::sin(theta);
746  dirs[2] = std::cos(theta) * std::cos(phi);
747  }
748 
749  void GeometryUtilities::SelectLocalHitlist(const std::vector<PxHit>& hitlist,
750  std::vector<const PxHit*>& hitlistlocal,
751  PxPoint& startHit,
752  double& linearlimit,
753  double& ortlimit,
754  double& lineslopetest) const
755  {
756  PxHit testHit;
758  hitlist, hitlistlocal, startHit, linearlimit, ortlimit, lineslopetest, testHit);
759  }
760 
764 
765  void GeometryUtilities::SelectLocalHitlist(const std::vector<PxHit>& hitlist,
766  std::vector<const PxHit*>& hitlistlocal,
767  PxPoint& startHit,
768  double& linearlimit,
769  double& ortlimit,
770  double& lineslopetest,
771  PxHit& averageHit) const
772  {
773  hitlistlocal.clear();
774  std::vector<unsigned int> hitlistlocal_index;
775 
776  hitlistlocal_index.clear();
777 
779  hitlist, hitlistlocal_index, startHit, linearlimit, ortlimit, lineslopetest);
780 
781  double timesum = 0;
782  double wiresum = 0;
783  for (size_t i = 0; i < hitlistlocal_index.size(); ++i) {
784 
785  hitlistlocal.push_back((const PxHit*)(&(hitlist.at(hitlistlocal_index.at(i)))));
786  timesum += hitlist.at(hitlistlocal_index.at(i)).t;
787  wiresum += hitlist.at(hitlistlocal_index.at(i)).w;
788  }
789 
790  averageHit.plane = startHit.plane;
791  if (hitlistlocal.size()) {
792  averageHit.w = wiresum / (double)hitlistlocal.size();
793  averageHit.t = timesum / ((double)hitlistlocal.size());
794  }
795  }
796 
797  void GeometryUtilities::SelectLocalHitlistIndex(const std::vector<PxHit>& hitlist,
798  std::vector<unsigned int>& hitlistlocal_index,
799  PxPoint& startHit,
800  double& linearlimit,
801  double& ortlimit,
802  double& lineslopetest) const
803  {
804  hitlistlocal_index.clear();
805  double locintercept = startHit.t - startHit.w * lineslopetest;
806 
807  for (size_t i = 0; i < hitlist.size(); ++i) {
808 
809  PxPoint hitonline;
810  GetPointOnLine(lineslopetest, locintercept, &hitlist.at(i), hitonline);
811 
812  // calculate linear distance from start point and orthogonal distance from axis
813  double lindist = Get2DDistance(&hitonline, &startHit);
814  double ortdist = Get2DDistance(&hitlist.at(i), &hitonline);
815 
816  if (lindist < linearlimit && ortdist < ortlimit) { hitlistlocal_index.push_back(i); }
817  }
818  }
819 
822 
823  void GeometryUtilities::SelectPolygonHitList(std::vector<PxHit> const& hitlist,
824  std::vector<PxHit const*>& hitlistlocal) const
825  {
826  if (empty(hitlist)) { throw UtilException("Provided empty hit list!"); }
827 
828  hitlistlocal.clear();
829  unsigned char plane = hitlist.front().plane;
830 
831  // Define subset of hits to define polygon
832  std::map<double, const PxHit*> hitmap;
833  double qtotal = 0;
834  for (auto const& h : hitlist) {
835  hitmap.try_emplace(h.charge, &h);
836  qtotal += h.charge;
837  }
838  double qintegral = 0;
839  std::vector<const PxHit*> ordered_hits;
840  ordered_hits.reserve(hitlist.size());
841  for (auto hiter = hitmap.rbegin(); qintegral < qtotal * 0.95 && hiter != hitmap.rend();
842  ++hiter) {
843 
844  qintegral += (*hiter).first;
845  ordered_hits.push_back((*hiter).second);
846  }
847 
848  // Define container to hold found polygon corner PxHit index & distance
849  std::vector<size_t> hit_index(8, 0);
850  std::vector<double> hit_distance(8, 1e9);
851 
852  // Loop over hits and find corner points in the plane view
853  // Also fill corner edge points
854  std::vector<PxPoint> edges(4, PxPoint(plane, 0, 0));
855  double wire_max = fWireReadoutGeom.Nwires({0, 0, plane}) * fWiretoCm;
856  double time_max = fDetProp.NumberTimeSamples() * fTimetoCm;
857 
858  for (size_t index = 0; index < ordered_hits.size(); ++index) {
859 
860  if (ordered_hits.at(index)->t < 0 || ordered_hits.at(index)->w < 0 ||
861  ordered_hits.at(index)->t > time_max || ordered_hits.at(index)->w > wire_max) {
862 
863  throw UtilException(Form("Invalid wire/time (%g,%g) ... range is (0=>%g,0=>%g)",
864  ordered_hits.at(index)->w,
865  ordered_hits.at(index)->t,
866  wire_max,
867  time_max));
868  }
869 
870  double dist = 0;
871 
872  // Comparison w/ (Wire,0)
873  dist = ordered_hits.at(index)->t;
874  if (dist < hit_distance.at(1)) {
875  hit_distance.at(1) = dist;
876  hit_index.at(1) = index;
877  edges.at(0).t = ordered_hits.at(index)->t;
878  edges.at(1).t = ordered_hits.at(index)->t;
879  }
880 
881  // Comparison w/ (WireMax,Time)
882  dist = wire_max - ordered_hits.at(index)->w;
883  if (dist < hit_distance.at(3)) {
884  hit_distance.at(3) = dist;
885  hit_index.at(3) = index;
886  edges.at(1).w = ordered_hits.at(index)->w;
887  edges.at(2).w = ordered_hits.at(index)->w;
888  }
889 
890  // Comparison w/ (Wire,TimeMax)
891  dist = time_max - ordered_hits.at(index)->t;
892  if (dist < hit_distance.at(5)) {
893  hit_distance.at(5) = dist;
894  hit_index.at(5) = index;
895  edges.at(2).t = ordered_hits.at(index)->t;
896  edges.at(3).t = ordered_hits.at(index)->t;
897  }
898 
899  // Comparison w/ (0,Time)
900  dist = ordered_hits.at(index)->w;
901  if (dist < hit_distance.at(7)) {
902  hit_distance.at(7) = dist;
903  hit_index.at(7) = index;
904  edges.at(0).w = ordered_hits.at(index)->w;
905  edges.at(3).w = ordered_hits.at(index)->w;
906  }
907  }
908  for (size_t index = 0; index < ordered_hits.size(); ++index) {
909 
910  double dist = 0;
911  // Comparison w/ (0,0)
912  dist = cet::sum_of_squares(ordered_hits.at(index)->t - edges.at(0).t,
913  ordered_hits.at(index)->w - edges.at(0).w);
914  if (dist < hit_distance.at(0)) {
915  hit_distance.at(0) = dist;
916  hit_index.at(0) = index;
917  }
918 
919  // Comparison w/ (WireMax,0)
920  dist = cet::sum_of_squares(ordered_hits.at(index)->t - edges.at(1).t,
921  ordered_hits.at(index)->w - edges.at(1).w);
922  if (dist < hit_distance.at(2)) {
923  hit_distance.at(2) = dist;
924  hit_index.at(2) = index;
925  }
926 
927  // Comparison w/ (WireMax,TimeMax)
928  dist = cet::sum_of_squares(ordered_hits.at(index)->t - edges.at(2).t,
929  ordered_hits.at(index)->w - edges.at(2).w);
930  if (dist < hit_distance.at(4)) {
931  hit_distance.at(4) = dist;
932  hit_index.at(4) = index;
933  }
934 
935  // Comparison w/ (0,TimeMax)
936  dist = cet::sum_of_squares(ordered_hits.at(index)->t - edges.at(3).t,
937  ordered_hits.at(index)->w - edges.at(3).w);
938  if (dist < hit_distance.at(6)) {
939  hit_distance.at(6) = dist;
940  hit_index.at(6) = index;
941  }
942  }
943 
944  // Loop over the resulting hit indexes and append unique hits to define the polygon to
945  // the return hit list
946  std::set<size_t> unique_index;
947  std::vector<size_t> candidate_polygon;
948  candidate_polygon.reserve(9);
949  for (auto& index : hit_index) {
950  if (unique_index.find(index) == unique_index.end()) {
951  unique_index.insert(index);
952  candidate_polygon.push_back(index);
953  }
954  }
955  for (auto& index : hit_index) {
956  candidate_polygon.push_back(index);
957  break;
958  }
959 
960  if (unique_index.size() > 8) throw UtilException("Size of the polygon > 8!");
961 
962  // Untangle Polygon
963  candidate_polygon = PolyOverlap(ordered_hits, candidate_polygon);
964 
965  hitlistlocal.clear();
966  for (unsigned int i = 0; i < (candidate_polygon.size() - 1); i++) {
967  hitlistlocal.push_back((const PxHit*)(ordered_hits.at(candidate_polygon.at(i))));
968  }
969  // check that polygon does not have more than 8 sides
970  if (unique_index.size() > 8) throw UtilException("Size of the polygon > 8!");
971  }
972 
973  std::vector<size_t> GeometryUtilities::PolyOverlap(std::vector<const PxHit*> ordered_hits,
974  std::vector<size_t> candidate_polygon) const
975  {
976  // loop over edges
977  for (unsigned int i = 0; i < (candidate_polygon.size() - 1); i++) {
978  double Ax = ordered_hits.at(candidate_polygon.at(i))->w;
979  double Ay = ordered_hits.at(candidate_polygon.at(i))->t;
980  double Bx = ordered_hits.at(candidate_polygon.at(i + 1))->w;
981  double By = ordered_hits.at(candidate_polygon.at(i + 1))->t;
982  // loop over edges that have not been checked yet... only ones further down in
983  // polygon
984  for (unsigned int j = i + 2; j < (candidate_polygon.size() - 1); j++) {
985  // avoid consecutive segments:
986  if (candidate_polygon.at(i) == candidate_polygon.at(j + 1))
987  continue;
988  else {
989  double Cx = ordered_hits.at(candidate_polygon.at(j))->w;
990  double Cy = ordered_hits.at(candidate_polygon.at(j))->t;
991  double Dx = ordered_hits.at(candidate_polygon.at(j + 1))->w;
992  double Dy = ordered_hits.at(candidate_polygon.at(j + 1))->t;
993 
994  if ((Clockwise(Ax, Ay, Cx, Cy, Dx, Dy) != Clockwise(Bx, By, Cx, Cy, Dx, Dy)) and
995  (Clockwise(Ax, Ay, Bx, By, Cx, Cy) != Clockwise(Ax, Ay, Bx, By, Dx, Dy))) {
996  size_t tmp = candidate_polygon.at(i + 1);
997  candidate_polygon.at(i + 1) = candidate_polygon.at(j);
998  candidate_polygon.at(j) = tmp;
999  // check that last element is still first (to close circle...)
1000  candidate_polygon.at(candidate_polygon.size() - 1) = candidate_polygon.at(0);
1001  // swapped polygon...now do recursion to make sure
1002  return PolyOverlap(ordered_hits, candidate_polygon);
1003  } // if crossing
1004  }
1005  } // second loop
1006  } // first loop
1007  return candidate_polygon;
1008  }
1009 
1010  bool GeometryUtilities::Clockwise(double const Ax,
1011  double const Ay,
1012  double const Bx,
1013  double const By,
1014  double const Cx,
1015  double const Cy) const
1016  {
1017  return (Cy - Ay) * (Bx - Ax) > (By - Ay) * (Cx - Ax);
1018  }
1019 
1020  PxHit GeometryUtilities::FindClosestHit(std::vector<PxHit> const& hitlist,
1021  unsigned int const wirein,
1022  double const timein) const
1023  {
1024  return hitlist[FindClosestHitIndex(hitlist, wirein, timein)];
1025  }
1026 
1027  unsigned int GeometryUtilities::FindClosestHitIndex(std::vector<PxHit> const& hitlist,
1028  unsigned int const wirein,
1029  double const timein) const
1030  {
1031  double min_length_from_start = 99999;
1032  unsigned int ret_ind = 0;
1033 
1034  for (unsigned int ii = 0; ii < hitlist.size(); ii++) {
1035  PxHit const& hit = hitlist[ii];
1036  double const dist_mod = Get2DDistance(wirein, timein, hit.w, hit.t);
1037  if (dist_mod < min_length_from_start) {
1038  min_length_from_start = dist_mod;
1039  ret_ind = ii;
1040  }
1041  }
1042 
1043  return ret_ind;
1044  }
1045 
1046 } // namespace
Float_t x
Definition: compare.C:6
double Get2Dslope(double deltawire, double deltatime) const
double Get2DDistance(double wire1, double time1, double wire2, double time2) const
detinfo::DetectorClocksData const & fClocks
Namespace for general, non-LArSoft-specific utilities.
Definition: PIDAAlg.h:26
unsigned int Nwires(PlaneID const &planeid) const
Returns the total number of wires in the specified plane.
GeometryUtilities(geo::GeometryCore const &geom, geo::WireReadoutGeom const &wireReadoutGeom, detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &propData)
Class def header for exception classes used in GeometryUtilities.
std::vector< double > vertangle
double PitchInView(unsigned int plane, double phi, double theta) const
WireID NearestWireID(Point_t const &pos) const
Returns the ID of wire closest to the specified position.
Definition: PlaneGeo.cxx:485
Unknown view.
Definition: geo_types.h:138
The data type to uniquely identify a Plane.
Definition: geo_types.h:364
double Temperature() const
In kelvin.
constexpr auto abs(T v)
Returns the absolute value of the argument.
Point_t toWorldCoords(LocalPoint_t const &local) const
Transform point from local plane frame to world frame.
Definition: PlaneGeo.h:1111
void GetDirectionCosines(double phi, double theta, double *dirs) const
double WireAngleToVertical(View_t view, TPCID const &tpcid) const
Returns the angle of the wires in the specified view from vertical.
PxPoint Get2DPointProjectionCM(geo::Point_t xyz, geo::PlaneID const &planeID) const
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:430
Float_t tmp
Definition: plot.C:35
int GetPointOnLine(double slope, double intercept, double wire1, double time1, double &wireout, double &timeout) const
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
std::optional< WireIDIntersection > ChannelsIntersect(raw::ChannelID_t c1, raw::ChannelID_t c2) const
Returns an intersection point of two channels.
double Efield(unsigned int planegap=0) const
kV/cm
detinfo::DetectorPropertiesData const & fDetProp
3-dimensional objects, potentially hits, clusters, prongs, etc.
Definition: geo_types.h:137
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
Access the description of the physical detector geometry.
int GetYZ(const PxPoint *p0, const PxPoint *p1, double *yz) const
View_t View() const
Which coordinate does this plane measure.
Definition: PlaneGeo.h:155
geo::WireReadoutGeom const & fWireReadoutGeom
void SelectLocalHitlistIndex(const std::vector< PxHit > &hitlist, std::vector< unsigned int > &hitlistlocal_index, PxPoint &startHit, double &linearlimit, double &ortlimit, double &lineslopetest) const
int GetProjectedPoint(const PxPoint *p0, const PxPoint *p1, PxPoint &pN) const
Interface for a class providing readout channel mapping to geometry.
double t
Definition: PxUtils.h:10
double Get2DPitchDistance(double angle, double inwire, double wire) const
int Get3DaxisN(int iplane0, int iplane1, double omega0, double omega1, double &phi, double &theta) const
geo::GeometryCore const & fGeom
std::vector< size_t > PolyOverlap(std::vector< const PxHit * > ordered_hits, std::vector< size_t > candidate_polygon) const
virtual raw::ChannelID_t PlaneWireToChannel(WireID const &wireID) const =0
Returns the channel ID a wire is connected to.
double GetTimeTicks(double x, unsigned int plane) const
void SelectLocalHitlist(const std::vector< PxHit > &hitlist, std::vector< const PxHit * > &hitlistlocal, PxPoint &startHit, double &linearlimit, double &ortlimit, double &lineslopetest) const
int GetPointOnLineWSlopes(double slope, double intercept, double ort_intercept, double &wireout, double &timeout) const
double DriftVelocity(double efield=0., double temperature=0.) const
cm/us
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
Description of the physical geometry of one entire detector.
Definition: GeometryCore.h:91
Detector simulation of raw signals on wires.
double w
Definition: PxUtils.h:9
Encapsulate the geometry of a wire .
bool Clockwise(double Ax, double Ay, double Bx, double By, double Cx, double Cy) const
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
void SelectPolygonHitList(const std::vector< PxHit > &hitlist, std::vector< const PxHit * > &hitlistlocal) const
int GetXYZ(const PxPoint *p0, const PxPoint *p1, double *xyz) const
double CalculatePitch(unsigned int iplane0, double phi, double theta) const
Encapsulate the construction of a single detector plane .
double dist(const TReal *x, const TReal *y, const unsigned int dimension)
Contains all timing reference information for the detector.
PxHit FindClosestHit(std::vector< PxHit > const &hitlist, unsigned int wirein, double timein) const
double Get2DangleFrom3D(unsigned int plane, double phi, double theta) const
double CalculatePitchPolar(unsigned int iplane0, double phi, double theta) const
double Get3DSpecialCaseTheta(int iplane0, int iplane1, double dw0, double dw1) const
constexpr T pi()
Returns the constant pi (up to 35 decimal digits of precision)
int trigger_offset(DetectorClocksData const &data)
unsigned int FindClosestHitIndex(std::vector< PxHit > const &hitlist, unsigned int wirein, double timein) const
constexpr double kINVALID_DOUBLE
double Get2DPitchDistanceWSlope(double slope, double inwire, double wire) const
PlaneGeo const & Plane(TPCID const &tpcid, View_t view) const
Returns the specified wire.
TPCGeo const & TPC(TPCID const &tpcid=details::tpc_zero) const
Returns the specified TPC.
Definition: GeometryCore.h:448
Float_t e
Definition: plot.C:35
double Get2Dangle(double deltawire, double deltatime) const
double sampling_rate(DetectorClocksData const &data)
Returns the period of the TPC readout electronics clock.
PxPoint Get2DPointProjection(geo::Point_t const &xyz, geo::PlaneID const &planeID) const
Float_t w
Definition: plot.C:20
Point3DBase_t< PlaneGeoCoordinatesTag > LocalPoint_t
Type of points in the local GDML wire plane frame.
Definition: PlaneGeo.h:94
Interface to geometry for wire readouts .
unsigned int plane
Definition: PxUtils.h:11
constexpr Point origin()
Returns a origin position with a point of the specified type.
Definition: geo_vectors.h:229
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
Definition: StdUtils.h:109
double WirePitch() const
Return the wire pitch (in centimeters). It is assumed constant.
Definition: PlaneGeo.h:312