LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
OpDetBacktrackerRecord.cxx
Go to the documentation of this file.
1 //
7 // based on the SimChannel object by seligman@nevis.columbia.edu
10 
11 #include <limits> // std::numeric_limits
12 #include <utility>
13 #include <stdexcept>
14 #include <algorithm> // std::lower_bound(), std::max()
15 #include <map>
16 
20 
22 
23 namespace sim{
24 
25  //-------------------------------------------------
26  SDP::SDP() //SDP stands for Scintillation Deposited Photons
27  : trackID (util::kBogusI)
28  , numPhotons (util::kBogusD)
29  , energy (util::kBogusD)
30  , x (util::kBogusD)
31  , y (util::kBogusD)
32  , z (util::kBogusD)
33  {}
34 
35  //-------------------------------------------------
36  SDP::SDP(sim::SDP const& sdp, int offset)
37  : SDP(sdp)
38  {
39  trackID += offset;
40  }
41 
42  // Default constructor
43  //-------------------------------------------------
45  : iOpDetNum(-1) //set an impossible channel number in the case where this is called without an opticalchannel.
46  //The reason for doing this is to follow the structure of SimChannel, which uses kBogusChannel
47  {}
48 
49  //-------------------------------------------------
51  : iOpDetNum(detNum)
52  {}
53 
54  //-------------------------------------------------
56  timePDclock_t iTimePDclock,
57  double numberPhotons,
58  double const* xyz,
59  double energy)
60  {
64  // look at the collection to see if the current iTimePDclock already
65  // exists, if not, add it, if so, just add a new track id to the
66  // vector, or update the information if track is already present
67 
68  // no photons? no good!
69  if (( numberPhotons < std::numeric_limits<double>::epsilon() )
70  || ( energy<=std::numeric_limits<double>::epsilon() ))
71  {
72  // will throw
73  LOG_ERROR("OpDetBacktrackerRecord")
74  << "AddTrackPhotons() trying to add to iTimePDclock #"
75  << iTimePDclock
76  << " "
77  << numberPhotons
78  << " photons with "
79  << energy
80  << " MeV of energy from track ID="
81  << trackID;
82  return;
83  } // if no photons
84 
85  auto itr = findClosestTimePDclockSDP(iTimePDclock);
86 
87  // check if this iTimePDclock value is in the vector, it is possible that
88  // the lower bound is different from the given TimePDclock, in which case
89  // we need to add something for that TimePDclock
90  if(itr == timePDclockSDPs.end() ||
91  itr->first != iTimePDclock){
92  std::vector<sim::SDP> sdplist;
93  sdplist.emplace_back(trackID,
94  numberPhotons,
95  energy,
96  xyz[0],
97  xyz[1],
98  xyz[2]
99  );
100  timePDclockSDPs.emplace(itr, iTimePDclock, std::move(sdplist) );
101  }
102  else { // we have that iTimePDclock already; itr points to it
103 
104  // loop over the SDP vector for this iTimePDclock and add the electrons
105  // to the entry with the same track id
106  for(auto& sdp : itr->second){
107 
108  if (sdp.trackID != trackID ) continue;
109 
110  // make a weighted average for the location information
111  double weight = sdp.numPhotons + numberPhotons;
112  sdp.x = (sdp.x * sdp.numPhotons + xyz[0]*numberPhotons)/weight;
113  sdp.y = (sdp.y * sdp.numPhotons + xyz[1]*numberPhotons)/weight;
114  sdp.z = (sdp.z * sdp.numPhotons + xyz[2]*numberPhotons)/weight;
115  sdp.numPhotons = weight;
116  sdp.energy = sdp.energy + energy;
117 
118  // found the track id we wanted, so return;
119  return;
120  } // for
121 
122  // if we never found the track id, then this is the first instance of
123  // the track id for this TimePDclock, so add sdp to the vector
124  itr->second.emplace_back(trackID,
125  numberPhotons,
126  energy,
127  xyz[0],
128  xyz[1],
129  xyz[2]
130  );
131 
132  } // end of else "We have that iTimePDclock already"
133 
134  } // OpDetBacktrackerRecord::AddIonizationElectrons()
135 
136 
137  //-------------------------------------------------
138  double OpDetBacktrackerRecord::Photons(timePDclock_t iTimePDclock) const //Number of photons
139  {
140  double numPhotons = 0.;
141 
142  auto itr = findClosestTimePDclockSDP(iTimePDclock);
143 
144  // check to see if this iTimePDclock value is in the map
145  if(itr != timePDclockSDPs.end() &&
146  itr->first == iTimePDclock){
147 
148  // loop over the list for this iTimePDclock value and add up
149  // the total number of electrons
150  for(auto sdp : itr->second){
151  numPhotons += sdp.numPhotons;
152  } // end loop over sim::SDP for this TimePDclock
153 
154  } // end if this iTimePDclock is represented in the map
155 
156  return numPhotons;
157  }
158 
159  //-------------------------------------------------
160  //Energy in each object is the energy deposited by the track step that left the photons.
162  {
163  double energy = 0.;
164 
165  auto itr = findClosestTimePDclockSDP(iTimePDclock);
166 
167  // check to see if this iTimePDclock value is in the map
168  if(itr != timePDclockSDPs.end() &&
169  itr->first == iTimePDclock){
170 
171  // loop over the list for this iTimePDclock value and add up
172  // the total number of photons
173  for(auto sdp : itr->second ){
174  energy += sdp.energy;
175  } // end loop over sim::SDP for this TimePDclock
176 
177  } // end if this iTimePDclock is represented in the map
178 
179  return energy;
180  }
181 
182  //-----------------------------------------------------------------------
183  // the start and end iTimePDclock values are assumed to be inclusive
184  std::vector<sim::SDP> OpDetBacktrackerRecord::TrackIDsAndEnergies(timePDclock_t startTimePDclock,
185  timePDclock_t endTimePDclock) const
186  {
187  // make a map of track ID values to sim::SDP objects
188 
189  if(startTimePDclock > endTimePDclock ){
190  mf::LogWarning("OpDetBacktrackerRecord") << "requested TimePDclock range is bogus: "
191  << startTimePDclock << " " << endTimePDclock
192  << " return empty vector";
193  return {}; // returns an empty vector
194  }
195 
196  std::map<TrackID_t, sim::SDP> idToSDP;
197 
198  //find the lower bound for this iTimePDclock and then iterate from there
199  auto itr = findClosestTimePDclockSDP(startTimePDclock);
200 
201  while(itr != timePDclockSDPs.end()){
202 
203  // check the iTimePDclock value for the iterator, break the loop if we
204  // are outside the range
205  if(itr->first > endTimePDclock) break;
206 
207  // grab the vector of SDPs for this TimePDclock
208  auto const& sdplist = itr->second;
209  // now loop over them and add their content to the map
210  for(auto const& sdp : sdplist){
211  auto itTrkSDP = idToSDP.find(sdp.trackID);
212  if( itTrkSDP != idToSDP.end() ){
213  // the SDP we are going to update:
214  sim::SDP& trackSDP = itTrkSDP->second;
215 
216  double const nPh1 = trackSDP.numPhotons;
217  double const nPh2 = sdp.numPhotons;
218  double const weight = nPh1 + nPh2;
219 
220  // make a weighted average for the location information
221  trackSDP.x = (sdp.x*nPh2 + trackSDP.x*nPh1)/weight;
222  trackSDP.y = (sdp.y*nPh2 + trackSDP.y*nPh1)/weight;
223  trackSDP.z = (sdp.z*nPh2 + trackSDP.z*nPh1)/weight;
224  trackSDP.numPhotons = weight;
225  } // end if the track id for this one is found
226  else{
227  idToSDP[sdp.trackID] = sim::SDP(sdp);
228  }
229  } // end loop over vector
230 
231  ++itr;
232  } // end loop over iTimePDclock values
233 
234  // now fill the vector with the sdps from the map
235  std::vector<sim::SDP> sdps;
236  sdps.reserve(idToSDP.size());
237  for(auto const& itr : idToSDP){
238  sdps.push_back(itr.second);
239  }
240 
241  return sdps;
242  }
243 
244  //-----------------------------------------------------------------------
245  // the start and end iTimePDclock values are assumed to be inclusive
246  std::vector<sim::TrackSDP> OpDetBacktrackerRecord::TrackSDPs(timePDclock_t startTimePDclock,
247  timePDclock_t endTimePDclock) const
248  {
249 
250  std::vector<sim::TrackSDP> trackSDPs;
251 
252  if(startTimePDclock > endTimePDclock ){
253  mf::LogWarning("OpDetBacktrackerRecord::TrackSDPs") << "requested iTimePDclock range is bogus: "
254  << startTimePDclock << " " << endTimePDclock
255  << " return empty vector";
256  return trackSDPs;
257  }
258 
259  double totalPhotons = 0.;
260  std::vector<sim::SDP> const sdps = TrackIDsAndEnergies(startTimePDclock, endTimePDclock);
261  for (auto const& sdp : sdps)
262  totalPhotons += sdp.numPhotons;
263 
264  // protect against a divide by zero below
265  if(totalPhotons < 1.e-5) totalPhotons = 1.;
266 
267  // loop over the entries in the map and fill the input vectors
268  for (auto const& sdp : sdps){
269  if(sdp.trackID == sim::NoParticleId) continue;
270  trackSDPs.emplace_back(sdp.trackID, sdp.numPhotons/totalPhotons, sdp.numPhotons);
271  }
272 
273  return trackSDPs;
274  }
275 
276 
277  //-----------------------------------------------------------------------
278  // Merge the collection of SDPs from one sim channel to another.
279  // Requires an agreed upon offset for G4 trackID
280  std::pair<OpDetBacktrackerRecord::TrackID_t,OpDetBacktrackerRecord::TrackID_t>
282  int offset)
283  {
284  if( this->OpDetNum() != channel.OpDetNum() )
285  throw std::runtime_error("ERROR OpDetBacktrackerRecord Merge: Trying to merge different channels!");
286 
287  std::pair<TrackID_t,TrackID_t> range_trackID(std::numeric_limits<int>::max(),
289 
290  for(auto const& itr : channel.timePDclockSDPsMap()){
291 
292  auto iTimePDclock = itr.first;
293  auto const& sdps = itr.second;
294 
295  // find the entry from this OpDetBacktrackerRecord corresponding to the iTimePDclock from the other
296  auto itrthis = findClosestTimePDclockSDP(iTimePDclock);
297 
298  // pick which SDP list we have to fill: new one or existing one
299  std::vector<sim::SDP>* curSDPVec;
300  if(itrthis == timePDclockSDPs.end() ||
301  itrthis->first != iTimePDclock){
302  timePDclockSDPs.emplace_back(iTimePDclock, std::vector<sim::SDP>());
303  curSDPVec = &(timePDclockSDPs.back().second);
304  }
305  else
306  curSDPVec = &(itrthis->second);
307 
308  for(auto const& sdp : sdps){
309  curSDPVec->emplace_back(sdp, offset);
310  if( sdp.trackID+offset < range_trackID.first )
311  range_trackID.first = sdp.trackID+offset;
312  if( sdp.trackID+offset > range_trackID.second )
313  range_trackID.second = sdp.trackID+offset;
314  }//end loop over SDPs
315 
316  }//end loop over TimePDclockSDPMap
317 
318 
319  return range_trackID;
320 
321  }
322 
323  //-------------------------------------------------
325 
326  bool operator()
327  (timePDclockSDP_t const& a, timePDclockSDP_t const& b) const
328  { return a.first < b.first; }
329 
330  bool operator()
331  (storedTimePDclock_t a_TimePDclock, timePDclockSDP_t const& b) const
332  { return a_TimePDclock < b.first; }
333 
334  bool operator()
335  (timePDclockSDP_t const& a, storedTimePDclock_t b_TimePDclock) const
336  { return a.first < b_TimePDclock; }
337 
338  }; // struct CompareByTimePDclock
339 
340 
342  {
343  return std::lower_bound
344  (timePDclockSDPs.begin(), timePDclockSDPs.end(), iTimePDclock, CompareByTimePDclock());
345  }
346 
348  (storedTimePDclock_t TimePDclock) const
349  {
350  return std::lower_bound
351  ( timePDclockSDPs.begin(), timePDclockSDPs.end(), TimePDclock, CompareByTimePDclock() );
352  }
353 
354 
355  //-------------------------------------------------
356 
357 
358 }
Float_t x
Definition: compare.C:6
Namespace for general, non-LArSoft-specific utilities.
Definition: PIDAAlg.h:17
int iOpDetNum
OpticalDetector where the photons were detected.
float x
x position of ionization [cm]
intermediate_table::iterator iterator
Float_t y
Definition: compare.C:6
Double_t z
Definition: plot.C:279
double Photons(timePDclock_t iTimePDclock) const
Returns the total number of scintillation photons on this Optical Detector in the specified timePDclo...
constexpr int kBogusI
obviously bogus integer value
std::pair< TrackID_t, TrackID_t > MergeOpDetBacktrackerRecord(const OpDetBacktrackerRecord &opDetNum, int offset)
Merges the deposits from another Optical Detector into this one.
SDP()
Default constructor (sets "bogus" values)
timePDclockSDP_t::first_type storedTimePDclock_t
Type for timePDclock tick used in the internal representation.
std::vector< sim::TrackSDP > TrackSDPs(timePDclock_t startTimePDclock, timePDclock_t endTimePDclock) const
Returns energies collected for each track within a time interval.
Energy deposited on a readout Optical Detector by simulated tracks.
#define LOG_ERROR(category)
timePDclockSDPs_t timePDclockSDPs
list of energy deposits for each timePDclock with signal
Int_t max
Definition: plot.C:27
int OpDetNum() const
Returns the readout Optical Detector this object describes.
intermediate_table::const_iterator const_iterator
TrackID_t trackID
Geant4 supplied track ID.
SDP::TrackID_t TrackID_t
Type of track ID (the value comes from Geant4)
static const int NoParticleId
Definition: sim.h:28
timePDclockSDPs_t::iterator findClosestTimePDclockSDP(storedTimePDclock_t timePDclock)
Return the iterator to the first timePDclockSDP not earlier than timePDclock.
double timePDclock_t
Type for iTimePDclock tick used in the interface.
double energy
Definition: plottest35.C:25
Monte Carlo Simulation.
void AddScintillationPhotons(TrackID_t trackID, timePDclock_t timePDclock, double numberPhotons, double const *xyz, double energy)
Add scintillation photons and energy to this OpticalDetector.
float y
y position of ionization [cm]
double weight
Definition: plottest35.C:25
double Energy(timePDclock_t iTimePDclock) const
Returns the total energy on this Optical Detector in the specified iTimePDclock [MeV].
std::pair< double, std::vector< sim::SDP > > timePDclockSDP_t
List of energy deposits at the same time (on this Optical Detector)
Int_t min
Definition: plot.C:26
float numPhotons
number of photons at the optical detector for this track ID and time
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
std::vector< sim::SDP > TrackIDsAndEnergies(timePDclock_t startTimePDclock, timePDclock_t endTimePDclock) const
Return all the recorded energy deposition within a time interval.
constexpr double kBogusD
obviously bogus double value
Float_t e
Definition: plot.C:34
float z
z position of ionization [cm]
Tools and modules for checking out the basics of the Monte Carlo.
timePDclockSDPs_t const & timePDclockSDPsMap() const
Returns all the deposited energy information as stored.