StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
AgUDecay.cxx
1 #include "AgUDecay.h"
2 #include "StMessMgr.h"
3 #include "TVirtualMCDecayer.h"
4 #include "TParticle.h"
5 #include "TClonesArray.h"
6 #include "StarDecayManager.h"
7 #include "St_geant_Maker/St_geant_Maker.h"
8 #include "StarGenerator/UTIL/StarParticleData.h"
9 
10 #include <stdexcept>
11 #include <string>
12 
13 #define geant3 St_geant_Maker::instance()->Geant3()
14 
16 
17 //__________________________________________________________________________________________________
18 // Useful exceptions for debugging
19 struct EnergyNotConserved : public std::runtime_error { EnergyNotConserved( std::string const& message ) : std::runtime_error( message ) { LOG_ERROR << message << endm; } };
20 struct StopOnParticle : public std::runtime_error { StopOnParticle ( std::string const& message ) : std::runtime_error( message ) { LOG_ERROR << message << endm; } };
21 struct MissingPdgEntry : public std::runtime_error { MissingPdgEntry ( std::string const& message ) : std::runtime_error( message ) { LOG_ERROR << message << endm; } };
22 //__________________________________________________________________________________________________
23 
24 
25 AgUDecay AgUDecay::sInstance;
26 //
27 // --------------------------------------------------------------------------------------------------
28 //
29 extern "C" {
30 
31  void agudcay_()
32  { static AgUDecay &decay = AgUDecay::instance();
33 
34  // Decay current particle on G3 stack
35  decay();
36 
37  };
38 
39  void gsking_(int &igk);
40 
41 }
42 //
43 void gsking( int igk ){ gsking_(igk); }
44 //
45 // --------------------------------------------------------------------------------------------------
46 //
47 
48 std::map<int,int> AgUDecay::mParticleStop;
49 
50 Int_t AgUDecay::operator()()
51 {
52 
53  Gctrak_t& gctrak = *(geant3->Gctrak()); // kinematics of current track
54  Gcking_t& gcking = *(geant3->Gcking()); // kinematics of decay products
55  Gckin3_t& gckin3 = *(geant3->Gckin3()); // vertex of decay products
56 
57  float x = gctrak.vect[0];
58  float y = gctrak.vect[1];
59  float z = gctrak.vect[2];
60 
61  // LOG_INFO << Form(">>> decay() called x=%f y=%f z=%f <<<",x,y,z) << endm;
62  if (0==mDecayer) return 0; // no decayer registerd
63 
64  // int np = 0;
65  mDecayer -> ForceDecay();
66 
67  int idGeant3 = geant3->Gckine()->ipart;
68 
69  double pmom = double( gctrak.vect[6] );
70  double px = double( gctrak.vect[3] ) * pmom;
71  double py = double( gctrak.vect[4] ) * pmom;
72  double pz = double( gctrak.vect[5] ) * pmom;
73  double E = double( gctrak.getot ); // Input energy
74 
75  mP[0] = px; mP[1] = py; mP[2] = pz; mP[3] = E;
76 
77  // Extract PDG ID from idPart
78  int idPdg = pdb.GetParticleG3( idGeant3 )->PdgCode();
79 
80  // Perform the decay
81  int nretry = 0;
82  int np = 0;
83 
84  AGAIN: while ( true ) {
85  if ( nretry ) {
86  LOG_WARN << "Decay chain rejected (all or in part) due to unknown PDG" << endm;
87  mArray->Print();
88  TString msg = Form("No path to decay after 1k attempts: idpdg=%i idg3=%i",idPdg,idGeant3);
89  if ( nretry > 1000 ) throw
90  MissingPdgEntry(msg.Data());
91  }
92  mArray -> Clear();
93 
94  // Perform the decay
95  mDecayer -> Decay( idPdg, &mP );
96 
97  // Retrieve the particles into the clones array
98  np = mDecayer -> ImportParticles( mArray ); if ( np<1 ) return np;
99 
100  // Possible that one or more particles are unknown to the PDG DB
101  // If so, we will repeat (and warn).
102 
103  bool go = false;
104  for ( int ip = 0; ip<np; ip++ ) {
105 
106  TParticle* part = (TParticle *)mArray->At(ip);
107 
108  // Advance past any "system" entry when checking validity
109  int thispdgid = part->GetPdgCode();
110  if ( thispdgid == idPdg ) go = true;
111  if ( !go ) continue;
112 
113  if ( 0 == part->GetPDG() && ++nretry ) {
114  if ( nretry==1000 ) {
115  LOG_INFO << "1k failures... this particle may be a culprit" << endm;
116  part->Print();
117  }
118  goto AGAIN;
119  }
120  }
121 
122  break; // Reach here only on a valid decay chain
123  }
124 
125 
126 
127  //
128  // Loop over daughter particles in the decay and stack them for
129  // transport. (Potentially recurses through the entire decay
130  // chain until it reaches particles known to the simulator).
131  //
132  TParticle* mother = (TParticle*)mArray->At(0);
133  if ( mParticleStop[idPdg] || mParticleStop[-idPdg] ) {
134  LOG_INFO << "User stop on pdgid = " << idPdg << endm;
135  LOG_INFO << "==================================================" << endm;
136  mother->Print();
137  LOG_INFO << "==================================================" << endm;
138  mArray->Print();
139  LOG_INFO << "==================================================" << endm;
140  throw StopOnParticle("found it");
141  }
142  // Possible that the decay is setup in a special "system" residing at zero, so
143  // start by searching for the PDG id we are decaying
144  for ( int i=0;i<np;i++ ) {
145  mother = (TParticle*)mArray->At(i); if ( mother->GetPdgCode() == idPdg ) break;
146  }
147  int first = mother->GetFirstDaughter();
148  int last = mother->GetLastDaughter();
149  double EnergySum = 0; // Energy conservation...
150  for ( int i=first /* first daughter */; i <= last; i++ )
151  {
152 
153  TParticle *particle = (TParticle *)mArray->At(i);
154  if ( 0==particle ) {
155  LOG_WARN << "Daughter " << i << " not valid for particle " << Form("%s [@0x%p]",mother->GetName(),mother) << endm;
156  mArray->Print();
157  continue;
158  }
159 
160  EnergySum += StackParticleForTransport( particle );
161 
162  }
163 
164  double violation;
165  if ( (violation = TMath::Abs(E - EnergySum)/E > 0.1E-5) ) {
166 #if 0
167  TParticle *particle = (TParticle *)mArray->At(0);
168  LOG_INFO << "Stop due to energy nonconservation on pdgid = " << idPdg << endm;
169  LOG_INFO << "==================================================" << endm;
170  particle->Print();
171  LOG_INFO << "==================================================" << endm;
172  mArray->Print();
173  LOG_INFO << "==================================================" << endm;
174  throw EnergyNotConserved( Form("%s decay violates E conservation", particle->GetName() ) );
175 #endif
176  mNonConservation++;
177  }
178 
179  return np;
180 }
181 //_____________________________________________________________________________
182 bool AgUDecay::MayTransport( const TParticle* particle )
183 {
184 
185  int first = particle->GetFirstDaughter();
186  int last = particle->GetLastDaughter();
187  int pdgid = particle->GetPdgCode();
188  int status = particle->GetStatusCode();
189  TParticlePDG *particlePDG = pdb.GetParticle(pdgid);
190  int g3id = particlePDG->TrackingCode();
191 
192  if ( 0 == g3id ) {
193  // For neutrinos, adjust the PDG entry...
194  int apdgid = TMath::Abs(pdgid);
195  if ( apdgid == 12 || apdgid == 14 || apdgid == 16 ) {
196  g3id = 4;
197  }
198  }
199 
200  if ( 0 == g3id ) // particle not known to G3
201  switch( mDiscovery ) {
202  case kDecay:
203  return false;
204  case kSpawn:
205  pdb.AddParticleToG3( particlePDG, mNextG3id++ );
206  assert(mNextG3id < 60000);
207  return true;
208  break;
209  default:
210  assert(0);
211  break;
212  }
213  return true;
214 
215 
216 
217 }
218 //_____________________________________________________________________________
219 double AgUDecay::StackParticleForTransport( const TParticle* particle )
220 {
221 
222  Gctrak_t& gctrak = *(geant3->Gctrak()); // kinematics of current track
223  Gcking_t& gcking = *(geant3->Gcking()); // kinematics of decay products
224  Gckin3_t& gckin3 = *(geant3->Gckin3()); // vertex of decay products
225 
226  double EnergySum = 0.0; // returns total energy of stacked particles
227 
228  int first = particle->GetFirstDaughter();
229  int last = particle->GetLastDaughter();
230  int pdgid = particle->GetPdgCode();
231  int status = particle->GetStatusCode();
232  TParticlePDG *particlePDG = pdb.GetParticle(pdgid);
233  int g3id = particlePDG->TrackingCode();
234 
235  // Stack the particle for transport by geant if possible,
236  // otherwise recursively stack daughters.
237  if ( 0 == MayTransport(particle) )
238  {
239  LOG_INFO << Form("%s [@0x%p] decayed in place", particle->GetName(),particle) << endm;
240  for ( int kid=first; kid<=last; kid++ )
241  {
242  TParticle* daughter = (TParticle*)mArray->At( kid );
243  LOG_INFO << Form(" %s [@x%p] visit kid: %s [@0x%p]", particle->GetName(),particle,daughter->GetName(),daughter) << endm;
244  EnergySum += StackParticleForTransport( daughter );
245  }
246  return EnergySum;
247  }
248 
249  if ( g3id == 4 || g3id == 0 ) {
250  LOG_INFO << Form("%s [@0x%p] ... ignore neutrinos for transport ...", particle->GetName(),particle) << endm;
251  EnergySum += particle->Energy();
252  return EnergySum;
253  }
254 
255 
256  // Stack this particle for transport
257  LOG_INFO << Form("%s [@0x%p] stacked for transport", particle->GetName(),particle) << endm;
258 
259  int &index = gcking.ngkine;
260 
261  // Throw particle on the stack
262  (gcking.gkin[index][0]) = particle->Px();
263  (gcking.gkin[index][1]) = particle->Py();
264  (gcking.gkin[index][2]) = particle->Pz();
265  (gcking.gkin[index][3]) = particle->Energy(); EnergySum += particle->Energy();
266 
267  (gcking.gkin[index][4]) = float(g3id);
268  // particlePDG->Print();
269 
270  // Decay vertex
271  (gckin3.gpos[index][0]) = gctrak.vect[0];
272  (gckin3.gpos[index][1]) = gctrak.vect[1];
273  (gckin3.gpos[index][2]) = gctrak.vect[2];
274 
275  // time of flight offset (mm)... (huh?)
276  (gcking.tofd[index]) = 0.;
277 
278  // Set the flag to handle the particle in GSKING. We currently skip particles
279  // which we have decayed with the "continue" statements above. This is because
280  // the STAR stepping routine drops the iflgk flag before the call to gsking which
281  // processes it....
282  //
283  // so in order to preserve the particle in the event record, we will need to add
284  // a call to gsking in this routine. (And test test test test...)
285  (gcking.iflgk[index]) = 0;
286 
287  // And increase stack counter
288  index++;
289 
290  // Return the energy sum for validation
291  return EnergySum;
292 }
293 //_____________________________________________________________________________________
294 AgUDecay::AgUDecay() : mDecayer( 0 ),
295  mArray( new TClonesArray("TParticle",1000) ),
296  mP(),
297  mDiscovery( kDecay ),
298  mNextG3id( 12345 ), // dynamic G3 id
299  mNonConservation(0)
300 {
301 
302 }
303 //_____________________________________________________________________________________
304 AgUDecay::~AgUDecay() {
305 }
TParticlePDG * GetParticleG3(const Int_t id)
Get a particle by G3 ID.
Interface between starsim and virtual decayer (VMC implementation)
Definition: AgUDecay.h:18
static StarParticleData & instance()
Returns a reference to the single instance of this class.
TParticlePDG * GetParticle(const Char_t *name)
Get a particle by name.
Interface to PDG information.
TParticlePDG * AddParticleToG3(const char *name, const double mass, const double lifetime, const double charge, const int tracktype, const int pdgcode, const int g3code, const double *bratio=0, const int *mode=0)