LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
GeometryCore.cxx
Go to the documentation of this file.
1 
9 // class header
11 
12 // lar includes
14 #include "larcorealg/CoreUtils/DereferenceIterator.h" // lar::util::dereferenceIteratorLoop()
19 #include "larcorealg/Geometry/Decomposer.h" // geo::vect::dot()
20 #include "larcorealg/Geometry/geo_vectors_utils.h" // geo::vect
22 
23 // Framework includes
24 #include "cetlib_except/exception.h"
26 
27 // ROOT includes
28 #include <TGeoManager.h>
29 #include <TGeoNode.h>
30 #include <TGeoVolume.h>
31 #include <TGeoMatrix.h>
32 #include <TGeoBBox.h>
33 #include <TGeoVolume.h>
34 // #include <Rtypes.h>
35 
36 // C/C++ includes
37 #include <cstddef> // size_t
38 #include <cctype> // ::tolower()
39 #include <cmath> // std::abs() ...
40 #include <vector>
41 #include <algorithm> // std::for_each(), std::transform()
42 #include <iterator> // std::back_inserter()
43 #include <utility> // std::swap()
44 #include <limits> // std::numeric_limits<>
45 #include <numeric> // std::accumulate
46 
47 
48 namespace geo {
49 
50  template <typename T>
51  inline T sqr(T v) { return v * v; }
52 
53 
54 
55  //......................................................................
57 
58 
59  //......................................................................
60  // Constructor.
62  fhicl::ParameterSet const& pset
63  )
64  : fSurfaceY (pset.get< double >("SurfaceY" ))
65  , fDetectorName (pset.get< std::string >("Name" ))
66  , fMinWireZDist (pset.get< double >("MinWireZDist", 3.0 ))
67  , fPositionWiggle (pset.get< double >("PositionEpsilon", 1.e-4))
68  {
69  std::transform(fDetectorName.begin(), fDetectorName.end(),
70  fDetectorName.begin(), ::tolower);
71  } // GeometryCore::GeometryCore()
72 
73 
74  //......................................................................
76  ClearGeometry();
77  } // GeometryCore::~GeometryCore()
78 
79 
80  //......................................................................
82  (std::shared_ptr<geo::ChannelMapAlg> pChannelMap)
83  {
84  SortGeometry(pChannelMap->Sorter());
85  UpdateAfterSorting(); // after channel mapping has sorted objects, set their IDs
86  pChannelMap->Initialize(fGeoData);
87  fChannelMapAlg = pChannelMap;
88 
89  } // GeometryCore::ApplyChannelMap()
90 
91  //......................................................................
93  std::string gdmlfile, std::string rootfile,
94  bool bForceReload /* = false*/
95  ) {
96 
97  if (gdmlfile.empty()) {
98  throw cet::exception("GeometryCore")
99  << "No GDML Geometry file specified!\n";
100  }
101 
102  if (rootfile.empty()) {
103  throw cet::exception("GeometryCore")
104  << "No ROOT Geometry file specified!\n";
105  }
106 
107  ClearGeometry();
108 
109  // Open the GDML file, and convert it into ROOT TGeoManager format.
110  // Then lock the gGeoManager to prevent future imports, for example
111  // in AuxDetGeometry
112  if( !gGeoManager || bForceReload ){
113  if (gGeoManager) TGeoManager::UnlockGeometry();
114  TGeoManager::Import(rootfile.c_str());
115  gGeoManager->LockGeometry();
116  }
117 
118  std::vector<const TGeoNode*> path(MaxWireDepthInGDML);
119  path[0] = gGeoManager->GetTopNode();
120  FindCryostat(path, 0);
121  FindAuxDet(path, 0);
122 
123  fGDMLfile = gdmlfile;
124  fROOTfile = rootfile;
125 
126  mf::LogInfo("GeometryCore") << "New detector geometry loaded from "
127  << "\n\t" << fROOTfile
128  << "\n\t" << fGDMLfile << "\n";
129 
130  } // GeometryCore::LoadGeometryFile()
131 
132  //......................................................................
134 
135  Cryostats().clear();
136 
137  // auxiliary detectors
138  std::for_each(AuxDets().begin(), AuxDets().end(),
139  std::default_delete<AuxDetGeo>());
140  AuxDets().clear();
141 
142  } // GeometryCore::ClearGeometry()
143 
144 
145  //......................................................................
147 
148  mf::LogInfo("GeometryCore") << "Sorting volumes...";
149 
150  sorter.SortAuxDets(AuxDets());
151 
152  //
153  // cryostats
154  //
156  [&sorter](auto& coll){ sorter.SortCryostats(coll); });
157 
159  for (geo::CryostatGeo& cryo: Cryostats())
160  {
161  cryo.SortSubVolumes(sorter);
162  cryo.UpdateAfterSorting(geo::CryostatID(c));
163  ++c;
164  } // for
165 
166  } // GeometryCore::SortGeometry()
167 
168 
169  //......................................................................
171 
172  for (size_t c = 0; c < Ncryostats(); ++c)
173  Cryostats()[c].UpdateAfterSorting(geo::CryostatID(c));
174 
175  allViews.clear();
176  for (geo::TPCGeo const& tpc: IterateTPCs()) {
177  auto const& TPCviews = tpc.Views();
178  allViews.insert(TPCviews.cbegin(), TPCviews.cend());
179  }
180 
181  } // GeometryCore::UpdateAfterSorting()
182 
183 
184  //......................................................................
185  TGeoManager* GeometryCore::ROOTGeoManager() const
186  {
187  return gGeoManager;
188  }
189 
190  //......................................................................
191  unsigned int GeometryCore::Nchannels() const
192  {
193  return fChannelMapAlg->Nchannels();
194  }
195 
196  //......................................................................
197  unsigned int GeometryCore::Nchannels(readout::ROPID const& ropid) const
198  {
199  return fChannelMapAlg->Nchannels(ropid);
200  } // GeometryCore::Nchannels(ROPID)
201 
202  //......................................................................
203  unsigned int GeometryCore::NOpDets() const
204  {
205  int N=0;
206  for(size_t cstat=0; cstat!=Ncryostats(); cstat++)
207  N += this->Cryostat(cstat).NOpDet();
208  return N;
209  }
210 
211  //......................................................................
212  unsigned int GeometryCore::NOpChannels() const
213  {
214  return fChannelMapAlg->NOpChannels(this->NOpDets());
215  }
216 
217  //......................................................................
218  unsigned int GeometryCore::MaxOpChannel() const
219  {
220  return fChannelMapAlg->MaxOpChannel(this->NOpDets());
221  }
222 
223  //......................................................................
224  unsigned int GeometryCore::NOpHardwareChannels(int opDet) const
225  {
226  return fChannelMapAlg->NOpHardwareChannels(opDet);
227  }
228 
229  //......................................................................
230  unsigned int GeometryCore::OpChannel(int detNum, int hardwareChannel) const
231  {
232  return fChannelMapAlg->OpChannel(detNum, hardwareChannel);
233  }
234 
235  //......................................................................
236  unsigned int GeometryCore::OpDetFromOpChannel(int opChannel) const
237  {
238  return fChannelMapAlg->OpDetFromOpChannel(opChannel);
239  }
240 
241  //......................................................................
242  unsigned int GeometryCore::HardwareChannelFromOpChannel(int opChannel) const
243  {
244  return fChannelMapAlg->HardwareChannelFromOpChannel(opChannel);
245  }
246 
247  //......................................................................
248  // Is this a valid OpChannel number?
249  bool GeometryCore::IsValidOpChannel(int opChannel) const
250  {
251  return fChannelMapAlg->IsValidOpChannel(opChannel, this->NOpDets());
252  }
253 
254  //......................................................................
255  unsigned int GeometryCore::NAuxDetSensitive(size_t const& aid) const
256  {
257  if( aid > NAuxDets() - 1)
258  throw cet::exception("Geometry") << "Requested AuxDet index " << aid
259  << " is out of range: " << NAuxDets();
260 
261  return AuxDets()[aid]->NSensitiveVolume();
262  }
263 
264  //......................................................................
265  // Number of different views, or wire orientations
266  unsigned int GeometryCore::Nviews() const
267  {
268  return MaxPlanes();
269  }
270 
271  //......................................................................
272  //
273  // Return the geometry description of the ith plane in the detector.
274  //
275  // \param cstat : input cryostat number, starting from 0
276  // \returns cryostat geometry for ith cryostat
277  //
278  // \throws geo::Exception if "cstat" is outside allowed range
279  //
280  CryostatGeo const& GeometryCore::Cryostat(CryostatID const& cryoid) const {
281  CryostatGeo const* pCryo = CryostatPtr(cryoid);
282  if(!pCryo) {
283  throw cet::exception("GeometryCore") << "Cryostat #"
284  << cryoid.Cryostat
285  << " does not exist\n";
286  }
287  return *pCryo;
288  } // GeometryCore::Cryostat(CryostatID)
289 
290  //......................................................................
291  //
292  // Return the geometry description of the ith AuxDet.
293  //
294  // \param ad : input AuxDet number, starting from 0
295  // \returns AuxDet geometry for ith AuxDet
296  //
297  // \throws geo::Exception if "ad" is outside allowed range
298  //
299  const AuxDetGeo& GeometryCore::AuxDet(unsigned int const ad) const
300  {
301  if(ad >= NAuxDets())
302  throw cet::exception("GeometryCore") << "AuxDet "
303  << ad
304  << " does not exist\n";
305 
306  return *(AuxDets()[ad]);
307  }
308 
309 
310  //......................................................................
312 
313  // first find the cryostat
314  geo::CryostatGeo const* cryo = PositionToCryostatPtr(point);
315  if (!cryo) return {};
316 
317  // then ask it about the TPC
318  geo::TPCID tpcid = cryo->PositionToTPCID(point, 1. + fPositionWiggle);
319  if (tpcid) return tpcid;
320 
321  // return an invalid TPC ID with cryostat information set:
322  tpcid.Cryostat = cryo->ID().Cryostat;
323  tpcid.markInvalid();
324  return tpcid;
325 
326  } // GeometryCore::FindTPCAtPosition()
327 
328 
329  //......................................................................
331  (geo::Point_t const& point) const
332  {
333  for (geo::CryostatGeo const& cryostat: IterateCryostats()) {
334  if (cryostat.ContainsPosition(point, 1.0 + fPositionWiggle))
335  return &cryostat;
336  }
337  return nullptr;
338  } // GeometryCore::PositionToCryostatPtr()
339 
340 
341  //......................................................................
343  (geo::Point_t const& point) const
344  {
345  geo::CryostatGeo const* cryo = PositionToCryostatPtr(point);
346  return cryo? cryo->ID(): geo::CryostatID{};
347  } // GeometryCore::PositionToCryostatID()
348 
349 
350  //......................................................................
352  (geo::Point_t const& worldLoc) const
353  {
354  geo::CryostatGeo const* cryo = PositionToCryostatPtr(worldLoc);
355  return cryo? cryo->ID().Cryostat: geo::CryostatID::InvalidID;
356  } // GeometryCore::FindCryostatAtPosition(Point)
357 
358 
359  //......................................................................
361  (double const worldLoc[3]) const
362  {
364  } // GeometryCore::FindCryostatAtPosition(double[])
365 
366 
367  //......................................................................
369  (geo::Point_t const& point) const
370  {
371  geo::CryostatGeo const* cryo = PositionToCryostatPtr(point);
372  return cryo? cryo->PositionToTPCptr(point, 1. + fPositionWiggle): nullptr;
373  } // GeometryCore::PositionToTPCptr()
374 
375 
376  //......................................................................
378  (geo::Point_t const& point) const
379  {
380  geo::TPCGeo const* tpc = PositionToTPCptr(point);
381  if (!tpc) {
382  throw cet::exception("GeometryCore")
383  << "Can't find any TPC at position " << point << "\n";
384  }
385  return *tpc;
386  } // GeometryCore::PositionToTPC()
387 
388 
389  //......................................................................
391  (double const worldLoc[3], TPCID& tpcid) const
392  {
393  geo::TPCGeo const& TPC = PositionToTPC(worldLoc);
394  tpcid = TPC.ID();
395  return TPC;
396  } // GeometryCore::PositionToTPC(double*, TPCID&)
397 
398 
399  //......................................................................
401  (double const worldLoc[3], unsigned int &tpc, unsigned int &cstat) const
402  {
403  geo::TPCGeo const& TPC = PositionToTPC(worldLoc);
404  cstat = TPC.ID().Cryostat;
405  tpc = TPC.ID().TPC;
406  return TPC;
407  } // GeometryCore::PositionToTPC(double*, TPCID&)
408 
409 
410  //......................................................................
412  geo::TPCGeo const* tpc = PositionToTPCptr(point);
413  return tpc? tpc->ID(): geo::TPCID{};
414  } // GeometryCore::PositionToTPCID()
415 
416 
417  //......................................................................
419  (geo::Point_t const& point) const
420  {
421  geo::CryostatGeo const* cstat = PositionToCryostatPtr(point);
422  if (!cstat) {
423  throw cet::exception("GeometryCore")
424  << "Can't find any cryostat at position " << point << "\n";
425  }
426  return *cstat;
427  } // GeometryCore::PositionToCryostat()
428 
429 
430  //......................................................................
432  (double const worldLoc[3], geo::CryostatID& cid) const
433  {
435 
436  if(cstat == geo::CryostatID::InvalidID)
437  throw cet::exception("GeometryCore") << "Can't find Cryostat for position ("
438  << worldLoc[0] << ","
439  << worldLoc[1] << ","
440  << worldLoc[2] << ")\n";
441  cid = geo::CryostatID(cstat);
442  return Cryostat(cid);
443  } // GeometryCore::PositionToCryostat(double[3], CryostatID)
444 
446  (double const worldLoc[3], unsigned int &cstat) const
447  {
448  geo::CryostatID cid;
449  geo::CryostatGeo const& cryo = PositionToCryostat(worldLoc, cid);
450  cstat = cid.Cryostat;
451  return cryo;
452  } // GeometryCore::PositionToCryostat(double[3], unsigned int)
453 
454  //......................................................................
455  unsigned int GeometryCore::FindAuxDetAtPosition(geo::Point_t const& point) const
456  {
457  // BUG the double brace syntax is required to work around clang bug 21629
458  // (https://bugs.llvm.org/show_bug.cgi?id=21629)
459  std::array<double, 3U> worldPos = {{ point.X(), point.Y(), point.Z() }};
460  return fChannelMapAlg->NearestAuxDet(worldPos.data(), AuxDets());
461  } // GeometryCore::FindAuxDetAtPosition()
462 
463  //......................................................................
464  unsigned int GeometryCore::FindAuxDetAtPosition(double const worldPos[3]) const
466 
467 
468  //......................................................................
470  (geo::Point_t const& point, unsigned int &ad) const
471  {
472  // locate the desired Auxiliary Detector
473  ad = FindAuxDetAtPosition(point);
474  return AuxDet(ad);
475  }
476 
477  //......................................................................
479  (double const worldLoc[3], unsigned int &ad) const
480  { return PositionToAuxDet(geo::vect::makePointFromCoords(worldLoc), ad); }
481 
482  //......................................................................
484  (geo::Point_t const& point, std::size_t& adg, std::size_t& sv) const
485  {
486  adg = FindAuxDetAtPosition(point);
487  // BUG the double brace syntax is required to work around clang bug 21629
488  // (https://bugs.llvm.org/show_bug.cgi?id=21629)
489  std::array<double, 3U> const worldPos = {{ point.X(), point.Y(), point.Z() }};
490  sv = fChannelMapAlg->NearestSensitiveAuxDet(worldPos.data(), AuxDets());
491  } // GeometryCore::FindAuxDetAtPosition()
492 
493  //......................................................................
495  (double const worldPos[3], size_t& adg, size_t& sv) const
496  { return FindAuxDetSensitiveAtPosition(geo::vect::makePointFromCoords(worldPos), adg, sv); }
497 
498 
499  //......................................................................
501  (geo::Point_t const& point, size_t& ad, size_t& sv) const
502  {
503  // locate the desired Auxiliary Detector
504  FindAuxDetSensitiveAtPosition(point, ad, sv);
505  return AuxDet(ad).SensitiveVolume(sv);
506  }
507 
508  //......................................................................
510  (double const worldLoc[3], size_t& ad, size_t& sv) const
511  { return PositionToAuxDetSensitive(geo::vect::makePointFromCoords(worldLoc), ad, sv); }
512 
513  //......................................................................
514  const AuxDetGeo& GeometryCore::ChannelToAuxDet(std::string const& auxDetName,
515  uint32_t const& channel) const
516  {
517  size_t adIdx = fChannelMapAlg->ChannelToAuxDet(AuxDets(), auxDetName, channel);
518  return this->AuxDet(adIdx);
519  }
520 
521  //......................................................................
522  const AuxDetSensitiveGeo& GeometryCore::ChannelToAuxDetSensitive(std::string const& auxDetName,
523  uint32_t const& channel) const
524  {
525  auto idx = fChannelMapAlg->ChannelToSensitiveAuxDet(AuxDets(), auxDetName, channel);
526  return this->AuxDet(idx.first).SensitiveVolume(idx.second);
527  }
528 
529 
530  //......................................................................
532  {
533  return fChannelMapAlg->SignalTypeForChannel(channel);
534  }
535 
536  //......................................................................
538  {
539  // map wire plane -> readout plane -> first channel,
540  // then use SignalType(channel)
541 
542  auto const ropid = WirePlaneToROP(pid);
543  if (!ropid.isValid) {
544  throw cet::exception("GeometryCore")
545  << "SignalType(): Mapping of wire plane " << std::string(pid)
546  << " to readout plane failed!\n";
547  }
548  return SignalType(ropid);
549 
550  } // GeometryCore::SignalType(PlaneID)
551 
552 
553  //......................................................................
555  return (channel == raw::InvalidChannelID)
556  ? geo::kUnknown: View(ChannelToROP(channel));
557  } // GeometryCore::View()
558 
559  //......................................................................
561  {
562  return pid? Plane(pid).View(): geo::kUnknown;
563  }
564 
565  //--------------------------------------------------------------------
567  return fChannelMapAlg->HasChannel(channel);
568  } // GeometryCore::HasChannel()
569 
570 
571  //......................................................................
572  std::set<PlaneID> const& GeometryCore::PlaneIDs() const
573  {
574  return fChannelMapAlg->PlaneIDs();
575  }
576 
577  //......................................................................
578  const std::string GeometryCore::GetWorldVolumeName() const
579  {
580  // For now, and possibly forever, this is a constant (given the
581  // definition of "nodeNames" above).
582  return std::string("volWorld");
583  }
584 
585  //......................................................................
587  std::set<std::string> const* vol_names;
588 
589  NodeNameMatcherClass(std::set<std::string> const& names)
590  : vol_names(&names) {}
591 
593  bool operator() (TGeoNode const& node) const
594  {
595  if (!vol_names) return true;
596  return vol_names->find(node.GetVolume()->GetName()) != vol_names->end();
597  }
598 
599  }; // NodeNameMatcherClass
600 
602  std::vector<TGeoNode const*> nodes;
603 
604  CollectNodesByName(std::set<std::string> const& names): matcher(names) {}
605 
607  void operator() (TGeoNode const& node)
608  { if (matcher(node)) nodes.push_back(&node); }
609 
610  void operator() (ROOTGeoNodeForwardIterator const& iter)
611  { operator() (**iter); }
612 
613  protected:
615  }; // CollectNodesByName
616 
618  std::vector<std::vector<TGeoNode const*>> paths;
619 
620  CollectPathsByName(std::set<std::string> const& names): matcher(names) {}
621 
623  void operator() (ROOTGeoNodeForwardIterator const& iter)
624  { if (matcher(**iter)) paths.push_back(iter.get_path()); }
625 
626  protected:
628  }; // CollectPathsByName
629 
630 
631 
632  std::vector<TGeoNode const*> GeometryCore::FindAllVolumes
633  (std::set<std::string> const& vol_names) const
634  {
635  CollectNodesByName node_collector(vol_names);
636 
637  ROOTGeoNodeForwardIterator iNode(ROOTGeoManager()->GetTopNode());
638  TGeoNode const* pCurrentNode;
639 
640  while ((pCurrentNode = *iNode)) {
641  node_collector(*pCurrentNode);
642  ++iNode;
643  } // while
644 
645  return node_collector.nodes;
646  } // GeometryCore::FindAllVolumes()
647 
648 
649  std::vector<std::vector<TGeoNode const*>> GeometryCore::FindAllVolumePaths
650  (std::set<std::string> const& vol_names) const
651  {
652  CollectPathsByName path_collector(vol_names);
653 
654  ROOTGeoNodeForwardIterator iNode(ROOTGeoManager()->GetTopNode());
655 
656  while (*iNode) {
657  path_collector(iNode);
658  ++iNode;
659  } // while
660 
661  return path_collector.paths;
662  } // GeometryCore::FindAllVolumePaths()
663 
664 
665 
666  //......................................................................
667  std::string GeometryCore::GetLArTPCVolumeName(geo::TPCID const& tpcid) const
668  {
669  return std::string(TPC(tpcid).ActiveVolume()->GetName());
670  }
671 
672  //......................................................................
674  {
675  return std::string(Cryostat(cid).Volume()->GetName());
676  }
677 
678  //......................................................................
680  {
681  return TPC(tpcid).ActiveHalfWidth();
682  }
683 
684  //......................................................................
686  {
687  return TPC(tpcid).ActiveHalfHeight();
688  }
689 
690  //......................................................................
692  {
693  return TPC(tpcid).ActiveLength();
694  }
695 
696  //......................................................................
698  (geo::CryostatID const& cid) const
699  {
700  return Cryostat(cid).HalfWidth();
701  }
702 
703  //......................................................................
705  (geo::CryostatID const& cid) const
706  {
707  return Cryostat(cid).HalfHeight();
708  }
709 
710  //......................................................................
712  {
713  return Cryostat(cid).Length();
714  }
715 
716  //......................................................................
718  (double* boundaries, geo::CryostatID const& cid) const
719  {
720  geo::CryostatGeo const& cryo = Cryostat(cid);
721  cryo.Boundaries(boundaries);
722  } // GeometryCore::CryostatBoundaries()
723 
724  //......................................................................
725  // This method returns the distance between the specified planes.
726  // p1 < p2
728  geo::TPCID const& tpcid,
730  ) const
731  {
732  return TPC(tpcid).PlanePitch(p1, p2);
733  }
734 
736  (geo::PlaneID const& pid1, geo::PlaneID const& pid2) const
737  {
738  return PlanePitch(pid1.asTPCID(), pid1.Plane, pid2.Plane);
739  }
740 
741  double GeometryCore::PlanePitch(unsigned int p1,
742  unsigned int p2,
743  unsigned int tpc,
744  unsigned int cstat) const
745  {
746  return PlanePitch(geo::TPCID(cstat, tpc), p1, p2);
747  }
748 
749  //......................................................................
750  // This method returns the distance between wires in a plane.
752  {
753  return Plane(planeid).WirePitch();
754  }
755 
756  //......................................................................
757  // This method returns the distance between wires in the specified view
758  // it assumes all planes of a given view have the same pitch
760  {
761  // look in cryostat 0, tpc 0 to find the plane with the
762  // specified view
763  return TPC({ 0, 0 }).Plane(view).WirePitch();
764  }
765 
766  //......................................................................
767  // This method returns the distance between wires in the specified view
768  // it assumes all planes of a given view have the same pitch
770  (geo::View_t view, geo::TPCID const& tpcid) const
771  {
772  // loop over the planes in cryostat 0, tpc 0 to find the plane with the
773  // specified view
774  geo::TPCGeo const& TPC = this->TPC(tpcid);
775  for (unsigned int p = 0; p < TPC.Nplanes(); ++p) {
776  geo::PlaneGeo const& plane = TPC.Plane(p);
777  if (plane.View() == view) return plane.ThetaZ();
778  } // for
779  throw cet::exception("GeometryCore") << "WireAngleToVertical(): no view \""
780  << geo::PlaneGeo::ViewName(view) << "\" (#" << ((int) view)
781  << ") in " << std::string(tpcid);
782  } // GeometryCore::WireAngleToVertical()
783 
784  //......................................................................
785  unsigned int GeometryCore::MaxTPCs() const {
786  unsigned int maxTPCs = 0;
787  for (geo::CryostatGeo const& cryo: Cryostats()) {
788  unsigned int maxTPCsInCryo = cryo.NTPC();
789  if (maxTPCsInCryo > maxTPCs) maxTPCs = maxTPCsInCryo;
790  } // for
791  return maxTPCs;
792  } // GeometryCore::MaxTPCs()
793 
794  //......................................................................
795  unsigned int GeometryCore::TotalNTPC() const {
796  // it looks like C++11 lambdas have made STL algorithms easier to use,
797  // but only so much:
798  return std::accumulate(Cryostats().begin(), Cryostats().end(), 0U,
799  [](unsigned int sum, geo::CryostatGeo const& cryo)
800  { return sum + cryo.NTPC(); }
801  );
802  } // GeometryCore::TotalNTPC()
803 
804  //......................................................................
805  unsigned int GeometryCore::MaxPlanes() const {
806  unsigned int maxPlanes = 0;
807  for (geo::CryostatGeo const& cryo: Cryostats()) {
808  unsigned int maxPlanesInCryo = cryo.MaxPlanes();
809  if (maxPlanesInCryo > maxPlanes) maxPlanes = maxPlanesInCryo;
810  } // for
811  return maxPlanes;
812  } // GeometryCore::MaxPlanes()
813 
814  //......................................................................
815  unsigned int GeometryCore::MaxWires() const {
816  unsigned int maxWires = 0;
817  for (geo::CryostatGeo const& cryo: Cryostats()) {
818  unsigned int maxWiresInCryo = cryo.MaxWires();
819  if (maxWiresInCryo > maxWires) maxWires = maxWiresInCryo;
820  } // for
821  return maxWires;
822  } // GeometryCore::MaxWires()
823 
824  //......................................................................
825  TGeoVolume const* GeometryCore::WorldVolume() const {
826  return gGeoManager->FindVolumeFast(GetWorldVolumeName().c_str());
827  }
828 
829  //......................................................................
831 
832  TGeoVolume const* world = WorldVolume();
833  if(!world) {
834  throw cet::exception("GeometryCore")
835  << "no world volume '" << GetWorldVolumeName() << "'\n";
836  }
837  TGeoShape const* s = world->GetShape();
838  if(!s) {
839  throw cet::exception("GeometryCore")
840  << "world volume '" << GetWorldVolumeName() << "' is shapeless!!!\n";
841  }
842 
843  double x1, x2, y1, y2, z1, z2;
844  s->GetAxisRange(1, x1, x2);
845  s->GetAxisRange(2, y1, y2);
846  s->GetAxisRange(3, z1, z2);
847 
848  // geo::BoxBoundedGeo constructor will sort the coordinates as needed
849  return geo::BoxBoundedGeo{ x1, x2, y1, y2, z1, z2 };
850  } // GeometryCore::WorldBox()
851 
852  //......................................................................
853  void GeometryCore::WorldBox(double* xlo, double* xhi,
854  double* ylo, double* yhi,
855  double* zlo, double* zhi) const
856  {
857  geo::BoxBoundedGeo const box = WorldBox();
858  if (xlo) *xlo = box.MinX();
859  if (ylo) *ylo = box.MinY();
860  if (zlo) *zlo = box.MinZ();
861  if (xhi) *xhi = box.MaxX();
862  if (yhi) *yhi = box.MaxY();
863  if (zhi) *zhi = box.MaxZ();
864  }
865 
866  //......................................................................
867  std::string GeometryCore::VolumeName(geo::Point_t const& point) const
868  {
869  // check that the given point is in the World volume at least
870  TGeoVolume const*volWorld = WorldVolume();
871  double halflength = ((TGeoBBox*)volWorld->GetShape())->GetDZ();
872  double halfheight = ((TGeoBBox*)volWorld->GetShape())->GetDY();
873  double halfwidth = ((TGeoBBox*)volWorld->GetShape())->GetDX();
874  if(std::abs(point.x()) > halfwidth ||
875  std::abs(point.y()) > halfheight ||
876  std::abs(point.z()) > halflength
877  ){
878  mf::LogWarning("GeometryCoreBadInputPoint") << "point (" << point.x() << ","
879  << point.y() << "," << point.z() << ") "
880  << "is not inside the world volume "
881  << " half width = " << halfwidth
882  << " half height = " << halfheight
883  << " half length = " << halflength
884  << " returning unknown volume name";
885  const std::string unknown("unknownVolume");
886  return unknown;
887  }
888 
889  return gGeoManager->FindNode(point.X(), point.Y(), point.Z())->GetName();
890  }
891 
892  //......................................................................
893  TGeoMaterial const* GeometryCore::Material(geo::Point_t const& point) const {
894  auto const pNode = gGeoManager->FindNode(point.X(), point.Y(), point.Z());
895  if (!pNode) return nullptr;
896  auto const pMedium = pNode->GetMedium();
897  return pMedium? pMedium->GetMaterial(): nullptr;
898  }
899 
900  //......................................................................
901  std::string GeometryCore::MaterialName(geo::Point_t const& point) const
902  {
903  // check that the given point is in the World volume at least
904  geo::BoxBoundedGeo worldBox = WorldBox();
905  if (!worldBox.ContainsPosition(point)) {
906  mf::LogWarning("GeometryCoreBadInputPoint")
907  << "point " << point << " is not inside the world volume "
908  << worldBox.Min() << " -- " << worldBox.Max()
909  << "; returning unknown material name";
910  return { "unknownMaterial" };
911  }
912  auto const pMaterial = Material(point);
913  if (!pMaterial) {
914  mf::LogWarning("GeometryCoreBadInputPoint")
915  << "material for point " << point
916  << " not found! returning unknown material name";
917  return { "unknownMaterial" };
918  }
919  return pMaterial->GetName();
920  }
921 
922  //......................................................................
923  void GeometryCore::FindCryostat(std::vector<const TGeoNode*>& path,
924  unsigned int depth)
925  {
926  const char* nm = path[depth]->GetName();
927  if( (strncmp(nm, "volCryostat", 11) == 0) ){
928  this->MakeCryostat(path, depth);
929  return;
930  }
931 
932  //explore the next layer down
933  unsigned int deeper = depth+1;
934  if(deeper >= path.size()){
935  throw cet::exception("GeometryCore") << "exceeded maximum TGeoNode depth\n";
936  }
937 
938  const TGeoVolume *v = path[depth]->GetVolume();
939  int nd = v->GetNdaughters();
940  for(int i = 0; i < nd; ++i){
941  path[deeper] = v->GetNode(i);
942  this->FindCryostat(path, deeper);
943  }
944 
945  }
946 
947  //......................................................................
948  void GeometryCore::MakeCryostat(std::vector<const TGeoNode*>& path, int depth)
949  {
950  Cryostats().emplace_back(path, depth);
951  }
952 
953  //......................................................................
954  void GeometryCore::FindAuxDet(std::vector<const TGeoNode*>& path,
955  unsigned int depth)
956  {
957  const char* nm = path[depth]->GetName();
958  if( (strncmp(nm, "volAuxDet", 9) == 0) ){
959  this->MakeAuxDet(path, depth);
960  return;
961  }
962 
963  //explore the next layer down
964  unsigned int deeper = depth+1;
965  if(deeper >= path.size()){
966  throw cet::exception("GeometryCore") << "exceeded maximum TGeoNode depth\n";
967  }
968 
969  const TGeoVolume *v = path[depth]->GetVolume();
970  int nd = v->GetNdaughters();
971  for(int i = 0; i < nd; ++i){
972  path[deeper] = v->GetNode(i);
973  this->FindAuxDet(path, deeper);
974  }
975 
976  }
977 
978  //......................................................................
979  void GeometryCore::MakeAuxDet(std::vector<const TGeoNode*>& path, int depth)
980  {
981  AuxDets().push_back(new AuxDetGeo(path, depth));
982  }
983 
984  //......................................................................
985  //
986  // Return the total mass of the detector
987  //
988  //
989  double GeometryCore::TotalMass(std::string vol) const
990  {
991  //the TGeoNode::GetVolume() returns the TGeoVolume of the detector outline
992  //and ROOT calculates the mass in kg for you
993  TGeoVolume *gvol = gGeoManager->FindVolumeFast(vol.c_str());
994  if(gvol) return gvol->Weight();
995 
996  throw cet::exception("GeometryCore") << "could not find specified volume '"
997  << vol
998  << " 'to determine total mass\n";
999  }
1000 
1001  //......................................................................
1003  (geo::Point_t const& p1, geo::Point_t const& p2) const
1004  {
1005 
1006  //The purpose of this method is to determine the column density
1007  //between the two points given. Do that by starting at p1 and
1008  //stepping until you get to the node of p2. calculate the distance
1009  //between the point just inside that node and p2 to get the last
1010  //bit of column density
1011  double columnD = 0.;
1012 
1013  //first initialize a track - get the direction cosines
1014  geo::Vector_t const dir = (p2 - p1).Unit();
1015 
1016  double const dxyz[3] = { dir.X(), dir.Y(), dir.Z() };
1017  double const cp1[3] = { p1.X(), p1.Y(), p1.Z() };
1018  gGeoManager->InitTrack(cp1, dxyz);
1019 
1020  //might be helpful to have a point to a TGeoNode
1021  TGeoNode *node = gGeoManager->GetCurrentNode();
1022 
1023  //check that the points are not in the same volume already.
1024  //if they are in different volumes, keep stepping until you
1025  //are in the same volume as the second point
1026  while(!gGeoManager->IsSameLocation(p2.X(), p2.Y(), p2.Z())){
1027  gGeoManager->FindNextBoundary();
1028  columnD += gGeoManager->GetStep()*node->GetMedium()->GetMaterial()->GetDensity();
1029 
1030  //the act of stepping puts you in the next node and returns that node
1031  node = gGeoManager->Step();
1032  }//end loop to get to volume of second point
1033 
1034  //now you are in the same volume as the last point, but not at that point.
1035  //get the distance between the current point and the last one
1036  geo::Point_t const last
1037  = geo::vect::makePointFromCoords(gGeoManager->GetCurrentPoint());
1038  double const lastStep = (p2 - last).R();
1039  columnD += lastStep*node->GetMedium()->GetMaterial()->GetDensity();
1040 
1041  return columnD;
1042  }
1043 
1044  //......................................................................
1045  std::vector< geo::WireID > GeometryCore::ChannelToWire( raw::ChannelID_t channel ) const
1046  {
1047  return fChannelMapAlg->ChannelToWire(channel);
1048  }
1049 
1050  //--------------------------------------------------------------------
1052  {
1053  return fChannelMapAlg->ChannelToROP(channel);
1054  } // GeometryCore::ChannelToROP()
1055 
1056 
1057  //----------------------------------------------------------------------------
1059  (geo::Point_t const& pos, geo::PlaneID const& planeid) const
1060  {
1061  return Plane(planeid).WireCoordinate(pos);
1062  }
1063 
1064  //----------------------------------------------------------------------------
1066  (double YPos, double ZPos, geo::PlaneID const& planeid) const
1067  {
1068  return fChannelMapAlg->WireCoordinate(YPos, ZPos, planeid);
1069  }
1070 
1071  //----------------------------------------------------------------------------
1072  // The NearestWire and PlaneWireToChannel are attempts to speed
1073  // up the simulation by memorizing the computationally intensive
1074  // setup steps for some geometry calculations. The results are
1075  // valid assuming the wire planes are comprised of straight,
1076  // parallel wires with constant pitch across the entire plane, with
1077  // a hierarchical numbering scheme - Ben J Oct 2011
1078  unsigned int GeometryCore::NearestWire
1079  (geo::Point_t const& point, geo::PlaneID const& planeid) const
1080  {
1081  return NearestWireID(point, planeid).Wire;
1082  // return fChannelMapAlg->NearestWire(worldPos, planeid);
1083  }
1084 
1085  //----------------------------------------------------------------------------
1086  unsigned int GeometryCore::NearestWire
1087  (const double worldPos[3], geo::PlaneID const& planeid) const
1088  {
1089  return NearestWire(TVector3(worldPos), planeid);
1090  }
1091 
1092  //----------------------------------------------------------------------------
1093  unsigned int GeometryCore::NearestWire
1094  (std::vector<double> const& worldPos, geo::PlaneID const& planeid) const
1095  {
1096  if(worldPos.size() > 3) throw cet::exception("GeometryCore") << "bad size vector for "
1097  << "worldPos: "
1098  << worldPos.size() << "\n";
1099  TVector3 wp(&(worldPos[0]));
1100  return NearestWire(wp, planeid);
1101  }
1102 
1103  //----------------------------------------------------------------------------
1105  (geo::Point_t const& worldPos, geo::PlaneID const& planeid) const
1106  {
1107  return Plane(planeid).NearestWireID(worldPos);
1108  }
1109 
1110  //----------------------------------------------------------------------------
1112  (std::vector<double> const& worldPos, geo::PlaneID const& planeid) const
1113  {
1114  if(worldPos.size() > 3) throw cet::exception("GeometryCore") << "bad size vector for "
1115  << "worldPos: "
1116  << worldPos.size() << "\n";
1117  TVector3 wp(&(worldPos[0]));
1118  return NearestWireID(wp, planeid);
1119  }
1120 
1121  //----------------------------------------------------------------------------
1123  (const double worldPos[3], geo::PlaneID const& planeid) const
1124  {
1125  return NearestWireID(TVector3(worldPos), planeid);
1126  }
1127 
1128  //----------------------------------------------------------------------------
1130  (const double worldPos[3], geo::PlaneID const& planeid) const
1131  {
1132  return NearestChannel(TVector3(worldPos), planeid);
1133  }
1134 
1135  //----------------------------------------------------------------------------
1137  (std::vector<double> const& worldPos, geo::PlaneID const& planeid) const
1138  {
1139  if(worldPos.size() > 3) throw cet::exception("GeometryCore") << "bad size vector for "
1140  << "worldPos: "
1141  << worldPos.size() << "\n";
1142  TVector3 wp(&(worldPos[0]));
1143  return NearestChannel(wp, planeid);
1144  }
1145 
1146  //----------------------------------------------------------------------------
1148  (geo::Point_t const& worldPos, geo::PlaneID const& planeid) const
1149  {
1150 
1151  // This method is supposed to return a channel number rather than
1152  // a wire number. Perform the conversion here (although, maybe
1153  // faster if we deal in wire numbers rather than channel numbers?)
1154 
1155  // NOTE on failure both NearestChannel() and upstream:
1156  // * according to documentation, should return invalid channel
1157  // * in the actual code throw an exception because of a BUG
1158  //
1159  // The following implementation automatically becomes in fact compliant to
1160  // the documentation if upstreams becomes compliant to.
1161  // When that happens, just delete this comment.
1162  geo::WireID const wireID = NearestWireID(worldPos, planeid);
1163  return wireID? PlaneWireToChannel(wireID): raw::InvalidChannelID;
1164  } // GeometryCore::NearestChannel()
1165 
1166  //--------------------------------------
1168  {
1169  return fChannelMapAlg->PlaneWireToChannel(wireid);
1170  }
1171 
1172  // Functions to allow determination if two wires intersect, and if so where.
1173  // This is useful information during 3D reconstruction.
1174  //......................................................................
1175  bool GeometryCore::ValueInRange(double value, double min, double max) const
1176  {
1177  if(min>max) std::swap(min,max);//protect against funny business due to wire angles
1178  if (std::abs(value-min)<1e-6||std::abs(value-max)<1e-6) return true;
1179  return (value>=min) && (value<=max);
1180  }
1181 
1182  //......................................................................
1184  (geo::WireID const& wireid, double *xyzStart, double *xyzEnd) const
1185  {
1186  Segment_t result = WireEndPoints(wireid);
1187 
1188  xyzStart[0] = result.start().X();
1189  xyzStart[1] = result.start().Y();
1190  xyzStart[2] = result.start().Z();
1191  xyzEnd[0] = result.end().X();
1192  xyzEnd[1] = result.end().Y();
1193  xyzEnd[2] = result.end().Z();
1194 
1195  if(xyzEnd[2]<xyzStart[2]){
1196  //ensure that "End" has higher z-value than "Start"
1197  std::swap(xyzStart[0],xyzEnd[0]);
1198  std::swap(xyzStart[1],xyzEnd[1]);
1199  std::swap(xyzStart[2],xyzEnd[2]);
1200  }
1201  if(xyzEnd[1]<xyzStart[1] && std::abs(xyzEnd[2]-xyzStart[2])<0.01){
1202  // if wire is vertical ensure that "End" has higher y-value than "Start"
1203  std::swap(xyzStart[0],xyzEnd[0]);
1204  std::swap(xyzStart[1],xyzEnd[1]);
1205  std::swap(xyzStart[2],xyzEnd[2]);
1206  }
1207 
1208  } // GeometryCore::WireEndPoints(WireID, 2x double*)
1209 
1210  //Changed to use WireIDsIntersect(). Apr, 2015 T.Yang
1211  //......................................................................
1214  double &y,
1215  double &z) const
1216  {
1217 
1218  // [GP] these errors should be exceptions, and this function is deprecated
1219  // because it violates interoperability
1220  std::vector<geo::WireID> chan1wires = ChannelToWire(c1);
1221  if (chan1wires.empty()) {
1222  mf::LogError("ChannelsIntersect")
1223  << "1st channel " << c1 << " maps to no wire (is it a real one?)";
1224  return false;
1225  }
1226  std::vector<geo::WireID> chan2wires = ChannelToWire(c2);
1227  if (chan2wires.empty()) {
1228  mf::LogError("ChannelsIntersect")
1229  << "2nd channel " << c2 << " maps to no wire (is it a real one?)";
1230  return false;
1231  }
1232 
1233  if (chan1wires.size() > 1) {
1234  mf::LogWarning("ChannelsIntersect")
1235  << "1st channel " << c1 << " maps to " << chan2wires.size()
1236  << " wires; using the first!";
1237  return false;
1238  }
1239  if (chan2wires.size() > 1) {
1240  mf::LogError("ChannelsIntersect")
1241  << "2nd channel " << c2 << " maps to " << chan2wires.size()
1242  << " wires; using the first!";
1243  return false;
1244  }
1245 
1246  geo::WireIDIntersection widIntersect;
1247  if (this->WireIDsIntersect(chan1wires[0],chan2wires[0],widIntersect)){
1248  y = widIntersect.y;
1249  z = widIntersect.z;
1250  return true;
1251  }
1252  else{
1253  y = widIntersect.y;
1254  z = widIntersect.z;
1255  return false;
1256  }
1257  }
1258 
1259 
1260  //......................................................................
1262  double A_start_x, double A_start_y, double A_end_x, double A_end_y,
1263  double B_start_x, double B_start_y, double B_end_x, double B_end_y,
1264  double& x, double& y
1265  ) const {
1266 
1267  // Equation from http://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
1268  // T.Yang Nov, 2014
1269  // Notation: x => coordinate orthogonal to the drift direction and to the beam direction
1270  // y => direction orthogonal to the previous and to beam direction
1271 
1272  double const denom = (A_start_x - A_end_x)*(B_start_y - B_end_y)
1273  - (A_start_y - A_end_y)*(B_start_x - B_end_x);
1274 
1275  if (coordIs.zero(denom)) return false;
1276 
1277  double const A = (A_start_x * A_end_y - A_start_y * A_end_x) / denom;
1278  double const B = (B_start_x * B_end_y - B_start_y * B_end_x) / denom;
1279 
1280  x = (B_start_x - B_end_x) * A - (A_start_x - A_end_x) * B;
1281  y = (B_start_y - B_end_y) * A - (A_start_y - A_end_y) * B;
1282 
1283  return true;
1284 
1285  } // GeometryCore::IntersectLines()
1286 
1287  //......................................................................
1289  double A_start_x, double A_start_y, double A_end_x, double A_end_y,
1290  double B_start_x, double B_start_y, double B_end_x, double B_end_y,
1291  double& x, double& y
1292  ) const {
1293 
1294  bool bCross = IntersectLines(
1295  A_start_x, A_start_y, A_end_x, A_end_y,
1296  B_start_x, B_start_y, B_end_x, B_end_y,
1297  x, y
1298  );
1299 
1300  if (bCross) {
1301  mf::LogWarning("IntersectSegments") << "The segments are parallel!";
1302  return false;
1303  }
1304 
1305  return PointWithinSegments(
1306  A_start_x, A_start_y, A_end_x, A_end_y,
1307  B_start_x, B_start_y, B_end_x, B_end_y,
1308  x, y
1309  );
1310 
1311  } // GeometryCore::IntersectSegments()
1312 
1313  //......................................................................
1315  const geo::WireID& wid1, const geo::WireID& wid2,
1316  geo::WireIDIntersection & widIntersect
1317  ) const {
1318 
1319  static_assert(
1320  std::numeric_limits<decltype(widIntersect.y)>::has_infinity,
1321  "the vector coordinate type can't represent infinity!"
1322  );
1323  constexpr auto infinity
1324  = std::numeric_limits<decltype(widIntersect.y)>::infinity();
1325 
1326  if (!WireIDIntersectionCheck(wid1, wid2)) {
1327  widIntersect.y = widIntersect.z = infinity;
1328  widIntersect.TPC = geo::TPCID::InvalidID;
1329  return false;
1330  }
1331 
1332  // get the endpoints to see if wires intersect
1333  Segment_t const w1 = WireEndPoints(wid1);
1334  Segment_t const w2 = WireEndPoints(wid2);
1335 
1336  // TODO extract the coordinates in the right way;
1337  // is it any worth, since then the result is in (y, z), whatever it means?
1338  bool const cross = IntersectLines(
1339  w1.start()[1], w1.start()[2], w1.end()[1], w1.end()[2],
1340  w2.start()[1], w2.start()[2], w2.end()[1], w2.end()[2],
1341  widIntersect.y, widIntersect.z
1342  );
1343  if (!cross) {
1344  widIntersect.y = widIntersect.z = infinity;
1345  widIntersect.TPC = geo::TPCID::InvalidID;
1346  return false;
1347  }
1348  bool const within = PointWithinSegments(
1349  w1.start()[1], w1.start()[2], w1.end()[1], w1.end()[2],
1350  w2.start()[1], w2.start()[2], w2.end()[1], w2.end()[2],
1351  widIntersect.y, widIntersect.z
1352  );
1353 
1354  widIntersect.TPC = (within? wid1.TPC: geo::TPCID::InvalidID);
1355 
1356  // return whether the intersection is within the length of both wires
1357  return within;
1358 
1359  } // GeometryCore::WireIDsIntersect(WireIDIntersection)
1360 
1361 
1362  //......................................................................
1364  const geo::WireID& wid1, const geo::WireID& wid2,
1365  geo::Point_t& intersection
1366  )
1367  const
1368  {
1369  //
1370  // This is not a real 3D intersection: the wires do not cross, since they
1371  // are required to belong to two different planes.
1372  //
1373  // After Christopher Backhouse suggestion, we take the point on the first
1374  // wire which is closest to the other one.
1375  //
1376  //
1377  static_assert(
1378  std::numeric_limits<decltype(intersection.X())>::has_infinity,
1379  "the vector coordinate type can't represent infinity!"
1380  );
1381  constexpr auto infinity
1382  = std::numeric_limits<decltype(intersection.X())>::infinity();
1383 
1384  if (!WireIDIntersectionCheck(wid1, wid2)) {
1385  intersection = { infinity, infinity, infinity };
1386  return false;
1387  }
1388 
1389  /*
1390  * the point on the first wire:
1391  *
1392  * p1(t) = c1 + t w1 (c1 the center of the wire, w1 its direction[1])
1393  *
1394  * has the minimal distance from the other wire (c2 + u w2, with the same
1395  * notation) at
1396  *
1397  * t = [(dc,w1) - (dc,w2)(w1,w2)] / [ 1 - (w1,w2)^2 ]
1398  * u = [-(dc,w2) + (dc,w1)(w1,w2)] / [ 1 - (w1,w2)^2 ]
1399  *
1400  * (where (a,b) is a scalar product and dc = (c2 - c1) ).
1401  * If w1 and w2 are unit vectors, t and u are in fact the distance of the
1402  * point from the center of the respective wires in "standard" geometry
1403  * units.
1404  *
1405  */
1406 
1407  geo::WireGeo const& wire1 = Wire(wid1);
1408  decltype(auto) c1 = wire1.GetCenter();
1409  decltype(auto) w1 = wire1.Direction();
1410 
1411  geo::WireGeo const& wire2 = Wire(wid2);
1412  decltype(auto) c2 = wire2.GetCenter();
1413  decltype(auto) w2 = wire2.Direction();
1414 
1415  auto const dc = c2 - c1;
1416 
1417  // note: we are not checking that w1 and w2 are not parallel.
1418  using geo::vect::dot;
1419  double const w1w2 = dot(w1, w2); // this is cos(angle), angle between wires
1420  double const cscAngle2 = 1.0 / (1.0 - sqr(w1w2)); // this is 1/sin^2(angle)
1421  double const dcw1 = dot(dc, w1);
1422  double const dcw2 = dot(dc, w2);
1423  double const t = (dcw1 - (dcw2 * w1w2)) * cscAngle2;
1424  double const u = (-dcw2 + (dcw1 * w1w2)) * cscAngle2;
1425 
1426  intersection = c1 + t * w1;
1427 
1428  bool const within
1429  = (std::abs(t) <= wire1.HalfL()) && (std::abs(u) <= wire2.HalfL());
1430 
1431  // return whether the intersection is within the length of both wires
1432  return within;
1433 
1434  } // GeometryCore::WireIDsIntersect(Point3D_t)
1435 
1436 
1437  //......................................................................
1439  (const geo::WireID& wid1, const geo::WireID& wid2, TVector3& intersection)
1440  const
1441  {
1442  geo::Point_t p;
1443  bool res = WireIDsIntersect(wid1, wid2, p);
1444  intersection = geo::vect::toTVector3(p);
1445  return res;
1446  } // GeometryCore::WireIDsIntersect(TVector3)
1447 
1448 
1449  //----------------------------------------------------------------------------
1451  (geo::PlaneID const& pid1, geo::PlaneID const& pid2) const
1452  {
1453  // how many planes in the TPC pid1 belongs to:
1454  const unsigned int nPlanes = Nplanes(pid1);
1455  if(nPlanes != 3) {
1456  throw cet::exception("GeometryCore")
1457  << "ThirdPlane() supports only TPCs with 3 planes, and I see "
1458  << nPlanes << " instead\n";
1459  }
1460 
1461  geo::PlaneID::PlaneID_t target_plane = nPlanes;
1462  for (geo::PlaneID::PlaneID_t iPlane = 0; iPlane < nPlanes; ++iPlane){
1463  if ((iPlane == pid1.Plane) || (iPlane == pid2.Plane)) continue;
1464  if (target_plane != nPlanes) {
1465  throw cet::exception("GeometryCore")
1466  << "ThirdPlane() found too many planes that are not "
1467  << std::string(pid1) << " nor " << std::string(pid2)
1468  << "! (first " << target_plane << ", then " << iPlane << ")\n";
1469  } // if we had a target already
1470  target_plane = iPlane;
1471  } // for
1472  if (target_plane == nPlanes) {
1473  throw cet::exception("GeometryCore")
1474  << "ThirdPlane() can't find a plane that is not " << std::string(pid1)
1475  << " nor " << std::string(pid2) << "!\n";
1476  }
1477 
1478  return geo::PlaneID(pid1, target_plane);
1479  } // GeometryCore::ThirdPlane()
1480 
1481 
1483  (geo::PlaneID const& pid1, geo::PlaneID const& pid2, const char* caller)
1484  {
1485  if(pid1.asTPCID() != pid2.asTPCID()) {
1486  throw cet::exception("GeometryCore")
1487  << caller << " needs two planes on the same TPC (got "
1488  << std::string(pid1) << " and " << std::string(pid2) << ")\n";
1489  }
1490  if(pid1 == pid2) { // was: return 999;
1491  throw cet::exception("GeometryCore")
1492  << caller << " needs two different planes, got "
1493  << std::string(pid1) << " twice\n";
1494  }
1495  } // GeometryCore::CheckIndependentPlanesOnSameTPC()
1496 
1497 
1499  geo::PlaneID const& pid1, double slope1,
1500  geo::PlaneID const& pid2, double slope2,
1501  geo::PlaneID const& output_plane
1502  ) const {
1503 
1504  CheckIndependentPlanesOnSameTPC(pid1, pid2, "ThirdPlaneSlope()");
1505 
1506  geo::TPCGeo const& TPC = this->TPC(pid1);
1507 
1508  // We need the "wire coordinate direction" for each plane.
1509  // This is perpendicular to the wire orientation.
1510  // PlaneGeo::PhiZ() defines the right orientation too.
1511  return ComputeThirdPlaneSlope(
1512  TPC.Plane(pid1).PhiZ(), slope1,
1513  TPC.Plane(pid2).PhiZ(), slope2,
1514  TPC.Plane(output_plane).PhiZ()
1515  );
1516  } // ThirdPlaneSlope()
1517 
1518 
1520  geo::PlaneID const& pid1, double slope1,
1521  geo::PlaneID const& pid2, double slope2
1522  ) const {
1523  geo::PlaneID target_plane = ThirdPlane(pid1, pid2);
1524  return ThirdPlaneSlope(pid1, slope1, pid2, slope2, target_plane);
1525  } // ThirdPlaneSlope()
1526 
1527 
1529  geo::PlaneID const& pid1, double slope1,
1530  geo::PlaneID const& pid2, double slope2,
1531  geo::PlaneID const& output_plane
1532  ) const {
1533 
1534  CheckIndependentPlanesOnSameTPC(pid1, pid2, "ThirdPlane_dTdW()");
1535 
1536  geo::TPCGeo const& TPC = this->TPC(pid1);
1537 
1538  double angle[3], pitch[3];
1539  geo::PlaneGeo const* const planes[3]
1540  = { &TPC.Plane(pid1), &TPC.Plane(pid2), &TPC.Plane(output_plane) };
1541 
1542  // We need wire pitch and "wire coordinate direction" for each plane.
1543  // The latter is perpendicular to the wire orientation.
1544  // PlaneGeo::PhiZ() defines the right orientation too.
1545  for (size_t i = 0; i < 3; ++i) {
1546  angle[i] = planes[i]->PhiZ();
1547  pitch[i] = planes[i]->WirePitch();
1548  } // for
1549 
1550  return ComputeThirdPlane_dTdW(
1551  angle[0], pitch[0], slope1,
1552  angle[1], pitch[1], slope2,
1553  angle[2], pitch[2]
1554  );
1555 
1556  } // GeometryCore::ThirdPlane_dTdW()
1557 
1558 
1560  geo::PlaneID const& pid1, double slope1,
1561  geo::PlaneID const& pid2, double slope2
1562  ) const {
1563  geo::PlaneID target_plane = ThirdPlane(pid1, pid2);
1564  return ThirdPlane_dTdW(pid1, slope1, pid2, slope2, target_plane);
1565  } // ThirdPlane_dTdW()
1566 
1567 
1568  // Given slopes dTime/dWire in two planes, return with the slope in the 3rd plane.
1569  // Requires slopes to be in the same metrics,
1570  // e.g. converted in a distances ratio.
1571  // B. Baller August 2014
1572  // Rewritten by T. Yang Apr 2015 using the equation in H. Greenlee's talk:
1573  // https://cdcvs.fnal.gov/redmine/attachments/download/1821/larsoft_apr20_2011.pdf
1574  // slide 2
1576  (double angle1, double slope1, double angle2, double slope2, double angle3)
1577  {
1578  // note that, if needed, the trigonometric functions can be pre-calculated.
1579 
1580  // Can't resolve very small slopes
1581  if ((std::abs(slope1) < 0.001) && (std::abs(slope2)) < 0.001) return 0.001;
1582 
1583  // We need the "wire coordinate direction" for each plane.
1584  // This is perpendicular to the wire orientation.
1585  double slope3 = 0.001;
1586  if (std::abs(slope1) > 0.001 && std::abs(slope2) > 0.001) {
1587  slope3
1588  = (
1589  + (1./slope1)*std::sin(angle3-angle2)
1590  - (1./slope2)*std::sin(angle3-angle1)
1591  ) / std::sin(angle1-angle2)
1592  ;
1593  }
1594  if (slope3 != 0.) slope3 = 1./slope3;
1595  else slope3 = 999.;
1596 
1597  return slope3;
1598  } // GeometryCore::ComputeThirdPlaneSlope()
1599 
1600 
1602  double angle1, double pitch1, double dTdW1,
1603  double angle2, double pitch2, double dTdW2,
1604  double angle_target, double pitch_target
1605  )
1606  {
1607  // we need to convert dt/dw into homogeneous coordinates, and then back;
1608  // slope = [dT * (TDCperiod / driftVelocity)] / [dW * wirePitch]
1609  // The coefficient of dT is assumed to be the same for all the planes,
1610  // and it finally cancels out. Pitches cancel out only if they are all
1611  // the same.
1612  return pitch_target * ComputeThirdPlaneSlope
1613  (angle1, dTdW1 / pitch1, angle2, dTdW2 / pitch2, angle_target);
1614  } // GeometryCore::ComputeThirdPlane_dTdW()
1615 
1616 
1617  //......................................................................
1618  // This function is called if it is determined that two wires in a single TPC must overlap.
1619  // To determine the yz coordinate of the wire intersection, we need to know the
1620  // endpoints of both wires in xyz-space, and also their orientation (angle), and the
1621  // inner dimensions of the TPC frame.
1622  // Note: This calculation is entirely dependent on an accurate GDML description of the TPC!
1623  // Mitch - Feb., 2011
1624  // Changed to use WireIDsIntersect(). It does not check whether the intersection is on both wires (the same as the old behavior). T. Yang - Apr, 2015
1625  //--------------------------------------------------------------------
1627  geo::WireID const& wid2,
1628  double &y, double &z) const
1629  {
1630  geo::WireIDIntersection widIntersect;
1631  bool const found = WireIDsIntersect(wid1, wid2, widIntersect);
1632  y = widIntersect.y;
1633  z = widIntersect.z;
1634  return found;
1635  }
1636 
1637  //============================================================================
1638  //=== TPC set information
1639  //===
1640  //--------------------------------------------------------------------
1641  unsigned int GeometryCore::NTPCsets(readout::CryostatID const& cryoid) const {
1642  return fChannelMapAlg->NTPCsets(cryoid);
1643  } // GeometryCore::NTPCsets()
1644 
1645 
1646  //--------------------------------------------------------------------
1647  unsigned int GeometryCore::MaxTPCsets() const {
1648  return fChannelMapAlg->MaxTPCsets();
1649  } // GeometryCore::MaxTPCsets()
1650 
1651 
1652  //--------------------------------------------------------------------
1653  bool GeometryCore::HasTPCset(readout::TPCsetID const& tpcsetid) const {
1654  return fChannelMapAlg->HasTPCset(tpcsetid);
1655  } // GeometryCore::HasTPCset()
1656 
1657 
1658  //--------------------------------------------------------------------
1660  (double const worldLoc[3]) const
1661  {
1662  return TPCtoTPCset(FindTPCAtPosition(worldLoc));
1663  } // GeometryCore::FindTPCsetAtPosition()
1664 
1665 
1666  //--------------------------------------------------------------------
1668  {
1669  return fChannelMapAlg->TPCtoTPCset(tpcid);
1670  } // GeometryCore::TPCtoTPCset()
1671 
1672 
1673  //--------------------------------------------------------------------
1674  std::vector<geo::TPCID> GeometryCore::TPCsetToTPCs
1675  (readout::TPCsetID const& tpcsetid) const
1676  {
1677  return fChannelMapAlg->TPCsetToTPCs(tpcsetid);
1678  } // GeometryCore::TPCsetToTPCs()
1679 
1680 
1681  //============================================================================
1682  //=== Readout plane information
1683  //===
1684  //--------------------------------------------------------------------
1685  unsigned int GeometryCore::NROPs(readout::TPCsetID const& tpcsetid) const {
1686  return fChannelMapAlg->NROPs(tpcsetid);
1687  } // GeometryCore::NROPs()
1688 
1689 
1690  //--------------------------------------------------------------------
1691  unsigned int GeometryCore::MaxROPs() const {
1692  return fChannelMapAlg->MaxROPs();
1693  } // GeometryCore::MaxROPs()
1694 
1695 
1696  //--------------------------------------------------------------------
1697  bool GeometryCore::HasROP(readout::ROPID const& ropid) const {
1698  return fChannelMapAlg->HasROP(ropid);
1699  } // GeometryCore::HasROP()
1700 
1701 
1702  //--------------------------------------------------------------------
1704  {
1705  return fChannelMapAlg->WirePlaneToROP(planeid);
1706  } // GeometryCore::WirePlaneToROP()
1707 
1708 
1709  //--------------------------------------------------------------------
1710  std::vector<geo::PlaneID> GeometryCore::ROPtoWirePlanes
1711  (readout::ROPID const& ropid) const
1712  {
1713  return fChannelMapAlg->ROPtoWirePlanes(ropid);
1714  } // GeometryCore::ROPtoWirePlanes()
1715 
1716 
1717  //--------------------------------------------------------------------
1718  std::vector<geo::TPCID> GeometryCore::ROPtoTPCs
1719  (readout::ROPID const& ropid) const
1720  {
1721  return fChannelMapAlg->ROPtoTPCs(ropid);
1722  } // GeometryCore::ROPtoTPCs()
1723 
1724 
1725  //--------------------------------------------------------------------
1727  (readout::ROPID const& ropid) const
1728  {
1729  return fChannelMapAlg->FirstChannelInROP(ropid);
1730  } // GeometryCore::FirstChannelInROP()
1731 
1732 
1733  //--------------------------------------------------------------------
1735  return View(fChannelMapAlg->FirstWirePlaneInROP(ropid));
1736  } // GeometryCore::View()
1737 
1738 
1739  //--------------------------------------------------------------------
1741  return fChannelMapAlg->SignalTypeForROPID(ropid);
1742  } // GeometryCore::SignalType(ROPID)
1743 
1744 
1745 
1746 
1747  //============================================================================
1748  //--------------------------------------------------------------------
1749  // Return gdml string which gives sensitive opdet name
1750  std::string GeometryCore::OpDetGeoName(unsigned int c) const
1751  {
1752  return Cryostat(c).OpDetGeoName();
1753  }
1754 
1755  //--------------------------------------------------------------------
1756  // Convert OpDet, Cryo into unique OpDet number
1757  unsigned int GeometryCore::OpDetFromCryo(unsigned int o, unsigned int c ) const
1758  {
1759  static bool Loaded=false;
1760  static std::vector<unsigned int> LowestID;
1761  static unsigned int NCryo;
1762  // If not yet loaded static parameters, do it
1763  if(Loaded == false){
1764 
1765  Loaded = true;
1766 
1767  // Store the lowest ID for each cryostat
1768  NCryo=Ncryostats();
1769  LowestID.resize(NCryo + 1);
1770  LowestID.at(0)=0;
1771  for(size_t cryo=0; cryo!=NCryo; ++cryo){
1772  LowestID.at(cryo+1)=LowestID.at(cryo)+Cryostat(c).NOpDet();
1773  }
1774 
1775  }
1776 
1777  if( (c < NCryo) && (o < Cryostat(c).NOpDet())){
1778  return LowestID.at(c)+o;
1779  }
1780  else{
1781  throw cet::exception("OpDetCryoToOpID Error") << "Coordinates c=" << c
1782  << ", o=" << o
1783  << " out of range. Abort\n";
1784  }
1785 
1786  // if all is well, we never get to this point in the method
1787  // but still a good idea to be sure to always return something.
1788 
1789  return INT_MAX;
1790  }
1791 
1792  //--------------------------------------------------------------------
1794  {
1795  return this->OpDetGeoFromOpDet(this->OpDetFromOpChannel(OpChannel));
1796  }
1797 
1798  //--------------------------------------------------------------------
1799  const OpDetGeo& GeometryCore::OpDetGeoFromOpDet(unsigned int OpDet) const
1800  {
1801  static bool Loaded=false;
1802  static std::vector<unsigned int> LowestID;
1803  static size_t NCryo;
1804  // If not yet loaded static parameters, do it
1805  if(Loaded == false){
1806 
1807  Loaded = true;
1808 
1809  // Store the lowest ID for each cryostat
1810  NCryo=Ncryostats();
1811  LowestID.resize(NCryo + 1);
1812  LowestID[0] = 0;
1813  for(size_t cryo = 0; cryo != NCryo; ++cryo){
1814  LowestID[cryo+1] = LowestID[cryo] + Cryostat(cryo).NOpDet();
1815  }
1816 
1817  }
1818 
1819  for(size_t i=0; i!=NCryo; ++i){
1820  if( (OpDet >= LowestID[i]) && (OpDet < LowestID[i+1]) ){
1821  int c = i;
1822  int o = OpDet-LowestID[i];
1823  return this->Cryostat(c).OpDet(o);
1824  }
1825  }
1826  // If we made it here, we didn't find the right combination. abort
1827  throw cet::exception("OpID To OpDetCryo error")<<"OpID out of range, "<< OpDet << "\n";
1828 
1829  // Will not reach due to exception
1830  return this->Cryostat(0).OpDet(0);
1831  }
1832 
1833 
1834  //--------------------------------------------------------------------
1835  // Find the closest OpChannel to this point, in the appropriate cryostat
1836  unsigned int GeometryCore::GetClosestOpDet(geo::Point_t const& point) const
1837  {
1838  geo::CryostatGeo const* cryo = PositionToCryostatPtr(point);
1839  if (!cryo) return std::numeric_limits<unsigned int>::max();
1840  int o = cryo->GetClosestOpDet(point);
1841  return OpDetFromCryo(o, cryo->ID().Cryostat);
1842  }
1843 
1844 
1845  //--------------------------------------------------------------------
1846  // Find the closest OpChannel to this point, in the appropriate cryostat
1847  unsigned int GeometryCore::GetClosestOpDet(double const* point) const
1849 
1850 
1851  //--------------------------------------------------------------------
1853  (const geo::WireID& wid1, const geo::WireID& wid2) const
1854  {
1855  if (wid1.asTPCID() != wid2) {
1856  mf::LogError("WireIDIntersectionCheck")
1857  << "Comparing two wires on different TPCs: return failure.";
1858  return false;
1859  }
1860  if (wid1.Plane == wid2.Plane) {
1861  mf::LogError("WireIDIntersectionCheck")
1862  << "Comparing two wires in the same plane: return failure";
1863  return false;
1864  }
1865  if (!HasWire(wid1)) {
1866  mf::LogError("WireIDIntersectionCheck")
1867  << "1st wire " << wid1 << " does not exist (max wire number: "
1868  << Nwires(wid1.planeID()) << ")";
1869  return false;
1870  }
1871  if (!HasWire(wid2)) {
1872  mf::LogError("WireIDIntersectionCheck")
1873  << "2nd wire " << wid2 << " does not exist (max wire number: "
1874  << Nwires(wid2.planeID()) << ")";
1875  return false;
1876  }
1877  return true;
1878  } // GeometryCore::WireIDIntersectionCheck()
1879 
1880 
1881  //--------------------------------------------------------------------
1883  double A_start_x, double A_start_y, double A_end_x, double A_end_y,
1884  double B_start_x, double B_start_y, double B_end_x, double B_end_y,
1885  double x, double y
1886  ) {
1887  return coordIs.withinSorted(x, A_start_x, A_end_x)
1888  && coordIs.withinSorted(y, A_start_y, A_end_y)
1889  && coordIs.withinSorted(x, B_start_x, B_end_x)
1890  && coordIs.withinSorted(y, B_start_y, B_end_y)
1891  ;
1892 
1893  } // GeometryCore::PointWithinSegments()
1894 
1895  //--------------------------------------------------------------------
1902 
1903  //--------------------------------------------------------------------
1904  //--- ROOTGeoNodeForwardIterator
1905  //---
1906 
1908  if (current_path.empty()) return *this;
1909  if (current_path.size() == 1) { current_path.pop_back(); return *this; }
1910 
1911  // I am done; all my descendants were also done already;
1912  // first look at my younger siblings
1913  NodeInfo_t& current = current_path.back();
1914  NodeInfo_t const& parent = current_path[current_path.size() - 2];
1915  if (++(current.sibling) < parent.self->GetNdaughters()) {
1916  // my next sibling exists, let's parse his descendents
1917  current.self = parent.self->GetDaughter(current.sibling);
1918  reach_deepest_descendant();
1919  }
1920  else current_path.pop_back(); // no sibling, it's time for mum
1921  return *this;
1922  } // ROOTGeoNodeForwardIterator::operator++
1923 
1924 
1925  //--------------------------------------------------------------------
1926  std::vector<TGeoNode const*> ROOTGeoNodeForwardIterator::get_path() const {
1927 
1928  std::vector<TGeoNode const*> node_path(current_path.size());
1929 
1930  std::transform(current_path.begin(), current_path.end(), node_path.begin(),
1931  [](NodeInfo_t const& node_info){ return node_info.self; });
1932  return node_path;
1933 
1934  } // ROOTGeoNodeForwardIterator::path()
1935 
1936 
1937  //--------------------------------------------------------------------
1939  Node_t descendent = current_path.back().self;
1940  while (descendent->GetNdaughters() > 0) {
1941  descendent = descendent->GetDaughter(0);
1942  current_path.emplace_back(descendent, 0U);
1943  } // while
1944  } // ROOTGeoNodeForwardIterator::reach_deepest_descendant()
1945 
1946  //--------------------------------------------------------------------
1947  void ROOTGeoNodeForwardIterator::init(TGeoNode const* start_node) {
1948  current_path.clear();
1949  if (!start_node) return;
1950  current_path.emplace_back(start_node, 0U);
1951  reach_deepest_descendant();
1952  } // ROOTGeoNodeForwardIterator::init()
1953 
1954  //--------------------------------------------------------------------
1955 
1956 } // namespace geo
Float_t x
Definition: compare.C:6
geo::TPCID const & ID() const
Returns the identifier of this TPC.
Definition: TPCGeo.h:278
unsigned int NAuxDetSensitive(size_t const &aid) const
Returns the number of sensitive components of auxiliary detector.
geo::Length_t WireCoordinate(double YPos, double ZPos, geo::PlaneID const &planeid) const
Returns the index of the nearest wire to the specified position.
std::set< PlaneID > const & PlaneIDs() const
Returns a list of possible PlaneIDs in the detector.
Geometry description of a TPC wireThe wire is a single straight segment on a wire plane...
Definition: WireGeo.h:61
void FindCryostat(std::vector< const TGeoNode * > &path, unsigned int depth)
Float_t s
Definition: plot.C:23
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space.
Definition: geo_vectors.h:167
unsigned int GetClosestOpDet(geo::Point_t const &point) const
std::vector< geo::TPCID > ROPtoTPCs(readout::ROPID const &ropid) const
Returns a list of ID of TPCs the specified ROP spans.
PlaneID const & planeID() const
Definition: geo_types.h:355
geo::Length_t CryostatHalfHeight(geo::CryostatID const &cid) const
Returns the height of the cryostat (y direction)
Specializations of geo_vectors_utils.h for ROOT old vector types.
double z
z position of intersection
Definition: geo_types.h:494
double PlanePitch(unsigned int p1=0, unsigned int p2=1) const
Returns the center of the TPC volume in world coordinates [cm].
Definition: TPCGeo.cxx:418
OpDetGeo const & OpDetGeoFromOpDet(unsigned int OpDet) const
Number of OpDets in the whole detector.
virtual void SortCryostats(std::vector< geo::CryostatGeo * > &cgeo) const =0
constexpr auto dot(Vector const &a, Vector const &b)
Return cross product of two vectors.
static std::string ViewName(geo::View_t view)
Returns the name of the specified view.
Definition: PlaneGeo.cxx:765
static constexpr UndefinedPos_t undefined_pos
Definition: GeometryCore.h:121
PlaneGeo const & Plane(unsigned int const p, unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified wire.
geo::Length_t DetHalfWidth(geo::TPCID const &tpcid) const
Returns the half width of the active volume of the specified TPC.
unsigned int TotalNTPC() const
Returns the total number of TPCs in the detector.
GeometryData_t fGeoData
The detector description data.
double Length_t
Type used for coordinates and distances. They are measured in centimeters.
Definition: geo_vectors.h:140
void LoadGeometryFile(std::string gdmlfile, std::string rootfile, bool bForceReload=false)
Loads the geometry information from the specified files.
CryostatGeo const & PositionToCryostat(geo::Point_t const &point) const
Returns the cryostat at specified location.
Float_t y1[n_points_granero]
Definition: compare.C:5
ROOTGeoNodeForwardIterator & operator++()
Points to the next node, or to nullptr if there are no more.
Encapsulate the geometry of the sensitive portion of an auxiliary detector.
geo::Length_t PlanePitch(geo::TPCID const &tpcid, geo::PlaneID::PlaneID_t p1=0, geo::PlaneID::PlaneID_t p2=1) const
Returns the distance between two planes.
static constexpr BeginPos_t begin_pos
Definition: GeometryCore.h:119
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
double ActiveHalfHeight() const
Half height (associated with y coordinate) of active TPC volume [cm].
Definition: TPCGeo.h:91
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
AuxDetSensitiveGeo const & SensitiveVolume(size_t sv) const
Definition: AuxDetGeo.h:159
Unknown view.
Definition: geo_types.h:83
unsigned int Nplanes() const
Number of planes in this tpc.
Definition: TPCGeo.h:145
Float_t x1[n_points_granero]
Definition: compare.C:5
std::string OpDetGeoName(unsigned int c=0) const
Returns gdml string which gives sensitive opdet name.
TPCID const & asTPCID() const
Conversion to TPCID (for convenience of notation).
Definition: geo_types.h:227
Float_t y
Definition: compare.C:6
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.
Int_t B
Definition: plot.C:25
unsigned int CryostatID_t
Type for the ID number.
Definition: geo_types.h:121
constexpr bool zero(Value_t value) const
Returns whether the value is no farther from 0 than the threshold.
AuxDetGeo const & PositionToAuxDet(geo::Point_t const &point, unsigned int &ad) const
Returns the auxiliary detector at specified location.
Double_t z
Definition: plot.C:279
double MinX() const
Returns the world x coordinate of the start of the box.
Definition: BoxBoundedGeo.h:90
The data type to uniquely identify a Plane.
Definition: geo_types.h:250
Silly utility to sort vectors indirectly.
Geometry information for a single TPC.
Definition: TPCGeo.h:37
unsigned int MaxROPs() const
Returns the largest number of ROPs a TPC set in the detector has.
Class identifying a set of TPC sharing readout channels.
Definition: readout_types.h:41
const std::string GetWorldVolumeName() const
Return the name of the world volume (needed by Geant4 simulation)
Point const & start() const
double ThirdPlaneSlope(geo::PlaneID const &pid1, double slope1, geo::PlaneID const &pid2, double slope2, geo::PlaneID const &output_plane) const
Returns the slope on the third plane, given it in the other two.
static constexpr EndPos_t end_pos
Definition: GeometryCore.h:120
unsigned int NOpHardwareChannels(int opDet) const
Number of electronics channels for all the optical detectors.
unsigned int NTPCsets(readout::CryostatID const &cryoid) const
Returns the total number of TPC sets in the specified cryostat.
readout::ROPID WirePlaneToROP(geo::PlaneID const &planeid) const
Returns the ID of the ROP planeid belongs to.
bool ChannelsIntersect(raw::ChannelID_t c1, raw::ChannelID_t c2, double &y, double &z) const
Returns an intersection point of two channels.
geo::TPCGeo const * PositionToTPCptr(geo::Point_t const &point) const
Returns the TPC at specified location.
TGeoVolume const * WorldVolume() const
Returns a pointer to the world volume.
std::vector< geo::WireID > ChannelToWire(raw::ChannelID_t const channel) const
Returns a list of wires connected to the specified TPC channel.
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:130
STL namespace.
unsigned int MaxWires() const
Returns the largest number of wires among all planes in this detector.
geo::TPCID PositionToTPCID(geo::Point_t const &point) const
Returns the ID of the TPC at specified location.
ProductStatus unknown()
Definition: ProductStatus.h:31
double MaxX() const
Returns the world x coordinate of the end of the box.
Definition: BoxBoundedGeo.h:93
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:313
const AuxDetSensitiveGeo & ChannelToAuxDetSensitive(std::string const &auxDetName, uint32_t const &channel) const
Returns the number of auxiliary detectors.
static constexpr std::size_t MaxWireDepthInGDML
Point const & end() const
bool IntersectSegments(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) const
Computes the intersection between two segments on a plane.
geo::CryostatID PositionToCryostatID(geo::Point_t const &point) const
Returns the ID of the cryostat at specified location.
SigType_t SignalType(geo::PlaneID const &pid) const
Returns the type of signal on the channels of specified TPC plane.
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
unsigned int TPC
TPC of intersection.
Definition: geo_types.h:495
Geometry information for a single cryostat.
Definition: CryostatGeo.h:36
std::set< std::string > const * vol_names
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
void FindAuxDet(std::vector< const TGeoNode * > &path, unsigned int depth)
readout::TPCsetID FindTPCsetAtPosition(double const worldLoc[3]) const
Returns the ID of the TPC set at specified location.
unsigned int NOpChannels() const
Number of electronics channels for all the optical detectors.
geo::PlaneID ThirdPlane(geo::PlaneID const &pid1, geo::PlaneID const &pid2) const
Returns the plane that is not in the specified arguments.
unsigned int GetClosestOpDet(geo::Point_t const &point) const
Find the nearest OpChannel to some point.
readout::TPCsetID TPCtoTPCset(geo::TPCID const &tpcid) const
Returns the ID of the TPC set tpcid belongs to.
TGeoManager * ROOTGeoManager() const
Access to the ROOT geometry description manager.
geo::Length_t WirePitch(geo::PlaneID const &planeid) const
Returns the distance between two consecutive wires.
unsigned int Nwires(unsigned int p, unsigned int tpc=0, unsigned int cstat=0) const
Returns the total number of wires in the specified plane.
unsigned int OpDetFromCryo(unsigned int o, unsigned int c) const
Get unique opdet number from cryo and internal count.
void CryostatBoundaries(double *boundaries, geo::CryostatID const &cid) const
Returns the boundaries of the specified cryostat.
Float_t y2[n_points_geant4]
Definition: compare.C:26
unsigned int OpDetFromOpChannel(int opChannel) const
Convert unique channel to detector number.
unsigned int Nchannels() const
Returns the number of TPC readout channels in the detector.
static 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).
std::vector< std::vector< TGeoNode const * > > paths
geo::TPCGeo const & PositionToTPC(geo::Point_t const &point) const
Returns the TPC at specified location.
constexpr bool withinSorted(Value_t value, Value_t lower, Value_t upper) const
Returns whether value is between bounds (included); bounds are sorted.
geo::TPCGeo const * PositionToTPCptr(geo::Point_t const &point, double wiggle) const
Returns a pointer to the TPC at specified location.
double ThetaZ() const
Angle of the wires from positive z axis; .
Definition: PlaneGeo.cxx:728
double TotalMass() const
Returns the total mass [kg] of the specified volume (default: world).
geo::CryostatID CryostatID
Definition: readout_types.h:30
static lar::util::RealComparisons< geo::Length_t > coordIs
Value of tolerance for equality comparisons.
geo::TPCID FindTPCAtPosition(double const worldLoc[3]) const
Returns the ID of the TPC at specified location.
T sqr(T v)
Access the description of detector geometry.
bool HasROP(readout::ROPID const &ropid) const
unsigned int PlaneID_t
Type for the ID number.
Definition: geo_types.h:251
View_t View() const
Which coordinate does this plane measure.
Definition: PlaneGeo.h:171
std::string OpDetGeoName() const
Get name of opdet geometry element.
Definition: CryostatGeo.h:311
NodeNameMatcherClass matcher
virtual void SortAuxDets(std::vector< geo::AuxDetGeo * > &adgeo) const =0
void SortGeometry(geo::GeoObjectSorter const &sorter)
Runs the sorting of geometry with the sorter provided by channel mapping.
unsigned int Nplanes(unsigned int tpc=0, unsigned int cstat=0) const
Returns the total number of wire planes in the specified TPC.
Int_t max
Definition: plot.C:27
constexpr ChannelID_t InvalidChannelID
ID of an invalid channel.
Definition: RawTypes.h:31
Offer iterators automatically dereferencing their values.
unsigned int MaxPlanes() const
Returns the largest number of planes among all TPCs in this detector.
Iterator to navigate through all the nodes.
std::set< geo::View_t > allViews
All views in the detector.
geo::Length_t DetHalfHeight(geo::TPCID const &tpcid) const
Returns the half height of the active volume of the specified TPC.
TCanvas * c1
Definition: plotHisto.C:7
void SortByPointers(Coll &coll, Sorter sorter)
Applies sorting indirectly, minimizing data copy.
TCanvas * c2
Definition: plot_hist.C:75
Classes to project and compose a vector on a plane.
geo::WireID NearestWireID(geo::Point_t const &pos) const
Returns the ID of wire closest to the specified position.
Definition: PlaneGeo.cxx:673
const OpDetGeo & OpDet(unsigned int iopdet) const
Return the iopdet&#39;th optical detector in the cryostat.
double PhiZ() const
Angle from positive z axis of the wire coordinate axis, in radians.
Definition: PlaneGeo.h:180
const AuxDetSensitiveGeo & PositionToAuxDetSensitive(geo::Point_t const &point, size_t &ad, size_t &sv) const
Returns the auxiliary detector at specified location.
raw::ChannelID_t FirstChannelInROP(readout::ROPID const &ropid) const
Returns the ID of the first channel in the specified readout plane.
void ClearGeometry()
Deletes the detector geometry structures.
unsigned int HardwareChannelFromOpChannel(int opChannel) const
Convert unique channel to hardware channel.
GeometryCore(fhicl::ParameterSet const &pset)
Initialize geometry from a given configuration.
enum geo::_plane_sigtype SigType_t
Enumerate the possible plane projections.
IteratorBox< TPC_iterator,&GeometryCore::begin_TPC,&GeometryCore::end_TPC > IterateTPCs() const
Enables ranged-for loops on all TPCs of the detector.
void FindAuxDetSensitiveAtPosition(geo::Point_t const &point, std::size_t &adg, std::size_t &sv) const
Fills the indices of the sensitive auxiliary detector at location.
bool WireIDIntersectionCheck(const geo::WireID &wid1, const geo::WireID &wid2) const
Wire ID check for WireIDsIntersect methods.
double ActiveHalfWidth() const
Half width (associated with x coordinate) of active TPC volume [cm].
Definition: TPCGeo.h:87
std::vector< evd::details::RawDigitInfo_t >::const_iterator begin(RawDigitCacheDataClass const &cache)
geo::WireID::WireID_t NearestWire(geo::Point_t const &point, geo::PlaneID const &planeid) const
Returns the index of wire closest to position in the specified TPC.
double HalfWidth() const
Half width of the cryostat [cm].
std::shared_ptr< const geo::ChannelMapAlg > fChannelMapAlg
Object containing the channel to wire mapping.
Geometry information for a single wire plane.The plane is represented in the geometry by a solid whic...
Definition: PlaneGeo.h:78
NodeNameMatcherClass(std::set< std::string > const &names)
Double_t R
Utilities to extend the interface of geometry vectors.
double MinZ() const
Returns the world z coordinate of the start of the box.
unsigned int NTPC() const
Number of TPCs in this cryostat.
Definition: CryostatGeo.h:155
geo::Length_t DetLength(geo::TPCID const &tpcid) const
Returns the length of the active volume of the specified TPC.
CryostatGeo const & Cryostat(geo::CryostatID const &cryoid) const
Returns the specified cryostat.
unsigned int MaxOpChannel() const
Largest optical channel number.
geo::Point_t Min() const
Returns the corner point with the smallest coordinates.
The data type to uniquely identify a TPC.
Definition: geo_types.h:195
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:258
double MassBetweenPoints(geo::Point_t const &p1, geo::Point_t const &p2) const
Returns the column density between two points.
~GeometryCore()
Destructor.
bool IntersectionPoint(geo::WireID const &wid1, geo::WireID const &wid2, double &y, double &z) const
Returns the intersection point of two wires.
void UpdateAfterSorting()
Performs all the updates needed after sorting.
void markInvalid()
Sets the ID as invalid.
Definition: geo_types.h:157
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) const
Computes the intersection between two lines on a plane.
View_t View(geo::PlaneID const &pid) const
Returns the view (wire orientation) on the channels of specified TPC plane.
AuxDetList_t & AuxDets()
Return the interfal auxiliary detectors list.
NodeNameMatcherClass matcher
Class identifying a set of planes sharing readout channels.
AuxDetGeo const & AuxDet(unsigned int const ad=0) const
Returns the specified auxiliary detector.
double ActiveLength() const
Length (associated with z coordinate) of active TPC volume [cm].
Definition: TPCGeo.h:95
Vector Direction() const
Returns the wire direction as a norm-one vector.
Definition: WireGeo.h:377
unsigned int NOpDets() const
Number of OpDets in the whole detector.
void ApplyChannelMap(std::shared_ptr< geo::ChannelMapAlg > pChannelMap)
Initializes the geometry to work with this channel map.
std::vector< TGeoNode const * > get_path() const
Returns the full path of the current node.
double fPositionWiggle
accounting for rounding errors when testing positions
double MaxY() const
Returns the world y coordinate of the end of the box.
Encapsulate the geometry of an auxiliary detector.
std::vector< TGeoNode const * > FindAllVolumes(std::set< std::string > const &vol_names) const
Returns all the nodes with volumes with any of the specified names.
double HalfHeight() const
Half height of the cryostat [cm].
readout::ROPID ChannelToROP(raw::ChannelID_t channel) const
unsigned int OpChannel(int detNum, int hardwareChannel) const
Convert detector number and hardware channel to unique channel.
double HalfL() const
Returns half the length of the wire [cm].
Definition: WireGeo.h:106
Encapsulate the geometry of an optical detector.
IteratorBox< cryostat_iterator,&GeometryCore::begin_cryostat,&GeometryCore::end_cryostat > IterateCryostats() const
Enables ranged-for loops on all cryostats of the detector.
std::string fGDMLfile
path to geometry file used for Geant4 simulation
bool WireIDsIntersect(WireID const &wid1, WireID const &wid2, geo::Point_t &intersection) const
Computes the intersection between two wires.
void MakeCryostat(std::vector< const TGeoNode * > &path, int depth)
WireGeo const & Wire(geo::WireID const &wireid) const
Returns the specified wire.
raw::ChannelID_t PlaneWireToChannel(WireID const &wireid) const
Returns the ID of the TPC channel connected to the specified wire.
geo::CryostatGeo const * PositionToCryostatPtr(geo::Point_t const &point) const
Returns the cryostat at specified location.
std::string value(boost::any const &)
A base class aware of world box coordinatesAn object describing a simple shape can inherit from this ...
Definition: BoxBoundedGeo.h:35
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.
CollectNodesByName(std::set< std::string > const &names)
std::vector< TGeoNode const * > nodes
TDirectory * dir
Definition: macro.C:5
geo::Length_t CryostatHalfWidth(geo::CryostatID const &cid) const
Returns the half width of the cryostat (x direction)
Int_t min
Definition: plot.C:26
unsigned int NOpDet() const
Number of optical detectors in this TPC.
Definition: CryostatGeo.h:295
TVector3 toTVector3(Vector const &v)
Converts a vector into a TVector3.
static const CryostatID_t InvalidID
Special code for an invalid ID.
Definition: geo_types.h:126
double y
y position of intersection
Definition: geo_types.h:493
std::string GetCryostatVolumeName(geo::CryostatID const &cid) const
Return the name of LAr TPC volume.
double MaxZ() const
Returns the world z coordinate of the end of the box.
unsigned int MaxTPCsets() const
Returns the largest number of TPC sets any cryostat in the detector has.
void init(TGeoNode const *start_node)
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
CryostatList_t & Cryostats()
Return the internal cryostat list.
Simple class with two points (a pair with aliases).
const AuxDetGeo & ChannelToAuxDet(std::string const &auxDetName, uint32_t const &channel) const
Returns the number of auxiliary detectors.
static const TPCID_t InvalidID
Special code for an invalid ID.
Definition: geo_types.h:200
void MakeAuxDet(std::vector< const TGeoNode * > &path, int depth)
static void CheckIndependentPlanesOnSameTPC(geo::PlaneID const &pid1, geo::PlaneID const &pid2, const char *caller)
void WireEndPoints(geo::WireID const &wireid, double *xyzStart, double *xyzEnd) const
Fills two arrays with the coordinates of the wire end points.
std::vector< geo::PlaneID > ROPtoWirePlanes(readout::ROPID const &ropid) const
Returns a list of ID of planes belonging to the specified ROP.
std::string fDetectorName
Name of the detector.
geo::Length_t CryostatLength(geo::CryostatID const &cid) const
Returns the length of the cryostat (z direction)
geo::WireID NearestWireID(geo::Point_t const &point, geo::PlaneID const &planeid) const
Returns the ID of wire closest to position in the specified TPC.
unsigned int FindAuxDetAtPosition(double const worldLoc[3]) const
Returns the index of the auxiliary detector at specified location.
TGeoMaterial const * Material(geo::Point_t const &point) const
Returns the material at the specified position.
Structures to distinguish the constructors.
Definition: GeometryCore.h:115
std::vector< std::vector< TGeoNode const * > > FindAllVolumePaths(std::set< std::string > const &vol_names) const
Returns paths of all nodes with volumes with the specified names.
geo::BoxBoundedGeo const & Boundaries() const
Returns boundaries of the cryostat (in centimetres).
Definition: CryostatGeo.h:99
std::vector< evd::details::RawDigitInfo_t >::const_iterator end(RawDigitCacheDataClass const &cache)
TPCGeo const & TPC(unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified TPC.
unsigned int NROPs(readout::TPCsetID const &tpcsetid) const
Returns the total number of ROP in the specified TPC set.
PlaneGeo const & Plane(geo::View_t view) const
Return the plane in the tpc with View_t view.
Definition: TPCGeo.cxx:298
std::string MaterialName(TVector3 const &point) const
Name of the deepest material containing the point xyz.
void GetCenter(double *xyz, double localz=0.0) const
Fills the world coordinate of a point on the wire.
Definition: WireGeo.cxx:68
double WireCoordinate(Point const &point) const
Returns the coordinate of the point on the plane, in wire units.
Definition: PlaneGeo.h:725
bool ValueInRange(double value, double min, double max) const
Returns whether a value is within the specified range.
unsigned int Nviews() const
Returns the number of views (different wire orientations)
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:27
Vector cross(Vector const &a, Vector const &b)
Return cross product of two vectors.
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:203
CollectPathsByName(std::set< std::string > const &names)
std::vector< geo::TPCID > TPCsetToTPCs(readout::TPCsetID const &tpcsetid) const
Returns a list of ID of TPCs belonging to the specified TPC set.
Float_t x2[n_points_geant4]
Definition: compare.C:26
Float_t e
Definition: plot.C:34
raw::ChannelID_t NearestChannel(geo::Point_t const &worldLoc, geo::PlaneID const &planeid) const
Returns the ID of the channel nearest to the specified position.
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:187
GENVECTOR_CONSTEXPR::geo::Point_t makePointFromCoords(Coords &&coords)
Creates a geo::Point_t from its coordinates (see makeFromCoords()).
Namespace collecting geometry-related classes utilities.
double MinY() const
Returns the world y coordinate of the start of the box.
geo::CryostatID::CryostatID_t FindCryostatAtPosition(geo::Point_t const &worldLoc) const
Returns the index of the cryostat at specified location.
double ThirdPlane_dTdW(geo::PlaneID const &pid1, double slope1, geo::PlaneID const &pid2, double slope2, geo::PlaneID const &output_plane) const
Returns dT/dW on the third plane, given it in the other two.
OpDetGeo const & OpDetGeoFromOpChannel(unsigned int OpChannel) const
Access the OpDetGeo object by OpDet or Channel Number.
unsigned int MaxTPCs() const
Returns the largest number of TPCs a cryostat in the detector has.
std::string fROOTfile
path to geometry file for geometry in GeometryCore
geo::Point_t Max() const
Returns the corner point with the largest coordinates.
bool IsValidOpChannel(int opChannel) const
Is this a valid OpChannel number?
std::string VolumeName(geo::Point_t const &point) const
Returns the name of the deepest volume containing specified point.
geo::TPCID PositionToTPCID(geo::Point_t const &point, double wiggle) const
Returns the ID of the TPC at specified location.
bool ContainsPosition(geo::Point_t const &point, double wiggle=1.0) const
Returns whether this volume contains the specified point.
double WireAngleToVertical(geo::View_t view, geo::TPCID const &tpcid) const
Returns the angle of the wires in the specified view from vertical.
CryostatGeo const * CryostatPtr(geo::CryostatID const &cryoid) const
Returns the specified cryostat.
bool HasChannel(raw::ChannelID_t channel) const
Returns whether the specified channel exists and is valid.
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:367
double Length() const
Length of the cryostat [cm].
Definition: CryostatGeo.h:91
unsigned int NAuxDets() const
Returns the number of auxiliary detectors.
The data type to uniquely identify a cryostat.
Definition: geo_types.h:120
std::string GetLArTPCVolumeName(geo::TPCID const &tpcid) const
Return the name of specified LAr TPC volume.
bool HasWire(geo::WireID const &wireid) const
Returns whether we have the specified wire.
geo::CryostatID const & ID() const
Returns the identifier of this cryostat.
Definition: CryostatGeo.h:116
bool HasTPCset(readout::TPCsetID const &tpcsetid) const
geo::BoxBoundedGeo WorldBox() const