LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
EMShower_module.cc
Go to the documentation of this file.
1 // Class: EMShower
3 // Module Type: producer
4 // File: EMShower_module.cc
5 // Author: Mike Wallbank (m.wallbank@sheffield.ac.uk), September 2015
6 //
7 // Module to make EM showers.
8 // Takes the output from cluster finding and track finding and combines
9 // information to make complete 3D shower.
10 //
11 // See DUNE-DocDB 1369 (public) for a detailed description.
13 
14 // Framework includes:
17 #include "fhiclcpp/ParameterSet.h"
27 
28 // LArSoft includes
44 
45 // ROOT includes
46 #include "TPrincipal.h"
47 #include "TVector3.h"
48 #include "TCanvas.h"
49 #include "TH2D.h"
50 #include "TStyle.h"
51 #include "TGraph2D.h"
52 #include "TF2.h"
53 #include "TTree.h"
54 
55 namespace shower {
56  class EMShower;
57 }
58 
60 public:
61 
62  EMShower(fhicl::ParameterSet const& pset);
63 
64  void produce(art::Event& evt);
65  void reconfigure(fhicl::ParameterSet const& p);
66 
67 private:
68 
77 
79  detinfo::DetectorProperties const* fDetProp = lar::providerFrom<detinfo::DetectorPropertiesService>();
80 
81  int fShower;
82  int fPlane;
83 
84  int fDebug;
85 
86 };
87 
88 shower::EMShower::EMShower(fhicl::ParameterSet const& pset) : fEMShowerAlg(pset.get<fhicl::ParameterSet>("EMShowerAlg")) {
89  this->reconfigure(pset);
90  produces<std::vector<recob::Shower> >();
91  produces<std::vector<recob::SpacePoint> >();
92  produces<art::Assns<recob::Shower, recob::Hit> >();
93  produces<art::Assns<recob::Shower, recob::Cluster> >();
94  produces<art::Assns<recob::Shower, recob::Track> >();
95  produces<art::Assns<recob::Shower, recob::SpacePoint> >();
96  produces<art::Assns<recob::SpacePoint, recob::Hit> >();
97 }
98 
100  fHitsModuleLabel = p.get<art::InputTag>("HitsModuleLabel");
101  fClusterModuleLabel = p.get<art::InputTag>("ClusterModuleLabel");
102  fTrackModuleLabel = p.get<art::InputTag>("TrackModuleLabel");
103  fPFParticleModuleLabel = p.get<art::InputTag>("PFParticleModuleLabel","");
104  fVertexModuleLabel = p.get<art::InputTag>("VertexModuleLabel","");
105  fCNNEMModuleLabel = p.get<art::InputTag>("CNNEMModuleLabel","");
106  fFindBadPlanes = p.get<bool> ("FindBadPlanes");
107  fSaveNonCompleteShowers = p.get<bool> ("SaveNonCompleteShowers");
108  fMakeSpacePoints = p.get<bool> ("MakeSpacePoints");
109  fUseCNNtoIDEMPFP = p.get<bool> ("UseCNNtoIDEMPFP");
110  fUseCNNtoIDEMHit = p.get<bool> ("UseCNNtoIDEMHit");
111  fMinTrackLikeScore = p.get<double> ("MinTrackLikeScore");
112  fShower = p.get<int>("Shower",-1);
113  fPlane = p.get<int>("Plane",-1);
114  fDebug = p.get<int>("Debug",0);
116 }
117 
119 
120  // Output -- showers and associations with hits and clusters
121  std::unique_ptr<std::vector<recob::Shower> > showers(new std::vector<recob::Shower>);
122  std::unique_ptr<std::vector<recob::SpacePoint> > spacePoints(new std::vector<recob::SpacePoint>);
123  std::unique_ptr<art::Assns<recob::Shower, recob::Cluster> > clusterAssociations(new art::Assns<recob::Shower, recob::Cluster>);
124  std::unique_ptr<art::Assns<recob::Shower, recob::Hit> > hitShowerAssociations(new art::Assns<recob::Shower, recob::Hit>);
125  std::unique_ptr<art::Assns<recob::Shower, recob::Track> > trackAssociations(new art::Assns<recob::Shower, recob::Track>);
126  std::unique_ptr<art::Assns<recob::Shower, recob::SpacePoint> > spShowerAssociations(new art::Assns<recob::Shower, recob::SpacePoint>);
127  std::unique_ptr<art::Assns<recob::SpacePoint, recob::Hit> > hitSpAssociations(new art::Assns<recob::SpacePoint, recob::Hit>);
128 
129  // Event has hits, tracks and clusters found already
130 
131  // Hits
133  std::vector<art::Ptr<recob::Hit> > hits;
134  if (evt.getByLabel(fHitsModuleLabel,hitHandle))
135  art::fill_ptr_vector(hits, hitHandle);
136 
137  // Tracks
139  std::vector<art::Ptr<recob::Track> > tracks;
140  if (evt.getByLabel(fTrackModuleLabel,trackHandle))
141  art::fill_ptr_vector(tracks, trackHandle);
142 
143  // Clusters
145  std::vector<art::Ptr<recob::Cluster> > clusters;
146  if (evt.getByLabel(fClusterModuleLabel,clusterHandle))
147  art::fill_ptr_vector(clusters, clusterHandle);
148 
149  // PFParticles
151  std::vector<art::Ptr<recob::PFParticle> > pfps;
152  if (evt.getByLabel(fPFParticleModuleLabel, pfpHandle))
153  art::fill_ptr_vector(pfps, pfpHandle);
154 
155  // PFParticles
157  std::vector<art::Ptr<recob::Vertex> > vertices;
158  if (evt.getByLabel(fVertexModuleLabel, vtxHandle))
159  art::fill_ptr_vector(vertices, vtxHandle);
160 
161  // Associations
162  art::FindManyP<recob::Hit> fmh(clusterHandle, evt, fClusterModuleLabel);
163  art::FindManyP<recob::Track> fmt(hitHandle, evt, fTrackModuleLabel);
166 
167  // Make showers
168  std::vector<std::vector<int> > newShowers;
169  std::vector<unsigned int> pfParticles;
170 
171  std::map<int,std::vector<int> > clusterToTracks;
172  std::map<int,std::vector<int> > trackToClusters;
173 
174  if (!pfpHandle.isValid()) {
175 
176  // Map between tracks and clusters
177  fEMShowerAlg.AssociateClustersAndTracks(clusters, fmh, fmt, clusterToTracks, trackToClusters);
178 
179  // Make initial showers
180  std::vector<std::vector<int> > initialShowers = fEMShowerAlg.FindShowers(trackToClusters);
181 
182  // Deal with views in which 2D reconstruction failed
183  std::vector<int> clustersToIgnore;
184  if (fFindBadPlanes)
185  clustersToIgnore = fEMShowerAlg.CheckShowerPlanes(initialShowers, clusters, fmh);
186  if (clustersToIgnore.size() > 0) {
187  clusterToTracks.clear();
188  trackToClusters.clear();
189  fEMShowerAlg.AssociateClustersAndTracks(clusters, fmh, fmt, clustersToIgnore, clusterToTracks, trackToClusters);
190  newShowers = fEMShowerAlg.FindShowers(trackToClusters);
191  }
192  else
193  newShowers = initialShowers;
194 
195  }
196 
197  else {
198 
199  // Use pfparticle information
201  for (size_t ipfp = 0; ipfp<pfps.size(); ++ipfp){
202  art::Ptr<recob::PFParticle> pfp = pfps[ipfp];
203  if (fCNNEMModuleLabel!="" && fUseCNNtoIDEMPFP){//use CNN to identify EM pfparticle
205  if (!hitResults){
206  throw cet::exception("EMShower") <<"Cannot get MVA results from "<<fCNNEMModuleLabel;
207  }
208  int trkLikeIdx = hitResults->getIndex("track");
209  int emLikeIdx = hitResults->getIndex("em");
210  if ((trkLikeIdx < 0) || (emLikeIdx < 0)){
211  throw cet::exception("EMShower") << "No em/track labeled columns in MVA data products.";
212  }
213  if (fmcp.isValid()){//find clusters
214  std::vector<art::Ptr<recob::Hit>> pfphits;
215  std::vector<art::Ptr<recob::Cluster> > clus = fmcp.at(ipfp);
216  for (size_t iclu = 0; iclu<clus.size(); ++iclu){
217  std::vector<art::Ptr<recob::Hit> > ClusterHits = fmh.at(clus[iclu].key());
218  pfphits.insert(pfphits.end(), ClusterHits.begin(), ClusterHits.end());
219  }
220  if (pfphits.size()){//find hits
221  auto vout = hitResults->getOutput(pfphits);
222  double trk_like = -1, trk_or_em = vout[trkLikeIdx] + vout[emLikeIdx];
223  if (trk_or_em > 0){
224  trk_like = vout[trkLikeIdx] / trk_or_em;
225  if (trk_like<fMinTrackLikeScore){ //EM like
226  std::vector<int> clusters;
227  for (size_t iclu = 0; iclu<clus.size(); ++iclu){
228  clusters.push_back(clus[iclu].key());
229  }
230  if (clusters.size()){
231  newShowers.push_back(clusters);
232  pfParticles.push_back(ipfp);
233  }
234  }
235  }
236  }
237  }
238  else{
239  throw cet::exception("EMShower") <<"Cannot get associated cluster for PFParticle "<<fPFParticleModuleLabel.encode()<<"["<<ipfp<<"]";
240  }
241  }
242  else if (pfp->PdgCode()==11){ //shower particle
243  if (fmcp.isValid()){
244  std::vector<int> clusters;
245  std::vector<art::Ptr<recob::Cluster> > clus = fmcp.at(ipfp);
246  for (size_t iclu = 0; iclu<clus.size(); ++iclu){
247  clusters.push_back(clus[iclu].key());
248  }
249  if (clusters.size()){
250  newShowers.push_back(clusters);
251  pfParticles.push_back(ipfp);
252  }
253  }
254  }
255  }
256  }
257 
258  // Make output larsoft products
259  int showerNum = 0;
260  for (std::vector<std::vector<int> >::iterator newShower = newShowers.begin(); newShower != newShowers.end(); ++newShower, ++showerNum) {
261 
262  if (showerNum != fShower and fShower != -1) continue;
263 
264  // New shower
265  if (fDebug > 0)
266  std::cout << std::endl << std::endl << "Start shower " << showerNum << std::endl;
267 
268  // New associations
269  art::PtrVector<recob::Hit> showerHits;
270  art::PtrVector<recob::Cluster> showerClusters;
271  art::PtrVector<recob::Track> showerTracks;
272  art::PtrVector<recob::SpacePoint> showerSpacePoints_p;
273 
274  std::vector<int> associatedTracks;
275 
276  // Make showers and associations
277  for (std::vector<int>::iterator showerCluster = (*newShower).begin(); showerCluster != (*newShower).end(); ++showerCluster) {
278 
279  // Clusters
280  art::Ptr<recob::Cluster> cluster = clusters.at(*showerCluster);
281  showerClusters.push_back(cluster);
282 
283  // Hits
284  std::vector<art::Ptr<recob::Hit> > showerClusterHits = fmh.at(cluster.key());
285  if (fCNNEMModuleLabel!="" && fUseCNNtoIDEMHit){//use CNN to identify EM hits
287  if (!hitResults){
288  throw cet::exception("EMShower") <<"Cannot get MVA results from "<<fCNNEMModuleLabel.encode();
289  }
290  int trkLikeIdx = hitResults->getIndex("track");
291  int emLikeIdx = hitResults->getIndex("em");
292  if ((trkLikeIdx < 0) || (emLikeIdx < 0)){
293  throw cet::exception("EMShower") << "No em/track labeled columns in MVA data products.";
294  }
295  for (auto & showerHit : showerClusterHits){
296  auto vout = hitResults->getOutput(showerHit);
297  double trk_like = -1, trk_or_em = vout[trkLikeIdx] + vout[emLikeIdx];
298  if (trk_or_em > 0){
299  trk_like = vout[trkLikeIdx] / trk_or_em;
300  if (trk_like<fMinTrackLikeScore){ //EM like
301  showerHits.push_back(showerHit);
302  }
303  }
304  }
305  }
306  else{
307  for (std::vector<art::Ptr<recob::Hit> >::iterator showerClusterHit = showerClusterHits.begin(); showerClusterHit != showerClusterHits.end(); ++showerClusterHit)
308  showerHits.push_back(*showerClusterHit);
309  }
310  // Tracks
311  if (!pfpHandle.isValid()) { // Only do this for non-pfparticle mode
312  std::vector<int> clusterTracks = clusterToTracks.at(*showerCluster);
313  for (std::vector<int>::iterator clusterTracksIt = clusterTracks.begin(); clusterTracksIt != clusterTracks.end(); ++clusterTracksIt)
314  if (std::find(associatedTracks.begin(), associatedTracks.end(), *clusterTracksIt) == associatedTracks.end())
315  associatedTracks.push_back(*clusterTracksIt);
316  }
317  }
318 
319  if (!pfpHandle.isValid()) { // For non-pfparticles, get space points from tracks
320  // Tracks and space points
321  for (std::vector<int>::iterator associatedTracksIt = associatedTracks.begin(); associatedTracksIt != associatedTracks.end(); ++associatedTracksIt) {
322  art::Ptr<recob::Track> showerTrack = tracks.at(*associatedTracksIt);
323  showerTracks.push_back(showerTrack);
324  }
325  }
326 
327  else { // For pfparticles, get space points from hits
329  for (size_t ihit = 0; ihit<showerHits.size(); ++ihit){
330  if (fmspp.isValid()){
331  std::vector<art::Ptr<recob::SpacePoint> > spacePoints_pfp = fmspp.at(ihit);
332  for (std::vector<art::Ptr<recob::SpacePoint> >::iterator spacePointsIt = spacePoints_pfp.begin(); spacePointsIt != spacePoints_pfp.end(); ++spacePointsIt)
333  showerSpacePoints_p.push_back(*spacePointsIt);
334  }
335  }
336  }
337 
338  if (!pfpHandle.isValid()) {
339 
340  // First, order the hits into the correct shower order in each plane
341  if (fDebug > 1)
342  std::cout << " ------------------ Ordering shower hits -------------------- " << std::endl;
343  std::map<int,std::vector<art::Ptr<recob::Hit> > > showerHitsMap = fEMShowerAlg.OrderShowerHits(showerHits, fPlane);
344  if (fDebug > 1)
345  std::cout << " ------------------ End ordering shower hits -------------------- " << std::endl;
346 
347  // Find the track at the start of the shower
348  std::unique_ptr<recob::Track> initialTrack;
349  std::map<int,std::vector<art::Ptr<recob::Hit> > > initialTrackHits;
350  fEMShowerAlg.FindInitialTrack(showerHitsMap, initialTrack, initialTrackHits, fPlane);
351 
352  // Make space points
353  std::vector<std::vector<art::Ptr<recob::Hit> > > hitAssns;
354  std::vector<recob::SpacePoint> showerSpacePoints;
355  if (fMakeSpacePoints)
356  showerSpacePoints = fEMShowerAlg.MakeSpacePoints(showerHitsMap, hitAssns);
357  else {
358  for (art::PtrVector<recob::Track>::const_iterator trackIt = showerTracks.begin(); trackIt != showerTracks.end(); ++trackIt) {
359  const std::vector<art::Ptr<recob::SpacePoint> > trackSpacePoints = fmsp.at(trackIt->key());
360  for (std::vector<art::Ptr<recob::SpacePoint> >::const_iterator trackSpIt = trackSpacePoints.begin(); trackSpIt != trackSpacePoints.end(); ++trackSpIt) {
361  showerSpacePoints.push_back(*(*trackSpIt));
362  hitAssns.push_back(std::vector<art::Ptr<recob::Hit> >());
363  }
364  }
365  }
366 
367  // Save space points
368  int firstSpacePoint = spacePoints->size(), nSpacePoint = 0;
369  for (std::vector<recob::SpacePoint>::const_iterator sspIt = showerSpacePoints.begin(); sspIt != showerSpacePoints.end(); ++sspIt, ++nSpacePoint) {
370  spacePoints->emplace_back(sspIt->XYZ(), sspIt->ErrXYZ(), sspIt->Chisq(), spacePoints->size());
371  util::CreateAssn(*this, evt, *(spacePoints.get()), hitAssns.at(nSpacePoint), *(hitSpAssociations.get()));
372  }
373  int lastSpacePoint = spacePoints->size();
374 
375  // Make shower object and associations
376  recob::Shower shower = fEMShowerAlg.MakeShower(showerHits, initialTrack, initialTrackHits);
377  shower.set_id(showerNum);
378  if ( fSaveNonCompleteShowers or (!fSaveNonCompleteShowers and shower.ShowerStart() != TVector3(0,0,0)) ) {
379  showers->push_back(shower);
380  util::CreateAssn(*this, evt, *(showers.get()), showerHits, *(hitShowerAssociations.get()));
381  util::CreateAssn(*this, evt, *(showers.get()), showerClusters, *(clusterAssociations.get()));
382  util::CreateAssn(*this, evt, *(showers.get()), showerTracks, *(trackAssociations.get()));
383  util::CreateAssn(*this, evt, *(showers.get()), *(spacePoints.get()), *(spShowerAssociations.get()), firstSpacePoint, lastSpacePoint);
384  }
385  else
386  mf::LogInfo("EMShower") << "Discarding shower " << showerNum << " due to incompleteness (SaveNonCompleteShowers == false)";
387  }
388 
389  else { // pfParticle
390 
391  if (vertices.size()) {
392  //found the most upstream vertex
393  TVector3 nuvtx(0,0,DBL_MAX);
394  for (auto & vtx: vertices){
395  double xyz[3];
396  vtx->XYZ(xyz);
397  if (xyz[2]<nuvtx.Z()){
398  nuvtx.SetXYZ(xyz[0], xyz[1], xyz[2]);
399  }
400  }
401 
402  TVector3 shwvtx(0,0,0);
403  double mindis = DBL_MAX;
404  for (auto &sp : showerSpacePoints_p){
405  double dis = sqrt(pow(nuvtx.X()-sp->XYZ()[0],2)+pow(nuvtx.X()-sp->XYZ()[1],2)+pow(nuvtx.X()-sp->XYZ()[2],2));
406  if (dis<mindis){
407  mindis = dis;
408  shwvtx.SetXYZ(sp->XYZ()[0], sp->XYZ()[1], sp->XYZ()[2]);
409  }
410  }
411 
412  art::Ptr<recob::Vertex> bestvtx;
413  mindis = DBL_MAX;
414  for (auto & vtx: vertices){
415  double xyz[3];
416  vtx->XYZ(xyz);
417  double dis = sqrt(pow(xyz[0]-shwvtx.X(),2)+pow(xyz[1]-shwvtx.Y(),2)+pow(xyz[2]-shwvtx.Z(),2));
418  if (dis<mindis){
419  mindis = dis;
420  bestvtx = vtx;
421  }
422  }
423 
424  int iok = 0;
425 
426  recob::Shower shower = fEMShowerAlg.MakeShower(showerHits, bestvtx, iok);
427  //shower.set_id(showerNum);
428  if (iok==0) {
429  showers->push_back(shower);
430  showers->back().set_id(showers->size()-1);
431  util::CreateAssn(*this, evt, *(showers.get()), showerHits, *(hitShowerAssociations.get()));
432  util::CreateAssn(*this, evt, *(showers.get()), showerClusters, *(clusterAssociations.get()));
433  util::CreateAssn(*this, evt, *(showers.get()), showerTracks, *(trackAssociations.get()));
434  util::CreateAssn(*this, evt, *(showers.get()), showerSpacePoints_p, *(spShowerAssociations.get()));
435  }
436  }
437 
438  }
439 
440  }
441 
442  // Put in event
443  evt.put(std::move(showers));
444  evt.put(std::move(spacePoints));
445  evt.put(std::move(hitShowerAssociations));
446  evt.put(std::move(clusterAssociations));
447  evt.put(std::move(trackAssociations));
448  evt.put(std::move(spShowerAssociations));
449  evt.put(std::move(hitSpAssociations));
450 
451 }
452 
key_type key() const
Definition: Ptr.h:356
void XYZ(double *xyz) const
Legacy method to access vertex position, preserved to avoid breaking code. Please try to use Vertex::...
Definition: Vertex.cxx:37
const TVector3 & ShowerStart() const
Definition: Shower.h:192
Encapsulate the construction of a single cyostat.
art::InputTag fClusterModuleLabel
intermediate_table::iterator iterator
std::vector< recob::SpacePoint > MakeSpacePoints(std::map< int, std::vector< art::Ptr< recob::Hit > > > hits, std::vector< std::vector< art::Ptr< recob::Hit > > > &hitAssns)
Makes space points from the shower hits in each plane.
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
iterator begin()
Definition: PtrVector.h:223
Declaration of signal hit object.
EMShower(fhicl::ParameterSet const &pset)
art::InputTag fVertexModuleLabel
std::map< int, std::vector< art::Ptr< recob::Hit > > > OrderShowerHits(const art::PtrVector< recob::Hit > &shower, int plane)
Takes the hits associated with a shower and orders them so they follow the direction of the shower...
int PdgCode() const
Return the type of particle as a PDG ID.
Definition: PFParticle.h:83
Cluster finding and building.
art::InputTag fTrackModuleLabel
ProductID put(std::unique_ptr< PROD > &&product)
Definition: Event.h:102
void set_id(const int id)
Definition: Shower.h:128
bool isValid() const
Definition: Handle.h:190
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
void hits()
Definition: readHits.C:15
std::vector< std::vector< int > > FindShowers(std::map< int, std::vector< int > > const &trackToClusters)
Makes showers given a map between tracks and all clusters associated with them.
intermediate_table::const_iterator const_iterator
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:42
Provides recob::Track data product.
void push_back(Ptr< U > const &p)
Definition: PtrVector.h:441
parameter set interface
std::string encode() const
Definition: InputTag.cc:36
T get(std::string const &key) const
Definition: ParameterSet.h:231
void AssociateClustersAndTracks(std::vector< art::Ptr< recob::Cluster > > const &clusters, art::FindManyP< recob::Hit > const &fmh, art::FindManyP< recob::Track > const &fmt, std::map< int, std::vector< int > > &clusterToTracks, std::map< int, std::vector< int > > &trackToClusters)
Map associated tracks and clusters together given their associated hits.
Definition: EMShowerAlg.cxx:43
art::ServiceHandle< geo::Geometry > fGeom
iterator end()
Definition: PtrVector.h:237
art::InputTag fHitsModuleLabel
art::InputTag fCNNEMModuleLabel
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.
art::InputTag fPFParticleModuleLabel
void produce(art::Event &evt)
size_type size() const
Definition: PtrVector.h:308
void FindInitialTrack(const std::map< int, std::vector< art::Ptr< recob::Hit > > > &hits, std::unique_ptr< recob::Track > &initialTrack, std::map< int, std::vector< art::Ptr< recob::Hit > > > &initialTrackHits, int plane)
Finds the initial track-like part of the shower and the hits in all views associated with it...
data_t::const_iterator const_iterator
Definition: PtrVector.h:61
void reconfigure(fhicl::ParameterSet const &p)
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
recob::Shower MakeShower(art::PtrVector< recob::Hit > const &hits, std::unique_ptr< recob::Track > const &initialTrack, std::map< int, std::vector< art::Ptr< recob::Hit > > > const &initialTrackHits)
Makes a recob::Shower object given the hits in the shower and the initial track-like part...
std::vector< int > CheckShowerPlanes(std::vector< std::vector< int > > const &initialShowers, std::vector< art::Ptr< recob::Cluster > > const &clusters, art::FindManyP< recob::Hit > const &fmh)
Takes the initial showers found and tries to resolve issues where one bad view ruins the event...
EMShowerAlg fEMShowerAlg
TCEvent evt
Definition: DataStructs.cxx:5
void fill_ptr_vector(std::vector< Ptr< T >> &ptrs, H const &h)
Definition: Ptr.h:464
detinfo::DetectorProperties const * fDetProp
static std::unique_ptr< MVAReader > create(const art::Event &evt, const art::InputTag &tag)
Definition: MVAReader.h:110
art framework interface to geometry description
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
Encapsulate the construction of a single detector plane.