LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
GeometryCore.cxx
Go to the documentation of this file.
1 
9 // class header
11 
12 // lar includes
16 #include "larcorealg/Geometry/Decomposer.h" // geo::vect::dot()
20 #include "larcorealg/Geometry/geo_vectors_utils.h" // geo::vect
23 
24 // Framework includes
25 #include "cetlib/pow.h"
26 #include "cetlib_except/exception.h"
27 #include "fhiclcpp/types/Table.h"
29 
30 // ROOT includes
31 #include <TGeoBBox.h>
32 #include <TGeoManager.h>
33 #include <TGeoMatrix.h>
34 #include <TGeoNode.h>
35 #include <TGeoVolume.h>
36 
37 // C/C++ includes
38 #include <algorithm> // std::for_each(), std::transform()
39 #include <cctype> // ::tolower()
40 #include <cmath> // std::abs() ...
41 #include <cstddef> // size_t
42 #include <iterator> // std::back_inserter()
43 #include <limits> // std::numeric_limits<>
44 #include <numeric> // std::accumulate
45 #include <sstream> // std::ostringstream
46 #include <tuple>
47 #include <utility> // std::swap()
48 #include <vector>
49 
50 namespace {
53  void CheckIndependentPlanesOnSameTPC(geo::PlaneID const& pid1,
54  geo::PlaneID const& pid2,
55  const char* caller)
56  {
57  if (pid1.asTPCID() != pid2.asTPCID()) {
58  throw cet::exception("GeometryCore")
59  << caller << " needs two planes on the same TPC (got " << std::string(pid1) << " and "
60  << std::string(pid2) << ")\n";
61  }
62  if (pid1 == pid2) { // was: return 999;
63  throw cet::exception("GeometryCore")
64  << caller << " needs two different planes, got " << std::string(pid1) << " twice\n";
65  }
66  }
67 }
68 
69 namespace geo {
70 
71  //......................................................................
72  // Constructor.
74  : fSurfaceY(pset.get<double>("SurfaceY"))
75  , fDetectorName(pset.get<std::string>("Name"))
76  , fMinWireZDist(pset.get<double>("MinWireZDist", 3.0))
77  , fPositionWiggle(pset.get<double>("PositionEpsilon", 1.e-4))
78  , fBuilderParameters(pset.get<fhicl::ParameterSet>("Builder", fhicl::ParameterSet()))
79  {
80  std::transform(fDetectorName.begin(), fDetectorName.end(), fDetectorName.begin(), ::tolower);
81  }
82 
83  //......................................................................
84  void GeometryCore::ApplyChannelMap(std::unique_ptr<ChannelMapAlg> pChannelMap)
85  {
86  SortGeometry(pChannelMap->Sorter());
87  UpdateAfterSorting(); // after channel mapping has sorted objects, set their IDs
88  pChannelMap->Initialize(fGeoData);
89  fChannelMapAlg = move(pChannelMap);
90  }
91 
92  //......................................................................
93  void GeometryCore::LoadGeometryFile(std::string gdmlfile,
94  std::string rootfile,
95  GeometryBuilder& builder,
96  bool bForceReload /* = false*/
97  )
98  {
99  if (gdmlfile.empty()) {
100  throw cet::exception("GeometryCore") << "No GDML Geometry file specified!\n";
101  }
102 
103  if (rootfile.empty()) {
104  throw cet::exception("GeometryCore") << "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)
114  TGeoManager::UnlockGeometry();
115  else { // very first time (or so it should)
116  // [20210630, petrillo@slac.stanford.edu]
117  // ROOT 6.22.08 allows us to choose the representation of lengths
118  // in the geometry objects parsed from GDML.
119  // In LArSoft we want them to be centimeters (ROOT standard).
120  // This was tracked as Redmine issue #25990, and I leave this mark
121  // because I feel that we'll be back to it not too far in the future.
122  // Despite the documentation (ROOT 6.22/08),
123  // it seems the units are locked from the beginning,
124  // so we unlock without prejudice.
125  TGeoManager::LockDefaultUnits(false);
126  TGeoManager::SetDefaultUnits(TGeoManager::kRootUnits);
127  TGeoManager::LockDefaultUnits(true);
128  }
129  TGeoManager::Import(rootfile.c_str());
130  gGeoManager->LockGeometry();
131  }
132 
133  BuildGeometry(builder);
134 
135  fGDMLfile = move(gdmlfile);
136  fROOTfile = move(rootfile);
137 
138  mf::LogInfo("GeometryCore") << "New detector geometry loaded from "
139  << "\n\t" << fROOTfile << "\n\t" << fGDMLfile << "\n";
140  } // GeometryCore::LoadGeometryFile()
141 
142  //......................................................................
143  void GeometryCore::LoadGeometryFile(std::string gdmlfile,
144  std::string rootfile,
145  bool bForceReload /* = false*/
146  )
147  {
149  {"tool_type"});
150  // this is a wink to the understanding that we might be using an art-based
151  // service provider configuration sprinkled with tools.
152  GeometryBuilderStandard builder{builderConfig()};
153  LoadGeometryFile(gdmlfile, rootfile, builder, bForceReload);
154  }
155 
156  //......................................................................
158  {
159  fGeoData = {};
160  }
161 
162  //......................................................................
164  {
165  mf::LogInfo("GeometryCore") << "Sorting volumes...";
166 
167  sorter.SortAuxDets(AuxDets());
168  sorter.SortCryostats(Cryostats());
169 
171  for (CryostatGeo& cryo : Cryostats()) {
172  cryo.SortSubVolumes(sorter);
173  cryo.UpdateAfterSorting(CryostatID(c));
174  ++c;
175  }
176  }
177 
178  //......................................................................
180  {
181  for (size_t c = 0; c < Ncryostats(); ++c)
182  Cryostats()[c].UpdateAfterSorting(CryostatID(c));
183 
184  allViews.clear();
185  for (auto const& tpc : Iterate<TPCGeo>()) {
186  auto const& TPCviews = tpc.Views();
187  allViews.insert(TPCviews.cbegin(), TPCviews.cend());
188  }
189  }
190 
191  //......................................................................
192  TGeoManager* GeometryCore::ROOTGeoManager() const
193  {
194  return gGeoManager;
195  }
196 
197  //......................................................................
198  unsigned int GeometryCore::Nchannels() const
199  {
200  return fChannelMapAlg->Nchannels();
201  }
202 
203  //......................................................................
204  unsigned int GeometryCore::Nchannels(readout::ROPID const& ropid) const
205  {
206  return fChannelMapAlg->Nchannels(ropid);
207  }
208 
209  //......................................................................
210  std::vector<raw::ChannelID_t> GeometryCore::ChannelsInTPCs() const
211  {
212  std::vector<raw::ChannelID_t> channels;
213  channels.reserve(fChannelMapAlg->Nchannels());
214 
215  for (auto const& ts : Iterate<readout::TPCsetID>()) {
216  for (auto const t : fChannelMapAlg->TPCsetToTPCs(ts)) {
217  for (auto const& wire : Iterate<WireID>(t)) {
218  channels.push_back(fChannelMapAlg->PlaneWireToChannel(wire));
219  }
220  }
221  }
222  std::sort(channels.begin(), channels.end());
223  auto last = std::unique(channels.begin(), channels.end());
224  channels.erase(last, channels.end());
225  return channels;
226  }
227 
228  //......................................................................
229  unsigned int GeometryCore::NOpDets() const
230  {
231  int N = 0;
232  for (size_t cstat = 0; cstat != Ncryostats(); ++cstat)
233  N += this->Cryostat(CryostatID(cstat)).NOpDet();
234  return N;
235  }
236 
237  //......................................................................
238  unsigned int GeometryCore::NOpChannels() const
239  {
240  return fChannelMapAlg->NOpChannels(this->NOpDets());
241  }
242 
243  //......................................................................
244  unsigned int GeometryCore::MaxOpChannel() const
245  {
246  return fChannelMapAlg->MaxOpChannel(this->NOpDets());
247  }
248 
249  //......................................................................
250  unsigned int GeometryCore::NOpHardwareChannels(int opDet) const
251  {
252  return fChannelMapAlg->NOpHardwareChannels(opDet);
253  }
254 
255  //......................................................................
256  unsigned int GeometryCore::OpChannel(int detNum, int hardwareChannel) const
257  {
258  return fChannelMapAlg->OpChannel(detNum, hardwareChannel);
259  }
260 
261  //......................................................................
262  unsigned int GeometryCore::OpDetFromOpChannel(int opChannel) const
263  {
264  return fChannelMapAlg->OpDetFromOpChannel(opChannel);
265  }
266 
267  //......................................................................
268  unsigned int GeometryCore::HardwareChannelFromOpChannel(int opChannel) const
269  {
270  return fChannelMapAlg->HardwareChannelFromOpChannel(opChannel);
271  }
272 
273  //......................................................................
274  bool GeometryCore::IsValidOpChannel(int opChannel) const
275  {
276  return fChannelMapAlg->IsValidOpChannel(opChannel, this->NOpDets());
277  }
278 
279  //......................................................................
280  unsigned int GeometryCore::NAuxDetSensitive(size_t const& aid) const
281  {
282  if (aid < NAuxDets()) { return AuxDets()[aid].NSensitiveVolume(); }
283  throw cet::exception("Geometry")
284  << "Requested AuxDet index " << aid << " is out of range: " << NAuxDets();
285  }
286 
287  //......................................................................
288  // Number of different views, or wire orientations
289  unsigned int GeometryCore::Nviews() const
290  {
291  return MaxPlanes();
292  }
293 
294  //......................................................................
295  //
296  // Return the geometry description of the ith plane in the detector.
297  //
298  // \param cstat : input cryostat number, starting from 0
299  // \returns cryostat geometry for ith cryostat
300  //
301  // \throws geo::Exception if "cstat" is outside allowed range
302  //
303  CryostatGeo const& GeometryCore::Cryostat(CryostatID const& cryoid) const
304  {
305  if (auto pCryo = CryostatPtr(cryoid)) { return *pCryo; }
306  throw cet::exception("GeometryCore") << "Cryostat #" << cryoid.Cryostat << " does not exist\n";
307  }
308 
309  //......................................................................
310  //
311  // Return the geometry description of the ith AuxDet.
312  //
313  // \param ad : input AuxDet number, starting from 0
314  // \returns AuxDet geometry for ith AuxDet
315  //
316  // \throws geo::Exception if "ad" is outside allowed range
317  //
318  const AuxDetGeo& GeometryCore::AuxDet(unsigned int const ad) const
319  {
320  if (ad >= NAuxDets())
321  throw cet::exception("GeometryCore") << "AuxDet " << ad << " does not exist\n";
322  return AuxDets()[ad];
323  }
324 
325  //......................................................................
327  {
328  // first find the cryostat
329  CryostatGeo const* cryo = PositionToCryostatPtr(point);
330  if (!cryo) return {};
331 
332  // then ask it about the TPC
333  TPCID tpcid = cryo->PositionToTPCID(point, 1. + fPositionWiggle);
334  if (tpcid) return tpcid;
335 
336  // return an invalid TPC ID with cryostat information set:
337  tpcid.Cryostat = cryo->ID().Cryostat;
338  tpcid.markInvalid();
339  return tpcid;
340  }
341 
342  //......................................................................
344  {
345  for (auto const& cryostat : Iterate<CryostatGeo>()) {
346  if (cryostat.ContainsPosition(point, 1.0 + fPositionWiggle)) return &cryostat;
347  }
348  return nullptr;
349  }
350 
351  //......................................................................
353  {
354  CryostatGeo const* cryo = PositionToCryostatPtr(point);
355  return cryo ? cryo->ID() : CryostatID{};
356  }
357 
358  //......................................................................
359  TPCGeo const* GeometryCore::PositionToTPCptr(Point_t const& point) const
360  {
361  CryostatGeo const* cryo = PositionToCryostatPtr(point);
362  return cryo ? cryo->PositionToTPCptr(point, 1. + fPositionWiggle) : nullptr;
363  }
364 
365  //......................................................................
366  TPCGeo const& GeometryCore::PositionToTPC(Point_t const& point) const
367  {
368  if (auto tpc = PositionToTPCptr(point)) { return *tpc; }
369  throw cet::exception("GeometryCore") << "Can't find any TPC at position " << point << "\n";
370  }
371 
372  //......................................................................
374  {
375  TPCGeo const* tpc = PositionToTPCptr(point);
376  return tpc ? tpc->ID() : TPCID{};
377  }
378 
379  //......................................................................
381  {
382  if (MaxTPCs() == 0) {
383  GetBeginID(id);
384  id.markInvalid();
385  }
386  else {
387  GetEndID(id.asCryostatID());
388  id.deepestIndex() = 0;
389  }
390  }
391 
392  //......................................................................
394  {
395  if (CryostatGeo const* cryo = CryostatPtr(id); cryo && cryo->NTPC() > 0)
396  return {id.Cryostat + 1, 0};
397  TPCID tpcid = GetBeginTPCID(id);
398  tpcid.markInvalid();
399  return tpcid;
400  }
401 
402  //......................................................................
404  {
405  if (auto cstat = PositionToCryostatPtr(point)) { return *cstat; }
406  throw cet::exception("GeometryCore") << "Can't find any cryostat at position " << point << "\n";
407  }
408 
409  //......................................................................
410  unsigned int GeometryCore::FindAuxDetAtPosition(Point_t const& point, double tolerance) const
411  {
412  return fChannelMapAlg->NearestAuxDet(point, AuxDets(), tolerance);
413  }
414 
415  //......................................................................
417  unsigned int& ad,
418  double tolerance) const
419  {
420  // locate the desired Auxiliary Detector
421  ad = FindAuxDetAtPosition(point, tolerance);
422  return AuxDet(ad);
423  }
424 
425  //......................................................................
427  std::size_t& adg,
428  std::size_t& sv,
429  double tolerance) const
430  {
431  adg = FindAuxDetAtPosition(point, tolerance);
432  sv = fChannelMapAlg->NearestSensitiveAuxDet(point, AuxDets(), tolerance);
433  }
434 
435  //......................................................................
437  size_t& ad,
438  size_t& sv,
439  double tolerance) const
440  {
441  // locate the desired Auxiliary Detector
442  FindAuxDetSensitiveAtPosition(point, ad, sv, tolerance);
443  return AuxDet(ad).SensitiveVolume(sv);
444  }
445 
446  //......................................................................
447  const AuxDetGeo& GeometryCore::ChannelToAuxDet(std::string const& auxDetName,
448  uint32_t const& channel) const
449  {
450  size_t adIdx = fChannelMapAlg->ChannelToAuxDet(AuxDets(), auxDetName, channel);
451  return this->AuxDet(adIdx);
452  }
453 
454  //......................................................................
455  const AuxDetSensitiveGeo& GeometryCore::ChannelToAuxDetSensitive(std::string const& auxDetName,
456  uint32_t const& channel) const
457  {
458  auto idx = fChannelMapAlg->ChannelToSensitiveAuxDet(AuxDets(), auxDetName, channel);
459  return this->AuxDet(idx.first).SensitiveVolume(idx.second);
460  }
461 
462  //......................................................................
464  {
465  return fChannelMapAlg->SignalTypeForChannel(channel);
466  }
467 
468  //......................................................................
470  {
471  // map wire plane -> readout plane -> first channel,
472  // then use SignalType(channel)
473 
474  auto const ropid = WirePlaneToROP(pid);
475  if (!ropid.isValid) {
476  throw cet::exception("GeometryCore") << "SignalType(): Mapping of wire plane "
477  << std::string(pid) << " to readout plane failed!\n";
478  }
479  return SignalType(ropid);
480  }
481 
482  //......................................................................
484  {
485  return (channel == raw::InvalidChannelID) ? kUnknown : View(ChannelToROP(channel));
486  }
487 
488  //......................................................................
490  {
491  return pid ? Plane(pid).View() : kUnknown;
492  }
493 
494  //--------------------------------------------------------------------
496  {
497  return fChannelMapAlg->HasChannel(channel);
498  }
499 
500  //......................................................................
501  const std::string GeometryCore::GetWorldVolumeName() const
502  {
503  // For now, and possibly forever, this is a constant (given the
504  // definition of "nodeNames" above).
505  return std::string("volWorld");
506  }
507 
508  //......................................................................
510  std::string const& name /* = "volDetEnclosure" */) const
511  {
512  auto const& path = FindDetectorEnclosure(name);
513  if (path.empty()) {
514  throw cet::exception("GeometryCore")
515  << "DetectorEnclosureBox(): can't find enclosure volume '" << name << "'\n";
516  }
517 
518  TGeoVolume const* pEncl = path.back()->GetVolume();
519  auto const* pBox = dynamic_cast<TGeoBBox const*>(pEncl->GetShape());
520 
521  // check that this is indeed a box
522  if (!pBox) {
523  // at initialisation time we don't know yet our real ID
524  throw cet::exception("GeometryCore")
525  << "Detector enclosure '" << name << "' is not a box! (it is a "
526  << pEncl->GetShape()->IsA()->GetName() << ")\n";
527  }
528 
529  LocalTransformation<TGeoHMatrix> trans(path, path.size() - 1);
530  // get the half width, height, etc of the cryostat
531  const double halfwidth = pBox->GetDX();
532  const double halfheight = pBox->GetDY();
533  const double halflength = pBox->GetDZ();
534 
535  return {trans.LocalToWorld(Point_t{-halfwidth, -halfheight, -halflength}),
536  trans.LocalToWorld(Point_t{+halfwidth, +halfheight, +halflength})};
537  }
538 
539  //......................................................................
563  public:
564  explicit ROOTGeoNodeForwardIterator(TGeoNode const* start_node);
565 
567  TGeoNode const* operator*() const
568  {
569  return current_path.empty() ? nullptr : current_path.back().self;
570  }
571 
573  ROOTGeoNodeForwardIterator& operator++();
574 
576  std::vector<TGeoNode const*> get_path() const;
577 
578  private:
579  struct NodeInfo_t {
580  TGeoNode const* self;
581  int sibling;
582  };
583 
585  std::vector<NodeInfo_t> current_path;
586 
587  void reach_deepest_descendant();
588  }; // class ROOTGeoNodeForwardIterator
589 
591  std::set<std::string> const* vol_names;
592 
593  NodeNameMatcherClass(std::set<std::string> const& names) : vol_names(&names) {}
594 
596  bool operator()(TGeoNode const& node) const
597  {
598  if (!vol_names) return true;
599  return vol_names->find(node.GetVolume()->GetName()) != vol_names->end();
600  }
601 
602  }; // NodeNameMatcherClass
603 
605  std::vector<TGeoNode const*> nodes;
606 
607  CollectNodesByName(std::set<std::string> const& names) : matcher(names) {}
608 
610  void operator()(TGeoNode const& node)
611  {
612  if (matcher(node)) nodes.push_back(&node);
613  }
614 
615  void operator()(ROOTGeoNodeForwardIterator const& iter) { operator()(**iter); }
616 
617  protected:
619  }; // CollectNodesByName
620 
622  std::vector<std::vector<TGeoNode const*>> paths;
623 
624  CollectPathsByName(std::set<std::string> const& names) : matcher(names) {}
625 
628  {
629  if (matcher(**iter)) paths.push_back(iter.get_path());
630  }
631 
632  protected:
634  }; // CollectPathsByName
635 
636  //......................................................................
637  std::vector<TGeoNode const*> GeometryCore::FindAllVolumes(
638  std::set<std::string> const& vol_names) const
639  {
640  CollectNodesByName node_collector(vol_names);
641 
642  ROOTGeoNodeForwardIterator iNode{ROOTGeoManager()->GetTopNode()};
643  TGeoNode const* pCurrentNode;
644 
645  while ((pCurrentNode = *iNode)) {
646  node_collector(*pCurrentNode);
647  ++iNode;
648  }
649 
650  return node_collector.nodes;
651  }
652 
653  //......................................................................
654  std::vector<std::vector<TGeoNode const*>> GeometryCore::FindAllVolumePaths(
655  std::set<std::string> const& vol_names) const
656  {
657  CollectPathsByName path_collector(vol_names);
658 
659  ROOTGeoNodeForwardIterator iNode(ROOTGeoManager()->GetTopNode());
660 
661  while (*iNode) {
662  path_collector(iNode);
663  ++iNode;
664  }
665 
666  return path_collector.paths;
667  }
668 
669  //......................................................................
670  std::string GeometryCore::GetLArTPCVolumeName(TPCID const& tpcid) const
671  {
672  return TPC(tpcid).ActiveVolume()->GetName();
673  }
674 
675  //......................................................................
676  std::string GeometryCore::GetCryostatVolumeName(CryostatID const& cid) const
677  {
678  return Cryostat(cid).Volume()->GetName();
679  }
680 
681  //......................................................................
683  {
684  return TPC(tpcid).ActiveHalfWidth();
685  }
686 
687  //......................................................................
689  {
690  return TPC(tpcid).ActiveHalfHeight();
691  }
692 
693  //......................................................................
695  {
696  return TPC(tpcid).ActiveLength();
697  }
698 
699  //......................................................................
701  {
702  return Cryostat(cid).HalfWidth();
703  }
704 
705  //......................................................................
707  {
708  return Cryostat(cid).HalfHeight();
709  }
710 
711  //......................................................................
713  {
714  return Cryostat(cid).Length();
715  }
716 
717  //......................................................................
719  {
720  if (MaxPlanes() == 0) {
721  GetBeginID(id);
722  id.markInvalid();
723  }
724  else {
725  GetEndID(id.asTPCID());
726  id.deepestIndex() = 0;
727  }
728  }
729 
730  //......................................................................
732  {
733  CryostatGeo const* cryo = CryostatPtr(id);
734  return (cryo && cryo->MaxPlanes() > 0) ? PlaneID{GetEndTPCID(id), 0} : GetBeginPlaneID(id);
735  }
736 
737  //......................................................................
739  {
740  if (TPCGeo const* TPC = TPCPtr(id); TPC && TPC->Nplanes() > 0) return {GetNextID(id), 0};
742  pid.markInvalid();
743  return pid;
744  }
745 
746  //......................................................................
747  // This method returns the distance between the specified planes.
748  // p1 < p2
749  double GeometryCore::PlanePitch(TPCID const& tpcid,
751  PlaneID::PlaneID_t p2) const
752  {
753  return TPC(tpcid).PlanePitch(p1, p2);
754  }
755 
756  double GeometryCore::PlanePitch(PlaneID const& pid1, PlaneID const& pid2) const
757  {
758  return PlanePitch(pid1.asTPCID(), pid1.Plane, pid2.Plane);
759  }
760 
761  //......................................................................
762  // This method returns the distance between wires in a plane.
764  {
765  return Plane(planeid).WirePitch();
766  }
767 
768  //......................................................................
769  // This method returns the distance between wires in the specified view
770  // it assumes all planes of a given view have the same pitch
772  {
773  // look in cryostat 0, tpc 0 to find the plane with the
774  // specified view
775  return TPC({0, 0}).Plane(view).WirePitch();
776  }
777 
778  //......................................................................
779  // This method returns the distance between wires in the specified view
780  // it assumes all planes of a given view have the same pitch
781  double GeometryCore::WireAngleToVertical(View_t view, TPCID const& tpcid) const
782  {
783  // loop over the planes in cryostat 0, tpc 0 to find the plane with the
784  // specified view
785  TPCGeo const& TPC = this->TPC(tpcid);
786  for (unsigned int p = 0; p < TPC.Nplanes(); ++p) {
787  PlaneGeo const& plane = TPC.Plane(p);
788  if (plane.View() == view) return plane.ThetaZ();
789  } // for
790  throw cet::exception("GeometryCore")
791  << "WireAngleToVertical(): no view \"" << PlaneGeo::ViewName(view) << "\" (#" << ((int)view)
792  << ") in " << std::string(tpcid);
793  }
794 
795  //......................................................................
796  unsigned int GeometryCore::MaxTPCs() const
797  {
798  unsigned int maxTPCs = 0;
799  for (CryostatGeo const& cryo : Cryostats()) {
800  unsigned int maxTPCsInCryo = cryo.NTPC();
801  if (maxTPCsInCryo > maxTPCs) maxTPCs = maxTPCsInCryo;
802  }
803  return maxTPCs;
804  }
805 
806  //......................................................................
807  unsigned int GeometryCore::TotalNTPC() const
808  {
809  // it looks like C++11 lambdas have made STL algorithms easier to use,
810  // but only so much:
811  return std::accumulate(
812  Cryostats().begin(), Cryostats().end(), 0U, [](unsigned int sum, CryostatGeo const& cryo) {
813  return sum + cryo.NTPC();
814  });
815  }
816 
817  //......................................................................
818  unsigned int GeometryCore::MaxPlanes() const
819  {
820  unsigned int maxPlanes = 0;
821  for (CryostatGeo const& cryo : Cryostats()) {
822  unsigned int maxPlanesInCryo = cryo.MaxPlanes();
823  if (maxPlanesInCryo > maxPlanes) maxPlanes = maxPlanesInCryo;
824  }
825  return maxPlanes;
826  }
827 
828  //......................................................................
829  unsigned int GeometryCore::MaxWires() const
830  {
831  unsigned int maxWires = 0;
832  for (CryostatGeo const& cryo : Cryostats()) {
833  unsigned int maxWiresInCryo = cryo.MaxWires();
834  if (maxWiresInCryo > maxWires) maxWires = maxWiresInCryo;
835  }
836  return maxWires;
837  }
838 
839  //......................................................................
841  {
842  if (MaxWires() == 0) {
843  GetBeginID(id);
844  id.markInvalid();
845  }
846  else {
847  GetEndID(id.asPlaneID());
848  id.deepestIndex() = 0;
849  }
850  }
851 
852  //......................................................................
854  {
855  CryostatGeo const* cryo = CryostatPtr(id);
856  if (cryo && cryo->MaxWires() > 0) return {GetEndPlaneID(id), 0};
857  WireID wid = GetBeginWireID(id);
858  wid.markInvalid();
859  return wid;
860  }
861 
862  //......................................................................
864  {
865  TPCGeo const* TPC = TPCPtr(id);
866  if (TPC && TPC->MaxWires() > 0) return {GetEndPlaneID(id), 0};
867  WireID wid = GetBeginWireID(id);
868  wid.markInvalid();
869  return wid;
870  }
871 
872  //......................................................................
874  {
875  if (PlaneGeo const* plane = PlanePtr(id); plane && plane->Nwires() > 0)
876  return {GetNextID(id), 0};
877  WireID wid = GetBeginWireID(id);
878  wid.markInvalid();
879  return wid;
880  }
881 
882  //......................................................................
883  TGeoVolume const* GeometryCore::WorldVolume() const
884  {
885  return gGeoManager->FindVolumeFast(GetWorldVolumeName().c_str());
886  }
887 
888  //......................................................................
890  {
891  TGeoVolume const* world = WorldVolume();
892  if (!world) {
893  throw cet::exception("GeometryCore") << "no world volume '" << GetWorldVolumeName() << "'\n";
894  }
895  TGeoShape const* s = world->GetShape();
896  if (!s) {
897  throw cet::exception("GeometryCore")
898  << "world volume '" << GetWorldVolumeName() << "' is shapeless!!!\n";
899  }
900 
901  double x1, x2, y1, y2, z1, z2;
902  s->GetAxisRange(1, x1, x2);
903  s->GetAxisRange(2, y1, y2);
904  s->GetAxisRange(3, z1, z2);
905 
906  // BoxBoundedGeo constructor will sort the coordinates as needed
907  return BoxBoundedGeo{x1, x2, y1, y2, z1, z2};
908  }
909 
910  //......................................................................
911  void GeometryCore::WorldBox(double* xlo,
912  double* xhi,
913  double* ylo,
914  double* yhi,
915  double* zlo,
916  double* zhi) const
917  {
918  BoxBoundedGeo const box = WorldBox();
919  if (xlo) *xlo = box.MinX();
920  if (ylo) *ylo = box.MinY();
921  if (zlo) *zlo = box.MinZ();
922  if (xhi) *xhi = box.MaxX();
923  if (yhi) *yhi = box.MaxY();
924  if (zhi) *zhi = box.MaxZ();
925  }
926 
927  //......................................................................
928  std::string GeometryCore::VolumeName(Point_t const& point) const
929  {
930  // check that the given point is in the World volume at least
931  TGeoVolume const* volWorld = WorldVolume();
932  double halflength = ((TGeoBBox*)volWorld->GetShape())->GetDZ();
933  double halfheight = ((TGeoBBox*)volWorld->GetShape())->GetDY();
934  double halfwidth = ((TGeoBBox*)volWorld->GetShape())->GetDX();
935  if (std::abs(point.x()) > halfwidth || std::abs(point.y()) > halfheight ||
936  std::abs(point.z()) > halflength) {
937  mf::LogWarning("GeometryCoreBadInputPoint")
938  << "point (" << point.x() << "," << point.y() << "," << point.z() << ") "
939  << "is not inside the world volume "
940  << " half width = " << halfwidth << " half height = " << halfheight
941  << " half length = " << halflength << " returning unknown volume name";
942  return "unknownVolume";
943  }
944 
945  return gGeoManager->FindNode(point.X(), point.Y(), point.Z())->GetName();
946  }
947 
948  //......................................................................
949  TGeoMaterial const* GeometryCore::Material(Point_t const& point) const
950  {
951  auto const pNode = gGeoManager->FindNode(point.X(), point.Y(), point.Z());
952  if (!pNode) return nullptr;
953  auto const pMedium = pNode->GetMedium();
954  return pMedium ? pMedium->GetMaterial() : nullptr;
955  }
956 
957  //......................................................................
958  std::string GeometryCore::MaterialName(Point_t const& point) const
959  {
960  // check that the given point is in the World volume at least
961  BoxBoundedGeo worldBox = WorldBox();
962  if (!worldBox.ContainsPosition(point)) {
963  mf::LogWarning("GeometryCoreBadInputPoint")
964  << "point " << point << " is not inside the world volume " << worldBox.Min() << " -- "
965  << worldBox.Max() << "; returning unknown material name";
966  return {"unknownMaterial"};
967  }
968  auto const pMaterial = Material(point);
969  if (!pMaterial) {
970  mf::LogWarning("GeometryCoreBadInputPoint")
971  << "material for point " << point << " not found! returning unknown material name";
972  return {"unknownMaterial"};
973  }
974  return pMaterial->GetName();
975  }
976 
977  //......................................................................
978  std::vector<TGeoNode const*> GeometryCore::FindDetectorEnclosure(
979  std::string const& name /* = "volDetEnclosure" */) const
980  {
981  std::vector<TGeoNode const*> path{ROOTGeoManager()->GetTopNode()};
982  if (!FindFirstVolume(name, path)) path.clear();
983  return path;
984  }
985 
986  //......................................................................
987  bool GeometryCore::FindFirstVolume(std::string const& name,
988  std::vector<const TGeoNode*>& path) const
989  {
990  assert(!path.empty());
991 
992  auto const* pCurrent = path.back();
993 
994  // first check the current layer
995  if (strncmp(name.c_str(), pCurrent->GetName(), name.length()) == 0) return true;
996 
997  //explore the next layer down
998  auto const* pCurrentVolume = pCurrent->GetVolume();
999  unsigned int nd = pCurrentVolume->GetNdaughters();
1000  for (unsigned int i = 0; i < nd; ++i) {
1001  path.push_back(pCurrentVolume->GetNode(i));
1002  if (FindFirstVolume(name, path)) return true;
1003  path.pop_back();
1004  }
1005  return false;
1006  }
1007 
1008  //......................................................................
1010  {
1011  GeoNodePath path{gGeoManager->GetTopNode()};
1012  Cryostats() = builder.extractCryostats(path);
1013  AuxDets() = builder.extractAuxiliaryDetectors(path);
1014  }
1015 
1016  //......................................................................
1017  //
1018  // Return the total mass of the detector
1019  //
1020  //
1021  double GeometryCore::TotalMass(std::string vol) const
1022  {
1023  //the TGeoNode::GetVolume() returns the TGeoVolume of the detector outline
1024  //and ROOT calculates the mass in kg for you
1025  TGeoVolume* gvol = gGeoManager->FindVolumeFast(vol.c_str());
1026  if (gvol) return gvol->Weight();
1027 
1028  throw cet::exception("GeometryCore")
1029  << "could not find specified volume '" << vol << " 'to determine total mass\n";
1030  }
1031 
1032  //......................................................................
1033  double GeometryCore::MassBetweenPoints(Point_t const& p1, Point_t const& p2) const
1034  {
1035  //The purpose of this method is to determine the column density
1036  //between the two points given. Do that by starting at p1 and
1037  //stepping until you get to the node of p2. calculate the distance
1038  //between the point just inside that node and p2 to get the last
1039  //bit of column density
1040  double columnD = 0.;
1041 
1042  //first initialize a track - get the direction cosines
1043  Vector_t const dir = (p2 - p1).Unit();
1044 
1045  double const dxyz[3] = {dir.X(), dir.Y(), dir.Z()};
1046  double const cp1[3] = {p1.X(), p1.Y(), p1.Z()};
1047  gGeoManager->InitTrack(cp1, dxyz);
1048 
1049  //might be helpful to have a point to a TGeoNode
1050  TGeoNode* node = gGeoManager->GetCurrentNode();
1051 
1052  //check that the points are not in the same volume already.
1053  //if they are in different volumes, keep stepping until you
1054  //are in the same volume as the second point
1055  while (!gGeoManager->IsSameLocation(p2.X(), p2.Y(), p2.Z())) {
1056  gGeoManager->FindNextBoundary();
1057  columnD += gGeoManager->GetStep() * node->GetMedium()->GetMaterial()->GetDensity();
1058 
1059  //the act of stepping puts you in the next node and returns that node
1060  node = gGeoManager->Step();
1061  } //end loop to get to volume of second point
1062 
1063  //now you are in the same volume as the last point, but not at that point.
1064  //get the distance between the current point and the last one
1065  Point_t const last = vect::makePointFromCoords(gGeoManager->GetCurrentPoint());
1066  double const lastStep = (p2 - last).R();
1067  columnD += lastStep * node->GetMedium()->GetMaterial()->GetDensity();
1068 
1069  return columnD;
1070  }
1071 
1072  //......................................................................
1073  std::string GeometryCore::Info(std::string indent /* = "" */) const
1074  {
1075  std::ostringstream sstr;
1076  Print(sstr, indent);
1077  return sstr.str();
1078  }
1079 
1080  //......................................................................
1081  std::vector<WireID> GeometryCore::ChannelToWire(raw::ChannelID_t channel) const
1082  {
1083  return fChannelMapAlg->ChannelToWire(channel);
1084  }
1085 
1086  //--------------------------------------------------------------------
1088  {
1089  return fChannelMapAlg->ChannelToROP(channel);
1090  }
1091 
1092  //----------------------------------------------------------------------------
1093  Length_t GeometryCore::WireCoordinate(Point_t const& pos, PlaneID const& planeid) const
1094  {
1095  return Plane(planeid).WireCoordinate(pos);
1096  }
1097 
1098  //----------------------------------------------------------------------------
1099  WireID GeometryCore::NearestWireID(Point_t const& worldPos, PlaneID const& planeid) const
1100  {
1101  return Plane(planeid).NearestWireID(worldPos);
1102  }
1103 
1104  //----------------------------------------------------------------------------
1106  PlaneID const& planeid) const
1107  {
1108  // This method is supposed to return a channel number rather than
1109  // a wire number. Perform the conversion here (although, maybe
1110  // faster if we deal in wire numbers rather than channel numbers?)
1111 
1112  // NOTE on failure both NearestChannel() and upstream:
1113  // * according to documentation, should return invalid channel
1114  // * in the actual code throw an exception because of a BUG
1115  //
1116  // The following implementation automatically becomes in fact compliant to
1117  // the documentation if upstreams becomes compliant to.
1118  // When that happens, just delete this comment.
1119  WireID const wireID = NearestWireID(worldPos, planeid);
1120  return wireID ? PlaneWireToChannel(wireID) : raw::InvalidChannelID;
1121  }
1122 
1123  //--------------------------------------
1125  {
1126  return fChannelMapAlg->PlaneWireToChannel(wireid);
1127  }
1128 
1129  //......................................................................
1130  void GeometryCore::WireEndPoints(WireID const& wireid, double* xyzStart, double* xyzEnd) const
1131  {
1132  Segment_t result = WireEndPoints(wireid);
1133 
1134  xyzStart[0] = result.start().X();
1135  xyzStart[1] = result.start().Y();
1136  xyzStart[2] = result.start().Z();
1137  xyzEnd[0] = result.end().X();
1138  xyzEnd[1] = result.end().Y();
1139  xyzEnd[2] = result.end().Z();
1140 
1141  if (xyzEnd[2] < xyzStart[2]) {
1142  //ensure that "End" has higher z-value than "Start"
1143  std::swap(xyzStart[0], xyzEnd[0]);
1144  std::swap(xyzStart[1], xyzEnd[1]);
1145  std::swap(xyzStart[2], xyzEnd[2]);
1146  }
1147  if (xyzEnd[1] < xyzStart[1] && std::abs(xyzEnd[2] - xyzStart[2]) < 0.01) {
1148  // if wire is vertical ensure that "End" has higher y-value than "Start"
1149  std::swap(xyzStart[0], xyzEnd[0]);
1150  std::swap(xyzStart[1], xyzEnd[1]);
1151  std::swap(xyzStart[2], xyzEnd[2]);
1152  }
1153  }
1154 
1155  //Changed to use WireIDsIntersect(). Apr, 2015 T.Yang
1156  //......................................................................
1159  double& y,
1160  double& z) const
1161  {
1162  // [GP] these errors should be exceptions, and this function is deprecated
1163  // because it violates interoperability
1164  std::vector<WireID> chan1wires = ChannelToWire(c1);
1165  if (chan1wires.empty()) {
1166  mf::LogError("ChannelsIntersect")
1167  << "1st channel " << c1 << " maps to no wire (is it a real one?)";
1168  return false;
1169  }
1170  std::vector<WireID> chan2wires = ChannelToWire(c2);
1171  if (chan2wires.empty()) {
1172  mf::LogError("ChannelsIntersect")
1173  << "2nd channel " << c2 << " maps to no wire (is it a real one?)";
1174  return false;
1175  }
1176 
1177  if (chan1wires.size() > 1) {
1178  mf::LogWarning("ChannelsIntersect")
1179  << "1st channel " << c1 << " maps to " << chan2wires.size() << " wires; using the first!";
1180  return false;
1181  }
1182  if (chan2wires.size() > 1) {
1183  mf::LogError("ChannelsIntersect")
1184  << "2nd channel " << c2 << " maps to " << chan2wires.size() << " wires; using the first!";
1185  return false;
1186  }
1187 
1188  WireIDIntersection widIntersect;
1189  if (this->WireIDsIntersect(chan1wires[0], chan2wires[0], widIntersect)) {
1190  y = widIntersect.y;
1191  z = widIntersect.z;
1192  return true;
1193  }
1194  else {
1195  y = widIntersect.y;
1196  z = widIntersect.z;
1197  return false;
1198  }
1199  }
1200 
1201  //......................................................................
1202  bool GeometryCore::WireIDsIntersect(const WireID& wid1,
1203  const WireID& wid2,
1204  WireIDIntersection& widIntersect) const
1205  {
1206  static_assert(std::numeric_limits<decltype(widIntersect.y)>::has_infinity,
1207  "the vector coordinate type can't represent infinity!");
1208  constexpr auto infinity = std::numeric_limits<decltype(widIntersect.y)>::infinity();
1209 
1210  if (!WireIDIntersectionCheck(wid1, wid2)) {
1211  widIntersect.y = widIntersect.z = infinity;
1212  widIntersect.TPC = TPCID::InvalidID;
1213  return false;
1214  }
1215 
1216  // get the endpoints to see if wires intersect
1217  Segment_t const w1 = WireEndPoints(wid1);
1218  Segment_t const w2 = WireEndPoints(wid2);
1219 
1220  // TODO extract the coordinates in the right way;
1221  // is it any worth, since then the result is in (y, z), whatever it means?
1222  bool const cross = IntersectLines(w1.start().Y(),
1223  w1.start().Z(),
1224  w1.end().Y(),
1225  w1.end().Z(),
1226  w2.start().Y(),
1227  w2.start().Z(),
1228  w2.end().Y(),
1229  w2.end().Z(),
1230  widIntersect.y,
1231  widIntersect.z);
1232  if (!cross) {
1233  widIntersect.y = widIntersect.z = infinity;
1234  widIntersect.TPC = TPCID::InvalidID;
1235  return false;
1236  }
1237  bool const within = lar::util::PointWithinSegments(w1.start().Y(),
1238  w1.start().Z(),
1239  w1.end().Y(),
1240  w1.end().Z(),
1241  w2.start().Y(),
1242  w2.start().Z(),
1243  w2.end().Y(),
1244  w2.end().Z(),
1245  widIntersect.y,
1246  widIntersect.z);
1247 
1248  widIntersect.TPC = (within ? wid1.TPC : TPCID::InvalidID);
1249 
1250  // return whether the intersection is within the length of both wires
1251  return within;
1252  }
1253 
1254  //......................................................................
1255  bool GeometryCore::WireIDsIntersect(const WireID& wid1,
1256  const WireID& wid2,
1257  Point_t& intersection) const
1258  {
1259  //
1260  // This is not a real 3D intersection: the wires do not cross, since they
1261  // are required to belong to two different planes.
1262  //
1263  // After Christopher Backhouse suggestion, we take the point on the first
1264  // wire which is closest to the other one.
1265  //
1266  //
1267  static_assert(std::numeric_limits<decltype(intersection.X())>::has_infinity,
1268  "the vector coordinate type can't represent infinity!");
1269  constexpr auto infinity = std::numeric_limits<decltype(intersection.X())>::infinity();
1270 
1271  if (!WireIDIntersectionCheck(wid1, wid2)) {
1272  intersection = {infinity, infinity, infinity};
1273  return false;
1274  }
1275 
1276  WireGeo const& wire1 = Wire(wid1);
1277  WireGeo const& wire2 = Wire(wid2);
1278 
1279  // distance of the intersection point from the center of the two wires:
1280  IntersectionPointAndOffsets<Point_t> intersectionAndOffset =
1281  WiresIntersectionAndOffsets(wire1, wire2);
1282  intersection = intersectionAndOffset.point;
1283 
1284  bool const within = ((std::abs(intersectionAndOffset.offset1) <= wire1.HalfL()) &&
1285  (std::abs(intersectionAndOffset.offset2) <= wire2.HalfL()));
1286 
1287  // return whether the intersection is within the length of both wires
1288  return within;
1289  }
1290 
1291  //----------------------------------------------------------------------------
1292  PlaneID GeometryCore::ThirdPlane(PlaneID const& pid1, PlaneID const& pid2) const
1293  {
1294  // how many planes in the TPC pid1 belongs to:
1295  const unsigned int nPlanes = Nplanes(pid1);
1296  if (nPlanes != 3) {
1297  throw cet::exception("GeometryCore")
1298  << "ThirdPlane() supports only TPCs with 3 planes, and I see " << nPlanes << " instead\n";
1299  }
1300 
1301  PlaneID::PlaneID_t target_plane = nPlanes;
1302  for (PlaneID::PlaneID_t iPlane = 0; iPlane < nPlanes; ++iPlane) {
1303  if ((iPlane == pid1.Plane) || (iPlane == pid2.Plane)) continue;
1304  if (target_plane != nPlanes) {
1305  throw cet::exception("GeometryCore")
1306  << "ThirdPlane() found too many planes that are not " << std::string(pid1) << " nor "
1307  << std::string(pid2) << "! (first " << target_plane << ", then " << iPlane << ")\n";
1308  } // if we had a target already
1309  target_plane = iPlane;
1310  } // for
1311  if (target_plane == nPlanes) {
1312  throw cet::exception("GeometryCore")
1313  << "ThirdPlane() can't find a plane that is not " << std::string(pid1) << " nor "
1314  << std::string(pid2) << "!\n";
1315  }
1316 
1317  return PlaneID(pid1, target_plane);
1318  }
1319 
1320  //----------------------------------------------------------------------------
1322  double slope1,
1323  PlaneID const& pid2,
1324  double slope2,
1325  PlaneID const& output_plane) const
1326  {
1327  CheckIndependentPlanesOnSameTPC(pid1, pid2, "ThirdPlaneSlope()");
1328 
1329  TPCGeo const& TPC = this->TPC(pid1);
1330 
1331  // We need the "wire coordinate direction" for each plane.
1332  // This is perpendicular to the wire orientation.
1333  // PlaneGeo::PhiZ() defines the right orientation too.
1334  return ComputeThirdPlaneSlope(TPC.Plane(pid1).PhiZ(),
1335  slope1,
1336  TPC.Plane(pid2).PhiZ(),
1337  slope2,
1338  TPC.Plane(output_plane).PhiZ());
1339  }
1340 
1341  //----------------------------------------------------------------------------
1343  double slope1,
1344  PlaneID const& pid2,
1345  double slope2) const
1346  {
1347  PlaneID target_plane = ThirdPlane(pid1, pid2);
1348  return ThirdPlaneSlope(pid1, slope1, pid2, slope2, target_plane);
1349  }
1350 
1351  //----------------------------------------------------------------------------
1353  double slope1,
1354  PlaneID const& pid2,
1355  double slope2,
1356  PlaneID const& output_plane) const
1357  {
1358  CheckIndependentPlanesOnSameTPC(pid1, pid2, "ThirdPlane_dTdW()");
1359 
1360  TPCGeo const& TPC = this->TPC(pid1);
1361 
1362  double angle[3], pitch[3];
1363  PlaneGeo const* const planes[3] = {
1364  &TPC.Plane(pid1), &TPC.Plane(pid2), &TPC.Plane(output_plane)};
1365 
1366  // We need wire pitch and "wire coordinate direction" for each plane.
1367  // The latter is perpendicular to the wire orientation.
1368  // PlaneGeo::PhiZ() defines the right orientation too.
1369  for (size_t i = 0; i < 3; ++i) {
1370  angle[i] = planes[i]->PhiZ();
1371  pitch[i] = planes[i]->WirePitch();
1372  }
1373 
1374  return ComputeThirdPlane_dTdW(
1375  angle[0], pitch[0], slope1, angle[1], pitch[1], slope2, angle[2], pitch[2]);
1376  }
1377 
1378  //----------------------------------------------------------------------------
1380  double slope1,
1381  PlaneID const& pid2,
1382  double slope2) const
1383  {
1384  PlaneID target_plane = ThirdPlane(pid1, pid2);
1385  return ThirdPlane_dTdW(pid1, slope1, pid2, slope2, target_plane);
1386  }
1387 
1388  //----------------------------------------------------------------------------
1389  // Given slopes dTime/dWire in two planes, return with the slope in the 3rd plane.
1390  // Requires slopes to be in the same metrics,
1391  // e.g. converted in a distances ratio.
1392  // B. Baller August 2014
1393  // Rewritten by T. Yang Apr 2015 using the equation in H. Greenlee's talk:
1394  // https://cdcvs.fnal.gov/redmine/attachments/download/1821/larsoft_apr20_2011.pdf
1395  // slide 2
1397  double slope1,
1398  double angle2,
1399  double slope2,
1400  double angle3)
1401  {
1402  // note that, if needed, the trigonometric functions can be pre-calculated.
1403 
1404  // Can't resolve very small slopes
1405  if ((std::abs(slope1) < 0.001) && (std::abs(slope2)) < 0.001) return 0.001;
1406 
1407  // We need the "wire coordinate direction" for each plane.
1408  // This is perpendicular to the wire orientation.
1409  double slope3 = 0.001;
1410  if (std::abs(slope1) > 0.001 && std::abs(slope2) > 0.001) {
1411  slope3 =
1412  (+(1. / slope1) * std::sin(angle3 - angle2) - (1. / slope2) * std::sin(angle3 - angle1)) /
1413  std::sin(angle1 - angle2);
1414  }
1415  if (slope3 != 0.)
1416  slope3 = 1. / slope3;
1417  else
1418  slope3 = 999.;
1419 
1420  return slope3;
1421  }
1422 
1423  //----------------------------------------------------------------------------
1425  double pitch1,
1426  double dTdW1,
1427  double angle2,
1428  double pitch2,
1429  double dTdW2,
1430  double angle_target,
1431  double pitch_target)
1432  {
1433  // we need to convert dt/dw into homogeneous coordinates, and then back;
1434  // slope = [dT * (TDCperiod / driftVelocity)] / [dW * wirePitch]
1435  // The coefficient of dT is assumed to be the same for all the planes,
1436  // and it finally cancels out. Pitches cancel out only if they are all
1437  // the same.
1438  return pitch_target *
1439  ComputeThirdPlaneSlope(angle1, dTdW1 / pitch1, angle2, dTdW2 / pitch2, angle_target);
1440  }
1441 
1442  //......................................................................
1443  // This function is called if it is determined that two wires in a single TPC must overlap.
1444  // To determine the yz coordinate of the wire intersection, we need to know the
1445  // endpoints of both wires in xyz-space, and also their orientation (angle), and the
1446  // inner dimensions of the TPC frame.
1447  // Note: This calculation is entirely dependent on an accurate GDML description of the TPC!
1448  // Mitch - Feb., 2011
1449  // 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
1450  //--------------------------------------------------------------------
1452  WireID const& wid2,
1453  double& y,
1454  double& z) const
1455  {
1456  WireIDIntersection widIntersect;
1457  bool const found = WireIDsIntersect(wid1, wid2, widIntersect);
1458  y = widIntersect.y;
1459  z = widIntersect.z;
1460  return found;
1461  }
1462 
1463  //============================================================================
1464  //=== TPC set information
1465  //===
1466  //--------------------------------------------------------------------
1467  unsigned int GeometryCore::NTPCsets(readout::CryostatID const& cryoid) const
1468  {
1469  return fChannelMapAlg->NTPCsets(cryoid);
1470  }
1471 
1472  //--------------------------------------------------------------------
1473  unsigned int GeometryCore::MaxTPCsets() const
1474  {
1475  return fChannelMapAlg->MaxTPCsets();
1476  }
1477 
1478  //--------------------------------------------------------------------
1479  bool GeometryCore::HasTPCset(readout::TPCsetID const& tpcsetid) const
1480  {
1481  return fChannelMapAlg->HasTPCset(tpcsetid);
1482  }
1483 
1484  //--------------------------------------------------------------------
1486  {
1487  return TPCtoTPCset(FindTPCAtPosition(worldLoc));
1488  }
1489 
1490  //--------------------------------------------------------------------
1492  {
1493  return fChannelMapAlg->TPCtoTPCset(tpcid);
1494  }
1495 
1496  //--------------------------------------------------------------------
1497  std::vector<TPCID> GeometryCore::TPCsetToTPCs(readout::TPCsetID const& tpcsetid) const
1498  {
1499  return fChannelMapAlg->TPCsetToTPCs(tpcsetid);
1500  }
1501 
1502  //============================================================================
1503  //=== Readout plane information
1504  //===
1505  //--------------------------------------------------------------------
1506  unsigned int GeometryCore::NROPs(readout::TPCsetID const& tpcsetid) const
1507  {
1508  return fChannelMapAlg->NROPs(tpcsetid);
1509  }
1510 
1511  //--------------------------------------------------------------------
1512  unsigned int GeometryCore::MaxROPs() const
1513  {
1514  return fChannelMapAlg->MaxROPs();
1515  }
1516 
1517  //--------------------------------------------------------------------
1518  bool GeometryCore::HasROP(readout::ROPID const& ropid) const
1519  {
1520  return fChannelMapAlg->HasROP(ropid);
1521  }
1522 
1523  //--------------------------------------------------------------------
1525  {
1526  return fChannelMapAlg->WirePlaneToROP(planeid);
1527  }
1528 
1529  //--------------------------------------------------------------------
1530  std::vector<PlaneID> GeometryCore::ROPtoWirePlanes(readout::ROPID const& ropid) const
1531  {
1532  return fChannelMapAlg->ROPtoWirePlanes(ropid);
1533  }
1534 
1535  //--------------------------------------------------------------------
1536  std::vector<TPCID> GeometryCore::ROPtoTPCs(readout::ROPID const& ropid) const
1537  {
1538  return fChannelMapAlg->ROPtoTPCs(ropid);
1539  }
1540 
1541  //--------------------------------------------------------------------
1543  {
1544  return fChannelMapAlg->FirstChannelInROP(ropid);
1545  }
1546 
1547  //--------------------------------------------------------------------
1549  {
1550  return View(fChannelMapAlg->FirstWirePlaneInROP(ropid));
1551  }
1552 
1553  //--------------------------------------------------------------------
1555  {
1556  return fChannelMapAlg->SignalTypeForROPID(ropid);
1557  }
1558 
1559  //============================================================================
1560  //--------------------------------------------------------------------
1561  // Return gdml string which gives sensitive opdet name
1562  std::string GeometryCore::OpDetGeoName(CryostatID const& cid) const
1563  {
1564  return Cryostat(cid).OpDetGeoName();
1565  }
1566 
1567  //--------------------------------------------------------------------
1568  // Convert OpDet, Cryo into unique OpDet number
1569  unsigned int GeometryCore::OpDetFromCryo(unsigned int o, unsigned int c) const
1570  {
1571  static bool Loaded = false;
1572  static std::vector<unsigned int> LowestID;
1573  static unsigned int NCryo;
1574 
1575  CryostatID const cid{c};
1576  // If not yet loaded static parameters, do it
1577  if (Loaded == false) {
1578 
1579  Loaded = true;
1580 
1581  // Store the lowest ID for each cryostat
1582  NCryo = Ncryostats();
1583  LowestID.resize(NCryo + 1);
1584  LowestID.at(0) = 0;
1585  for (size_t cryo = 0; cryo != NCryo; ++cryo) {
1586  LowestID.at(cryo + 1) = LowestID.at(cryo) + Cryostat(cid).NOpDet();
1587  }
1588  }
1589 
1590  if ((c < NCryo) && (o < Cryostat(cid).NOpDet())) { return LowestID.at(c) + o; }
1591 
1592  throw cet::exception("OpDetCryoToOpID Error")
1593  << "Coordinates c=" << c << ", o=" << o << " out of range. Abort\n";
1594  }
1595 
1596  //--------------------------------------------------------------------
1598  {
1599  return this->OpDetGeoFromOpDet(this->OpDetFromOpChannel(OpChannel));
1600  }
1601 
1602  //--------------------------------------------------------------------
1603  const OpDetGeo& GeometryCore::OpDetGeoFromOpDet(unsigned int OpDet) const
1604  {
1605  static bool Loaded = false;
1606  static std::vector<unsigned int> LowestID;
1607  static size_t NCryo;
1608  // If not yet loaded static parameters, do it
1609  if (Loaded == false) {
1610 
1611  Loaded = true;
1612 
1613  // Store the lowest ID for each cryostat
1614  NCryo = Ncryostats();
1615  LowestID.resize(NCryo + 1);
1616  LowestID[0] = 0;
1617  for (size_t cryo = 0; cryo != NCryo; ++cryo) {
1618  LowestID[cryo + 1] = LowestID[cryo] + Cryostat(CryostatID(cryo)).NOpDet();
1619  }
1620  }
1621 
1622  for (size_t i = 0; i != NCryo; ++i) {
1623  if ((OpDet >= LowestID[i]) && (OpDet < LowestID[i + 1])) {
1624  int c = i;
1625  int o = OpDet - LowestID[i];
1626  return this->Cryostat(CryostatID(c)).OpDet(o);
1627  }
1628  }
1629  // If we made it here, we didn't find the right combination. abort
1630  throw cet::exception("OpID To OpDetCryo error") << "OpID out of range, " << OpDet << "\n";
1631  }
1632 
1633  //--------------------------------------------------------------------
1634  // Find the closest OpChannel to this point, in the appropriate cryostat
1635  unsigned int GeometryCore::GetClosestOpDet(Point_t const& point) const
1636  {
1637  CryostatGeo const* cryo = PositionToCryostatPtr(point);
1638  if (!cryo) return std::numeric_limits<unsigned int>::max();
1639  int o = cryo->GetClosestOpDet(point);
1640  return OpDetFromCryo(o, cryo->ID().Cryostat);
1641  }
1642 
1643  //--------------------------------------------------------------------
1644  bool GeometryCore::WireIDIntersectionCheck(const WireID& wid1, const WireID& wid2) const
1645  {
1646  if (wid1.asTPCID() != wid2) {
1647  mf::LogError("WireIDIntersectionCheck")
1648  << "Comparing two wires on different TPCs: return failure.";
1649  return false;
1650  }
1651  if (wid1.Plane == wid2.Plane) {
1652  mf::LogError("WireIDIntersectionCheck")
1653  << "Comparing two wires in the same plane: return failure";
1654  return false;
1655  }
1656  if (!HasWire(wid1)) {
1657  mf::LogError("WireIDIntersectionCheck")
1658  << "1st wire " << wid1 << " does not exist (max wire number: " << Nwires(wid1.planeID())
1659  << ")";
1660  return false;
1661  }
1662  if (!HasWire(wid2)) {
1663  mf::LogError("WireIDIntersectionCheck")
1664  << "2nd wire " << wid2 << " does not exist (max wire number: " << Nwires(wid2.planeID())
1665  << ")";
1666  return false;
1667  }
1668  return true;
1669  }
1670 
1671  //--------------------------------------------------------------------
1672  //--- ROOTGeoNodeForwardIterator
1673  //---
1674 
1676  {
1677  if (start_node) {
1678  current_path.push_back({start_node, 0U});
1679  reach_deepest_descendant();
1680  }
1681  }
1682 
1684  {
1685  if (current_path.empty()) return *this;
1686  if (current_path.size() == 1) {
1687  current_path.pop_back();
1688  return *this;
1689  }
1690 
1691  // I am done; all my descendants were also done already;
1692  // first look at my younger siblings
1693  NodeInfo_t& current = current_path.back();
1694  NodeInfo_t const& parent = current_path[current_path.size() - 2];
1695  if (++(current.sibling) < parent.self->GetNdaughters()) {
1696  // my next sibling exists, let's parse his descendents
1697  current.self = parent.self->GetDaughter(current.sibling);
1698  reach_deepest_descendant();
1699  }
1700  else
1701  current_path.pop_back(); // no sibling, it's time for mum
1702  return *this;
1703  }
1704 
1705  //--------------------------------------------------------------------
1706  std::vector<TGeoNode const*> ROOTGeoNodeForwardIterator::get_path() const
1707  {
1708  std::vector<TGeoNode const*> node_path(current_path.size());
1709  std::transform(current_path.begin(),
1710  current_path.end(),
1711  node_path.begin(),
1712  [](NodeInfo_t const& node_info) { return node_info.self; });
1713  return node_path;
1714  }
1715 
1716  //--------------------------------------------------------------------
1718  {
1719  TGeoNode const* descendent = current_path.back().self;
1720  while (descendent->GetNdaughters() > 0) {
1721  descendent = descendent->GetDaughter(0);
1722  current_path.push_back({descendent, 0U});
1723  }
1724  }
1725 
1726 } // namespace geo
geo::TPCID const & ID() const
Returns the identifier of this TPC.
Definition: TPCGeo.h:270
unsigned int NAuxDetSensitive(size_t const &aid) const
Returns the number of sensitive components of auxiliary detector.
CryostatGeo const * PositionToCryostatPtr(Point_t const &point) const
Returns the cryostat at specified location.
WireID GetBeginWireID(CryostatID const &id) const
Returns the ID of the first wire in the specified cryostat.
Geometry description of a TPC wireThe wire is a single straight segment on a wire plane...
Definition: WireGeo.h:114
GeoID GetEndID() const
Returns the (possibly invalid) ID after the last subelement of the detector.
Definition: GeometryCore.h:385
unsigned int GetClosestOpDet(geo::Point_t const &point) const
std::string GetLArTPCVolumeName(TPCID const &tpcid=tpc_zero) const
Return the name of specified LAr TPC volume.
IDparameter< geo::CryostatID > CryostatID
Member type of validated geo::CryostatID parameter.
void LoadGeometryFile(std::string gdmlfile, std::string rootfile, GeometryBuilder &builder, bool bForceReload=false)
Loads the geometry information from the specified files.
Length_t WireCoordinate(Point_t const &pos, PlaneID const &planeid) const
Returns the index of the nearest wire to the specified position.
Specializations of geo_vectors_utils.h for ROOT old vector types.
double z
z position of intersection
Definition: geo_types.h:792
Functions to help with numbers.
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:361
OpDetGeo const & OpDetGeoFromOpDet(unsigned int OpDet) const
Returns the geo::OpDetGeo object for the given detector number.
static std::string ViewName(geo::View_t view)
Returns the name of the specified view.
Definition: PlaneGeo.cxx:682
TGeoNode const * operator*() const
Returns the pointer to the current node, or nullptr if none.
unsigned int TotalNTPC() const
Returns the total number of TPCs in the detector.
void SortGeometry(GeoObjectSorter const &sorter)
Runs the sorting of geometry with the sorter provided by channel mapping.
GeometryData_t fGeoData
The detector description data.
std::vector< PlaneID > ROPtoWirePlanes(readout::ROPID const &ropid) const
Returns a list of ID of planes belonging to the specified ROP.
static constexpr TPCID_t InvalidID
Special code for an invalid ID.
Definition: geo_types.h:397
std::vector< NodeInfo_t > current_path
which node, which sibling?
std::vector< WireID > ChannelToWire(raw::ChannelID_t const channel) const
Returns a list of wires connected to the specified TPC channel.
bool operator()(TGeoNode const &node) const
Returns whether the specified node matches a set of names.
unsigned int MaxPlanes() const
Returns the largest number of planes among the TPCs in this cryostat.
double Length_t
Type used for coordinates and distances. They are measured in centimeters.
Definition: geo_vectors.h:133
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.
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space.
Definition: geo_vectors.h:160
Encapsulate the geometry of the sensitive portion of an auxiliary detector.
GeoID GetBeginID() const
Returns the ID of the first element of the detector.
Definition: GeometryCore.h:357
bool HasWire(WireID const &wireid) const
Returns whether we have the specified wire.
unsigned int FindAuxDetAtPosition(Point_t const &point, double tolerance=0) const
Returns the index of the auxiliary detector at specified location.
void Print(Stream &&out, std::string indent=" ") const
Prints geometry information with maximum verbosity.
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
void BuildGeometry(GeometryBuilder &builder)
double ActiveHalfHeight() const
Half height (associated with y coordinate) of active TPC volume [cm].
Definition: TPCGeo.h:88
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
AuxDetSensitiveGeo const & SensitiveVolume(size_t sv) const
Definition: AuxDetGeo.h:143
Unknown view.
Definition: geo_types.h:142
unsigned int Nplanes() const
Number of planes in this tpc.
Definition: TPCGeo.h:137
Float_t x1[n_points_granero]
Definition: compare.C:5
PlaneGeo const * PlanePtr(PlaneID const &planeid) const
Returns the specified plane.
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.
Length_t DetHalfWidth(TPCID const &tpcid=tpc_zero) const
Returns the half width of the active volume of the specified TPC.
Double_t z
Definition: plot.C:276
double MinX() const
Returns the world x coordinate of the start of the box.
Definition: BoxBoundedGeo.h:90
unsigned int PlaneID_t
Type for the ID number.
Definition: geo_types.h:464
unsigned int GetClosestOpDet(Point_t const &point) const
Find the nearest OpChannel to some point.
The data type to uniquely identify a Plane.
Definition: geo_types.h:463
Geometry information for a single TPC.
Definition: TPCGeo.h:36
Length_t CryostatHalfWidth(CryostatID const &cid=cryostat_zero) const
Returns the half width of the cryostat (x direction)
bool WireIDsIntersect(WireID const &wid1, WireID const &wid2, Point_t &intersection) const
Computes the intersection between two wires.
std::vector< TPCID > TPCsetToTPCs(readout::TPCsetID const &tpcsetid) const
Returns a list of ID of TPCs belonging to the specified TPC set.
unsigned int MaxROPs() const
Returns the largest number of ROPs a TPC set in the detector has.
std::set< View_t > allViews
All views in the detector.
Class identifying a set of TPC sharing readout channels.
Definition: readout_types.h:72
BoxBoundedGeo DetectorEnclosureBox(std::string const &name="volDetEnclosure") const
const std::string GetWorldVolumeName() const
Return the name of the world volume (needed by Geant4 simulation)
Point const & start() const
Definition: GeometryCore.h:128
std::vector< TGeoNode const * > FindDetectorEnclosure(std::string const &name="volDetEnclosure") const
constexpr auto abs(T v)
Returns the absolute value of the argument.
unsigned int NOpHardwareChannels(int opDet) const
Number of electronics channels for all the optical detectors.
Cryostats_t extractCryostats(Path_t const &path)
Looks for all cryostats under the specified path.
bool ChannelsIntersect(raw::ChannelID_t c1, raw::ChannelID_t c2, double &y, double &z) const
Returns an intersection point of two channels.
TGeoVolume const * WorldVolume() const
Returns a pointer to the world volume.
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:211
STL namespace.
details::begin_type< T > begin() const
Initializes the specified ID with the ID of the first cryostat.
Definition: GeometryCore.h:529
unsigned int MaxWires() const
Returns the largest number of wires among all planes in this detector.
TPCID GetEndTPCID(CryostatID const &id) const
readout::TPCsetID FindTPCsetAtPosition(Point_t const &worldLoc) const
Returns the ID of the TPC set at specified location.
double MaxX() const
Returns the world x coordinate of the end of the box.
Definition: BoxBoundedGeo.h:93
virtual void SortAuxDets(std::vector< geo::AuxDetGeo > &adgeo) const =0
bool WireIDIntersectionCheck(const WireID &wid1, const WireID &wid2) const
Wire ID check for WireIDsIntersect methods.
const AuxDetSensitiveGeo & ChannelToAuxDetSensitive(std::string const &auxDetName, uint32_t const &channel) const
Returns the number of auxiliary detectors.
Point const & end() const
Definition: GeometryCore.h:131
double WireCoordinate(geo::Point_t const &point) const
Returns the coordinate of the point on the plane, in wire units.
Definition: PlaneGeo.h:797
void LocalToWorld(double const *local, double *world) const
Transforms a point from local frame to world frame.
bool FindFirstVolume(std::string const &name, std::vector< const TGeoNode * > &path) const
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
TGeoMaterial const * Material(Point_t const &point) const
Returns the material at the specified position.
unsigned int TPC
TPC of intersection.
Definition: geo_types.h:793
Geometry information for a single cryostat.
Definition: CryostatGeo.h:43
WireGeo const & Wire(WireID const &wireid) const
Returns the specified wire.
std::set< std::string > const * vol_names
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
Definition: GeometryCore.h:430
CryostatGeo const & Cryostat(CryostatID const &cryoid=cryostat_zero) const
Returns the specified cryostat.
void operator()(TGeoNode const &node)
If the name of the node matches, records the end node.
CryostatGeo const & PositionToCryostat(Point_t const &point) const
Returns the cryostat at specified location.
unsigned int NOpChannels() const
Number of electronics channels for all the optical detectors.
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).
Length_t CryostatHalfHeight(CryostatID const &cid=cryostat_zero) const
Returns the height of the cryostat (y direction)
TGeoManager * ROOTGeoManager() const
Access to the ROOT geometry description manager.
Length_t DetLength(TPCID const &tpcid=tpc_zero) const
Returns the length of the active volume of the specified TPC.
unsigned int OpDetFromCryo(unsigned int o, unsigned int c) const
Get unique opdet number from cryo and internal count.
std::string OpDetGeoName(CryostatID const &cid=cryostat_zero) const
Returns gdml string which gives sensitive opdet name.
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.
std::vector< std::vector< TGeoNode const * > > paths
TPCGeo const & TPC(TPCID const &tpcid=tpc_zero) const
Returns the specified TPC.
Definition: GeometryCore.h:722
double offset2
Distance from reference point of second line.
geo::TPCGeo const * PositionToTPCptr(geo::Point_t const &point, double wiggle) const
Returns a pointer to the TPC at specified location.
IDparameter< geo::PlaneID > PlaneID
Member type of validated geo::PlaneID parameter.
double ThetaZ() const
Angle of the wires from positive z axis; .
Definition: PlaneGeo.cxx:646
IntersectionPointAndOffsets< Point_t > WiresIntersectionAndOffsets(WireGeo const &wireA, WireGeo const &wireB)
Returns the point of wireA that is closest to wireB.
Definition: WireGeo.h:518
double TotalMass() const
Returns the total mass [kg] of the specified volume (default: world).
Definition: GeometryCore.h:319
bool IntersectLines(double A_start_x, double A_start_y, double A_end_x, double A_end_y, double B_start_x, double B_start_y, double B_end_x, double B_end_y, double &x, double &y)
Computes the intersection between two lines on a plane.
std::vector< TPCID > ROPtoTPCs(readout::ROPID const &ropid) const
Returns a list of ID of TPCs the specified ROP spans.
Access the description of detector geometry.
void operator()(ROOTGeoNodeForwardIterator const &iter)
If the name of the node matches, records the node full path.
virtual void SortCryostats(std::vector< geo::CryostatGeo > &cgeo) const =0
PlaneGeo const & Plane(PlaneID const &planeid) const
Returns the specified wire.
bool HasROP(readout::ROPID const &ropid) const
double WireAngleToVertical(View_t view, TPCID const &tpcid) const
Returns the angle of the wires in the specified view from vertical.
View_t View() const
Which coordinate does this plane measure.
Definition: PlaneGeo.h:166
std::string OpDetGeoName() const
Get name of opdet geometry element.
Definition: CryostatGeo.h:337
NodeNameMatcherClass matcher
std::string VolumeName(Point_t const &point) const
Returns the name of the deepest volume containing specified point.
constexpr ChannelID_t InvalidChannelID
ID of an invalid channel.
Definition: RawTypes.h:31
TPCID FindTPCAtPosition(Point_t const &point) const
Returns the ID of the TPC at specified location.
std::unique_ptr< const ChannelMapAlg > fChannelMapAlg
Object containing the channel to wire mapping.
unsigned int MaxPlanes() const
Returns the largest number of planes among all TPCs in this detector.
Iterator to navigate through all the nodes.
TCanvas * c1
Definition: plotHisto.C:7
TCanvas * c2
Definition: plot_hist.C:75
Class to transform between world and local coordinates.
const TGeoVolume * Volume() const
Pointer to ROOT&#39;s volume descriptor.
Definition: CryostatGeo.h:110
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:572
void operator()(ROOTGeoNodeForwardIterator const &iter)
const OpDetGeo & OpDet(unsigned int iopdet) const
Return the iopdet&#39;th optical detector in the cryostat.
Definition: CryostatGeo.cxx:95
const AuxDetSensitiveGeo & PositionToAuxDetSensitive(Point_t const &point, size_t &ad, size_t &sv, double tolerance=0) const
Returns the auxiliary detector at specified location.
ROOTGeoNodeForwardIterator(TGeoNode const *start_node)
double PhiZ() const
Angle from positive z axis of the wire coordinate axis, in radians.
Definition: PlaneGeo.h:175
AuxDets_t extractAuxiliaryDetectors(Path_t const &path)
Looks for all auxiliary detectors under the specified path.
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.
parameter set interface
TPCGeo const & PositionToTPC(Point_t const &point) const
Returns the TPC at specified location.
CryostatGeo const * CryostatPtr(CryostatID const &cryoid) const
Returns the specified cryostat.
Definition: GeometryCore.h:477
void FindAuxDetSensitiveAtPosition(Point_t const &point, std::size_t &adg, std::size_t &sv, double tolerance=0) const
Fills the indices of the sensitive auxiliary detector at location.
double ActiveHalfWidth() const
Half width (associated with x coordinate) of active TPC volume [cm].
Definition: TPCGeo.h:84
std::string MaterialName(Point_t const &point) const
Name of the deepest material containing the point xyz.
std::string indent(std::size_t const i)
double HalfWidth() const
Half width of the cryostat [cm].
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)
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:175
TPCID GetBeginTPCID(CryostatID const &id) const
Returns the ID of the first TPC in the specified cryostat.
Definition: GeometryCore.h:796
PlaneID GetBeginPlaneID(CryostatID const &id) const
Returns the ID of the first plane of the specified cryostat.
unsigned int MaxOpChannel() const
Largest optical channel number.
const TGeoVolume * ActiveVolume() const
Half width (associated with x coordinate) of active TPC volume [cm].
Definition: TPCGeo.h:108
std::string Info(std::string indent=" ") const
Returns a string with complete geometry information.
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:381
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:481
details::end_type< T > end() const
Initializes the specified ID with the ID of the first cryostat.
Definition: GeometryCore.h:535
void UpdateAfterSorting()
Performs all the updates needed after sorting.
void markInvalid()
Sets the ID as invalid.
Definition: geo_types.h:238
unsigned int MaxWires() const
Returns the largest number of wires among the planes in this TPC.
Definition: TPCGeo.cxx:284
readout::ROPID WirePlaneToROP(PlaneID const &planeid) const
Returns the ID of the ROP planeid belongs to.
AuxDetList_t & AuxDets()
Return the internal auxdet list.
unsigned int MaxWires() const
Returns the largest number of wires among the TPCs in this cryostat.
NodeNameMatcherClass matcher
Point point
Intersection point.
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:92
unsigned int NOpDets() const
Number of OpDets in the whole detector.
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.
constexpr TPCID const & asTPCID() const
Conversion to TPCID (for convenience of notation).
Definition: geo_types.h:438
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.
AuxDetGeo const & PositionToAuxDet(Point_t const &point, unsigned int &ad, double tolerance=0) const
Returns the auxiliary detector at specified location.
double HalfL() const
Returns half the length of the wire [cm].
Definition: WireGeo.h:172
Encapsulate the geometry of an optical detector.
std::string fGDMLfile
path to geometry file used for Geant4 simulation
BoxBoundedGeo WorldBox() const
CryostatID PositionToCryostatID(Point_t const &point) const
Returns the ID of the cryostat at specified location.
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
Definition: geo_vectors.h:180
double MassBetweenPoints(Point_t const &p1, Point_t const &p2) const
Returns the column density between two points.
unsigned int CryostatID_t
Type for the ID number.
Definition: geo_types.h:193
raw::ChannelID_t PlaneWireToChannel(WireID const &wireid) const
Returns the ID of the TPC channel connected to the specified wire.
Standard implementation of geometry extractor.
SigType_t SignalType(PlaneID const &pid) const
Returns the type of signal on the channels of specified TPC plane.
decltype(auto) get(T &&obj)
ADL-aware version of std::to_string.
Definition: StdUtils.h:120
unsigned int NTPCsets(geo::CryostatID const &cryoid) const
Returns the total number of TPC sets in the specified cryostat.
WireID NearestWireID(Point_t const &point, PlaneID const &planeid) const
Returns the ID of wire closest to position in the specified TPC.
A base class aware of world box coordinatesAn object describing a simple shape can inherit from this ...
Definition: BoxBoundedGeo.h:33
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
double ThirdPlane_dTdW(PlaneID const &pid1, double slope1, PlaneID const &pid2, double slope2, PlaneID const &output_plane) const
Returns dT/dW on the third plane, given it in the other two.
unsigned int NOpDet() const
Number of optical detectors in this TPC.
Definition: CryostatGeo.h:321
Length_t CryostatLength(CryostatID const &cid=cryostat_zero) const
Returns the length of the cryostat (z direction)
TPCGeo const * TPCPtr(TPCID const &tpcid) const
Returns the specified TPC.
Definition: GeometryCore.h:735
double y
y position of intersection
Definition: geo_types.h:791
void ApplyChannelMap(std::unique_ptr< ChannelMapAlg > pChannelMap)
Initializes the geometry to work with this channel map.
double MaxZ() const
Returns the world z coordinate of the end of the box.
Length_t PlanePitch(TPCID const &tpcid, PlaneID::PlaneID_t p1=0, PlaneID::PlaneID_t p2=1) const
Returns the distance between two planes.
unsigned int MaxTPCsets() const
Returns the largest number of TPC sets any cryostat in the detector has.
View_t View(PlaneID const &pid) const
Returns the view (wire orientation) on the channels of specified TPC plane.
unsigned int Nwires() const
Number of wires in this plane.
Definition: PlaneGeo.h:242
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
double ThirdPlaneSlope(PlaneID const &pid1, double slope1, PlaneID const &pid2, double slope2, PlaneID const &output_plane) const
Returns the slope on the third plane, given it in the other two.
CryostatList_t & Cryostats()
Return the internal cryostat list.
Simple class with two points (a pair with aliases).
Definition: GeometryCore.h:123
unsigned int Nwires(PlaneID const &planeid) const
Returns the total number of wires in the specified plane.
PlaneID ThirdPlane(PlaneID const &pid1, PlaneID const &pid2) const
Returns the plane that is not in the specified arguments.
readout::TPCsetID TPCtoTPCset(TPCID const &tpcid) const
Returns the ID of the TPC set tpcid belongs to.
const AuxDetGeo & ChannelToAuxDet(std::string const &auxDetName, uint32_t const &channel) const
Returns the number of auxiliary detectors.
raw::ChannelID_t NearestChannel(Point_t const &worldLoc, PlaneID const &planeid) const
Returns the ID of the channel nearest to the specified position.
std::string fDetectorName
Name of the detector.
Data structure for return values of LineClosestPointAndOffsets().
Manages the extraction of LArSoft geometry information from ROOT.
unsigned int Nplanes(TPCID const &tpcid=tpc_zero) const
Returns the total number of planes in the specified TPC.
Definition: GeometryCore.h:977
Representation of a node and its ancestry.
Definition: GeoNodePath.h:37
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.
Length_t DetHalfHeight(TPCID const &tpcid=tpc_zero) const
Returns the half height of the active volume of 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:252
constexpr PlaneID const & planeID() const
Definition: geo_types.h:620
bool IntersectionPoint(WireID const &wid1, WireID const &wid2, double &y, double &z) const
Returns the intersection point of two wires.
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:28
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:399
CollectPathsByName(std::set< std::string > const &names)
Collection of Physical constants used in LArSoft.
Float_t x2[n_points_geant4]
Definition: compare.C:26
Double_t sum
Definition: plot.C:31
GeoID GetNextID(GeoID const &id) const
Returns the ID next to the specified one.
Definition: GeometryCore.h:371
Float_t e
Definition: plot.C:35
WireID GetEndWireID(CryostatID const &id) const
GENVECTOR_CONSTEXPR::geo::Point_t makePointFromCoords(Coords &&coords)
Creates a geo::Point_t from its coordinates (see makeFromCoords()).
TPCGeo const * PositionToTPCptr(Point_t const &point) const
Returns the TPC at specified location.
Namespace collecting geometry-related classes utilities.
fhicl::ParameterSet fBuilderParameters
double MinY() const
Returns the world y coordinate of the start of the box.
double offset1
Distance from reference point of first line.
OpDetGeo const & OpDetGeoFromOpChannel(unsigned int OpChannel) const
Returns the geo::OpDetGeo object for the given 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.
std::string GetCryostatVolumeName(CryostatID const &cid) const
Return the name of LAr TPC volume.
Length_t WirePitch(PlaneID const &planeid=plane_zero) const
Returns the distance between two consecutive wires.
bool IsValidOpChannel(int opChannel) const
Is this a valid OpChannel number?
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.
TPCID PositionToTPCID(Point_t const &point) const
Returns the ID of the TPC at specified location.
Extracts of LArSoft geometry information from ROOT.
std::vector< raw::ChannelID_t > ChannelsInTPCs() const
Returns an std::vector<ChannelID_t> in all TPCs in a TPCSet.
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:378
double Length() const
Length of the cryostat [cm].
Definition: CryostatGeo.h:106
unsigned int NAuxDets() const
Returns the number of auxiliary detectors.
void WireEndPoints(WireID const &wireid, double *xyzStart, double *xyzEnd) const
Fills two arrays with the coordinates of the wire end points.
The data type to uniquely identify a cryostat.
Definition: geo_types.h:192
geo::CryostatID const & ID() const
Returns the identifier of this cryostat.
Definition: CryostatGeo.h:130
bool HasTPCset(readout::TPCsetID const &tpcsetid) const
PlaneID GetEndPlaneID(CryostatID const &id) const