ParticleList.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 /// \file ParticleList.cxx
3 /// \brief Particle list in DetSim contains Monte Carlo particle information.
4 ///
5 /// \version $Id: ParticleList.cxx,v 1.10 2010/05/13 16:12:20 seligman Exp $
6 /// \author seligman@nevis.columbia.edu
7 ////////////////////////////////////////////////////////////////////////
8 ///
9 /// Although there's nothing in the following class that assumes
10 /// units, the standard for LArSoft is that distances are in cm, and
11 /// energies are in GeV.
12 
13 #include "nutools/ParticleNavigation/ParticleList.h"
14 #include "nutools/ParticleNavigation/EveIdCalculator.h"
15 
16 #include "cetlib_except/exception.h"
18 
19 #include <TLorentzVector.h>
20 
21 #include <set>
22 // #include <iterator>
23 //#include <cmath>
24 // #include <memory>
25 
26 namespace sim {
27 
28  //----------------------------------------------------------------------------
29  // Constructor.
31  {
32  }
33 
34  //----------------------------------------------------------------------------
35  // Destructor
37  {
38  this->clear();
39  }
40 
41  //----------------------------------------------------------------------------
42  // Copy constructor. Note that since this class inherits from
43  // TObject, we have to copy its information explicitly.
45  {
46  ParticleList list;
47 
48  // Copy each entry in the other ParticleList.
49  for (std::pair<int, simb::MCParticle*> const& partInfo: m_particleList)
50  list.insert(partInfo.second? new simb::MCParticle(*(partInfo.second)): nullptr);
51 
52  list.m_archive = m_archive;
53 
54  return list;
55  } // ParticleList::MakeCopy()
56 
57  //-----------------------------------------------------------------------------
58  // Apply an energy cut to the particles.
59  void ParticleList::Cut( const double& cut )
60  {
61  // The safest way to do this is to create a list of track IDs that
62  // fail the cut, then delete those IDs.
63 
64  // Define a list of IDs.
65  typedef std::set< key_type > keyList_type;
66  keyList_type keyList;
67 
68  // Add each ID that fails the cut to the list.
69  for ( const_iterator i = m_particleList.begin(); i != m_particleList.end(); ++i ){
70  const simb::MCParticle* particle = (*i).second;
71  if (!particle) continue;
72  Double_t totalInitialEnergy = particle->E();
73  if ( totalInitialEnergy < cut ) {
74  keyList.insert( (*i).first );
75  }
76  }
77 
78  // Go through the list, deleting the particles that are on the list.
79  for ( keyList_type::const_iterator i = keyList.begin(); i != keyList.end(); ++i ){
80  this->erase( *i );
81  }
82  }
83 
84 
85  //----------------------------------------------------------------------------
87  {
88  const_iterator i = m_particleList.begin();
89  std::advance(i,index);
90  return (*i).first;
91  }
92  //----------------------------------------------------------------------------
94  {
95  const_iterator i = m_particleList.begin();
96  std::advance(i,index);
97  return (*i).second;
98  }
99 
100  //----------------------------------------------------------------------------
102  {
103  iterator i = m_particleList.begin();
104  std::advance(i,index);
105  return (*i).second;
106  }
107 
108  //----------------------------------------------------------------------------
109  bool ParticleList::IsPrimary( int trackID ) const
110  {
111  return m_primaries.find( trackID ) != m_primaries.end();
112  }
113 
114  //----------------------------------------------------------------------------
116  {
117  return m_primaries.size();
118  }
119 
120  //----------------------------------------------------------------------------
121  const simb::MCParticle* ParticleList::Primary( const int index ) const
122  {
123  // Advance "index" entries from the beginning of the primary list.
124  primaries_const_iterator primary = m_primaries.begin();
125  std::advance( primary, index );
126 
127  // Get the track ID from that entry in the list.
128  int trackID = *primary;
129 
130  // Find the entry in the particle list with that track ID.
131  const_iterator entry = m_particleList.find(trackID);
132 
133  // Return the Particle object in that entry.
134  return (*entry).second;
135  }
136 
137  //----------------------------------------------------------------------------
139  {
140  // Advance "index" entries from the beginning of the primary list.
141  primaries_const_iterator primary = m_primaries.begin();
142  std::advance( primary, index );
143 
144  // Get the track ID from that entry in the list.
145  int trackID = *primary;
146 
147  // Find the entry in the particle list with that track ID.
148  iterator entry = m_particleList.find(trackID);
149 
150  // Return the Particle object in that entry.
151  return (*entry).second;
152  }
153 
154 
155  //----------------------------------------------------------------------------
156  std::vector<const simb::MCParticle*> ParticleList::GetPrimaries() const
157  {
158  std::vector<const simb::MCParticle*> primaries;
159  primaries.reserve(m_primaries.size());
160  // for each particle, check if its track ID is in the primaries list
161  // iPartPair is std::pair<const int, simb::MCParticle*>
162  for (auto& iPartPair: m_particleList) {
163  if (m_primaries.count(iPartPair.first))
164  primaries.push_back(iPartPair.second);
165  } // for
166  if (primaries.size() != m_primaries.size()) {
167  throw cet::exception("ParticleList")
168  << "sim::ParticleList::GetPrimaries() collected " << primaries.size()
169  << " primaries, not " << m_primaries.size() << " as expected\n";
170  }
171  return primaries;
172  } // ParticleList::GetPrimaries()
173 
174 
175  //----------------------------------------------------------------------------
176 // void ParticleList::Add( const ParticleList& other )
177 // {
178 // int offset = 0;
179 // if ( ! m_particleList.empty() ){
180 // // Get the ID number of the last track in our list of particles.
181 // const_iterator last = m_particleList.end();
182 // --last;
183 // int lastTrackID = (*last).first;
184 
185 // // Compute an offset so that there will be no overlaps in
186 // // track numbers.
187 // offset = lastTrackID + 1;
188 
189 // // The first track ID number in the other list is probably 1,
190 // // or perhaps 0. But there's a chance that it might be a
191 // // negative number, if the user manually adds a negative track
192 // // ID as some indicator. Let's allow for that.
193 // int firstOtherTrackID = 0;
194 // if ( ! other.m_particleList.empty() ){
195 // // Get the first track number of the other list.
196 // firstOtherTrackID = (*(m_particleList.begin())).first;
197 
198 // if ( firstOtherTrackID < 0 ){
199 // offset -= firstOtherTrackID;
200 // }
201 // }
202 // }
203 
204 // // Create a new particle list from "other", with non-overlapping
205 // // track IDs with respect to our list.
206 // ParticleList adjusted = other + offset;
207 
208 // // Merge the two particle lists.
209 // m_particleList.insert( adjusted.m_particleList.begin(), adjusted.m_particleList.end() );
210 // m_primaries.insert( adjusted.m_primaries.begin(), adjusted.m_primaries.end() );
211 // }
212 
213  //----------------------------------------------------------------------------
214 // ParticleList ParticleList::Add( const int& offset ) const
215 // {
216 // // Start with a fresh ParticleList, the destination of the
217 // // particles with adjusted track numbers.
218 // ParticleList result;
219 
220 // // For each particle in our list:
221 // for ( const_iterator i = m_particleList.begin(); i != m_particleList.end(); ++i ){
222 // const simb::MCParticle* particle = (*i).second;
223 
224 // // Create a new particle with an adjusted track ID.
225 // simb::MCParticle* adjusted = new simb::MCParticle( particle->TrackId() + offset,
226 // particle->PdgCode(),
227 // particle->Process(),
228 // particle->Mother(),
229 // particle->Mass() );
230 
231 // adjusted->SetPolarization( particle->Polarization() );
232 
233 // // Copy all the daughters, adjusting the track ID.
234 // for ( int d = 0; d < particle->NumberDaughters(); ++d ){
235 // int daughterID = particle->Daughter(d);
236 // adjusted->AddDaughter( daughterID + offset );
237 // }
238 
239 // // Copy the trajectory points.
240 // for ( size_t t = 0; t < particle->NumberTrajectoryPoints(); ++t ){
241 // adjusted->AddTrajectoryPoint( particle->Position(t), particle->Momentum(t) );
242 // }
243 
244 // // Add the adjusted particle to the destination particle list.
245 // // This will also adjust the destination's list of primary
246 // // particles, if needed.
247 // result.insert( adjusted );
248 // }
249 
250 // return result;
251 // }
252 
253  //----------------------------------------------------------------------------
254  // Just in case: define the result of "scalar * ParticleList" to be
255  // the same as "ParticleList * scalar".
256 // ParticleList operator+(const int& value, const ParticleList& list)
257 // {
258 // return list + value;
259 // }
260 
261 
262  // This is the main "insertion" method for the ParticleList
263  // pseudo-array pseudo-map. It does the following:
264  // - Add the Particle to the list; if the track ID is already in the
265  // list, throw an exception.
266  // - If it's a primary particle, add it to the list of primaries.
268  {
269  int trackID = key(particle);
270  iterator insertion = m_particleList.lower_bound( trackID );
271  if ( insertion == m_particleList.end() ){
272  // The best "hint" we can give is that the particle will go at
273  // the end of the list.
274  m_particleList.insert( insertion, value_type( trackID, particle ) );
275  }
276  else if ( (*insertion).first == trackID ){
277  throw cet::exception("ParticleList") << "sim::ParticleList::insert - ERROR - "
278  << "track ID=" << trackID
279  << " is already in the list\n";
280  }
281  else{
282  // It turns out that the best hint we can give is one more
283  // than the result of lower_bound.
284  m_particleList.insert( ++insertion, value_type( trackID, particle ) );
285  }
286 
287  // If this is a primary particle, add it to the list. use
288  // rimary as the process string to look for as the P may or may not
289  // be capitalized
290  if ( particle->Process().find("rimary") != std::string::npos )
291  m_primaries.insert( trackID );
292  }
293 
294  //----------------------------------------------------------------------------
296  {
297  auto& part = m_particleList.at(key);
298  if (part == nullptr) return; // already archived, nothing to do
299 
300  // create a new archive item with the particle;
301  m_archive[key] = archived_info_type(*part);
302 
303  // dispose of the particle in the list (the cell will still be there
304  delete part;
305  part = nullptr;
306  } // ParticleList::Archive()
307 
308 
309  //----------------------------------------------------------------------------
311  Archive(key(part));
312  }
313 
314  //----------------------------------------------------------------------------
316  {
317  auto part = m_particleList.at(key);
318  return part? part->Mother(): m_archive.at(key).Mother();
319  } // ParticleList::GetMotherOf()
320 
321 
322  //----------------------------------------------------------------------------
324  {
325  for ( iterator i = m_particleList.begin(); i != m_particleList.end(); ++i ){
326  delete (*i).second;
327  }
328 
329  m_particleList.clear();
330  m_archive.clear();
331  m_primaries.clear();
332  }
333 
334  //----------------------------------------------------------------------------
335  // An erase that includes the deletion of the associated Particle*.
337  {
338  delete position->second;
339  return m_particleList.erase( position );
340  }
341 
343  {
344  iterator entry = m_particleList.find( abs(key) );
345  if (entry == m_particleList.end()) return 0;
346  erase(entry);
347  return 1;
348  }
349 
350 
351  //----------------------------------------------------------------------------
352  std::ostream& operator<< ( std::ostream& output, const ParticleList& list )
353  {
354  // Determine a field width for the particle number.
355  ParticleList::size_type numberOfParticles = list.size();
356  int numberOfDigits = (int) std::log10( (double) numberOfParticles ) + 1;
357 
358  // A simple header.
359  output.width( numberOfDigits );
360  output << "#" << ": < ID, particle >" << std::endl;
361 
362  // Write each particle on a separate line.
363  ParticleList::size_type nParticle = 0;
364  for ( ParticleList::const_iterator particle = list.begin();
365  particle != list.end(); ++particle, ++nParticle ){
366  output.width( numberOfDigits );
367  output << nParticle << ": "
368  << "<" << (*particle).first << ",";
369  if (particle->second)
370  output << *(particle->second);
371  else {
372  auto iArch = list.m_archive.find(particle->first);
373  if (iArch == list.m_archive.end())
374  output << "lost [INTERNAL ERROR!]";
375  else
376  output << "(archived) " << iArch->second;
377  }
378  output << ">" << std::endl;
379  }
380 
381  return output;
382  }
383 
384  //----------------------------------------------------------------------------
385  // Static variable for eve ID calculator. We're using an unique_ptr,
386  // so when this object is eventually deleted (at the end of the job)
387  // it will delete the underlying pointer.
388  static std::unique_ptr<EveIdCalculator> eveIdCalculator;
389 
390  //----------------------------------------------------------------------------
391  // The eve ID calculation.
392  int ParticleList::EveId( const int trackID ) const
393  {
394  // If the eve ID calculator has never been initialized, use the
395  // default method.
396  if ( eveIdCalculator.get() == 0 ){
398  }
399 
400  // If the eve ID calculator has changed, or we're looking at a
401  // different ParticleList, initialize the calculator.
402  static EveIdCalculator* saveEveIdCalculator = 0;
403  if ( saveEveIdCalculator != eveIdCalculator.get() ) {
404  saveEveIdCalculator = eveIdCalculator.get();
405  eveIdCalculator->Init( this );
406  }
407  if ( eveIdCalculator->ParticleList() != this ){
408  eveIdCalculator->Init( this );
409  }
410 
411  // After the "bookkeeping" tests, here's where we actually do the
412  // calculation.
413  return eveIdCalculator->CalculateEveId( trackID );
414  }
415 
416  //----------------------------------------------------------------------------
417  // Save a new eve ID calculation method.
419  {
420  eveIdCalculator.reset(calc);
421  }
422 
423  //----------------------------------------------------------------------------
424  std::ostream& operator<<
425  ( std::ostream& output, const ParticleList::archived_info_type& info )
426  {
427  output << "Mother ID=" << info.Mother() << std::endl;
428  return output;
429  }
430  //----------------------------------------------------------------------------
431 
432 } // namespace sim
double E(const int i=0) const
Definition: MCParticle.h:232
void insert(simb::MCParticle *value)
QList< Entry > entry
ParticleList MakeCopy() const
Returns a copy of this object.
key_type key(mapped_type const &part) const
Extracts the key from the specified value.
Definition: ParticleList.h:338
const key_type & TrackId(const size_type) const
primaries_type m_primaries
Definition: ParticleList.h:171
list_type::value_type value_type
Definition: ParticleList.h:130
list_type::const_iterator const_iterator
Definition: ParticleList.h:132
virtual ~ParticleList()
list_type::iterator iterator
Definition: ParticleList.h:131
int width() const
Definition: qtextstream.h:247
primaries_type::const_iterator primaries_const_iterator
Definition: ParticleList.h:168
intermediate_table::const_iterator const_iterator
int EveId(const int trackID) const
std::string Process() const
Definition: MCParticle.h:214
T abs(T value)
mapped_type const & Particle(const size_type) const
bool IsPrimary(int trackID) const
friend std::ostream & operator<<(std::ostream &output, const ParticleList &)
iterator begin()
Definition: ParticleList.h:305
list_type::size_type size_type
Definition: ParticleList.h:135
Monte Carlo Simulation.
void Cut(const double &)
int GetMotherOf(const key_type &key) const
This function seeks for the exact key, not its absolute value.
list_type::key_type key_type
Definition: ParticleList.h:128
static std::unique_ptr< EveIdCalculator > eveIdCalculator
std::vector< const simb::MCParticle * > GetPrimaries() const
const simb::MCParticle * Primary(const int) const
size_type erase(const key_type &key)
list_type m_particleList
Sorted list of particles in the event.
Definition: ParticleList.h:170
static void AdoptEveIdCalculator(EveIdCalculator *)
archive_type m_archive
archive of the particles no longer among us
Definition: ParticleList.h:173
size_type size() const
Definition: ParticleList.h:313
int NumberOfPrimaries() const
list_type::mapped_type mapped_type
Definition: ParticleList.h:129
void Archive(const key_type &key)
Removes the particle from the list, keeping minimal info of it.
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
QTextStream & endl(QTextStream &s)