LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
VertexFinder2D_module.cc
Go to the documentation of this file.
1 //
3 // VertexFinder2D class
4 //
5 // tjyang@fnal.gov
6 //
7 // This algorithm is designed to reconstruct the vertices using the
8 // 2D cluster information
9 //
10 // This is Preliminary Work and needs modifications
11 // ////////////////////////////////////////////////////////////////////////
12 #include <vector>
13 #include <string>
14 #include <iostream>
15 #include <iomanip>
16 #include <ios>
17 #include <sstream>
18 #include <fstream>
19 #include <cmath>
20 #include <algorithm>
21 #include <vector>
22 
23 // Framework includes
28 #include "fhiclcpp/ParameterSet.h"
36 
50 
51 #include "TMath.h"
52 #include "TH1D.h"
53 #include "TVectorD.h"
54 #include "TGeoManager.h"
55 #include "TMath.h"
56 #include "TGraph.h"
57 #include "TF1.h"
58 #include "TVector3.h"
59 
60 struct CluLen{
61  int index;
62  float length;
63 };
64 
65 bool myfunction (CluLen c1, CluLen c2) { return (c1.length>c2.length);}
66 
67 struct SortByWire {
68  bool operator() (art::Ptr<recob::Hit> const& h1, art::Ptr<recob::Hit> const& h2) const {
69  return h1->Channel() < h2->Channel();
70  }
71 };
72 
74 namespace vertex {
75 
77 
78  public:
79 
80  explicit VertexFinder2D(fhicl::ParameterSet const& pset);
81  virtual ~VertexFinder2D();
82  void beginJob();
83  void reconfigure(fhicl::ParameterSet const& p);
84 
85 
86  void produce(art::Event& evt);
87 
88  private:
89 
90  TH1D *dtIC;
91 
92  std::string fClusterModuleLabel;
93 
94  };
95 
96 }
97 
98 namespace vertex{
99 
100 //-----------------------------------------------------------------------------
101  VertexFinder2D::VertexFinder2D(fhicl::ParameterSet const& pset)
102  {
103  this->reconfigure(pset);
104  produces< std::vector<recob::Vertex> >();
105  produces< std::vector<recob::EndPoint2D> >();
106  produces< art::Assns<recob::EndPoint2D, recob::Hit> >();
107  produces< art::Assns<recob::Vertex, recob::Hit> >();
108  produces< art::Assns<recob::Vertex, recob::Shower> >();
109  produces< art::Assns<recob::Vertex, recob::Track> >();
110  }
111 //-----------------------------------------------------------------------------
112  VertexFinder2D::~VertexFinder2D()
113  {
114  }
115 
116  //---------------------------------------------------------------------------
117  void VertexFinder2D::reconfigure(fhicl::ParameterSet const& p)
118  {
119  fClusterModuleLabel = p.get< std::string >("ClusterModuleLabel");
120  return;
121  }
122  //-------------------------------------------------------------------------
124  // get access to the TFile service
126  dtIC = tfs->make<TH1D>("dtIC","It0-Ct0",100,-5,5);
127  dtIC->Sumw2();
128  }
129 
130 // //-----------------------------------------------------------------------------
131  void VertexFinder2D::produce(art::Event& evt)
132  {
133 
134 
136  const detinfo::DetectorProperties* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
137  // define TPC parameters
138  TString tpcName = geom->GetLArTPCVolumeName();
139 
140  double YC = (geom->DetHalfHeight())*2.;
141 
142  // wire angle with respect to the vertical direction
143  double Angle = geom->Plane(1).Wire(0).ThetaZ(false)-TMath::Pi()/2.;
144 
145  // Parameters temporary defined here, but possibly to be retrieved somewhere in the code
146  double timetick = detprop->SamplingRate()*1.e-3; //time sample in us
147  double presamplings = detprop->TriggerOffset(); //trigger offset
148 
149  double wire_pitch = geom->WirePitch(); //wire pitch in cm
150  double Efield_drift = detprop->Efield(); // Electric Field in the drift region in kV/cm
151  double Temperature = detprop->Temperature(); // LAr Temperature in K
152 
153  //drift velocity in the drift region (cm/us)
154  double driftvelocity = detprop->DriftVelocity(Efield_drift,Temperature);
155 
156  //time sample (cm)
157  double timepitch = driftvelocity*timetick;
158 
159  art::Handle< std::vector<recob::Cluster> > clusterListHandle;
160  evt.getByLabel(fClusterModuleLabel,clusterListHandle);
161 
163  for (unsigned int ii = 0; ii < clusterListHandle->size(); ++ii){
164  art::Ptr<recob::Cluster> clusterHolder(clusterListHandle,ii);
165  clusters.push_back(clusterHolder);
166  }
167 
168  art::FindManyP<recob::Hit> fmh(clusterListHandle, evt, fClusterModuleLabel);
169 
170  //Point to a collection of vertices to output.
171  std::unique_ptr<std::vector<recob::Vertex> > vcol(new std::vector<recob::Vertex>); //3D vertex
172  std::unique_ptr<std::vector<recob::EndPoint2D> > epcol(new std::vector<recob::EndPoint2D>); //2D vertex
173  std::unique_ptr< art::Assns<recob::EndPoint2D, recob::Hit> > assnep(new art::Assns<recob::EndPoint2D, recob::Hit>);
174  std::unique_ptr< art::Assns<recob::Vertex, recob::Shower> > assnsh(new art::Assns<recob::Vertex, recob::Shower>);
175  std::unique_ptr< art::Assns<recob::Vertex, recob::Track> > assntr(new art::Assns<recob::Vertex, recob::Track>);
176  std::unique_ptr< art::Assns<recob::Vertex, recob::Hit> > assnh(new art::Assns<recob::Vertex, recob::Hit>);
177 
178  // nplanes here is really being used as a proxy for the
179  // number of views in the detector
180  int nplanes = geom->Views().size();
181 
182  std::vector< std::vector<int> > Cls(nplanes); //index to clusters in each view
183  std::vector< std::vector<CluLen> > clulens(nplanes);
184 
185  std::vector<double> dtdwstart;
186 
187  //loop over clusters
188  for(size_t iclu = 0; iclu < clusters.size(); ++iclu){
189 
190  float w0 = clusters[iclu]->StartWire();
191  float w1 = clusters[iclu]->EndWire();
192  float t0 = clusters[iclu]->StartTick();
193  float t1 = clusters[iclu]->EndTick();
194 // t0 -= detprop->GetXTicksOffset(clusters[iclu]->View(),0,0);
195 // t1 -= detprop->GetXTicksOffset(clusters[iclu]->View(),0,0);
196 
197  CluLen clulen;
198  clulen.index = iclu;
199  clulen.length = sqrt(pow((w0-w1)*wire_pitch,2)+pow(detprop->ConvertTicksToX(t0,clusters[iclu]->View(),0,0)-detprop->ConvertTicksToX(t1,clusters[iclu]->View(),0,0),2));
200 
201  switch(clusters[iclu]->View()){
202 
203  case geo::kU :
204  clulens[0].push_back(clulen);
205  break;
206  case geo::kV :
207  clulens[1].push_back(clulen);
208  break;
209  case geo::kZ :
210  clulens[2].push_back(clulen);
211  break;
212  default :
213  break;
214  }
215 
216  std::vector<double> wires;
217  std::vector<double> times;
218 
219  std::vector< art::Ptr<recob::Hit> > hit = fmh.at(iclu);
220  std::sort(hit.begin(), hit.end(), SortByWire());
221  int n = 0;
222  for(size_t i = 0; i < hit.size(); ++i){
223  wires.push_back(hit[i]->WireID().Wire);
224  times.push_back(hit[i]->PeakTime());
225  ++n;
226  }
227  if(n>=2){
228  TGraph *the2Dtrack = new TGraph(std::min(10,n),&wires[0],&times[0]);
229  try{
230  the2Dtrack->Fit("pol1","Q");
231  TF1 *pol1=(TF1*) the2Dtrack->GetFunction("pol1");
232  double par[2];
233  pol1->GetParameters(par);
234  //std::cout<<iclu<<" "<<par[1]<<" "<<clusters[iclu]->dTdW()<<std::endl;
235  dtdwstart.push_back(par[1]);
236  }
237  catch(...){
238  mf::LogWarning("VertexFinder2D") << "Fitter failed";
239  delete the2Dtrack;
240  dtdwstart.push_back(std::tan(clusters[iclu]->StartAngle()));
241  continue;
242  }
243  delete the2Dtrack;
244  }
245  else dtdwstart.push_back(std::tan(clusters[iclu]->StartAngle()));
246 
247  }
248 
249  //sort clusters based on 2D length
250  for (size_t i = 0; i<clulens.size(); ++i){
251  std::sort (clulens[i].begin(),clulens[i].end(), myfunction);
252  for (size_t j = 0; j<clulens[i].size(); ++j){
253  Cls[i].push_back(clulens[i][j].index);
254  }
255  }
256 
257  std::vector< std::vector<int> > cluvtx(nplanes);
258  std::vector<double> vtx_w;
259  std::vector<double> vtx_t;
260 
261  for (int i = 0; i < nplanes; ++i){
262  if (Cls[i].size() >= 1){
263  //at least one cluster
264  //find the longest two clusters
265  int c1 = -1;
266  int c2 = -1;
267  double ww0 = -999;
268  double wb1 = -999;
269  double we1 = -999;
270  double wb2 = -999;
271  double we2 = -999;
272  double tt1 = -999;
273  double tt2 = -999;
274  double dtdw1 = -999;
275  double dtdw2 = -999;
276  double lclu1 = -999;
277  double lclu2 = -999;
278  for (unsigned j = 0; j<Cls[i].size(); ++j){
279  double lclu = std::sqrt(pow((clusters[Cls[i][j]]->StartWire()-clusters[Cls[i][j]]->EndWire())*13.5,2)
280  +pow(clusters[Cls[i][j]]->StartTick()-clusters[Cls[i][j]]->EndTick(),2));
281  bool rev = false;
282  bool deltaraylike = false;
283  bool enoughhits = false;
284  if (c1 != -1){
285  double wb = clusters[Cls[i][j]]->StartWire();
286  double we = clusters[Cls[i][j]]->EndWire();
287  double tt = clusters[Cls[i][j]]->StartTick();
288  double dtdw = dtdwstart[Cls[i][j]];
289  int nhits = fmh.at(Cls[i][j]).size();
290  ww0 = (tt-tt1+dtdw1*wb1-dtdw*wb)/(dtdw1-dtdw);
291  if (std::abs(wb1-ww0) > std::abs(we1-ww0)) rev = true;//reverse cluster dir
292  if ((!rev && ww0 > wb1+15)||(rev && ww0 < we1-15)) deltaraylike = true;
293  if (((!rev && ww0 > wb1+10)||(rev && ww0 < we1-10)) && nhits < 5) deltaraylike = true;
294  if (wb > wb1+20 && nhits < 20) deltaraylike = true;
295  if (wb > wb1+50 && nhits < 20) deltaraylike = true;
296  if (wb > wb1+8 && TMath::Abs(dtdw1-dtdw) < 0.15) deltaraylike = true;
297  if (std::abs(wb-wb1) > 30 && std::abs(we-we1) > 30) deltaraylike = true;
298  if (std::abs(tt-tt1) > 100) deltaraylike = true; //not really deltaray, but isolated cluster
299  //make sure there are enough hits in the cluster
300  //at leaset 2 hits if goes horizentally, at leaset 4 hits if goes vertically
301  double alpha = std::atan(dtdw);
302  if (nhits >= int(2+3*(1-std::abs(std::cos(alpha))))) enoughhits = true;
303  if (nhits < 5 && (ww0 < wb1-20 || ww0 > we1+20)) enoughhits = false;
304 
305  }
306  //do not replace the second cluster if the 3rd cluster is not consistent with the existing 2
307  bool replace = true;
308  if (c1 != -1 && c2 != -1){
309  double wb = clusters[Cls[i][j]]->StartWire();
310  double we = clusters[Cls[i][j]]->EndWire();
311  ww0 = (tt2-tt1+dtdw1*wb1-dtdw2*wb2)/(dtdw1-dtdw2);
312  if ((std::abs(ww0-wb1) < 10 || std::abs(ww0-we1) < 10) &&
313  (std::abs(ww0-wb2) < 10 || std::abs(ww0-we2) < 10)){
314  if (std::abs(ww0-wb) > 15 && std::abs(ww0-we) > 15) replace = false;
315  }
316  //std::cout<<c1<<" "<<c2<<" "<<ww0<<" "<<wb1<<" "<<wb2<<" "<<wb<<" "<<we<<std::endl;
317  }
318  if (lclu1 < lclu){
319  if (c1 != -1 && !deltaraylike && enoughhits){
320  lclu2 = lclu1;
321  c2 = c1;
322  wb2 = wb1;
323  we2 = we1;
324  tt2 = tt1;
325  dtdw2 = dtdw1;
326  }
327  lclu1 = lclu;
328  c1 = Cls[i][j];
329  wb1 = clusters[Cls[i][j]]->StartWire();
330  we1 = clusters[Cls[i][j]]->EndWire();
331  tt1 = clusters[Cls[i][j]]->StartTick();
332  if (wb1>we1){
333  wb1 = clusters[Cls[i][j]]->EndWire();
334  we1 = clusters[Cls[i][j]]->StartWire();
335  tt1 = clusters[Cls[i][j]]->EndTick();
336  }
337  dtdw1 = dtdwstart[Cls[i][j]];
338  }
339  else if (lclu2 < lclu){
340  if (!deltaraylike && enoughhits && replace){
341  lclu2 = lclu;
342  c2 = Cls[i][j];
343  wb2 = clusters[Cls[i][j]]->StartWire();
344  we2 = clusters[Cls[i][j]]->EndWire();
345  tt2 = clusters[Cls[i][j]]->StartTick();
346  dtdw2 = dtdwstart[Cls[i][j]];
347  }
348  }
349  }
350  if (c1 != -1 && c2 != -1){
351  cluvtx[i].push_back(c1);
352  cluvtx[i].push_back(c2);
353 
354  double w1 = clusters[c1]->StartWire();
355  double t1 = clusters[c1]->StartTick();
356  if (clusters[c1]->StartWire()>clusters[c1]->EndWire()){
357  w1 = clusters[c1]->EndWire();
358  t1 = clusters[c1]->EndTick();
359  }
360  double k1 = dtdwstart[c1];
361  double w2 = clusters[c2]->StartWire();
362  double t2 = clusters[c2]->StartTick();
363  if (clusters[c2]->StartWire()>clusters[c2]->EndWire()){
364  w1 = clusters[c2]->EndWire();
365  t1 = clusters[c2]->EndTick();
366  }
367  double k2 = dtdwstart[c2];
368 // std::cout<<c1<<" "<<w1<<" "<<t1<<" "<<k1<<" "<<std::endl;
369 // std::cout<<c2<<" "<<w2<<" "<<t2<<" "<<k2<<" "<<std::endl;
370  //calculate the vertex
371  if (std::abs(k1-k2) < 0.5){
372  vtx_w.push_back(w1);
373  vtx_t.push_back(t1);
374  }
375  else{
376  double t0 = (k1*k2*(w1-w2)+k1*t2-k2*t1)/(k1-k2);
377  double w0 = (t2-t1+k1*w1-k2*w2)/(k1-k2);
378  vtx_w.push_back(w0);
379  vtx_t.push_back(t0);
380  }
381  }
382  else if (Cls[i].size() >= 1){
383  if (c1 != -1){
384  cluvtx[i].push_back(c1);
385  vtx_w.push_back(wb1);
386  vtx_t.push_back(tt1);
387  }
388  else{
389  cluvtx[i].push_back(Cls[i][0]);
390  vtx_w.push_back(clusters[Cls[i][0]]->StartWire());
391  vtx_t.push_back(clusters[Cls[i][0]]->StartTick());
392  }
393  }
394  //save 2D vertex
395  // make an empty art::PtrVector of hits
398  std::vector< art::Ptr<recob::Hit> > hits = fmh.at(Cls[i][0]);
399  double totalQ = 0.;
400  for(size_t h = 0; h < hits.size(); ++h) totalQ += hits[h]->Integral();
401 
402  geo::WireID wireID(hits[0]->WireID().Cryostat,
403  hits[0]->WireID().TPC,
404  hits[0]->WireID().Plane,
405  (unsigned int)vtx_w.back()); //for update to EndPoint2D ... WK 4/22/13
406 
407  recob::EndPoint2D vertex(vtx_t.back(),
408  wireID, //for update to EndPoint2D ... WK 4/22/13
409  1,
410  epcol->size(),
411  clusters[Cls[i][0]]->View(),
412  totalQ);
413  epcol->push_back(vertex);
414 
415  util::CreateAssn(*this, evt, *epcol, hits, *assnep);
416 
417  }
418  else{
419  //no cluster found
420  vtx_w.push_back(-1);
421  vtx_t.push_back(-1);
422  }
423  }
424  //std::cout<<vtx_w[0]<<" "<<vtx_t[0]<<" "<<vtx_w[1]<<" "<<vtx_t[1]<<std::endl;
425 
426  Double_t vtxcoord[3];
427  if (Cls[0].size()>0&&Cls[1].size()>0){//ignore w view
428  double Iw0 = (vtx_w[0]+3.95)*wire_pitch;
429  double Cw0 = (vtx_w[1]+1.84)*wire_pitch;
430 
431  double It0 = vtx_t[0] - presamplings;
432  It0 *= timepitch;
433  double Ct0 = vtx_t[1] - presamplings ;
434  Ct0 *= timepitch;
435  vtxcoord[0] = detprop->ConvertTicksToX(vtx_t[1],1,0,0);
436  vtxcoord[1] = (Cw0-Iw0)/(2.*std::sin(Angle));
437  vtxcoord[2] = (Cw0+Iw0)/(2.*std::cos(Angle))-YC/2.*std::tan(Angle);
438 
439  double yy,zz;
440  if(vtx_w[0]>=0&&vtx_w[0]<=239&&vtx_w[1]>=0&&vtx_w[1]<=239){
441  if(geom->ChannelsIntersect(geom->PlaneWireToChannel(0,(int)((Iw0/wire_pitch)-3.95)),
442  geom->PlaneWireToChannel(1,(int)((Cw0/wire_pitch)-1.84)),
443  yy,zz)){
444  //channelsintersect provides a slightly more accurate set of y and z coordinates.
445  // use channelsintersect in case the wires in question do cross.
446  vtxcoord[1] = yy;
447  vtxcoord[2] = zz;
448  }
449  else{
450  vtxcoord[0] = -99999;
451  vtxcoord[1] = -99999;
452  vtxcoord[2] = -99999;
453  }
454  }
455  dtIC->Fill(It0-Ct0);
456  }
457  else{
458  vtxcoord[0] = -99999;
459  vtxcoord[1] = -99999;
460  vtxcoord[2] = -99999;
461  }
462 
465  art::PtrVector<recob::Track> vTracks_vec;
466  art::PtrVector<recob::Shower> vShowers_vec;
467 
468  recob::Vertex the3Dvertex(vtxcoord, vcol->size());
469  vcol->push_back(the3Dvertex);
470 
471  if(vShowers_vec.size() > 0){
472  util::CreateAssn(*this, evt, *vcol, vShowers_vec, *assnsh);
473  // get the hits associated with each track and associate those with the vertex
475  // for(size_t p = 0; p < vShowers_vec.size(); ++p){
476  // std::vector< art::Ptr<recob::Hit> > hits = fms.at(p);
477  // util::CreateAssn(*this, evt, *vcol, hits, *assnh);
478  // }
479  }
480 
481  if(vTracks_vec.size() > 0){
482  util::CreateAssn(*this, evt, *vcol, vTracks_vec, *assntr);
483  // get the hits associated with each track and associate those with the vertex
485  // for(size_t p = 0; p < vTracks_vec.size(); ++p){
486  // std::vector< art::Ptr<recob::Hit> > hits = fmt.at(p);
487  // util::CreateAssn(*this, evt, *vcol, hits, *assnh);
488  // }
489  }
490 
491  LOG_VERBATIM("Summary") << std::setfill('-') << std::setw(175) << "-" << std::setfill(' ');
492  LOG_VERBATIM("Summary") << "VertexFinder2D Summary:";
493  for(size_t i = 0; i<epcol->size(); ++i) LOG_VERBATIM("Summary") << epcol->at(i) ;
494  for(size_t i = 0; i<vcol->size(); ++i) LOG_VERBATIM("Summary") << vcol->at(i) ;
495 
496  evt.put(std::move(epcol));
497  evt.put(std::move(vcol));
498  evt.put(std::move(assnep));
499  evt.put(std::move(assntr));
500  evt.put(std::move(assnsh));
501  evt.put(std::move(assnh));
502 
503  } // end of produce
504 } // end of vertex namespace
505 
506 // //-----------------------------------------------------------------------------
507 
508 
509 
510 namespace vertex{
511 
513 
514 } // end of vertex namespace
code to link reconstructed objects back to the MC truth information
PlaneGeo const & Plane(unsigned int const p, unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified wire.
TTree * t1
Definition: plottest35.C:26
Encapsulate the construction of a single cyostat.
virtual int TriggerOffset() const =0
WireGeo const & Wire(unsigned int iwire) const
Definition: PlaneGeo.cxx:506
Planes which measure V.
Definition: geo_types.h:77
Declaration of signal hit object.
std::set< geo::View_t > const & Views() const
Returns a list of possible views in the detector.
bool ChannelsIntersect(raw::ChannelID_t c1, raw::ChannelID_t c2, double &y, double &z) const
Returns an intersection point of two channels.
virtual double SamplingRate() const =0
Returns the period of the TPC readout electronics clock.
Planes which measure Z direction.
Definition: geo_types.h:79
Double_t zz
Definition: plot.C:279
Definition of vertex object for LArSoft.
Definition: Vertex.h:35
double ThetaZ() const
Returns angle of wire with respect to z axis in the Y-Z plane in radians.
Definition: WireGeo.h:192
geo::Length_t WirePitch(geo::PlaneID const &planeid) const
Returns the distance between two consecutive wires.
bool myfunction(CluLen c1, CluLen c2)
ProductID put(std::unique_ptr< PROD > &&product)
Definition: Event.h:102
Definition: type_traits.h:56
Planes which measure U.
Definition: geo_types.h:76
void hits()
Definition: readHits.C:15
geo::Length_t DetHalfHeight(geo::TPCID const &tpcid) const
Returns the half height of the active volume of the specified TPC.
TCanvas * c1
Definition: plotHisto.C:7
TCanvas * c2
Definition: plot_hist.C:75
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:42
void beginJob()
Definition: Breakpoints.cc:14
void push_back(Ptr< U > const &p)
Definition: PtrVector.h:441
virtual double Temperature() const =0
T get(std::string const &key) const
Definition: ParameterSet.h:231
std::vector< evd::details::RawDigitInfo_t >::const_iterator begin(RawDigitCacheDataClass const &cache)
bool CreateAssn(PRODUCER const &prod, art::Event &evt, std::vector< T > const &a, art::Ptr< U > const &b, art::Assns< U, T > &assn, std::string a_instance, size_t indx=UINT_MAX)
Creates a single one-to-one association.
Declaration of cluster object.
Provides recob::Track data product.
bool SortByWire(art::Ptr< recob::Hit > const &h1, art::Ptr< recob::Hit > const &h2)
size_type size() const
Definition: PtrVector.h:308
Detector simulation of raw signals on wires.
TTree * t2
Definition: plottest35.C:36
TH1F * h2
Definition: plot.C:46
Encapsulate the geometry of a wire.
virtual double ConvertTicksToX(double ticks, int p, int t, int c) const =0
raw::ChannelID_t PlaneWireToChannel(WireID const &wireid) const
Returns the ID of the TPC channel connected to the specified wire.
T * make(ARGS...args) const
Utility object to perform functions of association.
Encapsulate the construction of a single detector plane.
bool getByLabel(std::string const &label, std::string const &productInstanceName, Handle< PROD > &result) const
Definition: DataViewImpl.h:344
Int_t min
Definition: plot.C:26
virtual double DriftVelocity(double efield=0., double temperature=0.) const =0
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
TH1F * h1
Definition: plot.C:43
Char_t n[5]
std::vector< evd::details::RawDigitInfo_t >::const_iterator end(RawDigitCacheDataClass const &cache)
#define LOG_VERBATIM(category)
virtual double Efield(unsigned int planegap=0) const =0
Returns the nominal electric field in the specified volume.
recob::tracking::Plane Plane
Definition: TrackState.h:17
raw::ChannelID_t Channel() const
ID of the readout channel the hit was extracted from.
Definition: Hit.h:231
art framework interface to geometry description
Encapsulate the construction of a single detector plane.
std::string GetLArTPCVolumeName(geo::TPCID const &tpcid) const
Return the name of specified LAr TPC volume.
vertex reconstruction