All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ShowerTrajPointdEdx_tool.cc
Go to the documentation of this file.
1 //############################################################################
2 //### Name: ShowerTrajPointdEdx ###
3 //### Author: Dominic Barker (dominic.barker@sheffield.ac.uk) ###
4 //### Date: 13.05.19 ###
5 //### Description: Tool for finding the dEdx of the start track of the ###
6 //### shower using the standard calomitry module. This ###
7 //### takes the sliding fit trajectory to make a 3D dEdx. ###
8 //### This module is best used with the sliding linear fit ###
9 //### and ShowerTrackTrajToSpacePoint ###
10 //############################################################################
11 
12 //Framework Includes
13 #include "art/Utilities/ToolMacros.h"
14 
15 //LArSoft Includes
24 
25 namespace ShowerRecoTools {
26 
28 
29  public:
30  ShowerTrajPointdEdx(const fhicl::ParameterSet& pset);
31 
32  //Physics Function. Calculate the dEdx.
33  int CalculateElement(const art::Ptr<recob::PFParticle>& pfparticle,
34  art::Event& Event,
35  reco::shower::ShowerElementHolder& ShowerEleHolder) override;
36 
37  void FinddEdxLength(std::vector<double>& dEdx_vec, std::vector<double>& dEdx_val);
38 
39  private:
40  //Servcies and Algorithms
41  art::ServiceHandle<geo::Geometry> fGeom;
43 
44  //fcl parameters
45  float fMinAngleToWire; //Minimum angle between the wire direction and the shower
46  //direction for the spacepoint to be used. Default means
47  //the cut has no effect. In radians.
48  float fShapingTime; //Shaping time of the ASIC defualt so we don't cut on track
49  //going too much into the plane. In Microseconds
50  float fMinDistCutOff; //Distance in wires a hit has to be from the start position
51  //to be used
52  float fMaxDist, MaxDist; //Distance in wires a that a trajectory point can be from a
53  //spacepoint to match to it.
55  dEdxTrackLength; //Max Distance a spacepoint can be away from the start of the
56  //track. In cm
57  float fdEdxCut;
58  bool fUseMedian; //Use the median value as the dEdx rather than the mean.
59  bool fCutStartPosition; //Remove hits using MinDistCutOff from the vertex as well.
60 
61  bool fT0Correct; // Whether to look for a T0 associated to the PFP
62  bool fSCECorrectPitch; // Whether to correct the "squeezing" of pitch, requires corrected input
63  bool
64  fSCECorrectEField; // Whether to use the local electric field, from SpaceChargeService, in recombination calc.
65  bool
66  fSCEInputCorrected; // Whether the input has already been corrected for spatial SCE distortions
67 
68  art::InputTag fPFParticleLabel;
69  int fVerbose;
70 
77  };
78 
79  ShowerTrajPointdEdx::ShowerTrajPointdEdx(const fhicl::ParameterSet& pset)
80  : IShowerTool(pset.get<fhicl::ParameterSet>("BaseTools"))
81  , fCalorimetryAlg(pset.get<fhicl::ParameterSet>("CalorimetryAlg"))
82  , fMinAngleToWire(pset.get<float>("MinAngleToWire"))
83  , fShapingTime(pset.get<float>("ShapingTime"))
84  , fMinDistCutOff(pset.get<float>("MinDistCutOff"))
85  , fMaxDist(pset.get<float>("MaxDist"))
86  , fdEdxTrackLength(pset.get<float>("dEdxTrackLength"))
87  , fdEdxCut(pset.get<float>("dEdxCut"))
88  , fUseMedian(pset.get<bool>("UseMedian"))
89  , fCutStartPosition(pset.get<bool>("CutStartPosition"))
90  , fT0Correct(pset.get<bool>("T0Correct"))
91  , fSCECorrectPitch(pset.get<bool>("SCECorrectPitch"))
92  , fSCECorrectEField(pset.get<bool>("SCECorrectEField"))
93  , fSCEInputCorrected(pset.get<bool>("SCEInputCorrected"))
94  , fPFParticleLabel(pset.get<art::InputTag>("PFParticleLabel"))
95  , fVerbose(pset.get<int>("Verbose"))
96  , fShowerStartPositionInputLabel(pset.get<std::string>("ShowerStartPositionInputLabel"))
97  , fInitialTrackSpacePointsInputLabel(pset.get<std::string>("InitialTrackSpacePointsInputLabel"))
98  , fInitialTrackInputLabel(pset.get<std::string>("InitialTrackInputLabel"))
99  , fShowerdEdxOutputLabel(pset.get<std::string>("ShowerdEdxOutputLabel"))
100  , fShowerBestPlaneOutputLabel(pset.get<std::string>("ShowerBestPlaneOutputLabel"))
101  , fShowerdEdxVecOutputLabel(pset.get<std::string>("ShowerdEdxVecOutputLabel"))
102  {
104  throw cet::exception("ShowerTrajPointdEdx")
105  << "Can only correct for SCE if input is already corrected" << std::endl;
106  }
107  }
108 
109  int
110  ShowerTrajPointdEdx::CalculateElement(const art::Ptr<recob::PFParticle>& pfparticle,
111  art::Event& Event,
112  reco::shower::ShowerElementHolder& ShowerEleHolder)
113  {
114 
115  MaxDist = fMaxDist;
117 
118  // Shower dEdx calculation
119  if (!ShowerEleHolder.CheckElement(fShowerStartPositionInputLabel)) {
120  if (fVerbose)
121  mf::LogError("ShowerTrajPointdEdx") << "Start position not set, returning " << std::endl;
122  return 1;
123  }
124  if (!ShowerEleHolder.CheckElement(fInitialTrackSpacePointsInputLabel)) {
125  if (fVerbose)
126  mf::LogError("ShowerTrajPointdEdx")
127  << "Initial Track Spacepoints is not set returning" << std::endl;
128  return 1;
129  }
130  if (!ShowerEleHolder.CheckElement(fInitialTrackInputLabel)) {
131  if (fVerbose) mf::LogError("ShowerTrajPointdEdx") << "Initial Track is not set" << std::endl;
132  return 1;
133  }
134 
135  //Get the initial track hits
136  std::vector<art::Ptr<recob::SpacePoint>> tracksps;
137  ShowerEleHolder.GetElement(fInitialTrackSpacePointsInputLabel, tracksps);
138 
139  if (tracksps.empty()) {
140  if (fVerbose)
141  mf::LogWarning("ShowerTrajPointdEdx") << "no spacepointsin the initial track" << std::endl;
142  return 0;
143  }
144 
145  // Get the spacepoints
146  auto const spHandle = Event.getValidHandle<std::vector<recob::SpacePoint>>(fPFParticleLabel);
147 
148  // Get the hits associated with the space points
149  const art::FindManyP<recob::Hit>& fmsp =
150  ShowerEleHolder.GetFindManyP<recob::Hit>(spHandle, Event, fPFParticleLabel);
151 
152  //Only consider hits in the same tpcs as the vertex.
153  TVector3 ShowerStartPosition = {-999, -999, -999};
154  ShowerEleHolder.GetElement(fShowerStartPositionInputLabel, ShowerStartPosition);
155  geo::TPCID vtxTPC = fGeom->FindTPCAtPosition(ShowerStartPosition);
156 
157  //Get the initial track
158  recob::Track InitialTrack;
159  ShowerEleHolder.GetElement(fInitialTrackInputLabel, InitialTrack);
160 
161  double pfpT0Time(0); // If no T0 found, assume the particle happened at trigger time (0)
162  if (fT0Correct) {
163  auto const pfpHandle = Event.getValidHandle<std::vector<recob::PFParticle>>(fPFParticleLabel);
164  const art::FindManyP<anab::T0>& fmpfpt0 =
165  ShowerEleHolder.GetFindManyP<anab::T0>(pfpHandle, Event, fPFParticleLabel);
166  std::vector<art::Ptr<anab::T0>> pfpT0Vec = fmpfpt0.at(pfparticle.key());
167  if (pfpT0Vec.size() == 1) { pfpT0Time = pfpT0Vec.front()->Time(); }
168  }
169 
170  //Don't care that I could use a vector.
171  std::map<int, std::vector<double>> dEdx_vec;
172  std::map<int, std::vector<double>> dEdx_vecErr;
173  std::map<int, int> num_hits;
174 
175  for (geo::PlaneID plane_id : fGeom->IteratePlaneIDs()) {
176  dEdx_vec[plane_id.Plane] = {};
177  dEdx_vecErr[plane_id.Plane] = {};
178  num_hits[plane_id.Plane] = 0;
179  }
180 
181  auto const clockData =
182  art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(Event);
183  auto const detProp =
184  art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataFor(Event, clockData);
185 
186  //Loop over the spacepoints
187  for (auto const sp : tracksps) {
188 
189  //Get the associated hit
190  std::vector<art::Ptr<recob::Hit>> hits = fmsp.at(sp.key());
191  if (hits.empty()) {
192  if (fVerbose)
193  mf::LogWarning("ShowerTrajPointdEdx")
194  << "no hit for the spacepoint. This suggest the find many is wrong." << std::endl;
195  continue;
196  }
197  const art::Ptr<recob::Hit> hit = hits[0];
198  double wirepitch = fGeom->WirePitch((geo::PlaneID)hit->WireID());
199 
200  //Only consider hits in the same tpc
201  geo::PlaneID planeid = hit->WireID();
202  geo::TPCID TPC = planeid.asTPCID();
203  if (TPC != vtxTPC) { continue; }
204 
205  //Ignore spacepoints within a few wires of the vertex.
206  const TVector3 pos = IShowerTool::GetLArPandoraShowerAlg().SpacePointPosition(sp);
207  double dist_from_start = (pos - ShowerStartPosition).Mag();
208 
209  if (fCutStartPosition) {
210  if (dist_from_start < fMinDistCutOff * wirepitch) { continue; }
211 
212  if (dist_from_start > dEdxTrackLength) { continue; }
213  }
214 
215  //Find the closest trajectory point of the track. These should be in order if the user has used ShowerTrackTrajToSpacePoint_tool but the sake of gernicness I'll get the cloest sp.
216  unsigned int index = 999;
217  double MinDist = 999;
218  for (unsigned int traj = 0; traj < InitialTrack.NumberTrajectoryPoints(); ++traj) {
219 
220  geo::Point_t TrajPositionPoint = InitialTrack.LocationAtPoint(traj);
221  TVector3 TrajPosition = {
222  TrajPositionPoint.X(), TrajPositionPoint.Y(), TrajPositionPoint.Z()};
223 
224  //ignore bogus info.
225  auto flags = InitialTrack.FlagsAtPoint(traj);
226  if (flags.isSet(recob::TrajectoryPointFlagTraits::NoPoint)) { continue; }
227 
228  const TVector3 dist = pos - TrajPosition;
229 
230  if (dist.Mag() < MinDist && dist.Mag() < MaxDist * wirepitch) {
231  MinDist = dist.Mag();
232  index = traj;
233  }
234  }
235 
236  //If there is no matching trajectory point then bail.
237  if (index == 999) { continue; }
238 
239  geo::Point_t TrajPositionPoint = InitialTrack.LocationAtPoint(index);
240  TVector3 TrajPosition = {TrajPositionPoint.X(), TrajPositionPoint.Y(), TrajPositionPoint.Z()};
241 
242  geo::Point_t TrajPositionStartPoint = InitialTrack.LocationAtPoint(0);
243  TVector3 TrajPositionStart = {
244  TrajPositionStartPoint.X(), TrajPositionStartPoint.Y(), TrajPositionStartPoint.Z()};
245 
246  //Ignore values with 0 mag from the start position
247  if ((TrajPosition - TrajPositionStart).Mag() == 0) { continue; }
248  if ((TrajPosition - ShowerStartPosition).Mag() == 0) { continue; }
249 
250  if ((TrajPosition - TrajPositionStart).Mag() < fMinDistCutOff * wirepitch) { continue; }
251 
252  //Get the direction of the trajectory point
253  geo::Vector_t TrajDirection_vec = InitialTrack.DirectionAtPoint(index);
254  TVector3 TrajDirection = {
255  TrajDirection_vec.X(), TrajDirection_vec.Y(), TrajDirection_vec.Z()};
256 
257  //If the direction is in the same direction as the wires within some tolerance the hit finding struggles. Let remove these.
258  // Note that we project in the YZ plane to make sure we are not cutting on
259  // the angle into the wire planes, that should be done by the shaping time cut
260  TVector3 TrajDirectionYZ = {0, TrajDirection_vec.Y(), TrajDirection_vec.Z()};
261  TVector3 PlaneDirection = fGeom->Plane(planeid).GetIncreasingWireDirection();
262 
263  if (std::abs((TMath::Pi() / 2 - TrajDirectionYZ.Angle(PlaneDirection))) < fMinAngleToWire) {
264  if (fVerbose) mf::LogWarning("ShowerTrajPointdEdx") << "remove from angle cut" << std::endl;
265  continue;
266  }
267 
268  //If the direction is too much into the wire plane then the shaping amplifer cuts the charge. Lets remove these events.
269  double velocity = detProp.DriftVelocity(detProp.Efield(), detProp.Temperature());
270  double distance_in_x = TrajDirection.X() * (wirepitch / TrajDirection.Dot(PlaneDirection));
271  double time_taken = std::abs(distance_in_x / velocity);
272 
273  //Shaping time doesn't seem to exist in a global place so add it as a fcl.
274  if (fShapingTime < time_taken) {
275  if (fVerbose) mf::LogWarning("ShowerTrajPointdEdx") << "move for shaping time" << std::endl;
276  continue;
277  }
278 
279  if ((TrajPosition - TrajPositionStart).Mag() > dEdxTrackLength) { continue; }
280 
281  //Iterate the number of hits on the plane
282  ++num_hits[planeid.Plane];
283 
284  //If we still exist then we can be used in the calculation. Calculate the 3D pitch
285  double trackpitch = (TrajDirection * (wirepitch / TrajDirection.Dot(PlaneDirection))).Mag();
286 
287  if (fSCECorrectPitch) {
289  trackpitch, pos, TrajDirection.Unit(), hit->WireID().TPC);
290  }
291 
292  //Calculate the dQdx
293  double dQdx = hit->Integral() / trackpitch;
294 
295  //Calculate the dEdx
296  double localEField = detProp.Efield();
297  if (fSCECorrectEField) {
298  localEField = IShowerTool::GetLArPandoraShowerAlg().SCECorrectEField(localEField, pos);
299  }
300  double dEdx = fCalorimetryAlg.dEdx_AREA(
301  clockData, detProp, dQdx, hit->PeakTime(), planeid.Plane, pfpT0Time, localEField);
302 
303  //Add the value to the dEdx
304  dEdx_vec[planeid.Plane].push_back(dEdx);
305  }
306 
307  //Choose max hits based on hitnum
308  int max_hits = 0;
309  int best_plane = -std::numeric_limits<int>::max();
310  for (auto const& [plane, numHits] : num_hits) {
311  if (fVerbose > 2) std::cout << "Plane: " << plane << " with size: " << numHits << std::endl;
312  if (numHits > max_hits) {
313  best_plane = plane;
314  max_hits = numHits;
315  }
316  }
317 
318  if (best_plane < 0) {
319  if (fVerbose)
320  mf::LogError("ShowerTrajPointdEdx") << "No hits in any plane, returning " << std::endl;
321  return 1;
322  }
323 
324  //Search for blow ups and gradient changes.
325  //Electrons have a very flat dEdx as function of energy till ~10MeV.
326  //If there is a sudden jump particle has probably split
327  //If there is very large dEdx we have either calculated it wrong (probably) or the Electron is coming to end.
328  //Assumes hits are ordered!
329  std::map<int, std::vector<double>> dEdx_vec_cut;
330  for (geo::PlaneID plane_id : fGeom->IteratePlaneIDs()) {
331  dEdx_vec_cut[plane_id.Plane] = {};
332  }
333 
334  for (auto& dEdx_plane : dEdx_vec) {
335  FinddEdxLength(dEdx_plane.second, dEdx_vec_cut[dEdx_plane.first]);
336  }
337 
338  //Never have the stats to do a landau fit and get the most probable value. User decides if they want the median value or the mean.
339  std::vector<double> dEdx_val;
340  std::vector<double> dEdx_valErr;
341  for (auto const& dEdx_plane : dEdx_vec_cut) {
342 
343  if ((dEdx_plane.second).empty()) {
344  dEdx_val.push_back(-999);
345  dEdx_valErr.push_back(-999);
346  continue;
347  }
348 
349  if (fUseMedian) {
350  dEdx_val.push_back(TMath::Median((dEdx_plane.second).size(), &(dEdx_plane.second)[0]));
351  }
352  else {
353  //Else calculate the mean value.
354  double dEdx_mean = 0;
355  for (auto const& dEdx : dEdx_plane.second) {
356  if (dEdx > 10 || dEdx < 0) { continue; }
357  dEdx_mean += dEdx;
358  }
359  dEdx_val.push_back(dEdx_mean / (float)(dEdx_plane.second).size());
360  }
361  }
362 
363  if (fVerbose > 1) {
364  std::cout << "#Best Plane: " << best_plane << std::endl;
365  for (unsigned int plane = 0; plane < dEdx_vec.size(); plane++) {
366  std::cout << "#Plane: " << plane << " #" << std::endl;
367  std::cout << "#Median: " << dEdx_val[plane] << " #" << std::endl;
368  if (fVerbose > 2) {
369  for (auto const& dEdx : dEdx_vec_cut[plane]) {
370  std::cout << "dEdx: " << dEdx << std::endl;
371  }
372  }
373  }
374  }
375 
376  //Need to sort out errors sensibly.
377  ShowerEleHolder.SetElement(dEdx_val, dEdx_valErr, fShowerdEdxOutputLabel);
378  ShowerEleHolder.SetElement(best_plane, fShowerBestPlaneOutputLabel);
379  ShowerEleHolder.SetElement(dEdx_vec_cut, fShowerdEdxVecOutputLabel);
380  return 0;
381  }
382 
383  void
384  ShowerTrajPointdEdx::FinddEdxLength(std::vector<double>& dEdx_vec, std::vector<double>& dEdx_val)
385  {
386 
387  //As default do not apply this cut.
388  if (fdEdxCut > 10) {
389  dEdx_val = dEdx_vec;
390  return;
391  }
392 
393  //Can only do this with 4 hits.
394  if (dEdx_vec.size() < 4) {
395  dEdx_val = dEdx_vec;
396  return;
397  }
398 
399  bool upperbound = false;
400 
401  //See if we are in the upper bound or upper bound defined by the cut.
402  int upperbound_int = 0;
403  if (dEdx_vec[0] > fdEdxCut) { ++upperbound_int; }
404  if (dEdx_vec[1] > fdEdxCut) { ++upperbound_int; }
405  if (dEdx_vec[2] > fdEdxCut) { ++upperbound_int; }
406  if (upperbound_int > 1) { upperbound = true; }
407 
408  dEdx_val.push_back(dEdx_vec[0]);
409  dEdx_val.push_back(dEdx_vec[1]);
410  dEdx_val.push_back(dEdx_vec[2]);
411 
412  for (unsigned int dEdx_iter = 2; dEdx_iter < dEdx_vec.size(); ++dEdx_iter) {
413 
414  //The Function of dEdx as a function of E is flat above ~10 MeV.
415  //We are looking for a jump up (or down) above the ladau width in the dEx
416  //to account account for pair production.
417  //Dom Estimates that the somwhere above 0.28 MeV will be a good cut but 999 will prevent this stage.
418  double dEdx = dEdx_vec[dEdx_iter];
419 
420  //We are really poo at physics and so attempt to find the pair production
421  if (upperbound) {
422  if (dEdx > fdEdxCut) {
423  dEdx_val.push_back(dEdx);
424  if (fVerbose > 1) std::cout << "Adding dEdx: " << dEdx << std::endl;
425  continue;
426  }
427  else {
428  //Maybe its a landau fluctation lets try again.
429  if (dEdx_iter < dEdx_vec.size() - 1) {
430  if (dEdx_vec[dEdx_iter + 1] > fdEdxCut) {
431  if (fVerbose > 1)
432  std::cout << "Next dEdx hit is good removing hit" << dEdx << std::endl;
433  continue;
434  }
435  }
436  //I'll let one more value
437  if (dEdx_iter < dEdx_vec.size() - 2) {
438  if (dEdx_vec[dEdx_iter + 2] > fdEdxCut) {
439  if (fVerbose > 1)
440  std::cout << "Next Next dEdx hit is good removing hit" << dEdx << std::endl;
441  continue;
442  }
443  }
444  //We are hopefully we have one of our electrons has died.
445  break;
446  }
447  }
448  else {
449  if (dEdx < fdEdxCut) {
450  dEdx_val.push_back(dEdx);
451  if (fVerbose > 1) std::cout << "Adding dEdx: " << dEdx << std::endl;
452  continue;
453  }
454  else {
455  //Maybe its a landau fluctation lets try again.
456  if (dEdx_iter < dEdx_vec.size() - 1) {
457  if (dEdx_vec[dEdx_iter + 1] > fdEdxCut) {
458  if (fVerbose > 1)
459  std::cout << "Next dEdx hit is good removing hit " << dEdx << std::endl;
460  continue;
461  }
462  }
463  //I'll let one more value
464  if (dEdx_iter < dEdx_vec.size() - 2) {
465  if (dEdx_vec[dEdx_iter + 2] > fdEdxCut) {
466  if (fVerbose > 1)
467  std::cout << "Next Next dEdx hit is good removing hit " << dEdx << std::endl;
468  continue;
469  }
470  }
471  //We are hopefully in the the pair production zone.
472  break;
473  }
474  }
475  }
476  return;
477  }
478 
479 }
480 
481 DEFINE_ART_CLASS_TOOL(ShowerRecoTools::ShowerTrajPointdEdx)
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space.
Definition: geo_vectors.h:164
double SCECorrectPitch(double const &pitch, TVector3 const &pos, TVector3 const &dir, unsigned int const &TPC) const
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
Definition: UtilFunc.cxx:42
static constexpr Flag_t NoPoint
The trajectory point is not defined.
Point_t const & LocationAtPoint(size_t i) const
The data type to uniquely identify a Plane.
Definition: geo_types.h:472
void SetElement(T &dataproduct, const std::string &Name, bool checktag=false)
size_t NumberTrajectoryPoints() const
Various functions related to the presence and the number of (valid) points.
static constexpr bool
const art::FindManyP< T1 > & GetFindManyP(const art::ValidHandle< std::vector< T2 > > &handle, const art::Event &evt, const art::InputTag &moduleTag)
Definition: T0.h:16
process_name hit
Definition: cheaterreco.fcl:51
art::ServiceHandle< geo::Geometry > fGeom
double SCECorrectEField(double const &EField, TVector3 const &pos) const
BEGIN_PROLOG TPC
T abs(T value)
bool CheckElement(const std::string &Name) const
The data type to uniquely identify a TPC.
Definition: geo_types.h:386
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:493
int GetElement(const std::string &Name, T &Element) const
float dEdx(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, TP3D &tp3d)
Definition: PFPUtils.cxx:2687
int CalculateElement(const art::Ptr< recob::PFParticle > &pfparticle, art::Event &Event, reco::shower::ShowerElementHolder &ShowerEleHolder) override
Provides recob::Track data product.
const shower::LArPandoraShowerAlg & GetLArPandoraShowerAlg() const
Definition: IShowerTool.h:88
constexpr TPCID const & asTPCID() const
Conversion to TPCID (for convenience of notation).
Definition: geo_types.h:446
constexpr double dist(const TReal *x, const TReal *y, const unsigned int dimension)
double dEdx_AREA(detinfo::DetectorClocksData const &clock_data, detinfo::DetectorPropertiesData const &det_prop, recob::Hit const &hit, double pitch, double T0=0) const
void FinddEdxLength(std::vector< double > &dEdx_vec, std::vector< double > &dEdx_val)
PointFlags_t const & FlagsAtPoint(size_t i) const
Vector_t DirectionAtPoint(size_t i) const
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:48
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:184
BEGIN_PROLOG could also be cout
auto const detProp
Track from a non-cascading particle.A recob::Track consists of a recob::TrackTrajectory, plus additional members relevant for a &quot;fitted&quot; track:
ShowerTrajPointdEdx(const fhicl::ParameterSet &pset)
TVector3 SpacePointPosition(art::Ptr< recob::SpacePoint > const &sp) const