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