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