LArSoft  v10_04_05
Liquid Argon Software toolkit - https://larsoft.org/
WireReadoutGeom.cxx
Go to the documentation of this file.
1 
13 
15 
16 #include "TGeoManager.h"
17 
18 #include <algorithm>
19 #include <cassert>
20 
21 namespace {
24  void CheckIndependentPlanesOnSameTPC(geo::PlaneID const& pid1,
25  geo::PlaneID const& pid2,
26  const char* caller)
27  {
28  if (pid1.asTPCID() != pid2.asTPCID()) {
29  throw cet::exception("GeometryCore")
30  << caller << " needs two planes on the same TPC (got " << std::string(pid1) << " and "
31  << std::string(pid2) << ")\n";
32  }
33  if (pid1 == pid2) {
34  throw cet::exception("GeometryCore")
35  << caller << " needs two different planes, got " << std::string(pid1) << " twice\n";
36  }
37  }
38 
39  //......................................................................
40  std::vector<double> Pitches(std::vector<geo::PlaneGeo> const& planes)
41  {
42  std::vector<double> result;
43  result.reserve(planes.size());
44  geo::Point_t refPlaneCenter = planes[0].GetCenter();
45  for (size_t p = 0; p < planes.size(); ++p) {
46  geo::Point_t const& center = planes[p].GetCenter();
47  result[p] = (p == 0) ? 0.0 : result[p - 1] + std::abs(center.X() - refPlaneCenter.X());
48  refPlaneCenter = center;
49  }
50  return result;
51  }
52 
53  //......................................................................
54  std::set<geo::View_t> Views(std::vector<geo::PlaneGeo> const& planes)
55  {
56  std::set<geo::View_t> result;
57  std::transform(planes.cbegin(),
58  planes.cend(),
59  std::inserter(result, result.begin()),
60  [](auto const& plane) { return plane.View(); });
61  return result;
62  }
63 }
64 
65 namespace geo {
66 
68  std::unique_ptr<WireReadoutGeometryBuilder> builder,
69  std::unique_ptr<WireReadoutSorter> sorter)
72  , fGeom{geom}
73  {
74  GeoNodePath path{geom->ROOTGeoManager()->GetTopNode()};
75  auto planesPerTPC = builder->extractPlanes(path);
76 
77  Compare<WireGeo> compareWires = [&sorter](auto const& a, auto const& b) {
78  return sorter->compareWires(a, b);
79  };
80 
81  // Update views
82  std::set<View_t> updatedViews;
83  for (auto const& tpc : fGeom->Iterate<TPCGeo>()) {
84  auto& planes = fPlanes[tpc.ID()] = planesPerTPC.at(tpc.Hash());
85  SortPlanes(tpc.ID(), planes);
86  SortSubVolumes(planes, compareWires);
87  UpdateAfterSorting(tpc, planes);
88 
89  auto const& TPCviews = ::Views(planes);
90  updatedViews.insert(TPCviews.cbegin(), TPCviews.cend());
91  fPlane0Pitch[tpc.ID()] = Pitches(planes);
92  }
93  allViews = std::move(updatedViews);
94  }
96 
97  //......................................................................
98  void WireReadoutGeom::SortPlanes(TPCID const& tpcid, std::vector<PlaneGeo>& planes) const
99  {
100  // Sort planes by increasing drift distance.
101  //
102  // This function should work in bootstrap mode, relying on least things as
103  // possible. Therefore we compute here a proxy of the drift axis.
104 
105  // Determine the drift axis (or close to): from TPC center to plane center
106 
107  // Instead of using the plane center, which might be not available yet, we use the
108  // plane box center, which only needs the geometry description to be available.
109 
110  // We use the first plane -- it does not make any difference.
111  auto const TPCcenter = fGeom->TPC(tpcid).GetCenter();
112  auto const driftAxis = vect::normalize(planes[0].GetBoxCenter() - TPCcenter);
113 
114  auto by_distance = [&TPCcenter, &driftAxis](auto const& a, auto const& b) {
115  return vect::dot(a.GetBoxCenter() - TPCcenter, driftAxis) <
116  vect::dot(b.GetBoxCenter() - TPCcenter, driftAxis);
117  };
118  cet::sort_all(planes, by_distance);
119  }
120 
121  //......................................................................
122  // Returns distance between plane 0 to each of the remaining planes not the distance
123  // between two consecutive planes
124  double WireReadoutGeom::Plane0Pitch(TPCID const& tpcid, unsigned int p) const
125  {
126  return fPlane0Pitch.at(tpcid)[p];
127  }
128 
129  //......................................................................
130  double WireReadoutGeom::PlanePitch(TPCID const& tpcid, unsigned int p1, unsigned int p2) const
131  {
132  auto const& plane0_pitch = fPlane0Pitch.at(tpcid);
133  return std::abs(plane0_pitch[p2] - plane0_pitch[p1]);
134  }
135 
136  //......................................................................
137  // Sort the PlaneGeo objects and the WireGeo objects inside
138  void WireReadoutGeom::SortSubVolumes(std::vector<PlaneGeo>& planes,
139  Compare<WireGeo> compareWires) const
140  {
141  for (PlaneGeo& plane : planes)
142  plane.SortWires(compareWires);
143  }
144 
145  //......................................................................
146  void WireReadoutGeom::UpdateAfterSorting(TPCGeo const& tpc, std::vector<PlaneGeo>& planes)
147  {
148  // ask the planes to update; also check
149  for (unsigned int p = 0; p < planes.size(); ++p) {
150  planes[p].UpdateAfterSorting(PlaneID(tpc.ID(), p), tpc);
151 
152  // check that the plane normal is opposite to the TPC drift direction
153  assert(lar::util::makeVector3DComparison(1e-5).equal(-(planes[p].GetNormalDirection()),
154  tpc.DriftDir()));
155  }
156  }
157 
158  //......................................................................
159  // Number of different views, or wire orientations
160  unsigned int WireReadoutGeom::Nviews() const
161  {
162  return MaxPlanes();
163  }
164 
165  //......................................................................
166  unsigned int WireReadoutGeom::MaxPlanes() const
167  {
168  unsigned int maxPlanes = 0;
169  for (auto const& [tpc_id, planes] : fPlanes) {
170  unsigned int maxPlanesInTPC = planes.size();
171  if (maxPlanesInTPC > maxPlanes) maxPlanes = maxPlanesInTPC;
172  }
173  return maxPlanes;
174  }
175 
176  //......................................................................
177  unsigned int WireReadoutGeom::MaxWires() const
178  {
179  unsigned int maxWires = 0;
180  for (PlaneGeo const& plane : Iterate<PlaneGeo>()) {
181  unsigned int maxWiresInPlane = plane.Nwires();
182  if (maxWiresInPlane > maxWires) maxWires = maxWiresInPlane;
183  }
184  return maxWires;
185  }
186 
187  //......................................................................
188  bool WireReadoutGeom::HasPlane(PlaneID const& planeid) const
189  {
190  return PlanePtr(planeid) != nullptr;
191  }
192 
193  //......................................................................
194  unsigned int WireReadoutGeom::Nplanes(TPCID const& tpcid) const
195  {
196  auto it = fPlanes.find(tpcid);
197  if (it == fPlanes.cend()) { return 0; }
198  return it->second.size();
199  }
200 
201  //......................................................................
202  PlaneGeo const& WireReadoutGeom::FirstPlane(TPCID const& tpcid) const
203  {
204  if (auto const* plane_ptr = PlanePtr({tpcid, 0})) { return *plane_ptr; }
205  throw cet::exception("WireReadoutGeom")
206  << "TPC with ID " << tpcid << " does not have a first plane.";
207  }
208 
209  //......................................................................
210  PlaneGeo const& WireReadoutGeom::Plane(TPCID const& tpcid, View_t const view) const
211  {
212  auto it = fPlanes.find(tpcid);
213  if (it == fPlanes.cend()) {
214  throw cet::exception("WireReadoutGeom") << "No TPC with ID " << tpcid << " supported.";
215  }
216  for (PlaneGeo const& plane : it->second) {
217  if (plane.View() == view) { return plane; }
218  }
219  throw cet::exception("WireReadoutGeom")
220  << "TPCGeo " << tpcid << " has no plane for view #" << (size_t)view << "\n";
221  }
222 
223  //......................................................................
224  PlaneGeo const& WireReadoutGeom::Plane(PlaneID const& planeid) const
225  {
226  if (auto const* plane_ptr = PlanePtr(planeid)) { return *plane_ptr; }
227  throw cet::exception("WireReadoutGeom") << "Plane with ID " << planeid << " is not supported.";
228  }
229 
230  //......................................................................
231  PlaneGeo const* WireReadoutGeom::PlanePtr(PlaneID const& planeid) const
232  {
233  auto const [tpc_id, plane] = std::make_pair(planeid.parentID(), planeid.Plane);
234  auto it = fPlanes.find(tpc_id);
235  if (it == fPlanes.cend()) { return nullptr; }
236  if (std::size_t const n = it->second.size(); n <= plane) { return nullptr; }
237  return &it->second[plane];
238  }
239 
240  //......................................................................
241  std::set<View_t> WireReadoutGeom::Views(TPCID const& tpcid) const
242  {
243  auto it = fPlanes.find(tpcid);
244  if (it == fPlanes.cend()) { return {}; }
245  return ::Views(it->second);
246  }
247 
248  //......................................................................
249  unsigned int WireReadoutGeom::Nwires(PlaneID const& planeid) const
250  {
251  PlaneGeo const* pPlane = PlanePtr(planeid);
252  return pPlane ? pPlane->NElements() : 0;
253  }
254 
255  //......................................................................
256  bool WireReadoutGeom::HasWire(WireID const& wireid) const
257  {
258  PlaneGeo const* pPlane = PlanePtr(wireid);
259  return pPlane ? pPlane->HasWire(wireid) : false;
260  }
261 
262  //......................................................................
263  WireGeo const* WireReadoutGeom::WirePtr(WireID const& wireid) const
264  {
265  PlaneGeo const* pPlane = PlanePtr(wireid);
266  return pPlane ? pPlane->WirePtr(wireid) : nullptr;
267  }
268 
269  //......................................................................
270  WireGeo const& WireReadoutGeom::Wire(WireID const& wireid) const
271  {
272  return Plane(wireid).Wire(wireid);
273  }
274 
275  //......................................................................
276  void WireReadoutGeom::WireEndPoints(WireID const& wireid, double* xyzStart, double* xyzEnd) const
277  {
278  auto const [start, end] = WireEndPoints(wireid);
279 
280  xyzStart[0] = start.X();
281  xyzStart[1] = start.Y();
282  xyzStart[2] = start.Z();
283  xyzEnd[0] = end.X();
284  xyzEnd[1] = end.Y();
285  xyzEnd[2] = end.Z();
286 
287  if (xyzEnd[2] < xyzStart[2]) {
288  // Ensure that "End" has higher z-value than "Start"
289  std::swap(xyzStart[0], xyzEnd[0]);
290  std::swap(xyzStart[1], xyzEnd[1]);
291  std::swap(xyzStart[2], xyzEnd[2]);
292  }
293  if (xyzEnd[1] < xyzStart[1] && std::abs(xyzEnd[2] - xyzStart[2]) < 0.01) {
294  // If wire is vertical ensure that "End" has higher y-value than "Start"
295  std::swap(xyzStart[0], xyzEnd[0]);
296  std::swap(xyzStart[1], xyzEnd[1]);
297  std::swap(xyzStart[2], xyzEnd[2]);
298  }
299  }
300 
301  //......................................................................
302  std::optional<WireIDIntersection> WireReadoutGeom::WireIDsIntersect(WireID const& wid1,
303  WireID const& wid2) const
304  {
305  if (!WireIDIntersectionCheck(wid1, wid2)) { return std::nullopt; }
306 
307  // get the endpoints to see if wires intersect
308  Segment const w1 = WireEndPoints(wid1);
309  Segment const w2 = WireEndPoints(wid2);
310 
311  // TODO extract the coordinates in the right way;
312  // is it any worth, since then the result is in (y, z), whatever it means?
313  WireIDIntersection result;
314  bool const cross = IntersectLines(start(w1).Y(),
315  start(w1).Z(),
316  finish(w1).Y(),
317  finish(w1).Z(),
318  start(w2).Y(),
319  start(w2).Z(),
320  finish(w2).Y(),
321  finish(w2).Z(),
322  result.y,
323  result.z);
324  if (!cross) { return std::nullopt; }
325 
326  bool const within = lar::util::PointWithinSegments(start(w1).Y(),
327  start(w1).Z(),
328  finish(w1).Y(),
329  finish(w1).Z(),
330  start(w2).Y(),
331  start(w2).Z(),
332  finish(w2).Y(),
333  finish(w2).Z(),
334  result.y,
335  result.z);
336 
337  if (!within) { return std::nullopt; }
338 
339  result.TPC = wid1.TPC;
340  return result;
341  }
342 
343  //......................................................................
345  WireID const& wid2,
346  Point_t& intersection) const
347  {
348  // This is not a real 3D intersection: the wires do not cross, since they are required
349  // to belong to two different planes.
350  //
351  // We take the point on the first wire which is closest to the other one.
352  static_assert(std::numeric_limits<decltype(intersection.X())>::has_infinity,
353  "the vector coordinate type can't represent infinity!");
354  constexpr auto infinity = std::numeric_limits<decltype(intersection.X())>::infinity();
355 
356  if (!WireIDIntersectionCheck(wid1, wid2)) {
357  intersection = {infinity, infinity, infinity};
358  return false;
359  }
360 
361  WireGeo const& wire1 = Wire(wid1);
362  WireGeo const& wire2 = Wire(wid2);
363 
364  // Distance of the intersection point from the center of the two wires:
365  IntersectionPointAndOffsets<Point_t> intersectionAndOffset =
366  WiresIntersectionAndOffsets(wire1, wire2);
367  intersection = intersectionAndOffset.point;
368 
369  return std::abs(intersectionAndOffset.offset1) <= wire1.HalfL() &&
370  std::abs(intersectionAndOffset.offset2) <= wire2.HalfL();
371  }
372 
373  //......................................................................
374  // This method returns the distance between wires in the specified view it assumes all
375  // planes of a given view have the same pitch
376  double WireReadoutGeom::WireAngleToVertical(View_t view, TPCID const& tpcid) const
377  {
378  for (PlaneGeo const& plane : Iterate<PlaneGeo>(tpcid)) {
379  if (plane.View() == view) return plane.ThetaZ();
380  } // for
381  throw cet::exception("WireReadoutGeom")
382  << "WireAngleToVertical(): no view \"" << PlaneGeo::ViewName(view) << "\" (#" << ((int)view)
383  << ") in " << std::string(tpcid);
384  }
385 
386  //----------------------------------------------------------------------------
387  unsigned int WireReadoutGeom::NOpChannels(unsigned int NOpDets) const
388  {
389  // By default just return the number of optical detectos
390  return NOpDets;
391  }
392 
393  //----------------------------------------------------------------------------
394  unsigned int WireReadoutGeom::MaxOpChannel(unsigned int NOpDets) const
395  {
396  // By default just return the number of optical detectos
397  return NOpChannels(NOpDets);
398  }
399 
400  //----------------------------------------------------------------------------
401  unsigned int WireReadoutGeom::NOpHardwareChannels(unsigned int /*opDet*/) const
402  {
403  // By default, 1 channel per optical detector
404  return 1;
405  }
406 
407  //----------------------------------------------------------------------------
408  unsigned int WireReadoutGeom::OpChannel(unsigned int detNum, unsigned int /* channel */) const
409  {
410  return detNum;
411  }
412 
413  //----------------------------------------------------------------------------
414  unsigned int WireReadoutGeom::OpDetFromOpChannel(unsigned int opChannel) const
415  {
416  return opChannel;
417  }
418 
419  //----------------------------------------------------------------------------
420  OpDetGeo const& WireReadoutGeom::OpDetGeoFromOpChannel(unsigned int opChannel) const
421  {
422  return fGeom->OpDetGeoFromOpDet(OpDetFromOpChannel(opChannel));
423  }
424 
425  //----------------------------------------------------------------------------
426  unsigned int WireReadoutGeom::HardwareChannelFromOpChannel(unsigned int /* opChannel */) const
427  {
428  return 0;
429  }
430 
431  //----------------------------------------------------------------------------
432  bool WireReadoutGeom::IsValidOpChannel(unsigned int opChannel, unsigned int NOpDets) const
433  {
434  // Check channel number
435  if (opChannel >= NOpChannels(NOpDets)) return false;
436 
437  // Check opdet number
438  unsigned int opdet = OpDetFromOpChannel(opChannel);
439  if (opdet >= NOpDets) return false;
440 
441  // Check hardware channel number
442  unsigned int hChan = HardwareChannelFromOpChannel(opChannel);
443  return hChan < NOpHardwareChannels(opdet);
444  }
445 
447  {
448  return SignalTypeForChannelImpl(channel);
449  }
450 
452  {
453  return SignalTypeForROPIDImpl(ropid);
454  }
455 
457  {
458  return SignalType(FirstChannelInROP(ropid));
459  }
460 
461  //......................................................................
462  std::vector<raw::ChannelID_t> WireReadoutGeom::ChannelsInTPCs() const
463  {
464  std::vector<raw::ChannelID_t> channels;
465  channels.reserve(Nchannels());
466 
467  for (auto const& ts : Iterate<readout::TPCsetID>()) {
468  for (auto const t : TPCsetToTPCs(ts)) {
469  for (auto const& wire : Iterate<WireID>(t)) {
470  channels.push_back(PlaneWireToChannel(wire));
471  }
472  }
473  }
474  std::sort(channels.begin(), channels.end());
475  auto last = std::unique(channels.begin(), channels.end());
476  channels.erase(last, channels.end());
477  return channels;
478  }
479 
480  //......................................................................
481  unsigned int WireReadoutGeom::NOpChannels() const
482  {
483  return NOpChannels(fGeom->NOpDets());
484  }
485 
486  //......................................................................
487  unsigned int WireReadoutGeom::MaxOpChannel() const
488  {
489  return MaxOpChannel(fGeom->NOpDets());
490  }
491 
492  //......................................................................
493  bool WireReadoutGeom::IsValidOpChannel(int opChannel) const
494  {
495  return IsValidOpChannel(opChannel, fGeom->NOpDets());
496  }
497 
498  //......................................................................
500  {
501  // map wire plane -> readout plane -> first channel, then use SignalType(channel)
502 
503  auto const ropid = WirePlaneToROP(pid);
504  if (!ropid.isValid) {
505  throw cet::exception("WireReadoutGeom") << "SignalType(): Mapping of wire plane "
506  << std::string(pid) << " to readout plane failed!\n";
507  }
508  return SignalType(ropid);
509  }
510 
511  //......................................................................
513  {
514  auto const pid = FirstWirePlaneInROP(ropid);
515  return pid ? Plane(pid).View() : kUnknown;
516  }
517 
519  {
520  return (channel == raw::InvalidChannelID) ? kUnknown : View(ChannelToROP(channel));
521  }
522 
523  //----------------------------------------------------------------------------
525  PlaneID const& planeid) const
526  {
527  // This method is supposed to return a channel number rather than a wire number.
528  // Perform the conversion here (although, maybe faster if we deal in wire numbers
529  // rather than channel numbers?)
530 
531  // NOTE on failure both NearestChannel() and upstream:
532  // * according to documentation, should return invalid channel
533  // * in the actual code throw an exception because of a BUG
534  //
535  // The following implementation automatically becomes in fact compliant to the
536  // documentation if upstreams becomes compliant to. When that happens, just delete
537  // this comment.
538  WireID const wireID = Plane(planeid).NearestWireID(worldPos);
539  return wireID ? PlaneWireToChannel(wireID) : raw::InvalidChannelID;
540  }
541 
542  //......................................................................
543  std::optional<WireIDIntersection> WireReadoutGeom::ChannelsIntersect(
544  raw::ChannelID_t const c1,
545  raw::ChannelID_t const c2) const
546  {
547  // [GP] these errors should be exceptions, and this function is deprecated because it
548  // violates interoperability
549  std::vector<WireID> chan1wires = ChannelToWire(c1);
550  if (chan1wires.empty()) {
551  mf::LogError("ChannelsIntersect")
552  << "1st channel " << c1 << " maps to no wire (is it a real one?)";
553  return std::nullopt;
554  }
555  std::vector<WireID> chan2wires = ChannelToWire(c2);
556  if (chan2wires.empty()) {
557  mf::LogError("ChannelsIntersect")
558  << "2nd channel " << c2 << " maps to no wire (is it a real one?)";
559  return std::nullopt;
560  }
561 
562  if (chan1wires.size() > 1) {
563  mf::LogWarning("ChannelsIntersect")
564  << "1st channel " << c1 << " maps to " << chan2wires.size() << " wires; using the first!";
565  return std::nullopt;
566  }
567  if (chan2wires.size() > 1) {
568  mf::LogError("ChannelsIntersect")
569  << "2nd channel " << c2 << " maps to " << chan2wires.size() << " wires; using the first!";
570  return std::nullopt;
571  }
572 
573  return WireIDsIntersect(chan1wires[0], chan2wires[0]);
574  }
575 
577  {
578  return TPCtoTPCset(fGeom->FindTPCAtPosition(worldLoc));
579  }
580 
581  //--------------------------------------------------------------------
582  bool WireReadoutGeom::WireIDIntersectionCheck(WireID const& wid1, WireID const& wid2) const
583  {
584  if (wid1.asTPCID() != wid2) {
585  mf::LogError("WireIDIntersectionCheck")
586  << "Comparing two wires on different TPCs: return failure.";
587  return false;
588  }
589  if (wid1.Plane == wid2.Plane) {
590  mf::LogError("WireIDIntersectionCheck")
591  << "Comparing two wires in the same plane: return failure";
592  return false;
593  }
594  if (!HasWire(wid1)) {
595  mf::LogError("WireIDIntersectionCheck")
596  << "1st wire " << wid1 << " does not exist (max wire number: " << Nwires(wid1.planeID())
597  << ")";
598  return false;
599  }
600  if (!HasWire(wid2)) {
601  mf::LogError("WireIDIntersectionCheck")
602  << "2nd wire " << wid2 << " does not exist (max wire number: " << Nwires(wid2.planeID())
603  << ")";
604  return false;
605  }
606  return true;
607  }
608 
609  //----------------------------------------------------------------------------
610  PlaneID WireReadoutGeom::ThirdPlane(PlaneID const& pid1, PlaneID const& pid2) const
611  {
612  // how many planes in the TPC pid1 belongs to:
613  unsigned const int nPlanes = Nplanes(pid1);
614  if (nPlanes != 3) {
615  throw cet::exception("GeometryCore")
616  << "ThirdPlane() supports only TPCs with 3 planes, and I see " << nPlanes << " instead\n";
617  }
618 
619  PlaneID::PlaneID_t target_plane = nPlanes;
620  for (PlaneID::PlaneID_t iPlane = 0; iPlane < nPlanes; ++iPlane) {
621  if ((iPlane == pid1.Plane) || (iPlane == pid2.Plane)) continue;
622  if (target_plane != nPlanes) {
623  throw cet::exception("GeometryCore")
624  << "ThirdPlane() found too many planes that are not " << std::string(pid1) << " nor "
625  << std::string(pid2) << "! (first " << target_plane << ", then " << iPlane << ")\n";
626  } // if we had a target already
627  target_plane = iPlane;
628  } // for
629  if (target_plane == nPlanes) {
630  throw cet::exception("GeometryCore")
631  << "ThirdPlane() can't find a plane that is not " << std::string(pid1) << " nor "
632  << std::string(pid2) << "!\n";
633  }
634 
635  return PlaneID(pid1, target_plane);
636  }
637 
638  //----------------------------------------------------------------------------
640  double slope1,
641  PlaneID const& pid2,
642  double slope2,
643  PlaneID const& output_plane) const
644  {
645  CheckIndependentPlanesOnSameTPC(pid1, pid2, "ThirdPlaneSlope()");
646 
647  // We need the "wire coordinate direction" for each plane. This is perpendicular to
648  // the wire orientation. PlaneGeo::PhiZ() defines the right orientation too.
649  return ComputeThirdPlaneSlope(
650  Plane(pid1).PhiZ(), slope1, Plane(pid2).PhiZ(), slope2, Plane(output_plane).PhiZ());
651  }
652 
653  //----------------------------------------------------------------------------
655  double slope1,
656  PlaneID const& pid2,
657  double slope2) const
658  {
659  return ThirdPlaneSlope(pid1, slope1, pid2, slope2, ThirdPlane(pid1, pid2));
660  }
661 
662  //----------------------------------------------------------------------------
664  double slope1,
665  PlaneID const& pid2,
666  double slope2,
667  PlaneID const& output_plane) const
668  {
669  CheckIndependentPlanesOnSameTPC(pid1, pid2, "ThirdPlane_dTdW()");
670 
671  double angle[3], pitch[3];
672  PlaneGeo const* const planes[3] = {&Plane(pid1), &Plane(pid2), &Plane(output_plane)};
673 
674  // We need wire pitch and "wire coordinate direction" for each plane. The latter is
675  // perpendicular to the wire orientation. PlaneGeo::PhiZ() defines the right
676  // orientation too.
677  for (size_t i = 0; i < 3; ++i) {
678  angle[i] = planes[i]->PhiZ();
679  pitch[i] = planes[i]->WirePitch();
680  }
681 
682  return ComputeThirdPlane_dTdW(
683  angle[0], pitch[0], slope1, angle[1], pitch[1], slope2, angle[2], pitch[2]);
684  }
685 
686  //----------------------------------------------------------------------------
688  double slope1,
689  PlaneID const& pid2,
690  double slope2) const
691  {
692  return ThirdPlane_dTdW(pid1, slope1, pid2, slope2, ThirdPlane(pid1, pid2));
693  }
694 
695  //----------------------------------------------------------------------------
696  // Given slopes dTime/dWire in two planes, return with the slope in the 3rd plane.
697  // Requires slopes to be in the same metrics, e.g. converted in a distances ratio.
698 
699  // Note: Uses equation in H. Greenlee's talk:
700  // https://cdcvs.fnal.gov/redmine/attachments/download/1821/larsoft_apr20_2011.pdf
701  // slide 2
703  double slope1,
704  double angle2,
705  double slope2,
706  double angle3)
707  {
708  // note that, if needed, the trigonometric functions can be pre-calculated.
709 
710  // Can't resolve very small slopes
711  if ((std::abs(slope1) < 0.001) && (std::abs(slope2)) < 0.001) return 0.001;
712 
713  // We need the "wire coordinate direction" for each plane. This is perpendicular to
714  // the wire orientation.
715  double slope3 = 0.001;
716  if (std::abs(slope1) > 0.001 && std::abs(slope2) > 0.001) {
717  slope3 =
718  (+(1. / slope1) * std::sin(angle3 - angle2) - (1. / slope2) * std::sin(angle3 - angle1)) /
719  std::sin(angle1 - angle2);
720  }
721  if (slope3 != 0.)
722  slope3 = 1. / slope3;
723  else
724  slope3 = 999.;
725 
726  return slope3;
727  }
728 
729  //----------------------------------------------------------------------------
731  double pitch1,
732  double dTdW1,
733  double angle2,
734  double pitch2,
735  double dTdW2,
736  double angle_target,
737  double pitch_target)
738  {
739  // we need to convert dt/dw into homogeneous coordinates, and then back;
740  // slope = [dT * (TDCperiod / driftVelocity)] / [dW * wirePitch]
741  // The coefficient of dT is assumed to be the same for all the planes, and it finally
742  // cancels out. Pitches cancel out only if they are all the same.
743  return pitch_target *
744  ComputeThirdPlaneSlope(angle1, dTdW1 / pitch1, angle2, dTdW2 / pitch2, angle_target);
745  }
746 
747 }
unsigned int NElements() const
Number of wires in this plane.
Definition: PlaneGeo.h:232
Geometry description of a TPC wireThe wire is a single straight segment on a wire plane...
Definition: WireGeo.h:112
virtual readout::ROPID ChannelToROP(raw::ChannelID_t channel) const =0
Returns the ID of the ROP the channel belongs to.
double z
z position of intersection
Definition: geo_types.h:584
Functions to help with numbers.
PlaneID ThirdPlane(PlaneID const &pid1, PlaneID const &pid2) const
Returns the plane that is not in the specified arguments.
static auto const & start(Segment const &s)
unsigned int Nwires(PlaneID const &planeid) const
Returns the total number of wires in the specified plane.
static std::string ViewName(View_t view)
Returns the name of the specified view.
Definition: PlaneGeo.cxx:584
double Plane0Pitch(TPCID const &tpcid, unsigned int p1) const
PlaneGeo const * PlanePtr(PlaneID const &planeid) const
Returns the specified plane.
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
WireID NearestWireID(Point_t const &pos) const
Returns the ID of wire closest to the specified position.
Definition: PlaneGeo.cxx:485
bool IsValidOpChannel(int opChannel) const
Is this a valid OpChannel number?
Unknown view.
Definition: geo_types.h:138
static double ComputeThirdPlane_dTdW(double angle1, double pitch1, double dTdW1, double angle2, double pitch2, double dTdW2, double angle_target, double pitch_target)
Returns the slope on the third plane, given it in the other two.
bool HasWire(WireID const &wireid) const
Returns whether we have the specified wire.
virtual unsigned int Nchannels() const =0
Returns the total number of channels present (not necessarily contiguous)
void SortPlanes(TPCID const &tpcid, std::vector< PlaneGeo > &planes) const
Sorts (in place) the specified PlaneGeo objects by drift distance.
unsigned int PlaneID_t
Type for the ID number.
Definition: geo_types.h:365
The data type to uniquely identify a Plane.
Definition: geo_types.h:364
Geometry information for a single TPC.
Definition: TPCGeo.h:33
Class identifying a set of TPC sharing readout channels.
Definition: readout_types.h:54
constexpr auto abs(T v)
Returns the absolute value of the argument.
virtual unsigned int OpDetFromOpChannel(unsigned int opChannel) const
Returns the optical detector the specified optical channel belongs.
WireGeo const & Wire(unsigned int iwire) const
Definition: PlaneGeo.cxx:403
virtual unsigned int NOpHardwareChannels(unsigned int opDet) const
Returns the number of channels in the specified optical detectors.
double WireAngleToVertical(View_t view, TPCID const &tpcid) const
Returns the angle of the wires in the specified view from vertical.
double PlanePitch(TPCID const &tpcid, unsigned int p1=0, unsigned int p2=1) const
WireGeo const * WirePtr(WireID const &wireid) const
Returns the specified wire.
SigType_t SignalType(PlaneID const &pid) const
Returns the type of signal on the channels of specified TPC plane.
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.
unsigned int TPC
TPC of intersection.
Definition: geo_types.h:585
std::map< TPCID, std::vector< PlaneGeo > > fPlanes
bool HasPlane(PlaneID const &planeid) const
Returns whether we have the specified plane.
std::map< TPCID, std::vector< double > > fPlane0Pitch
Pitch between planes.
bool PointWithinSegments(double A_start_x, double A_start_y, double A_end_x, double A_end_y, double B_start_x, double B_start_y, double B_end_x, double B_end_y, double x, double y)
Returns whether x and y are within both specified ranges (A and B).
WireReadoutGeom(GeometryCore const *geom, std::unique_ptr< WireReadoutGeometryBuilder > builder, std::unique_ptr< WireReadoutSorter > sorter)
WireGeo const & Wire(WireID const &wireid) const
Returns the specified wire.
virtual PlaneID FirstWirePlaneInROP(readout::ROPID const &ropid) const =0
Returns the ID of the first plane belonging to the specified ROP.
double offset2
Distance from reference point of second line.
IDparameter< geo::PlaneID > PlaneID
Member type of validated geo::PlaneID parameter.
std::vector< raw::ChannelID_t > ChannelsInTPCs() const
Returns an std::vector<ChannelID_t> in all TPCs in a TPCSet.
IntersectionPointAndOffsets< Point_t > WiresIntersectionAndOffsets(WireGeo const &wireA, WireGeo const &wireB)
Returns the point of wireA that is closest to wireB.
Definition: WireGeo.h:516
bool IntersectLines(double A_start_x, double A_start_y, double A_end_x, double A_end_y, double B_start_x, double B_start_y, double B_end_x, double B_end_y, double &x, double &y)
Computes the intersection between two lines on a plane.
Access the description of the physical detector geometry.
static double ComputeThirdPlaneSlope(double angle1, double slope1, double angle2, double slope2, double angle_target)
Returns the slope on the third plane, given it in the other two.
OpDetGeo const & OpDetGeoFromOpChannel(unsigned int opChannel) const
Returns the optical detector the specified optical channel belongs.
Point_t GetCenter() const
Returns the center of the TPC volume in world coordinates [cm].
Definition: TPCGeo.h:132
View_t View() const
Which coordinate does this plane measure.
Definition: PlaneGeo.h:155
readout::TPCsetID FindTPCsetAtPosition(Point_t const &worldLoc) const
Returns the total number of TPC sets in the specified cryostat.
unsigned int MaxPlanes() const
Returns the largest number of planes among all TPCs in this detector.
constexpr ChannelID_t InvalidChannelID
ID of an invalid channel.
Definition: RawTypes.h:31
TPCID FindTPCAtPosition(Point_t const &point) const
Returns the ID of the TPC at specified location.
std::set< View_t > const & Views() const
Returns a list of possible views in the detector.
TCanvas * c1
Definition: plotHisto.C:7
auto makeVector3DComparison(RealType threshold)
Creates a Vector3DComparison from a RealComparisons object.
TCanvas * c2
Definition: plot_hist.C:75
void UpdateAfterSorting(TPCGeo const &tpc, std::vector< PlaneGeo > &planes)
std::function< bool(T const &, T const &)> Compare
Definition: fwd.h:22
virtual readout::ROPID WirePlaneToROP(PlaneID const &planeid) const =0
Returns the ID of the ROP planeid belongs to.
double PhiZ() const
Angle from positive z axis of the wire coordinate axis, in radians.
Definition: PlaneGeo.h:164
static auto const & finish(Segment const &s)
enum geo::_plane_sigtype SigType_t
Enumerate the possible plane projections.
std::pair< Point_t, Point_t > Segment
unsigned int MaxWires() const
Returns the total number of wires in the specified plane.
Geometry information for a single wire plane.The plane is represented in the geometry by a solid whic...
Definition: PlaneGeo.h:67
unsigned int Nviews() const
Returns the number of views (different wire orientations)
virtual SigType_t SignalTypeForROPIDImpl(readout::ROPID const &ropid) const
Return the signal type on the specified readout plane.
virtual raw::ChannelID_t PlaneWireToChannel(WireID const &wireID) const =0
Returns the channel ID a wire is connected to.
void SortSubVolumes(std::vector< PlaneGeo > &planes, Compare< WireGeo > compareWires) const
double ThirdPlane_dTdW(PlaneID const &pid1, double slope1, PlaneID const &pid2, double slope2, PlaneID const &output_plane) const
Returns dT/dW on the third plane, given it in the other two.
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
constexpr auto dot(Vector const &a, OtherVector const &b)
Return cross product of two vectors.
Description of the physical geometry of one entire detector.
Definition: GeometryCore.h:91
Point point
Intersection point.
Class identifying a set of planes sharing readout channels.
unsigned int NOpDets() const
Number of OpDets in the whole detector.
raw::ChannelID_t NearestChannel(Point_t const &worldLoc, PlaneID const &planeid) const
Returns the ID of the channel nearest to the specified position.
bool WireIDsIntersect(WireID const &wid1, WireID const &wid2, Point_t &intersection) const
Computes the intersection between two wires.
unsigned int Nplanes(TPCID const &tpcid=details::tpc_zero) const
Returns the total number of planes in the specified TPC.
Encapsulate the geometry of an auxiliary detector.
virtual ~WireReadoutGeom()
double HalfL() const
Returns half the length of the wire [cm].
Definition: WireGeo.h:170
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
virtual unsigned int HardwareChannelFromOpChannel(unsigned int opChannel) const
Returns the hardware channel number of specified optical channel.
PlaneGeo const & FirstPlane(TPCID const &tpcid) const
Returns the first plane of the specified TPC.
virtual std::vector< WireID > ChannelToWire(raw::ChannelID_t channel) const =0
bool HasWire(unsigned int iwire) const
Returns whether a wire with index iwire is present in this plane.
Definition: PlaneGeo.h:241
auto WirePtr(unsigned int iwire) const
Returns the wire number iwire from this plane.
Definition: PlaneGeo.h:282
View_t View(raw::ChannelID_t const channel) const
Returns the view (wire orientation) on the specified TPC channel.
unsigned int MaxOpChannel() const
Largest optical channel number.
double y
y position of intersection
Definition: geo_types.h:583
virtual std::vector< TPCID > TPCsetToTPCs(readout::TPCsetID const &tpcsetid) const =0
Returns a list of ID of TPCs belonging to the specified TPC set.
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
range_type< T > Iterate() const
Definition: Iterable.h:121
virtual raw::ChannelID_t FirstChannelInROP(readout::ROPID const &ropid) const =0
Returns the ID of the first channel in the specified readout plane.
unsigned int NOpChannels() const
Number of electronics channels for all the optical detectors.
Data structure for return values of LineClosestPointAndOffsets().
Representation of a node and its ancestry.
Definition: GeoNodePath.h:34
Char_t n[5]
bool WireIDIntersectionCheck(WireID const &wid1, WireID const &wid2) const
Wire ID check for WireIDsIntersect methods.
GeometryCore const * fGeom
constexpr PlaneID const & planeID() const
Definition: geo_types.h:471
PlaneGeo const & Plane(TPCID const &tpcid, View_t view) const
Returns the specified wire.
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:28
Vector cross(Vector const &a, Vector const &b)
Return cross product of two vectors.
Vector normalize(Vector const &v)
Returns a vector parallel to v and with norm 1.
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:315
TPCGeo const & TPC(TPCID const &tpcid=details::tpc_zero) const
Returns the specified TPC.
Definition: GeometryCore.h:448
Float_t e
Definition: plot.C:35
Vector_t DriftDir() const
Returns the direction of the drift (vector pointing toward the planes).
Definition: TPCGeo.h:84
ROOT libraries.
virtual unsigned int OpChannel(unsigned int detNum, unsigned int hwchannel=0) const
Returns the channel ID of the specified hardware channel.
virtual SigType_t SignalTypeForChannelImpl(raw::ChannelID_t const channel) const =0
Return the signal type of the specified channel.
double offset1
Distance from reference point of first line.
TPCID const & ID() const
Returns the identifier of this TPC.
Definition: TPCGeo.h:147
void WireEndPoints(WireID const &wireid, double *xyzStart, double *xyzEnd) const
Fills two arrays with the coordinates of the wire end points.
std::set< View_t > allViews
All views in the detector.
Interface to geometry for wire readouts .
double ThirdPlaneSlope(PlaneID const &pid1, double slope1, PlaneID const &pid2, double slope2, PlaneID const &output_plane) const
Returns the slope on the third plane, given it in the other two.
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
double WirePitch() const
Return the wire pitch (in centimeters). It is assumed constant.
Definition: PlaneGeo.h:312
constexpr TPCID const & asTPCID() const
Conversion to PlaneID (for convenience of notation).
Definition: geo_types.h:409
OpDetGeo const & OpDetGeoFromOpDet(unsigned int OpDet) const
Returns the geo::OpDetGeo object for the given detector number.
constexpr ParentID_t const & parentID() const
Return the parent ID of this one (a TPC ID).
Definition: geo_types.h:402
virtual readout::TPCsetID TPCtoTPCset(TPCID const &tpcid) const =0
Returns the ID of the TPC set tpcid belongs to.