LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
SimEnergyDeposit.h
Go to the documentation of this file.
1 //
8 // The detector simulation (presently LArG4, which invokes Geant4)
9 // propagates particles through the detector in intervals of "steps".
10 // In Geant4, a step is normally defined by the smallest of the distance
11 // from the current position of the particle to the point where it
12 // enters a new volume boundary, the particle undergoes some "interesting"
13 // physics event, or the range of the particle due to its energy falls
14 // below a given limit.
15 //
16 // In LArG4, an additional limit is applied: We force the steps to be
17 // small (typically 1/10th the wire spacing in the planes of the TPC)
18 // so we can process the energy deposited by each step into
19 // electron clusters.
20 //
21 // The SimEnergyDeposit class defines what Geant4 truth information for
22 // each step is passed to the ionization->sim::SimChannel conversion,
23 // and for the optical-photon->sim::SimPhoton conversion.
24 //
25 // William Seligman, Nevis Labs, 10/12/2017
26 //
27 
28 #ifndef SimEnergyDeposit_h
29 #define SimEnergyDeposit_h
30 
31 // LArSoft includes
32 // Define the LArSoft standard geometry types and methods.
34 
35 // ROOT includes
36 #include "Math/GenVector/Cartesian3D.h"
37 #include "Math/GenVector/PositionVector3D.h"
38 #include "Math/GenVector/PxPyPzE4D.h"
39 #include "Math/GenVector/LorentzVector.h"
40 
41 // C++ includes
42 #include <iostream>
43 
44 namespace sim
45 {
47  {
48  public:
49 
50  // Define the types for the private members below.
51  using Length_t = float;
52  using Point_t = ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D<Length_t> >;
53 
54  // Since we're using LArSoft geometry types, the typical way to
55  // construct a SimEnergyDeposit might be:
56  // sim::SimEnergyDeposit sed(numPhotons,
57  // numElectrons,
58  // stepEnergy,
59  // { startX, startY, startZ },
60  // { endX, endY, endZ },
61  // startTime,
62  // endTime,
63  // trackID,
64  // pdgCode);
65 
66  SimEnergyDeposit(int np = 0,
67  int ne = 0,
68  double e = 0.,
69  Point_t start = {0.,0.,0.},
70  Point_t end = {0.,0.,0.},
71  double t0 = 0.,
72  double t1 = 0.,
73  int id = 0,
74  int pdg = 0)
75  : numPhotons(np)
76  , numElectrons(ne)
77  , edep(e)
78  , startPos(start)
79  , endPos(end)
80  , startTime(t0)
81  , endTime(t1)
82  , trackID(id)
83  , pdgCode(pdg)
84  {}
85 
86 
87 #ifndef __GCCXML__
88  // Accessors, hidden from the ROOT dictionary generation.
89  // Note that even if we store a value as float, we return
90  // it as double so the user doesn't have to think about
91  // precision issues.
92 
93  int NumPhotons() const { return numPhotons; }
94  int NumElectrons() const { return numElectrons; }
95  double Energy() const { return edep; }
96  geo::Point_t Start() const { return { startPos.X(), startPos.Y(), startPos.Z() }; }
97  geo::Point_t End() const { return { endPos.X(), endPos.Y(), endPos.Z() }; }
98  double Time() const { return (startTime+endTime)/2.; }
99  int TrackID() const { return trackID; }
100  int PdgCode() const { return pdgCode; }
101 
102  // While it's clear how a SimEnergyDeposit will be created by its
103  // constructor, it's not clear how users will want to access its
104  // data. So give them as many different kinds of accessors as I
105  // can think of.
106  geo::Length_t StartX() const { return startPos.X(); }
107  geo::Length_t StartY() const { return startPos.Y(); }
108  geo::Length_t StartZ() const { return startPos.Z(); }
109  double StartT() const { return startTime; }
110  geo::Length_t EndX() const { return endPos.X(); }
111  geo::Length_t EndY() const { return endPos.Y(); }
112  geo::Length_t EndZ() const { return endPos.Z(); }
113  double EndT() const { return endTime; }
114 
115  // Step mid-point.
117  return {
118  ( startPos.X() + endPos.X() )/2.
119  , ( startPos.Y() + endPos.Y() )/2.
120  , ( startPos.Z() + endPos.Z() )/2.
121  };
122  }
123  geo::Length_t MidPointX() const { return ( startPos.X() + endPos.X() )/2.; }
124  geo::Length_t MidPointY() const { return ( startPos.Y() + endPos.Y() )/2.; }
125  geo::Length_t MidPointZ() const { return ( startPos.Z() + endPos.Z() )/2.; }
126  geo::Length_t X() const { return ( startPos.X() + endPos.X() )/2.; }
127  geo::Length_t Y() const { return ( startPos.Y() + endPos.Y() )/2.; }
128  geo::Length_t Z() const { return ( startPos.Z() + endPos.Z() )/2.; }
129  double T() const { return (startTime+endTime)/2.; }
130  double T0() const { return startTime; }
131  double T1() const { return endTime; }
132  double E() const { return edep; }
133 
134  // Step length. (Recall that the difference between two
135  // geo::Point_t objects is a geo::Vector_t; we get the length from
136  // spherical coordinates.
137  geo::Length_t StepLength() const { return ( endPos - startPos ).R(); }
138 
139  // Just in case someone wants to store sim::SimEnergyDeposit
140  // objects in a sorted container, define a sort function. Note
141  // that the ideal sort order is dependent of the analysis you're
142  // trying to perform; for example, if you're dealing with cosmic
143  // rays coming along the y-axis, sorting first by z may cause some
144  // tasks like insertions to take a very long time.
145 
146  bool operator<(const SimEnergyDeposit& rhs) const
147  {
148  return trackID < rhs.trackID
149  && startTime < rhs.startTime
150  && startPos.Z() < rhs.startPos.Z()
151  && startPos.Y() < rhs.startPos.Y()
152  && startPos.X() < rhs.startPos.X()
153  && edep > rhs.edep; // sort by _decreasing_ energy
154  }
155 
156 #endif // __GCCXML__
157 
158  private:
159  // While the accessors above return all values in double
160  // precision, store whatever we can in single precision to save
161  // memory and disk space.
162 
163  // There are roughly 7 digits of decimal precision in a float.
164  // This will suffice for energy. A float (as opposed to a double)
165  // can hold a little more than 7 digits of decimal precision. The
166  // smallest position resolution in the simulation is about 0.1mm,
167  // or 10^-4m. With seven digits of precision, that means a float
168  // can be accurate to up to the range of 10^3m. That's why the
169  // definition of our local Point_t (see above) is based on float,
170  // while geo::Point_t is based on double.
171 
172  // If the above reasoning is wrong, just change the definition of
173  // Length_t near the top of this file. Of course, also edit these
174  // comments if you do, because you're a good and responsible
175  // programmer.
176 
177  // For time, it's possible for long-lived particles like neutrons
178  // to deposit energy after billions of ns. Chances are time cuts
179  // will take care of that, but let's make sure that any overlay studies
180  // won't suffer due to lack of precision.
181 
182  int numPhotons; //< of scintillation photons
183  int numElectrons; //< of ionization electrons
184  float edep; //< energy deposition (MeV)
185  Point_t startPos; //< positions in (cm)
187  double startTime; //< (ns)
188  double endTime; //< (ns)
189  int trackID; //< simulation track id
190  int pdgCode; //< pdg code of particle to avoid lookup by particle type later
191  };
192  /*
193 #ifndef __GCCXML__
194  // Class utility functions.
195 
196  // The format of the sim::SimEnergyDeposit output. I'm using a
197  // template for the ostream type, since LArSoft may have some
198  // special classes for its output streams.
199  template <typename Stream>
200  Stream& operator<<(Stream&& os, const sim::SimEnergyDeposit& sed)
201  {
202  // Note that the geo::Point_t type (returned by Start() and End())
203  // has an ostream operator defined for it.
204  os << "trackID " << sed.TrackID()
205  << " pdgCode=" << sed.PdgCode()
206  << " start=" << sed.Start()
207  << " t0=" << sed.T0()
208  << " end=" << sed.End()
209  << " t1=" << sed.T1() << " [cm,ns]"
210  << " E=" << sed.E() << "[GeV]"
211  << " #photons=" << sed.NumPhotons();
212  return os;
213  }
214 
215  // It can be more memory efficient to sort objects by pointers;
216  // e.g., if you've got an unsorted
217  // std::vector<sim::SimEnergyDeposit>, create a
218  // std::set<sim::SimEnergyDeposit*,sim::CompareSED> so you're not
219  // duplicating the objects in memory. The following definition
220  // covers sorting the pointers.
221  bool compareSED(const SimEnergyDeposit* const lhs, const SimEnergyDeposit* const rhs)
222  {
223  return (*lhs) < (*rhs);
224  }
225 #endif // __GCCXML__
226  */
227 } // namespace sim
228 #endif // SimEnergyDeposit_n
geo::Length_t StartX() const
code to link reconstructed objects back to the MC truth information
geo::Length_t EndZ() const
geo::Length_t StepLength() const
geo::Length_t EndY() const
TTree * t1
Definition: plottest35.C:26
double Length_t
Type used for coordinates and distances. They are measured in centimeters.
Definition: geo_vectors.h:140
geo::Length_t Y() const
geo::Length_t StartY() const
double StartT() const
recob::tracking::Point_t Point_t
geo::Length_t Z() const
geo::Length_t EndX() const
SimEnergyDeposit(int np=0, int ne=0, double e=0., Point_t start={0., 0., 0.}, Point_t end={0., 0., 0.}, double t0=0., double t1=0., int id=0, int pdg=0)
geo::Point_t Start() const
geo::Point_t End() const
Definitions of geometry vector data types.
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< Length_t > > Point_t
double Time() const
geo::Point_t MidPoint() const
geo::Length_t StartZ() const
Monte Carlo Simulation.
geo::Length_t MidPointX() const
geo::Length_t MidPointY() const
bool operator<(const SimEnergyDeposit &rhs) const
geo::Length_t MidPointZ() const
std::vector< evd::details::RawDigitInfo_t >::const_iterator end(RawDigitCacheDataClass const &cache)
double Energy() const
Float_t e
Definition: plot.C:34
geo::Length_t X() const
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:187