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