OpDetBacktrackerRecord.h
Go to the documentation of this file.
1 /*
2  * @file OpDetBacktrackerRecord.h
3  * @brief object containing MC truth information necessary for backtracking Photons.
4  * Based on SimChannels by seligman@nevis.columbia.edu
5  * @author jason.stock@mines.sdsmt.edu
6  * @see OpDetBacktrackerRecord.cxx
7  *
8  * This class uses only LArSoft libraries that are header only.
9  */
10 
11 #ifndef LARSIMOBJ_SIMULATION_OPDETBACKTRACKERRECORD_H
12 #define LARSIMOBJ_SIMULATION_OPDETBACKTRACKERRECORD_H
13 
14 // C/C++ standard libraries
15 #include <string>
16 #include <vector>
17 #include <utility> // std::pair
18 
19 
20 namespace sim {
21 
22  /// Ionization photons from a Geant4 track
23  struct TrackSDP{
24  int trackID; ///< Geant4 supplied trackID
25  float energyFrac; ///< fraction of OpHit energy from the particle with this trackID
26  float energy; ///< energy from the particle with this trackID [MeV]
27 
28  TrackSDP() {}
29 
30 
31  TrackSDP(int id, float phF, float ph) : trackID(id), energyFrac(phF), energy (ph) {}
32 
33 
34  };
35 
36 
37  /**
38  * This class stores information about the Scintillation Light from the simulation
39  * of a small step of a track through the TPC active volume.
40  *
41  * Scintillation information consists of both energy and number of photons.
42  * It is of paramount importance to understand what each field stores:
43  *
44  * - position: where the scintillation occurred (from Geant4 simulation)
45  * - track ID: Geant4 track ID of the ionizing particle
46  * - energy: amount of energy in G4Step (from Geant4 simulation)
47  * - photons: amount of photons reaching the optical detector
48  *
49  * Note the different definition of the photons respect to the rest:
50  * it describes the photons at the OpticlaDetector,
51  * while all the other quantities can be related to the moment the scintillation
52  * happened.
53  *
54  * The number of photons is the result of the OpFastScintillation sim, so no real photons are simulated.
55  *
56  * Each SDP is also typically associated with a time (timePDclock) count, that is
57  * the time at which the scintillation photons are generated, as drift time is assumed to be zero for the
58  * photons. This time will differ from the time reflected in recob::OpHits as the time stored does not
59  * account for any signal processing time. The backtracker will handle that with a FCL parameter
60  * called Delay. Each experiment will have to determine the correct Delay to use with their system.
61  * For dune10KT the delay is ~300 ns.
62  *
63  * The SDP (Scintillation Deposited Photons) records are generated in OpFastScintillation.cxx.
64  *
65  */
66  struct SDP{
67 
68  /// Type of track ID (the value comes from Geant4)
69  typedef int TrackID_t;
70 
71  /// Default constructor (sets "bogus" values)
72  SDP();
73 
74 
75  /// Constructor: copies an SDP, and applies the specified offset to track ID
76  SDP(SDP const& sdp, int offset);
77 
78  /// Constructor: sets all data members
79  SDP(TrackID_t tid,
80  float nPh,
81  float e,
82  float xpos,
83  float ypos,
84  float zpos)
85  : trackID (tid)
86  , numPhotons (nPh)
87  , energy (e)
88  , x (xpos)
89  , y (ypos)
90  , z (zpos)
91  {}
92 
93 
94  TrackID_t trackID; ///< Geant4 supplied track ID
95  float numPhotons; ///< number of photons at the optical detector for this track ID and time
96  float energy; ///< energy deposited by ionization
97  float x; ///< x position of ionization [cm]
98  float y; ///< y position of ionization [cm]
99  float z; ///< z position of ionization [cm]
100  }; // struct SDP
101 
102 
103  /// List of energy deposits at the same time (on this Optical Detector)
104  typedef std::pair< double, std::vector<sim::SDP> > timePDclockSDP_t;
105 
106  /**
107  * @brief Energy deposited on a readout Optical Detector by simulated tracks
108  *
109  * This class stores a time organized list of scintillation photons detected connected to the G4 tracks
110  * they originated from. This class also tracks the energy deposited by those tracks, and what fraction of the
111  * energy deposited is realted to the photons detected by this OpDet.
112  *
113  * The information is organized by time: it is divided by timePDclock ticks (units of ns), and
114  * each timePDclock tick where some energy was deposited appears in a separate entry,
115  * while the quiet timePDclock ticks are omitted.
116  * For each timePDclock, the information is stored as a list of energy deposits;
117  * each deposit comes from a single Geant4 track and stores the location where
118  * the ionization happened according to the simulation (see `sim::SDP` class).
119  *
120  * Note that there can be multiple energy deposit records (that is `sim::SDP`)
121  * for a single track in a single timePDclock tick.
122  */
124  {
125  public:
126  /// Type for timePDclock tick used in the internal representation
127  typedef timePDclockSDP_t::first_type storedTimePDclock_t;
128 
129  /// Type of list of energy deposits for each timePDclock with signal
130  typedef std::vector<timePDclockSDP_t> timePDclockSDPs_t;
131 
132  private:
133  int iOpDetNum; ///< OpticalDetector where the photons were detected
134  timePDclockSDPs_t timePDclockSDPs; ///< list of energy deposits for each timePDclock with signal
135 
136 
137  public:
138 
139  // Default constructor
141 
142  /// Type for iTimePDclock tick used in the interface
143  //typedef unsigned short timePDclock_t;
144  typedef double timePDclock_t;//This is the G4Time from OpFastScintillation. (ns)
145 
146  /// Type of track ID (the value comes from Geant4)
148 
149 
150  /// Constructor: immediately sets the Optical Detector number
151  explicit OpDetBacktrackerRecord(int detNum);
152 
153  /**
154  * @brief Add scintillation photons and energy to this OpticalDetector
155  * @param trackID ID of simulated track depositing this energy (from Geant4)
156  * @param timePDclock tick when this deposit was collected (ns)
157  * @param numberPhotons detected at the OpticalDetector at this time from this track
158  * @param xyz coordinates of original location of ionization/scintillation (3D array) [cm]
159  * @param energy energy deposited at this point by this track [MeV]
160  *
161  */
162  void AddScintillationPhotons(TrackID_t trackID,
163  timePDclock_t timePDclock,
164  double numberPhotons,
165  double const* xyz,
166  double energy);
167 
168  /// Returns the readout Optical Detector this object describes
169  int OpDetNum() const;
170 
171  /**
172  * @brief Return all the recorded energy deposition within a time interval
173  * @param startTimePDclock iTimePDclock tick opening the time window
174  * @param endTimePDclock iTimePDclock tick closing the time window (included in the interval)
175  * @return a collection of energy deposit information from all tracks
176  *
177  * This method returns the energy deposited on this Optical Detector by each track
178  * ID active in the specified iTimePDclock time interval.
179  *
180  * Each entry pertains a single track ID. For each entry, all energy
181  * deposit information is merged into a single record. It includes:
182  * * energy and number of photons, as the integral in the time interval
183  * * position, as average weighted by the number of photons
184  * * the ID of the track depositing this energy
185  *
186  * Entries are sorted by track ID number.
187  */
188  std::vector<sim::SDP> TrackIDsAndEnergies(timePDclock_t startTimePDclock,
189  timePDclock_t endTimePDclock) const;
190 
191  /**
192  * @brief Returns all the deposited energy information as stored
193  * @return all the deposited energy information as stored in the object
194  *
195  * The returned list is organized in pairs. Each pair contains all
196  * ionization information in a single iTimePDclock tick (collection of `sim::SDP`),
197  * and the number of that tick. The information is sorted by increasing timePDclock
198  * tick.
199  *
200  * See the class description for the details of the ionization information
201  * content.
202  */
203  timePDclockSDPs_t const& timePDclockSDPsMap() const;
204 
205 
206  /// Returns the total number of scintillation photons on this Optical Detector in the specified timePDclock
207  double Photons(timePDclock_t iTimePDclock) const;
208 
209  /// Returns the total energy on this Optical Detector in the specified iTimePDclock [MeV]
210  double Energy(timePDclock_t iTimePDclock) const;
211 
212  /**
213  * @brief Returns energies collected for each track within a time interval
214  * @param startTimePDclock iTimePDclock tick opening the time window
215  * @param endTimePDclock iTimePDclock tick closing the time window (included in the interval)
216  * @return a collection of energy and fraction from each track in interval
217  * @see TrackIDsAndEnergies()
218  *
219  * This method returns the energy deposited on this Optical Detector by each track
220  * ID active in the specified iTimePDclock time interval.
221  *
222  * Each entry pertains a single track ID. For each entry, all energy
223  * deposit information is merged into a single record. It includes:
224  * * energy of the track, as the integral in the time interval [MeV]
225  * * energy fraction respect to the total (see below)
226  * * the ID of the track depositing this energy
227  *
228  * The energy fraction is the energy deposited by the track on this Optical Detector
229  * in the specified time interval, divided by the total of the energy
230  * deposited by all tracks on this Optical Detector in that same time interval.
231  *
232  * Entries are sorted by track ID number.
233  */
234  std::vector<sim::TrackSDP> TrackSDPs(timePDclock_t startTimePDclock,
235  timePDclock_t endTimePDclock) const;
236 
237  /// Comparison: sorts by Optical Detector ID
238  bool operator< (const OpDetBacktrackerRecord& other) const;
239 
240  /// Comparison: true if OpDetBacktrackerRecords have the same Optical Detector ID
241  bool operator== (const OpDetBacktrackerRecord& other) const;
242 
243  /**
244  * @brief Merges the deposits from another Optical Detector into this one
245  * @param opDetNum the sim::OpDetBacktrackerRecord holding information to be merged
246  * @param offset track ID offset for the merge
247  * @return range of the IDs of the added tracks
248  *
249  * The information from the specified simulated opDetRecord is added to the
250  * current one.
251  * This is achieved by appending the energy deposit information (`sim::SDP`)
252  * at each iTimePDclock tick from the merged opDetRecord to the list of existing energy
253  * deposits for that iTimePDclock tick.
254  *
255  * In addition, the track IDs of the merged opDetRecord are added an offset,
256  * so that they can be distinguished from the existing ones.
257  * This is useful when simulating tracks with multiple Geant4 runs. Geant4
258  * will reuse track IDs on each run, and using the highest number of track
259  * ID from one run as the offset for the next avoids track ID collisions.
260  * Note however that this function does not perform any collision check, and
261  * it is caller's duty to ensure that the offset is properly large.
262  * The return value is a pair including the lowest and the largest track IDs
263  * added to this opDetRecord, equivalent to the lowest and the highest track IDs
264  * present in the merged opDetRecord, both augmented by the applied offset.
265  *
266  * The opDetNum number of the merged opDetRecord is ignored.
267  */
268  std::pair<TrackID_t,TrackID_t> MergeOpDetBacktrackerRecord
269  (const OpDetBacktrackerRecord& opDetNum, int offset);
270 
271 
272  /**
273  * @brief Dumps the full content of the OpDetBacktrackerRecord into a stream
274  * @tparam Stream an ostream-like stream object
275  * @param out the stream to send the information into
276  * @param indent indentation of the lines (default: none)
277  * @param first_indent indentation for the first line (default: as indent)
278  */
279  template <typename Stream>
280  void Dump(Stream&& out, std::string indent, std::string first_indent) const;
281 
282  /// Documentation at `Dump(Stream&&, std::string, std::string) const`.
283  template <typename Stream>
284  void Dump(Stream&& out, std::string indent = "") const
285  { Dump(std::forward<Stream>(out), indent, indent); }
286 
287 
288  private:
289  /// Comparison functor, sorts by increasing timePDclocktick value
290  struct CompareByTimePDclock;
291 
292  /// Return the iterator to the first timePDclockSDP not earlier than timePDclock
293  timePDclockSDPs_t::iterator findClosestTimePDclockSDP(storedTimePDclock_t timePDclock);
294 
295  /// Return the (constant) iterator to the first timePDclockSDP not earlier than timePDclock
296  timePDclockSDPs_t::const_iterator findClosestTimePDclockSDP
297  (storedTimePDclock_t timePDclock) const;
298 
299 
300  };
301 
302 } // namespace sim
303 
304 
305 inline bool sim::OpDetBacktrackerRecord::operator< (const sim::OpDetBacktrackerRecord& other) const { return iOpDetNum < other.OpDetNum(); }
306 inline bool sim::OpDetBacktrackerRecord::operator== (const sim::OpDetBacktrackerRecord& other) const { return iOpDetNum == other.OpDetNum(); }
308 inline int sim::OpDetBacktrackerRecord::OpDetNum() const { return iOpDetNum; }
309 
310 
311 // -----------------------------------------------------------------------------
312 // --- template implementation
313 // ---
314 template <class Stream>
316  (Stream&& out, std::string indent, std::string first_indent) const
317 {
318  out << first_indent << "OpDet #" << OpDetNum() << " read " << timePDclockSDPs.size()
319  << " timePDclocks:\n";
320  double opDet_energy = 0., opDet_photons = 0.;
321  for (const auto& timePDclockinfo: timePDclockSDPs) {
322  auto const iTimePDclock = timePDclockinfo.first;
323  out << indent << " timePDclock #" << iTimePDclock
324  << " with " << timePDclockinfo.second.size() << " SDPs\n";
325  double timePDclock_energy = 0., timePDclock_photons = 0.;
326  for (const sim::SDP& sdp: timePDclockinfo.second) {
327  out << indent
328  << " (" << sdp.x << ", " << sdp.y << ", " << sdp.z << ") "
329  << sdp.numPhotons << " photons, " << sdp.energy << "MeV (trkID="
330  << sdp.trackID << ")\n";
331  timePDclock_energy += sdp.energy;
332  timePDclock_photons += sdp.numPhotons;
333  } // for SDPs
334  out << indent << " => timePDclock #" << iTimePDclock << " CH #" << OpDetNum()
335  << " collected " << timePDclock_energy << " MeV and "
336  << timePDclock_photons <<" photons. \n";
337  opDet_energy += timePDclock_energy;
338  opDet_photons += timePDclock_photons;
339  } // for timePDclocks
340  out << indent << " => channel #" << OpDetNum() << " collected "
341  << opDet_photons << " photons and "<< opDet_energy << " MeV.\n" ;
342 } // sim::OpDetBacktrackerRecord::Dump<>()
343 
344 
345 #endif // LARSIMOBJ_SIMULATION_OPDETBACKTRACKERRECORD_H
346 
347 ////////////////////////////////////////////////////////////////////////
intermediate_table::iterator iterator
int iOpDetNum
OpticalDetector where the photons were detected.
float x
x position of ionization [cm]
bool operator<(const OpDetBacktrackerRecord &other) const
Comparison: sorts by Optical Detector ID.
TH3F * xpos
Definition: doAna.cpp:29
SDP(TrackID_t tid, float nPh, float e, float xpos, float ypos, float zpos)
Constructor: sets all data members.
std::string string
Definition: nybbler.cc:12
std::vector< timePDclockSDP_t > timePDclockSDPs_t
Type of list of energy deposits for each timePDclock with signal.
intermediate_table::const_iterator const_iterator
void Dump(Stream &&out, std::string indent="") const
Documentation at Dump(Stream&&, std::string, std::string) const.
timePDclockSDP_t::first_type storedTimePDclock_t
Type for timePDclock tick used in the internal representation.
Energy deposited on a readout Optical Detector by simulated tracks.
TH3F * ypos
Definition: doAna.cpp:30
timePDclockSDPs_t timePDclockSDPs
list of energy deposits for each timePDclock with signal
TH3F * zpos
Definition: doAna.cpp:31
int OpDetNum() const
Returns the readout Optical Detector this object describes.
const double e
int trackID
Geant4 supplied trackID.
TrackID_t trackID
Geant4 supplied track ID.
SDP::TrackID_t TrackID_t
Type of track ID (the value comes from Geant4)
void Dump(Stream &&out, std::string indent, std::string first_indent) const
Dumps the full content of the OpDetBacktrackerRecord into a stream.
float energyFrac
fraction of OpHit energy from the particle with this trackID
double timePDclock_t
Type for iTimePDclock tick used in the interface.
Code to link reconstructed objects back to the MC truth information.
Ionization photons from a Geant4 track.
float y
y position of ionization [cm]
int TrackID_t
Type of track ID (the value comes from Geant4)
TrackSDP(int id, float phF, float ph)
std::pair< double, std::vector< sim::SDP > > timePDclockSDP_t
List of energy deposits at the same time (on this Optical Detector)
float numPhotons
number of photons at the optical detector for this track ID and time
float energy
energy deposited by ionization
bool operator==(const OpDetBacktrackerRecord &other) const
Comparison: true if OpDetBacktrackerRecords have the same Optical Detector ID.
list x
Definition: train.py:276
float energy
energy from the particle with this trackID [MeV]
float z
z position of ionization [cm]
timePDclockSDPs_t const & timePDclockSDPsMap() const
Returns all the deposited energy information as stored.
bool operator<(const BeamGateInfo &lhs, const BeamGateInfo &rhs)
Definition: BeamGateInfo.h:45
bool operator==(ModuleKeyAndType const &a, ModuleKeyAndType const &b) noexcept