LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
SimChannel.cxx
Go to the documentation of this file.
1 
9 #include <limits> // std::numeric_limits
10 #include <utility>
11 #include <stdexcept>
12 #include <algorithm> // std::lower_bound(), std::max()
13 #include <map>
14 
18 
20 
21 namespace sim{
22 
23  //-------------------------------------------------
25  : trackID (util::kBogusI)
26  , numElectrons(util::kBogusD)
27  , energy (util::kBogusD)
28  , x (util::kBogusD)
29  , y (util::kBogusD)
30  , z (util::kBogusD)
31  {}
32 
33  //-------------------------------------------------
34  IDE::IDE(sim::IDE const& ide, int offset)
35  : IDE(ide)
36  {
37  trackID += offset;
38  }
39 
40  // Default constructor
41  //-------------------------------------------------
43  : fChannel(raw::InvalidChannelID)
44  {}
45 
46  //-------------------------------------------------
48  : fChannel(channel)
49  {}
50 
51  //-------------------------------------------------
53  TDC_t tdc,
54  double numberElectrons,
55  double const* xyz,
56  double energy)
57  {
58  // look at the collection to see if the current TDC already
59  // exists, if not, add it, if so, just add a new track id to the
60  // vector, or update the information if track is already present
61 
62  // no electrons? no energy? no good!
63  if ((numberElectrons < std::numeric_limits<double>::epsilon())
64  || (energy <= std::numeric_limits<double>::epsilon()))
65  {
66  // will throw
67  LOG_ERROR("SimChannel")
68  << "AddIonizationElectrons() trying to add to TDC #"
69  << tdc
70  << " "
71  << numberElectrons
72  << " electrons with "
73  << energy
74  << " MeV of energy from track ID="
75  << trackID;
76  return;
77  } // if no energy or no electrons
78 
79  auto itr = findClosestTDCIDE(tdc);
80 
81  // check if this tdc value is in the vector, it is possible that
82  // the lower bound is different from the given tdc, in which case
83  // we need to add something for that tdc
84  if(itr == fTDCIDEs.end() ||
85  itr->first != tdc){
86  std::vector<sim::IDE> idelist;
87  idelist.emplace_back(trackID,
88  numberElectrons,
89  energy,
90  xyz[0],
91  xyz[1],
92  xyz[2]
93  );
94  fTDCIDEs.emplace(itr, tdc, std::move(idelist) );
95  }
96  else { // we have that TDC already; itr points to it
97 
98  // loop over the IDE vector for this tdc and add the electrons
99  // to the entry with the same track id
100  for(auto& ide : itr->second){
101 
102  if (ide.trackID != trackID ) continue;
103 
104  // make a weighted average for the location information
105  double weight = ide.numElectrons + numberElectrons;
106  ide.x = (ide.x * ide.numElectrons + xyz[0]*numberElectrons)/weight;
107  ide.y = (ide.y * ide.numElectrons + xyz[1]*numberElectrons)/weight;
108  ide.z = (ide.z * ide.numElectrons + xyz[2]*numberElectrons)/weight;
109  ide.numElectrons = weight;
110  ide.energy = ide.energy + energy;
111 
112  // found the track id we wanted, so return;
113  return;
114  } // for
115 
116  // if we never found the track id, then this is the first instance of
117  // the track id for this tdc, so add ide to the vector
118  itr->second.emplace_back(trackID,
119  numberElectrons,
120  energy,
121  xyz[0],
122  xyz[1],
123  xyz[2]
124  );
125 
126  } // if new TDC ... else
127 
128  } // SimChannel::AddIonizationElectrons()
129 
130 
131  //-------------------------------------------------
132  double SimChannel::Charge(TDC_t tdc) const
133  {
134  double charge = 0.;
135 
136  auto itr = findClosestTDCIDE(tdc);
137 
138  // check to see if this tdc value is in the map
139  if(itr != fTDCIDEs.end() &&
140  itr->first == tdc){
141 
142  // loop over the list for this tdc value and add up
143  // the total number of electrons
144  for(auto ide : itr->second){
145  charge += ide.numElectrons;
146  } // end loop over sim::IDE for this tdc
147 
148  } // end if this tdc is represented in the map
149 
150  return charge;
151  }
152 
153  //-------------------------------------------------
154  double SimChannel::Energy(TDC_t tdc) const
155  {
156  double energy = 0.;
157 
158  auto itr = findClosestTDCIDE(tdc);
159 
160  // check to see if this tdc value is in the map
161  if(itr != fTDCIDEs.end() &&
162  itr->first == tdc){
163 
164  // loop over the list for this tdc value and add up
165  // the total number of electrons
166  for(auto ide : itr->second ){
167  energy += ide.energy;
168  } // end loop over sim::IDE for this tdc
169 
170  } // end if this tdc is represented in the map
171 
172  return energy;
173  }
174 
175 
176  //-----------------------------------------------------------------------
177  // the start and end tdc values are assumed to be inclusive
178  std::vector<sim::IDE> SimChannel::TrackIDsAndEnergies(TDC_t startTDC,
179  TDC_t endTDC) const
180  {
181  // make a map of track ID values to sim::IDE objects
182 
183  if(startTDC > endTDC ){
184  mf::LogWarning("SimChannel") << "requested tdc range is bogus: "
185  << startTDC << " " << endTDC
186  << " return empty vector";
187  return {}; // returns an empty vector
188  }
189 
190  std::map<TrackID_t, sim::IDE> idToIDE;
191 
192  //find the lower bound for this tdc and then iterate from there
193  auto itr = findClosestTDCIDE(startTDC);
194 
195  while(itr != fTDCIDEs.end()){
196 
197  // check the tdc value for the iterator, break the loop if we
198  // are outside the range
199  if(itr->first > endTDC) break;
200 
201  // grab the vector of IDEs for this tdc
202  auto const& idelist = itr->second;
203  // now loop over them and add their content to the map
204  for(auto const& ide : idelist){
205  auto itTrkIDE = idToIDE.find(ide.trackID);
206  if( itTrkIDE != idToIDE.end() ){
207  // the IDE we are going to update:
208  sim::IDE& trackIDE = itTrkIDE->second;
209 
210  double const nel1 = trackIDE.numElectrons;
211  double const nel2 = ide.numElectrons;
212  double const en1 = trackIDE.energy;
213  double const en2 = ide.energy;
214  double const energy = en1 + en2;
215  double const weight = nel1 + nel2;
216 
217  // make a weighted average for the location information
218  trackIDE.x = (ide.x*nel2 + trackIDE.x*nel1)/weight;
219  trackIDE.y = (ide.y*nel2 + trackIDE.y*nel1)/weight;
220  trackIDE.z = (ide.z*nel2 + trackIDE.z*nel1)/weight;
221  trackIDE.numElectrons = weight;
222  trackIDE.energy = energy;
223  } // end if the track id for this one is found
224  else{
225  idToIDE[ide.trackID] = sim::IDE(ide);
226  }
227  } // end loop over vector
228 
229  ++itr;
230  } // end loop over tdc values
231 
232  // now fill the vector with the ides from the map
233  std::vector<sim::IDE> ides;
234  ides.reserve(idToIDE.size());
235  for(auto const& itr : idToIDE){
236  ides.push_back(itr.second);
237  }
238 
239  return ides;
240  }
241 
242  //-----------------------------------------------------------------------
243  // the start and end tdc values are assumed to be inclusive
244  std::vector<sim::TrackIDE> SimChannel::TrackIDEs(TDC_t startTDC,
245  TDC_t endTDC) const
246  {
247 
248  std::vector<sim::TrackIDE> trackIDEs;
249 
250  if(startTDC > endTDC ){
251  mf::LogWarning("SimChannel::TrackIDEs") << "requested tdc range is bogus: "
252  << startTDC << " " << endTDC
253  << " return empty vector";
254  return trackIDEs;
255  }
256 
257  double totalE = 0.;
258  std::vector<sim::IDE> const ides = TrackIDsAndEnergies(startTDC, endTDC);
259  for (auto const& ide : ides)
260  totalE += ide.energy;
261 
262  // protect against a divide by zero below
263  if(totalE < 1.e-5) totalE = 1.;
264 
265  // loop over the entries in the map and fill the input vectors
266  for (auto const& ide : ides){
267  if(ide.trackID == sim::NoParticleId) continue;
268  trackIDEs.emplace_back(ide.trackID, ide.energy/totalE, ide.energy, ide.numElectrons);
269  }
270 
271  return trackIDEs;
272  }
273 
274 
275  //-----------------------------------------------------------------------
276  // Merge the collection of IDEs from one sim channel to another.
277  // Requires an agreed upon offset for G4 trackID
278  std::pair<SimChannel::TrackID_t,SimChannel::TrackID_t>
280  int offset)
281  {
282  if( this->Channel() != channel.Channel() )
283  throw std::runtime_error("ERROR SimChannel Merge: Trying to merge different channels!");
284 
285  std::pair<TrackID_t,TrackID_t> range_trackID(std::numeric_limits<int>::max(),
287 
288  for(auto const& itr : channel.TDCIDEMap()){
289 
290  auto tdc = itr.first;
291  auto const& ides = itr.second;
292 
293  // find the entry from this SimChannel corresponding to the tdc from the other
294  auto itrthis = findClosestTDCIDE(tdc);
295 
296  // pick which IDE list we have to fill: new one or existing one
297  std::vector<sim::IDE>* curIDEVec;
298  if(itrthis == fTDCIDEs.end() ||
299  itrthis->first != tdc){
300  fTDCIDEs.emplace_back(tdc, std::vector<sim::IDE>());
301  curIDEVec = &(fTDCIDEs.back().second);
302  }
303  else
304  curIDEVec = &(itrthis->second);
305 
306  for(auto const& ide : ides){
307  curIDEVec->emplace_back(ide, offset);
308  if( ide.trackID+offset < range_trackID.first )
309  range_trackID.first = ide.trackID+offset;
310  if( ide.trackID+offset > range_trackID.second )
311  range_trackID.second = ide.trackID+offset;
312  }//end loop over IDEs
313 
314  }//end loop over TDCIDEMap
315 
316 
317  return range_trackID;
318 
319  }
320 
321  //-------------------------------------------------
323 
324  bool operator()
325  (TDCIDE const& a, TDCIDE const& b) const
326  { return a.first < b.first; }
327 
328  bool operator()
329  (StoredTDC_t a_tdc, TDCIDE const& b) const
330  { return a_tdc < b.first; }
331 
332  bool operator()
333  (TDCIDE const& a, StoredTDC_t b_tdc) const
334  { return a.first < b_tdc; }
335 
336  }; // struct CompareByTDC
337 
338 
340  {
341  return std::lower_bound
342  (fTDCIDEs.begin(), fTDCIDEs.end(), tdc, CompareByTDC());
343  }
344 
346  (StoredTDC_t tdc) const
347  {
348  return std::lower_bound
349  (fTDCIDEs.begin(), fTDCIDEs.end(), tdc, CompareByTDC());
350  }
351 
352 
353  //-------------------------------------------------
354 
355 
356 }
Float_t x
Definition: compare.C:6
TrackID_t trackID
Geant4 supplied track ID.
Definition: SimChannel.h:115
std::pair< TrackID_t, TrackID_t > MergeSimChannel(const SimChannel &channel, int offset)
Merges the deposits from another channel into this one.
Definition: SimChannel.cxx:279
raw::ChannelID_t fChannel
readout channel where electrons are collected
Definition: SimChannel.h:153
float z
z position of ionization [cm]
Definition: SimChannel.h:120
Namespace for general, non-LArSoft-specific utilities.
Definition: PIDAAlg.h:17
Energy deposited on a readout channel by simulated tracks.
Definition: SimChannel.h:143
std::pair< unsigned short, std::vector< sim::IDE > > TDCIDE
List of energy deposits at the same time (on this channel)
Definition: SimChannel.h:125
intermediate_table::iterator iterator
double Energy(TDC_t tdc) const
Returns the total energy on this channel in the specified TDC [MeV].
Definition: SimChannel.cxx:154
Float_t y
Definition: compare.C:6
Double_t z
Definition: plot.C:279
constexpr int kBogusI
obviously bogus integer value
Raw data description.
Definition: RawTypes.h:6
unsigned int TDC_t
Definition: SimChannel.h:165
float x
x position of ionization [cm]
Definition: SimChannel.h:118
#define LOG_ERROR(category)
TDCIDEs_t fTDCIDEs
list of energy deposits for each TDC with signal
Definition: SimChannel.h:154
Int_t max
Definition: plot.C:27
constexpr ChannelID_t InvalidChannelID
ID of an invalid channel.
Definition: RawTypes.h:31
intermediate_table::const_iterator const_iterator
double Charge(TDC_t tdc) const
Returns the total number of ionization electrons on this channel in the specified TDC...
Definition: SimChannel.cxx:132
Ionization at a point of the TPC sensitive volume.
Definition: SimChannel.h:87
static const int NoParticleId
Definition: sim.h:28
float energy
energy deposited by ionization by this track ID and time [MeV]
Definition: SimChannel.h:117
std::vector< sim::TrackIDE > TrackIDEs(TDC_t startTDC, TDC_t endTDC) const
Returns energies collected for each track within a time interval.
Definition: SimChannel.cxx:244
double energy
Definition: plottest35.C:25
Monte Carlo Simulation.
TDCIDEs_t::iterator findClosestTDCIDE(StoredTDC_t tdc)
Return the iterator to the first TDCIDE not earlier than tdc.
Definition: SimChannel.cxx:339
float y
y position of ionization [cm]
Definition: SimChannel.h:119
void AddIonizationElectrons(TrackID_t trackID, TDC_t tdc, double numberElectrons, double const *xyz, double energy)
Add ionization electrons and energy to this channel.
Definition: SimChannel.cxx:52
raw::ChannelID_t Channel() const
Returns the readout channel this object describes.
Definition: SimChannel.h:332
double weight
Definition: plottest35.C:25
Int_t min
Definition: plot.C:26
std::vector< sim::IDE > TrackIDsAndEnergies(TDC_t startTDC, TDC_t endTDC) const
Return all the recorded energy deposition within a time interval.
Definition: SimChannel.cxx:178
IDE::TrackID_t TrackID_t
Type of track ID (the value comes from Geant4)
Definition: SimChannel.h:168
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
object containing MC truth information necessary for making RawDigits and doing back tracking ...
TDCIDEs_t const & TDCIDEMap() const
Returns all the deposited energy information as stored.
Definition: SimChannel.h:331
constexpr double kBogusD
obviously bogus double value
IDE()
Default constructor (sets "bogus" values)
Definition: SimChannel.cxx:24
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:27
Float_t e
Definition: plot.C:34
Tools and modules for checking out the basics of the Monte Carlo.
float numElectrons
number of electrons at the readout for this track ID and time
Definition: SimChannel.h:116
TDCIDE::first_type StoredTDC_t
Type for TDC tick used in the internal representation.
Definition: SimChannel.h:147