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
weight
Definition: test.py:257
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)
Code to link reconstructed objects back to the MC truth information.
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
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
IDE()
Default constructor (sets "bogus" values)
Definition: SimChannel.cxx:24
Tools and modules for checking out the basics of the Monte Carlo.
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:28
Collection of Physical constants used in LArSoft.
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