LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
LArPandoraGeometry.cxx
Go to the documentation of this file.
1 
7 #include "cetlib_except/exception.h"
8 
13 
15 
16 #include <iomanip>
17 #include <set>
18 #include <sstream>
19 
20 namespace lar_pandora
21 {
22 
24 {
25  // Detector gaps can only be loaded once - throw an exception if the output lists are already filled
26  if (!listOfGaps.empty())
27  throw cet::exception("LArPandora") << " LArPandoraGeometry::LoadDetectorGaps --- the list of gaps already exists ";
28 
29  // Loop over drift volumes and write out the dead regions at their boundaries
30  LArDriftVolumeList driftVolumeList;
31  LArPandoraGeometry::LoadGeometry(driftVolumeList);
32 
33  for (LArDriftVolumeList::const_iterator iter1 = driftVolumeList.begin(), iterEnd1 = driftVolumeList.end(); iter1 != iterEnd1; ++iter1)
34  {
35  const LArDriftVolume &driftVolume1 = *iter1;
36 
37  for (LArDriftVolumeList::const_iterator iter2 = iter1, iterEnd2 = driftVolumeList.end(); iter2 != iterEnd2; ++iter2)
38  {
39  const LArDriftVolume &driftVolume2 = *iter2;
40 
41  if (driftVolume1.GetVolumeID() == driftVolume2.GetVolumeID())
42  continue;
43 
44  const float maxDisplacement(30.f); // TODO: 30cm should be fine, but can we do better than a hard-coded number here?
45  const float deltaZ(std::fabs(driftVolume1.GetCenterZ() - driftVolume2.GetCenterZ()));
46  const float deltaY(std::fabs(driftVolume1.GetCenterY() - driftVolume2.GetCenterY()));
47  const float deltaX(std::fabs(driftVolume1.GetCenterX() - driftVolume2.GetCenterX()));
48  const float widthX(0.5f * (driftVolume1.GetWidthX() + driftVolume2.GetWidthX()));
49  const float gapX(deltaX - widthX);
50 
51  if (gapX < 0.f || gapX > maxDisplacement || deltaY > maxDisplacement || deltaZ > maxDisplacement)
52  continue;
53 
54  const float X1((driftVolume1.GetCenterX() < driftVolume2.GetCenterX()) ? (driftVolume1.GetCenterX() + 0.5f * driftVolume1.GetWidthX()) :
55  (driftVolume2.GetCenterX() + 0.5f * driftVolume2.GetWidthX()));
56  const float X2((driftVolume1.GetCenterX() > driftVolume2.GetCenterX()) ? (driftVolume1.GetCenterX() - 0.5f * driftVolume1.GetWidthX()) :
57  (driftVolume2.GetCenterX() - 0.5f * driftVolume2.GetWidthX()));
58  const float Y1(std::min((driftVolume1.GetCenterY() - 0.5f * driftVolume1.GetWidthY()),
59  (driftVolume2.GetCenterY() - 0.5f * driftVolume2.GetWidthY())));
60  const float Y2(std::max((driftVolume1.GetCenterY() + 0.5f * driftVolume1.GetWidthY()),
61  (driftVolume2.GetCenterY() + 0.5f * driftVolume2.GetWidthY())));
62  const float Z1(std::min((driftVolume1.GetCenterZ() - 0.5f * driftVolume1.GetWidthZ()),
63  (driftVolume2.GetCenterZ() - 0.5f * driftVolume2.GetWidthZ())));
64  const float Z2(std::max((driftVolume1.GetCenterZ() + 0.5f * driftVolume1.GetWidthZ()),
65  (driftVolume2.GetCenterZ() + 0.5f * driftVolume2.GetWidthZ())));
66 
67  listOfGaps.push_back(LArDetectorGap(X1, Y1, Z1, X2, Y2, Z2));
68  }
69  }
70 }
71 
72 //------------------------------------------------------------------------------------------------------------------------------------------
73 
75 {
76  if (!outputVolumeList.empty())
77  throw cet::exception("LArPandora") << " LArPandoraGeometry::LoadGeometry --- the list of drift volumes already exists ";
78 
79  // Use a global coordinate system but keep drift volumes separate
80  LArDriftVolumeList inputVolumeList;
81  LArPandoraGeometry::LoadGeometry(inputVolumeList);
82  LArPandoraGeometry::LoadGlobalDaughterGeometry(inputVolumeList, outputVolumeList);
83 
84  // Create mapping between tpc/cstat labels and drift volumes
85  for (const LArDriftVolume &driftVolume : outputVolumeList)
86  {
87  for (const LArDaughterDriftVolume &tpcVolume : driftVolume.GetTpcVolumeList())
88  {
89  (void) outputVolumeMap.insert(LArDriftVolumeMap::value_type(LArPandoraGeometry::GetTpcID(tpcVolume.GetCryostat(), tpcVolume.GetTpc()), driftVolume));
90  }
91  }
92 }
93 
94 //------------------------------------------------------------------------------------------------------------------------------------------
95 
96 unsigned int LArPandoraGeometry::GetVolumeID(const LArDriftVolumeMap &driftVolumeMap, const unsigned int cstat, const unsigned int tpc)
97 {
98  if (driftVolumeMap.empty())
99  throw cet::exception("LArPandora") << " LArPandoraGeometry::GetVolumeID --- detector geometry map is empty";
100 
101  LArDriftVolumeMap::const_iterator iter = driftVolumeMap.find(LArPandoraGeometry::GetTpcID(cstat, tpc));
102 
103  if (driftVolumeMap.end() == iter)
104  throw cet::exception("LArPandora") << " LArPandoraGeometry::GetVolumeID --- found a TPC that doesn't belong to a drift volume";
105 
106  return iter->second.GetVolumeID();
107 }
108 
109 //------------------------------------------------------------------------------------------------------------------------------------------
110 
111 geo::View_t LArPandoraGeometry::GetGlobalView(const unsigned int cstat, const unsigned int tpc, const geo::View_t hit_View)
112 {
113  const bool switchUV(LArPandoraGeometry::ShouldSwitchUV(cstat, tpc));
114 
115  // ATTN This implicitly assumes that there will be u, v and (maybe) one of either w or y views
116  if ((hit_View == geo::kW) || (hit_View == geo::kY))
117  {
118  return geo::kW;
119  }
120  else if(hit_View == geo::kU)
121  {
122  return (switchUV ? geo::kV : geo::kU);
123  }
124  else if(hit_View == geo::kV)
125  {
126  return (switchUV ? geo::kU : geo::kV);
127  }
128  else
129  {
130  throw cet::exception("LArPandora") << " LArPandoraGeometry::GetGlobalView --- found an unknown plane view (not U, V or W) ";
131  }
132 }
133 
134 //------------------------------------------------------------------------------------------------------------------------------------------
135 
136 unsigned int LArPandoraGeometry::GetTpcID(const unsigned int cstat, const unsigned int tpc)
137 {
138  // We assume there will never be more than 10000 TPCs in a cryostat!
139  if (tpc >= 10000)
140  throw cet::exception("LArPandora") << " LArPandoraGeometry::GetTpcID --- found a TPC with an ID greater than 10000 ";
141 
142  return ((10000 * cstat) + tpc);
143 }
144 
145 //------------------------------------------------------------------------------------------------------------------------------------------
146 
147 bool LArPandoraGeometry::ShouldSwitchUV(const unsigned int cstat, const unsigned int tpc)
148 {
149  // We determine whether U and V views should be switched by checking the drift direction
151  const geo::TPCGeo &theTpc(theGeometry->TPC(tpc, cstat));
152 
153  const bool isPositiveDrift(theTpc.DriftDirection() == geo::kPosX);
154  return LArPandoraGeometry::ShouldSwitchUV(isPositiveDrift);
155 }
156 
157 //------------------------------------------------------------------------------------------------------------------------------------------
158 
159 bool LArPandoraGeometry::ShouldSwitchUV(const bool isPositiveDrift)
160 {
161  // We assume that all multiple drift volume detectors have the APA - CPA - APA - CPA design
162  return isPositiveDrift;
163 }
164 
165 //------------------------------------------------------------------------------------------------------------------------------------------
166 
168 {
169  // This method will group TPCs into "drift volumes" (these are regions of the detector that share a common drift direction,
170  // common range of x coordinates, and common detector parameters such as wire pitch and wire angle).
171  if (!driftVolumeList.empty())
172  throw cet::exception("LArPandora") << " LArPandoraGeometry::LoadGeometry --- detector geometry has already been loaded ";
173 
174  typedef std::set<unsigned int> UIntSet;
175 
176  // Pandora requires three independent images, and ability to correlate features between images (via wire angles and transformation plugin).
178  const unsigned int nWirePlanes(theGeometry->MaxPlanes());
179 
180  if (nWirePlanes > 3)
181  throw cet::exception("LArPandora") << " LArPandoraGeometry::LoadGeometry --- More than three wire planes present ";
182 
183  // We here check the plane information only for the first tpc in the first cryostat.
184  if ((0 == theGeometry->Ncryostats()) || (0 == theGeometry->NTPC(0)))
185  throw cet::exception("LArPandora") << " LArPandoraGeometry::LoadGeometry --- unable to access first tpc in first cryostat ";
186 
187  std::unordered_set<geo::_plane_proj> planeSet;
188  for (unsigned int iPlane = 0; iPlane < nWirePlanes; ++iPlane)
189  (void) planeSet.insert(theGeometry->TPC(0, 0).Plane(iPlane).View());
190 
191  if ((nWirePlanes != planeSet.size()) || !planeSet.count(geo::kU) || !planeSet.count(geo::kV) || (planeSet.count(geo::kW) && planeSet.count(geo::kY)))
192  throw cet::exception("LArPandora") << " LArPandoraGeometry::LoadGeometry --- expect to find u and v views; if there is one further view, it must be w or y ";
193 
194  const bool useYPlane((nWirePlanes > 2) && planeSet.count(geo::kY));
195 
196  const float wirePitchU(theGeometry->WirePitch(geo::kU));
197  const float wirePitchV(theGeometry->WirePitch(geo::kV));
198  const float wirePitchW((nWirePlanes < 3) ? 0.5f * (wirePitchU + wirePitchV) : (useYPlane) ? theGeometry->WirePitch(geo::kY) :
199  theGeometry->WirePitch(geo::kW));
200 
201  const float maxDeltaTheta(0.01f); // leave this hard-coded for now
202 
203  // Loop over cryostats
204  for (unsigned int icstat = 0; icstat < theGeometry->Ncryostats(); ++icstat)
205  {
206  UIntSet cstatList;
207 
208  // Loop over TPCs in in this cryostat
209  for (unsigned int itpc1 = 0; itpc1 < theGeometry->NTPC(icstat); ++itpc1)
210  {
211  if (cstatList.end() != cstatList.find(itpc1))
212  continue;
213 
214  // Use this TPC to seed a drift volume
215  const geo::TPCGeo &theTpc1(theGeometry->TPC(itpc1, icstat));
216  cstatList.insert(itpc1);
217 
218  const float wireAngleU(0.5f * M_PI - theGeometry->WireAngleToVertical(geo::kU, itpc1, icstat));
219  const float wireAngleV(0.5f * M_PI - theGeometry->WireAngleToVertical(geo::kV, itpc1, icstat));
220  const float wireAngleW((nWirePlanes < 3) ? 0.f : (useYPlane) ? (std::fabs(0.5f * M_PI - theGeometry->WireAngleToVertical(geo::kY, itpc1, icstat))) :
221  (0.5f * M_PI - theGeometry->WireAngleToVertical(geo::kW, itpc1, icstat)));
222 
223  double localCoord1[3] = {0., 0., 0.};
224  double worldCoord1[3] = {0., 0., 0.};
225  theTpc1.LocalToWorld(localCoord1, worldCoord1);
226 
227  const double min1(worldCoord1[0] - 0.5 * theTpc1.ActiveHalfWidth());
228  const double max1(worldCoord1[0] + 0.5 * theTpc1.ActiveHalfWidth());
229 
230  float driftMinX(worldCoord1[0] - theTpc1.ActiveHalfWidth());
231  float driftMaxX(worldCoord1[0] + theTpc1.ActiveHalfWidth());
232  float driftMinY(worldCoord1[1] - theTpc1.ActiveHalfHeight());
233  float driftMaxY(worldCoord1[1] + theTpc1.ActiveHalfHeight());
234  float driftMinZ(worldCoord1[2] - 0.5f * theTpc1.ActiveLength());
235  float driftMaxZ(worldCoord1[2] + 0.5f * theTpc1.ActiveLength());
236 
237  const bool isPositiveDrift(theTpc1.DriftDirection() == geo::kPosX);
238 
239  UIntSet tpcList;
240  tpcList.insert(itpc1);
241 
242  // Now identify the other TPCs associated with this drift volume
243  for (unsigned int itpc2 = itpc1+1; itpc2 < theGeometry->NTPC(icstat); ++itpc2)
244  {
245  if (cstatList.end() != cstatList.find(itpc2))
246  continue;
247 
248  const geo::TPCGeo &theTpc2(theGeometry->TPC(itpc2, icstat));
249 
250  if (theTpc1.DriftDirection() != theTpc2.DriftDirection())
251  continue;
252 
253  const float dThetaU(theGeometry->WireAngleToVertical(geo::kU, itpc1, icstat) - theGeometry->WireAngleToVertical(geo::kU, itpc2, icstat));
254  const float dThetaV(theGeometry->WireAngleToVertical(geo::kV, itpc1, icstat) - theGeometry->WireAngleToVertical(geo::kV, itpc2, icstat));
255  const float dThetaW((nWirePlanes < 3) ? 0.f : (useYPlane) ? (theGeometry->WireAngleToVertical(geo::kY, itpc1, icstat) - theGeometry->WireAngleToVertical(geo::kY, itpc2, icstat)) :
256  (theGeometry->WireAngleToVertical(geo::kW, itpc1, icstat) - theGeometry->WireAngleToVertical(geo::kW, itpc2, icstat)));
257 
258  if (dThetaU > maxDeltaTheta || dThetaV > maxDeltaTheta || dThetaW > maxDeltaTheta)
259  continue;
260 
261  double localCoord2[3] = {0., 0., 0.};
262  double worldCoord2[3] = {0., 0., 0.};
263  theTpc2.LocalToWorld(localCoord2, worldCoord2);
264 
265  const double min2(worldCoord2[0] - 0.5 * theTpc2.ActiveHalfWidth());
266  const double max2(worldCoord2[0] + 0.5 * theTpc2.ActiveHalfWidth());
267 
268  if ((min2 > max1) || (min1 > max2))
269  continue;
270 
271  cstatList.insert(itpc2);
272  tpcList.insert(itpc2);
273 
274  driftMinX = std::min(driftMinX, static_cast<float>(worldCoord2[0] - theTpc2.ActiveHalfWidth()));
275  driftMaxX = std::max(driftMaxX, static_cast<float>(worldCoord2[0] + theTpc2.ActiveHalfWidth()));
276  driftMinY = std::min(driftMinY, static_cast<float>(worldCoord2[1] - theTpc2.ActiveHalfHeight()));
277  driftMaxY = std::max(driftMaxY, static_cast<float>(worldCoord2[1] + theTpc2.ActiveHalfHeight()));
278  driftMinZ = std::min(driftMinZ, static_cast<float>(worldCoord2[2] - 0.5f * theTpc2.ActiveLength()));
279  driftMaxZ = std::max(driftMaxZ, static_cast<float>(worldCoord2[2] + 0.5f * theTpc2.ActiveLength()));
280  }
281 
282  // Collate the tpc volumes in this drift volume
283  LArDaughterDriftVolumeList tpcVolumeList;
284 
285  for(const unsigned int itpc : tpcList)
286  {
287  tpcVolumeList.push_back(LArDaughterDriftVolume(icstat, itpc));
288  }
289 
290  // Create new daughter drift volume (volume ID = 0 to N-1)
291  driftVolumeList.push_back(LArDriftVolume(driftVolumeList.size(), isPositiveDrift,
292  wirePitchU, wirePitchV, wirePitchW, wireAngleU, wireAngleV, wireAngleW,
293  0.5f * (driftMaxX + driftMinX), 0.5f * (driftMaxY + driftMinY), 0.5f * (driftMaxZ + driftMinZ),
294  (driftMaxX - driftMinX), (driftMaxY - driftMinY), (driftMaxZ - driftMinZ),
295  (wirePitchU + wirePitchV + wirePitchW + 0.1f), tpcVolumeList));
296  }
297  }
298 
299  if (driftVolumeList.empty())
300  throw cet::exception("LArPandora") << " LArPandoraGeometry::LoadGeometry --- failed to find any drift volumes in this detector geometry ";
301 }
302 
303 //------------------------------------------------------------------------------------------------------------------------------------------
304 
306 {
307  // This method will create one or more daughter volumes (these share a common drift orientation along the X-axis,
308  // have parallel or near-parallel wire angles, and similar wire pitches)
309  //
310  // ATTN: we assume that the U and V planes have equal and opposite wire orientations
311 
312  if (!daughterVolumeList.empty())
313  throw cet::exception("LArPandora") << " LArPandoraGeometry::LoadGlobalDaughterGeometry --- daughter geometry has already been loaded ";
314 
315  if (driftVolumeList.empty())
316  throw cet::exception("LArPandora") << " LArPandoraGeometry::LoadGlobalDaughterGeometry --- detector geometry has not yet been loaded ";
317 
318  // Create daughter drift volumes
319  for (const LArDriftVolume &driftVolume : driftVolumeList)
320  {
321  const bool switchViews(LArPandoraGeometry::ShouldSwitchUV(driftVolume.IsPositiveDrift()));
322  const float daughterWirePitchU(switchViews ? driftVolume.GetWirePitchV() : driftVolume.GetWirePitchU());
323  const float daughterWirePitchV(switchViews ? driftVolume.GetWirePitchU() : driftVolume.GetWirePitchV());
324  const float daughterWirePitchW(driftVolume.GetWirePitchW());
325  const float daughterWireAngleU(switchViews ? driftVolume.GetWireAngleV() : driftVolume.GetWireAngleU());
326  const float daughterWireAngleV(switchViews ? driftVolume.GetWireAngleU() : driftVolume.GetWireAngleV());
327  const float daughterWireAngleW(driftVolume.GetWireAngleW());
328 
329  daughterVolumeList.push_back(LArDriftVolume(driftVolume.GetVolumeID(), driftVolume.IsPositiveDrift(),
330  daughterWirePitchU, daughterWirePitchV, daughterWirePitchW, daughterWireAngleU, daughterWireAngleV, daughterWireAngleW,
331  driftVolume.GetCenterX(), driftVolume.GetCenterY() , driftVolume.GetCenterZ(),
332  driftVolume.GetWidthX(), driftVolume.GetWidthY(), driftVolume.GetWidthZ(),
333  driftVolume.GetSigmaUVZ(), driftVolume.GetTpcVolumeList()));
334  }
335 
336  if (daughterVolumeList.empty())
337  throw cet::exception("LArPandora") << " LArPandoraGeometry::LoadGlobalDaughterGeometry --- failed to create daughter geometry list ";
338 }
339 
340 //------------------------------------------------------------------------------------------------------------------------------------------
341 //------------------------------------------------------------------------------------------------------------------------------------------
342 
343 LArDriftVolume::LArDriftVolume(const unsigned int volumeID, const bool isPositiveDrift,
344  const float wirePitchU, const float wirePitchV, const float wirePitchW, const float wireAngleU, const float wireAngleV, const float wireAngleW,
345  const float centerX, const float centerY, const float centerZ, const float widthX, const float widthY, const float widthZ,
346  const float sigmaUVZ, const LArDaughterDriftVolumeList &tpcVolumeList) :
347  m_volumeID(volumeID),
348  m_isPositiveDrift(isPositiveDrift),
349  m_wirePitchU(wirePitchU),
350  m_wirePitchV(wirePitchV),
351  m_wirePitchW(wirePitchW),
352  m_wireAngleU(wireAngleU),
353  m_wireAngleV(wireAngleV),
354  m_wireAngleW(wireAngleW),
355  m_centerX(centerX),
356  m_centerY(centerY),
357  m_centerZ(centerZ),
358  m_widthX(widthX),
359  m_widthY(widthY),
360  m_widthZ(widthZ),
361  m_sigmaUVZ(sigmaUVZ),
362  m_tpcVolumeList(tpcVolumeList)
363 {
364 }
365 
366 //------------------------------------------------------------------------------------------------------------------------------------------
367 
369 {
370  return m_tpcVolumeList;
371 }
372 
373 } // namespace lar_pandora
float GetWidthZ() const
Return Z span of drift volume.
static geo::View_t GetGlobalView(const unsigned int cstat, const unsigned int tpc, const geo::View_t hit_View)
Convert to global coordinate system.
daughter drift volume class to hold properties of daughter drift volumes
std::vector< LArDetectorGap > LArDetectorGapList
LArDriftVolume(const unsigned int volumeID, const bool isPositiveDrift, const float wirePitchU, const float wirePitchV, const float wirePitchW, const float wireAngleU, const float wireAngleV, const float wireAngleW, const float centerX, const float centerY, const float centerZ, const float widthX, const float widthY, const float widthZ, const float sigmaUVZ, const LArDaughterDriftVolumeList &tpcVolumeList)
Constructor.
Helper functions for extracting detector geometry for use in reconsruction.
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
Planes which measure V.
Definition: geo_types.h:77
std::map< unsigned int, LArDriftVolume > LArDriftVolumeMap
LArDaughterDriftVolumeList m_tpcVolumeList
Geometry information for a single TPC.
Definition: TPCGeo.h:37
std::vector< LArDriftVolume > LArDriftVolumeList
static unsigned int GetVolumeID(const LArDriftVolumeMap &driftVolumeMap, const unsigned int cstat, const unsigned int tpc)
Get drift volume ID from a specified cryostat/tpc pair.
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
geo::Length_t WirePitch(geo::PlaneID const &planeid) const
Returns the distance between two consecutive wires.
Planes which measure Y direction.
Definition: geo_types.h:80
Double_t X2
Definition: plot.C:266
float GetCenterZ() const
Return Z position at centre of drift volume.
TFile f
Definition: plotHisto.C:6
static void LoadGeometry(LArDriftVolumeList &outputVolumeList, LArDriftVolumeMap &outputVolumeMap)
Load drift volume geometry.
Planes which measure U.
Definition: geo_types.h:76
View_t View() const
Which coordinate does this plane measure.
Definition: PlaneGeo.h:171
Int_t max
Definition: plot.C:27
unsigned int MaxPlanes() const
Returns the largest number of planes among all TPCs in this detector.
const LArDaughterDriftVolumeList & GetTpcVolumeList() const
Return list of daughter drift volumes associated with this drift volume.
static unsigned int GetTpcID(const unsigned int cstat, const unsigned int tpc)
Generate a unique identifier for each TPC.
intermediate_table::const_iterator const_iterator
float GetCenterX() const
Return X position at centre of drift volume.
Double_t X1
Definition: plot.C:266
Double_t Y1
Definition: plot.C:266
unsigned int GetVolumeID() const
Return unique ID.
static bool ShouldSwitchUV(const unsigned int cstat, const unsigned int tpc)
Return whether U/V should be switched in global coordinate system for this cryostat/tpc.
static void LoadGlobalDaughterGeometry(const LArDriftVolumeList &driftVolumeList, LArDriftVolumeList &daughterVolumeList)
This method will create one or more daughter volumes (these share a common drift orientation along th...
Double_t Z2
Definition: plot.C:266
Encapsulate the geometry of a wire.
unsigned int NTPC(unsigned int cstat=0) const
Returns the total number of TPCs in the specified cryostat.
std::vector< LArDaughterDriftVolume > LArDaughterDriftVolumeList
Double_t Z1
Definition: plot.C:266
Drift towards positive X values.
Definition: geo_types.h:108
Encapsulate the construction of a single detector plane.
Int_t min
Definition: plot.C:26
float GetWidthY() const
Return Y span of drift volume.
float GetCenterY() const
Return Y position at centre of drift volume.
TPCGeo const & TPC(unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified TPC.
drift volume class to hold properties of drift volume
Planes which measure W (third view for Bo, MicroBooNE, etc).
Definition: geo_types.h:78
PlaneGeo const & Plane(geo::View_t view) const
Return the plane in the tpc with View_t view.
Definition: TPCGeo.cxx:299
float GetWidthX() const
Return X span of drift volume.
double WireAngleToVertical(geo::View_t view, geo::TPCID const &tpcid) const
Returns the angle of the wires in the specified view from vertical.
art framework interface to geometry description
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
drift volume class to hold properties of drift volume
Double_t Y2
Definition: plot.C:266
Encapsulate the construction of a single detector plane.
static void LoadDetectorGaps(LArDetectorGapList &listOfGaps)
Load the 2D gaps that go with the chosen geometry.