LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
APAGeometryAlg.cxx
Go to the documentation of this file.
1 //
3 // \fileAPAGeometryAlg.cxx
4 //
5 // tylerdalion@gmail.com
6 //
7 // Geometry interface to smooth over the awkwardness of fitting an
8 // APA into LArSoft. It is geared towards making reconstruction simpler
9 //
11 
12 
13 //Framework includes:
19 
28 
29 #include <cmath>
30 #include <vector>
31 #include <algorithm>
32 #include <iostream>
33 #include <fstream>
34 #include <cstdlib>
35 
36 
37 namespace apa{
38 
40  {
41  this->reconfigure(pset);
42  this->Init();
43  }
44 
45 
46  //----------------------------------------------------------
48  {
49  this->Init();
50  }
51 
52  //----------------------------------------------------------
54  {
55  }
56 
57  //----------------------------------------------------------
59  {
60  }
61 
62  //----------------------------------------------------------
64  {
65 
66  // find the number of channels per APA
67  uint32_t channel = 0;
68  while( fGeom->ChannelToWire(channel+1)[0].TPC < 2 ) channel++;
69  fChannelsPerAPA = channel + 1;
70 
71  // Step through channel c and find the view boundaries, until
72  // outside of first APA - these help optimize ChannelToAPAView
73  // (very dependent on the conventions implimented in the channel map)
74  fFirstU = 0;
75  uint32_t c = 1;
76  geo::WireID wid = (fGeom->ChannelToWire(c))[0];
77  geo::WireID lastwid;
78  while( wid.TPC < 2 ){
79 
80  if( fGeom->View(c) == geo::kV && fGeom->View(c-1) == geo::kU ){
81  fLastU = c-1;
82  fFirstV = c; }
83 
84  if( fGeom->View(c) == geo::kZ && fGeom->View(c-1) == geo::kV ){
85  fLastV = c-1;
86  fFirstZ0 = c; }
87 
88  if( wid.TPC == lastwid.TPC + 1 ){
89  fLastZ0 = c-1;
90  fFirstZ1 = c; }
91 
92  lastwid = wid;
93  c++;
94  wid = (fGeom->ChannelToWire(c))[0]; // for the while condition
95 
96  }
97 
98  fLastZ1 = c - 1;
99 
100 
101  if( fLastZ1 + 1 != fChannelsPerAPA ) throw cet::exception("APAGeometryAlg")
102  << "Channel boundaries are inconsistent.\n";
103 
104  // some other things that will be needed
105  fAPAsPerCryo = fGeom->NTPC(0)/2;
108 
109  }
110 
111 
112  //----------------------------------------------------------
113  void APAGeometryAlg::ChannelToAPA( uint32_t chan,
114  unsigned int & apa,
115  unsigned int & cryo){
116 
117  cryo = chan / (fAPAsPerCryo*fChannelsPerAPA);
118 
119  // Number apa uniquely across cryostats so that
120  // apa to recob::Object maps are easy to work with.
121  // If we decide to reset APA number per cryo, uncomment:
122  //chan -= cryo*fAPAsPerCryo*fChannelsPerAPA;
123  apa = chan / fChannelsPerAPA;
124 
125  return;
126  }
127 
128  //----------------------------------------------------------
129  unsigned int APAGeometryAlg::ChannelToAPA( uint32_t chan ){
130 
131  return chan / fChannelsPerAPA;
132  }
133 
134 
135  //----------------------------------------------------------
137 
138  switch(geoview){
139  default :
140  return 0;
141  case geo::kU :
142  return ChannelsInAPAView( kU );
143  case geo::kV :
144  return ChannelsInAPAView( kV );
145  case geo::kZ :
147  return ChannelsInAPAView( kZ0 );
148  else throw cet::exception("ChannelsInView")
149  << "Both Z sides should have the same amount of channels\n";
150  }
151 
152  }
153 
154 
155  //----------------------------------------------------------
157 
158  switch(apaview){
159  default :
160  return 0;
161  case kU :
162  return fFirstV-fFirstU;
163  case kV :
164  return fFirstZ0-fFirstV;
165  case kZ0 :
166  return fFirstZ1-fFirstZ0;
167  case kZ1 :
168  return fLastZ1-fFirstZ1 + 1;
169  }
170 
171  }
172 
173 
174  //----------------------------------------------------------
176  unsigned int apa,
177  unsigned int cryo ){
178 
179 
180  switch(geoview){
181  default :
182  return 0 + (uint32_t)(apa + cryo*fAPAsPerCryo)*fChannelsPerAPA;
183  case geo::kU :
184  return fFirstU + (uint32_t)(apa + cryo*fAPAsPerCryo)*fChannelsPerAPA;
185  case geo::kV :
186  return fFirstV + (uint32_t)(apa + cryo*fAPAsPerCryo)*fChannelsPerAPA;
187  case geo::kZ :
188  //TODO: would need tpc number for the rest of this
189  return fFirstZ0 + (uint32_t)(apa + cryo*fAPAsPerCryo)*fChannelsPerAPA;
190  }
191 
192  }
193 
194  //----------------------------------------------------------
195  uint32_t APAGeometryAlg::FirstChannelInView( uint32_t chan ){
196 
197  geo::View_t geoview = fGeom->View(chan);
198  unsigned int apa, cryo;
199  this->ChannelToAPA( chan, apa, cryo );
200  return this->FirstChannelInView( geoview, chan );
201 
202  }
203 
204  //----------------------------------------------------------
206  uint32_t chan ){
207 
208  unsigned int apa, cryo;
209  this->ChannelToAPA( chan, apa, cryo );
210  return this->FirstChannelInView( geoview, apa, cryo );
211 
212  }
213 
214 
215 
216  //----------------------------------------------------------
218 
219  // it seems trivial to do this for U and V, but this gives a side to
220  // geo::kZ, unlike Geometry::View(c), as is often needed in disambiguation
221 
222  geo::View_t view = fGeom->View( chan );
223  switch(view){
224  default :
225  break;
226  case geo::kU :
227  return kU;
228  case geo::kV :
229  return kV;
230  case geo::kZ :
231  unsigned int modchan = chan % fChannelsPerAPA;
232  // Channel mapping number in the order of U, V, Z0, then Z1
233  if( modchan > fLastV && modchan < fFirstZ1 ) return kZ0;
234  if( modchan > fLastZ0 ) return kZ1;
235  }
236 
237  return kUnknown;
238 
239  }
240 
241 
242  //----------------------------------------------------------
243  std::vector<geo::WireID> APAGeometryAlg::ChanSegsPerSide(uint32_t chan, unsigned int side){
244 
245  std::vector<geo::WireID> wids = fGeom->ChannelToWire(chan);
246  return this->ChanSegsPerSide(wids, side);
247 
248  }
249 
250 
251 
252  //----------------------------------------------------------
253  std::vector<geo::WireID> APAGeometryAlg::ChanSegsPerSide(std::vector<geo::WireID> wids, unsigned int side)
254  {
255  // Given a vector of wireIDs and an APA side, return
256  // the wireIDs the the tpc side where tpc%2 = side
257 
258  std::vector<geo::WireID> thisSide;
259 
260  for(size_t i = 0; i < wids.size(); i++)
261  if( wids[i].TPC % 2 == side ) thisSide.push_back(wids[i]);
262 
263  return thisSide;
264  }
265 
266 
267 
268 
269  //----------------------------------------------------------
271  uint32_t chan,
272  unsigned int const plane,
273  unsigned int const tpc,
274  unsigned int const cstat )
275  {
276 
277  std::vector<geo::WireID> cWids = fGeom->ChannelToWire( chan );
278 
279  if( cWids[0].Cryostat != cstat )
280  throw cet::exception("APAGeometryAlg") << "Channel " << chan
281  << "not in cryostat " << cstat << "\n";
282  if( std::floor( cWids[0].TPC / 2 ) != std::floor( tpc / 2 ) )
283  throw cet::exception("APAGeometryAlg") << "Channel " << chan
284  << "not in APA " << std::floor(tpc/2) << "\n";
285 
286  // special case for vertical wires
287  if(fGeom->View(chan)==geo::kZ) return fGeom->ChannelToWire(chan)[0];
288 
289  unsigned int xyzWire = fGeom->NearestWireID( WorldLoc, plane, tpc, cstat ).Wire;
290 
291  // The desired wire ID will be the only channel
292  // segment within half the channel range.
293  geo::WireID wid;
294  for(size_t i=0; i<cWids.size(); i++){
295  if( cWids[i].TPC != tpc ) continue;
296  if( std::abs((int)cWids[i].Wire - (int)xyzWire) < fChannelRange[plane]/2 ) wid=cWids[i];
297  }
298 
299  return wid;
300 
301  }
302 
303 
304  //----------------------------------------------------------
305  bool APAGeometryAlg::LineSegChanIntersect( TVector3 xyzStart, TVector3 xyzEnd, uint32_t chan,
306  std::vector<geo::WireID> & widsCrossed,
307  bool ExtendLine = true )
308  {
309 
310  // This assumes a smooth wire numbering, and that the line seg is contained in a tpc.
311  // Meant for use with the approximate line calculated
312  // by matching cluster endpoints in disambiguation.
313 
314  // Find tpc, use midpoint in case start/end is on a boundary
315  unsigned int tpc, cryo;
316  double xyzMid[3];
317  xyzMid[0] = (xyzStart[0]+xyzEnd[0])/2;
318  xyzMid[1] = (xyzStart[1]+xyzEnd[1])/2;
319  xyzMid[2] = (xyzStart[2]+xyzEnd[2])/2;
320  fGeom->PositionToTPC(xyzMid, tpc, cryo);
321 
322  // Find the nearest wire number to the line segment endpoints
323  std::vector<geo::WireID> wids = fGeom->ChannelToWire(chan);
324  unsigned int startW = fGeom->NearestWire( xyzStart, wids[0].Plane, tpc, cryo );
325  unsigned int endW = fGeom->NearestWire( xyzEnd, wids[0].Plane, tpc, cryo );
326 
327  if( startW > endW ) std::swap(startW, endW);
328 
329 
330  // Loop through wireIDs and check for intersection, if in the right TPC
331  for( size_t w = 0; w < wids.size(); w++ ){
332  if( wids[w].TPC != tpc ) continue;
333  if( wids[w].Cryostat != cryo ) throw cet::exception("LineSegChanIntersect")
334  << "Channel and line not in the same crostat.\n";
335 
336  // If the current wire id wire number is inbetween the start/end
337  // point wires, the line segment intersects the wireID at some point.
338 
339  // TODO: for now, extend range, but that is application specific. fix asap
340  // The longer we make the range, the more conservative it is, so it is safe
341  // to extend the range a bit to get hits at the ends of the line
342  unsigned int ext = 0;
343  if ( ExtendLine) ext = 10;
344 
345  if( fGeom->ValueInRange( wids[w].Wire*1., (startW-ext)*1., (endW+ext)*1. ) ) widsCrossed.push_back(wids[w]);
346 
347  }
348 
349  if( widsCrossed.size() > 0 ) return true;
350  else return false;
351 
352  }
353 
354 
355 
356  //----------------------------------------------------------
357  std::vector<double> APAGeometryAlg::ThreeChanPos( uint32_t u, uint32_t v, uint32_t z )
358  {
359 
360  // Say we've associated a U, V, and Z channel -- perhaps by associating hits
361  // or cluster endpoints -- these don't necessarily all intersect, but they
362  // are hopefully pretty close. Find the center of the 3 intersections.
363 
364  // get data needed along the way
365  std::vector< geo::WireIDIntersection > UVIntersects;
366  this->APAChannelsIntersect( u, v, UVIntersects );
367  std::vector< double > UVzToZ(UVIntersects.size());
368  geo::WireID Zwid = fGeom->ChannelToWire(z)[0];
369  unsigned int cryo = Zwid.Cryostat;
370  unsigned int tpc = Zwid.TPC;
371  std::vector<geo::WireID> Uwids = fGeom->ChannelToWire(u);
372  std::vector<geo::WireID> Vwids = fGeom->ChannelToWire(v);
373  std::vector<geo::WireID> UwidsInTPC, VwidsInTPC;
374  for(size_t i=0; i<Uwids.size(); i++) if( Uwids[i].TPC==tpc ) UwidsInTPC.push_back(Uwids[i]);
375  for(size_t i=0; i<Vwids.size(); i++) if( Vwids[i].TPC==tpc ) VwidsInTPC.push_back(Vwids[i]);
376  double Zcent[3] = {0.};
377  fGeom->WireIDToWireGeo( Zwid ).GetCenter(Zcent);
378 
379  std::cout << "Zcent = " << Zcent[2] << ", UVintersects zpos = ";
380  for(size_t uv=0; uv<UVIntersects.size(); uv++){
381  std::cout << UVIntersects[uv].z << ", ";
382  }
383  std::cout << "\n";
384 
387 
388  //std::cout << "U = " << u << " V = " << v << ", " << UVIntersects.size() << std::endl;
389 
390  if( UVIntersects.size() == 0 ){
391  if( UwidsInTPC.size() > 1 || VwidsInTPC.size() > 1 )
392  throw cet::exception("ThreeChanPos") << "U/V channels don't intersect, bad return.\n";
393 
394  // Now assume there are only one of each u and v wireIDs on in this TPC
395  mf::LogWarning("ThreeChanPos") << "No U/V intersect, exceptional channels. See if U or V intersects Z\n";
396  std::vector<double> yzCenter(2,0.);
397  geo::WireID Uwid = UwidsInTPC[0];
398  geo::WireID Vwid = VwidsInTPC[0];
399  geo::WireIDIntersection UZInt, VZInt;
400  bool checkUZ = fGeom->WireIDsIntersect( Uwid, Zwid, UZInt );
401  bool checkVZ = fGeom->WireIDsIntersect( Vwid, Zwid, VZInt );
402  if( !checkUZ && !checkVZ )
403  throw cet::exception("NoChanIntersect") << "No channels intersect, bad return.\n";
404  if( checkUZ && !checkVZ ){ yzCenter[0] = UZInt.y; yzCenter[1] = UZInt.z; }
405  if( checkVZ && !checkUZ ){ yzCenter[0] = VZInt.y; yzCenter[1] = VZInt.z; }
406  if( checkUZ && checkVZ ){ yzCenter[0] = (VZInt.y+UZInt.y)/2; yzCenter[1] = (VZInt.z+UZInt.z)/2; }
407  return yzCenter;
408  }
409 
412 
413 
414  // In case the uv channels intersect twice on the same side, choose the best case.
415  // Note: this will not happen for APAs with UV angle at about 36, but will for 45
416  std::cout << "UVzToZ = ";
417  for( size_t widI = 0; widI < UVIntersects.size(); widI++ ){
418  UVzToZ[widI] = std::abs( UVIntersects[widI].z - Zcent[2] );
419  std::cout << UVzToZ[widI] << ", ";
420  }
421  std::cout<<"\n";
422 
423  unsigned int bestWidI = 0;
424  double minZdiff = fGeom->Cryostat(cryo).TPC(tpc).Length(); // start it out at maximum z
425  for( unsigned int widI = 0; widI < UVIntersects.size(); widI++ ){
426 
427  //std::cout << "widI = " << widI << std::endl;
428 
429  if( UVIntersects[widI].TPC == tpc && UVzToZ[widI] < minZdiff ){
430  minZdiff = UVzToZ[widI];
431  bestWidI = widI;
432  //std::cout << "bestWidI = " << bestWidI << std::endl;
433  }
434  }
435  geo::WireIDIntersection ChosenUVInt = UVIntersects[bestWidI];
436 
437  // Now having the UV intersection, get the UZ and VZ
438  double UVInt[3] = {0.};
439  UVInt[1] = ChosenUVInt.y; UVInt[2] = ChosenUVInt.z;
440  geo::WireID Uwid = this->NearestWireIDOnChan( UVInt, u, 0, tpc, cryo );
441  geo::WireID Vwid = this->NearestWireIDOnChan( UVInt, v, 1, tpc, cryo );
442  geo::WireIDIntersection UZInt, VZInt;
443  bool checkUZ = fGeom->WireIDsIntersect( Uwid, Zwid, UZInt );
444  bool checkVZ = fGeom->WireIDsIntersect( Vwid, Zwid, VZInt );
445 
446  std::cout << "UZint.z = " << UZInt.z << " (" << checkUZ << "), VZint.z = " << VZInt.z << " (" << checkVZ << ")\n";
447 
448  // find the center
449  std::vector<double> yzCenter(2,0.);
450 
451 
452  if( !checkUZ || !checkVZ ){
453  //throw cet::exception("ThreeChanPos") << "WireIDs were expected to intersect.\n";
454 
455  std::cout << "ChosenUVint.y = " << ChosenUVInt.y << "ChosenUVint.z = " << ChosenUVInt.z << std::endl;
456 
457  //temporary case
458  yzCenter[0] = ChosenUVInt.y;
459  yzCenter[1] = ChosenUVInt.z;
460 
461 
462  } else {
463 
464  yzCenter[0] = (ChosenUVInt.y + UZInt.y + VZInt.y)/3;
465  yzCenter[1] = (ChosenUVInt.z + UZInt.z + VZInt.z)/3;
466 
467  }
468 
469 
470  return yzCenter;
471 
472  }
473 
474 
475 
476 
477  //----------------------------------------------------------
478  bool APAGeometryAlg::APAChannelsIntersect( uint32_t chan1, uint32_t chan2,
479  std::vector< geo::WireIDIntersection >& IntersectVector )
480  {
481 
482 
483  // Get the WireIDs and view for each channel, make sure views are different
484  geo::WireIDIntersection widIntersect;
485  std::vector< geo::WireID > wids1 = fGeom->ChannelToWire( chan1 );
486  std::vector< geo::WireID > wids2 = fGeom->ChannelToWire( chan2 );
487  geo::View_t view1 = fGeom->View( chan1 );
488  geo::View_t view2 = fGeom->View( chan2 );
489  if( view1 == view2 ){
490  mf::LogWarning("APAChannelsIntersect") << "Comparing two channels in the same view, return false";
491  return false; }
492  if( wids1[0].Cryostat != wids2[0].Cryostat ||
493  this->ChannelToAPA(chan1) != this->ChannelToAPA(chan2) ){
494  throw cet::exception("APAChannelsIntersect") << "Comparing two channels in in different APAs: "
495  << "channel " << chan1 << " in Cryo "
496  << wids1[0].Cryostat << ", APA " << this->ChannelToAPA(chan1)
497  << ", and channel " << chan2 << " in Cryo "
498  << wids2[0].Cryostat << ", APA " << this->ChannelToAPA(chan2)
499  << "\n";
500  return false; }
501 
502 
503  // Loop through wids1 and see if wids2 has any intersecting wires,
504  // given that the WireIDs are in the same TPC
505  for( unsigned int i1 = 0; i1 < wids1.size() ; i1++){
506  for( unsigned int i2 = 0; i2 < wids2.size() ; i2++){
507 
508  // make sure it is reasonable to intersect
509  if( wids1[i1].Plane == wids2[i2].Plane ||
510  wids1[i1].TPC != wids2[i2].TPC || // not reasonable for a *WireID*
511  wids1[i1].Cryostat != wids2[i2].Cryostat ) continue;
512 
513 // std::cout << "Checking: \n WireID 1 = ("
514 // << wids1[i1].Cryostat << "," << wids1[i1].TPC << ","
515 // << wids1[i1].Plane << "," << wids1[i1].Wire
516 // << ") \n WireID 2 = ("
517 // << wids2[i2].Cryostat << "," << wids2[i2].TPC << ","
518 // << wids2[i2].Plane << "," << wids2[i2].Wire << ")" << std::endl;
519 
520  // Check if they even intersect; if they do, push back
521  if( fGeom->WireIDsIntersect( wids1[i1], wids2[i2], widIntersect ) ){
522 
523 // std::cout << "we have an intersect" << std::endl;
524 
525  IntersectVector.push_back( widIntersect );
526  }
527  }
528  }
529 
530  // Of all considered configurations, there are never more than
531  // 4 intersections per channel pair
532  if( IntersectVector.size() > 4 ){
533  mf::LogWarning("APAChannelsIntersect") << "Got " << IntersectVector.size()
534  << " intersections for channels "
535  << chan1 << " and " << chan2
536  << " - never expect more than 4, so far"; }
537 
538 
539  // With increasing IntersectVector index, the WireID
540  // vector indices of the intersecting wireIDs increase.
541  // This matches the direction in which ChannelToWire
542  // builds its output WireID vector in the APA/35t Alg
543  std::sort( IntersectVector.begin(), IntersectVector.end() );
544 
545  // return true if any intersection points were found
546  if( IntersectVector.size() == 0 ) return false;
547  else return true;
548 
549  }
550 
551 
552 
553 
554 } //end namespace apa
bool APAChannelsIntersect(uint32_t chan1, uint32_t chan2, std::vector< geo::WireIDIntersection > &IntersectVector)
If the channels intersect, get all intersections.
double z
z position of intersection
Definition: geo_types.h:494
Encapsulate the construction of a single cyostat.
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
Planes which measure V.
Definition: geo_types.h:77
void Init()
Initialize some chanel numbers to speed up other methods.
unsigned int ChannelToAPA(uint32_t chan)
Get number of the APA containing the given channel.
Declaration of signal hit object.
Double_t z
Definition: plot.C:279
art::ServiceHandle< geo::Geometry > fGeom
std::vector< geo::WireID > ChannelToWire(raw::ChannelID_t const channel) const
Returns a list of wires connected to the specified TPC channel.
Planes which measure Z direction.
Definition: geo_types.h:79
U view on both sides of the APA.
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:313
unsigned int fAPAsPerCryo
V view on both sides of the APA.
geo::Length_t WirePitch(geo::PlaneID const &planeid) const
Returns the distance between two consecutive wires.
double Length() const
Length is associated with z coordinate [cm].
Definition: TPCGeo.h:107
geo::TPCGeo const & PositionToTPC(geo::Point_t const &point) const
Returns the TPC at specified location.
Z view on the larger-x side of the APA.
enum apa::_apa_plane_proj APAView_t
Planes which measure U.
Definition: geo_types.h:76
bool LineSegChanIntersect(TVector3 xyzStart, TVector3 xyzEnd, uint32_t chan, std::vector< geo::WireID > &widsCrossed, bool ExtendLine)
If a line given by start/end points intersects a channel.
uint32_t FirstChannelInView(geo::View_t geoview, unsigned int apa, unsigned int cryo)
APAView_t APAView(uint32_t chan)
Get which of the 4 APA views the channel is in.
geo::WireID::WireID_t NearestWire(geo::Point_t const &point, geo::PlaneID const &planeid) const
Returns the index of wire closest to position in the specified TPC.
std::vector< double > ThreeChanPos(uint32_t u, uint32_t v, uint32_t z)
Find the center of the 3 intersections, choose best if multiple.
std::vector< geo::WireID > ChanSegsPerSide(uint32_t chan, unsigned int side)
CryostatGeo const & Cryostat(geo::CryostatID const &cryoid) const
Returns the specified cryostat.
unsigned int fChannelsPerAPA
All APAs have this same number of channels.
View_t View(geo::PlaneID const &pid) const
Returns the view (wire orientation) on the channels of specified TPC plane.
Definition of data types for geometry description.
Z view on the smaller-x side of the APA.
unsigned int ChannelsInAPAView(APAView_t apaview)
Encapsulate the geometry of a wire.
unsigned int NTPC(unsigned int cstat=0) const
Returns the total number of TPCs in the specified cryostat.
bool WireIDsIntersect(WireID const &wid1, WireID const &wid2, geo::Point_t &intersection) const
Computes the intersection between two wires.
Encapsulate the construction of a single detector plane.
unsigned int ChannelsInView(geo::View_t geoview)
const TPCGeo & TPC(unsigned int itpc) const
Return the itpc&#39;th TPC in the cryostat.
double y
y position of intersection
Definition: geo_types.h:493
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
geo::WireID NearestWireID(geo::Point_t const &point, geo::PlaneID const &planeid) const
Returns the ID of wire closest to position in the specified TPC.
Declaration of basic channel signal object.
void reconfigure(fhicl::ParameterSet const &p)
void GetCenter(double *xyz, double localz=0.0) const
Fills the world coordinate of a point on the wire.
Definition: WireGeo.cxx:68
bool ValueInRange(double value, double min, double max) const
Returns whether a value is within the specified range.
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:203
recob::tracking::Plane Plane
Definition: TrackState.h:17
Float_t w
Definition: plot.C:23
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
Encapsulate the construction of a single detector plane.
WireGeo const & WireIDToWireGeo(geo::WireID const &wireid) const
Returns the specified wire.
geo::WireID NearestWireIDOnChan(const double WorldLoc[3], uint32_t chan, unsigned int const plane, unsigned int const tpc=0, unsigned int const cstat=0)