FairShip
Loading...
Searching...
No Matches
TEvtGenDecayer.cxx
Go to the documentation of this file.
1// SPDX-License-Identifier: LGPL-3.0-or-later
2// SPDX-FileCopyrightText: Copyright CERN for the benefit of the SHiP
3// Collaboration
4
5#include "TEvtGenDecayer.h"
6
7#include "FairLogger.h"
8#include "TClonesArray.h"
9#include "TLorentzVector.h"
10#include "TMCProcess.h"
11#include "TParticle.h"
12#include "TPythia8.h"
13#include "TRandom.h"
14#include "TSystem.h"
15
16// Define EVTGEN_CPP11 for older EvtGen versions to enable MT random generator
17// This will become obsolete with newer EvtGen versions
18#ifndef EVTGEN_CPP11
19#define EVTGEN_CPP11
20#endif
21
22// EvtGen includes
23#include "EvtGen/EvtGen.hh"
24#include "EvtGenBase/EvtAbsRadCorr.hh"
25#include "EvtGenBase/EvtId.hh"
26#include "EvtGenBase/EvtMTRandomEngine.hh"
27#include "EvtGenBase/EvtPDL.hh"
28#include "EvtGenBase/EvtParticle.hh"
29#include "EvtGenBase/EvtParticleFactory.hh"
30#include "EvtGenBase/EvtRandom.hh"
31#include "EvtGenBase/EvtVector4R.hh"
32#include "EvtGenExternal/EvtExternalGenList.hh"
33
34//_____________________________________________________________________________
36 : TVirtualMCDecayer(),
37 fPythia8Decayer(nullptr),
38 fEvtGen(nullptr),
39 fDecayFile(""),
40 fParticleFile(""),
41 fEvtGenProducts(nullptr),
42 fHasEvtGenDecay(kFALSE) {
43 // Default constructor
44 fEvtGenParticles.clear();
45 fEvtGenProducts = new TClonesArray("TParticle");
46}
47
48//_____________________________________________________________________________
50 // Destructor
52 if (fEvtGen) delete fEvtGen;
54}
55
56//_____________________________________________________________________________
58 // Initialize both EvtGen and Pythia8 decayers
59
60 // Initialize fallback Pythia8 decayer
61 fPythia8Decayer = new TPythia8Decayer();
62 fPythia8Decayer->Init();
63
64 // Initialize EvtGen if decay files are specified
65 if (fDecayFile != "" && fParticleFile != "") {
66 // Set up EvtGen random engine with ROOT's random number generator seed
67 UInt_t seed = gRandom->GetSeed();
68
69 // Also seed Pythia8 with the same seed for consistency
70 TPythia8* pythia8 = TPythia8::Instance();
71 if (pythia8) {
72 pythia8->Pythia8()->readString(Form("Random:seed = %u", seed));
73 pythia8->Pythia8()->readString("Random:setSeed = on");
74 pythia8->Pythia8()->init(); // Re-initialize with new seed
75 LOG(debug) << "TEvtGenDecayer: Pythia8 RNG seeded with " << seed;
76 }
77
78 EvtRandomEngine* randomEngine = new EvtMTRandomEngine(seed);
79 EvtRandom::setRandomEngine(randomEngine);
80
81 LOG(info) << "TEvtGenDecayer: Random engine initialized with seed " << seed;
82
83 // Set up external generators with PHOTOS radiative corrections
84 std::string photonType("gamma");
85 bool useEvtGenRandom(true);
86 bool convertPythiaCodes(false);
87 std::string pythiaDir("");
88
89 EvtExternalGenList* externalGenList = new EvtExternalGenList(
90 convertPythiaCodes, pythiaDir, photonType, useEvtGenRandom);
91
92 // Get the interface to the radiative correction engine (PHOTOS)
93 EvtAbsRadCorr* radCorrEngine = externalGenList->getPhotosModel();
94 if (radCorrEngine) {
95 LOG(info) << "TEvtGenDecayer: PHOTOS radiative corrections enabled";
96 } else {
97 LOG(warning) << "TEvtGenDecayer: PHOTOS not available, proceeding "
98 "without radiative corrections";
99 }
100
101 // Get the interface to other external generators
102 std::list<EvtDecayBase*> extraModels = externalGenList->getListOfModels();
103
104 // Create EvtGen instance
105 fEvtGen = new EvtGen(fDecayFile.Data(), fParticleFile.Data(), randomEngine,
106 radCorrEngine, &extraModels, 1, false);
107
108 LOG(debug) << "TEvtGenDecayer: EvtGen created with " << EvtPDL::entries()
109 << " particle entries";
110
111 LOG(info) << "TEvtGenDecayer: EvtGen initialized with decay file: "
112 << fDecayFile.Data()
113 << ", particle file: " << fParticleFile.Data();
114 } else {
115 LOG(debug)
116 << "TEvtGenDecayer: No EvtGen files specified, using Pythia8 only";
117 }
118
119 // Log summary at end of Init
120 LOG(info) << "TEvtGenDecayer initialized - EvtGen: "
121 << (fEvtGen ? "YES" : "NO")
122 << ", Pythia8 fallback: " << (fPythia8Decayer ? "YES" : "NO")
123 << ", Particles configured for EvtGen: " << fEvtGenParticles.size();
124
125 for (size_t i = 0; i < fEvtGenParticles.size(); i++) {
126 LOG(debug) << " EvtGen particle: PDG " << fEvtGenParticles[i];
127 }
128}
129
130//_____________________________________________________________________________
131void TEvtGenDecayer::Decay(Int_t pdg, TLorentzVector* p) {
132 // Main decay method - route to EvtGen or Pythia8 based on particle type
133
134 // Debug output for decay calls (highest verbosity)
135 LOG(debug2) << "TEvtGenDecayer::Decay called for PDG " << pdg
136 << " (E=" << p->E() << ", p=" << p->P() << ")";
137
138 // Check if this particle should use EvtGen
139 Bool_t useEvtGen = UseEvtGenForParticle(pdg);
140 Bool_t evtGenAvailable = (fEvtGen != nullptr);
141
142 LOG(debug1) << "UseEvtGenForParticle(" << pdg << ") = " << useEvtGen
143 << ", EvtGen available = " << evtGenAvailable;
144
145 if (useEvtGen && evtGenAvailable) {
146 LOG(debug) << "Routing PDG " << pdg << " to EvtGen";
147 DecayWithEvtGen(pdg, p);
148 } else {
149 LOG(debug) << "Routing PDG " << pdg << " to Pythia8 fallback";
150 DecayWithPythia8(pdg, p);
151 }
152}
153
154//_____________________________________________________________________________
156 // Check if this particle should be handled by EvtGen
157 LOG(debug2) << "UseEvtGenForParticle: Checking PDG " << pdg
158 << " against EvtGen particle list";
159
160 for (Int_t evtGenPdg : fEvtGenParticles) {
161 if (pdg == evtGenPdg) {
162 LOG(debug2) << "UseEvtGenForParticle: Match found - PDG " << pdg
163 << " should use EvtGen";
164 return kTRUE;
165 }
166 }
167
168 LOG(warning) << "UseEvtGenForParticle: PDG " << pdg
169 << " not in EvtGen particle list, falling back to Pythia8";
170 return kFALSE;
171}
172
173//_____________________________________________________________________________
174void TEvtGenDecayer::DecayWithEvtGen(Int_t pdg, TLorentzVector* p) {
175 // Decay particle using EvtGen
176
177 if (!fEvtGen) {
178 // Fall back to Pythia8 if EvtGen not available
179 DecayWithPythia8(pdg, p);
180 return;
181 }
182
183 LOG(debug1) << "DecayWithEvtGen: Decaying PDG " << pdg << " with EvtGen";
184
185 try {
186 // Convert TLorentzVector to EvtGen format
187 EvtVector4R p4(p->E(), p->Px(), p->Py(), p->Pz());
188
189 // Get EvtGen particle ID from PDG code
190 EvtId evtId = EvtPDL::evtIdFromStdHep(pdg);
191
192 // Check if EvtId is valid before creating particle
193 if (evtId.getId() < 0 ||
194 static_cast<size_t>(evtId.getId()) >= EvtPDL::entries()) {
195 LOG(warning) << "TEvtGenDecayer: Invalid EvtId for PDG " << pdg
196 << " (EvtId: " << evtId.getId()
197 << "), falling back to Pythia8";
198 DecayWithPythia8(pdg, p);
199 return;
200 }
201
202 // Create EvtGen particle
203 EvtParticle* parent = EvtParticleFactory::particleFactory(evtId, p4);
204
205 if (parent) {
206 // Generate decay
207 fEvtGen->generateDecay(parent);
208
209 // Convert EvtGen decay products to ROOT format
210 ConvertEvtGenDecay(parent);
211
212 LOG(debug1)
213 << "TEvtGenDecayer: EvtGen decay products converted and stored";
214
215 // Clean up
216 parent->deleteTree();
217 } else {
218 LOG(warning) << "TEvtGenDecayer: Could not create EvtParticle for PDG "
219 << pdg;
220 // Fall back to Pythia8
221 DecayWithPythia8(pdg, p);
222 }
223 } catch (const std::exception& e) {
224 LOG(error) << "TEvtGenDecayer: EvtGen exception for PDG " << pdg << ": "
225 << e.what();
226 // Fall back to Pythia8 on any exception
227 DecayWithPythia8(pdg, p);
228 }
229}
230
231//_____________________________________________________________________________
232void TEvtGenDecayer::ConvertEvtGenDecay(EvtParticle* parent) {
233 // Convert EvtGen decay products to ROOT/GEANT4 format
234 // Clear previous decay products
235 fEvtGenProducts->Clear();
236 fHasEvtGenDecay = kTRUE;
237
238 int nDaughters = parent->getNDaug();
239 LOG(debug2) << "ConvertEvtGenDecay: Converting " << nDaughters
240 << " daughter particles";
241
242 // Convert each daughter particle to TParticle format
243 for (int i = 0; i < nDaughters; i++) {
244 EvtParticle* daughter = parent->getDaug(i);
245 EvtVector4R p4 = daughter->getP4();
246 int pdgId = EvtPDL::getStdHep(daughter->getId());
247
248 // Create TParticle (ROOT format)
249 TParticle* particle = new ((*fEvtGenProducts)[i]) TParticle();
250 particle->SetPdgCode(pdgId);
251 particle->SetMomentum(p4.get(1), p4.get(2), p4.get(3),
252 p4.get(0)); // px, py, pz, E
253 particle->SetProductionVertex(0, 0, 0, 0); // Produced at origin
254 particle->SetStatusCode(1); // Stable particle
255
256 LOG(debug2) << " Daughter " << i << ": PDG=" << pdgId
257 << ", E=" << p4.get(0) << ", px=" << p4.get(1)
258 << ", py=" << p4.get(2) << ", pz=" << p4.get(3);
259 }
260
261 LOG(debug1) << "ConvertEvtGenDecay: Stored "
262 << fEvtGenProducts->GetEntriesFast() << " particles";
263}
264
265//_____________________________________________________________________________
266void TEvtGenDecayer::DecayWithPythia8(Int_t pdg, TLorentzVector* p) {
267 // Decay particle using Pythia8 decayer
268 LOG(debug1) << "DecayWithPythia8: Handling PDG " << pdg << " with Pythia8";
269
270 // Mark that this decay will use Pythia8 products
271 fHasEvtGenDecay = kFALSE;
272
273 if (fPythia8Decayer) {
274 fPythia8Decayer->Decay(pdg, p);
275 }
276}
277
278//_____________________________________________________________________________
279Int_t TEvtGenDecayer::ImportParticles(TClonesArray* particles) {
280 // Import particles - return EvtGen products if available, otherwise delegate
281 // to Pythia8
283 LOG(debug1) << "ImportParticles: Returning "
284 << fEvtGenProducts->GetEntriesFast() << " EvtGen particles";
285
286 // Copy EvtGen particles to the provided array
287 particles->Clear();
288 int nParticles = fEvtGenProducts->GetEntriesFast();
289 for (int i = 0; i < nParticles; i++) {
290 TParticle* srcParticle = static_cast<TParticle*>(fEvtGenProducts->At(i));
291 new ((*particles)[i]) TParticle(*srcParticle);
292 }
293
294 // Reset the flag for next decay
295 fHasEvtGenDecay = kFALSE;
296 return nParticles;
297 } else {
298 // Fall back to Pythia8
299 LOG(debug1) << "ImportParticles: Delegating to Pythia8";
300 if (fPythia8Decayer) {
301 return fPythia8Decayer->ImportParticles(particles);
302 }
303 return 0;
304 }
305}
306
307//_____________________________________________________________________________
308void TEvtGenDecayer::SetEvtGenDecayFile(const char* decayFile) {
309 fDecayFile = decayFile;
310}
311
312//_____________________________________________________________________________
313void TEvtGenDecayer::SetEvtGenParticleFile(const char* particleFile) {
314 fParticleFile = particleFile;
315}
316
317//_____________________________________________________________________________
319 fEvtGenParticles.push_back(pdg);
320 LOG(info) << "TEvtGenDecayer: Added PDG " << pdg << " to EvtGen particle list"
321 << " (Total: " << fEvtGenParticles.size() << ")";
322}
323
324//_____________________________________________________________________________
326 if (fPythia8Decayer) fPythia8Decayer->SetForceDecay(type);
327}
328
329//_____________________________________________________________________________
331 if (fPythia8Decayer) fPythia8Decayer->ForceDecay();
332}
333
334//_____________________________________________________________________________
336 if (fPythia8Decayer) return fPythia8Decayer->GetPartialBranchingRatio(ipart);
337 return 0.0;
338}
339
340//_____________________________________________________________________________
342 if (fPythia8Decayer) return fPythia8Decayer->GetLifetime(kf);
343 return 0.0;
344}
345
346//_____________________________________________________________________________
348 if (fPythia8Decayer) fPythia8Decayer->ReadDecayTable();
349}
const Int_t debug
std::vector< Int_t > fEvtGenParticles
void ReadDecayTable() override
Bool_t fHasEvtGenDecay
Int_t ImportParticles(TClonesArray *particles) override
void SetForceDecay(Int_t type) override
EvtGen * fEvtGen
void DecayWithPythia8(Int_t pdg, TLorentzVector *p)
TString fParticleFile
void AddEvtGenParticle(Int_t pdg)
void SetEvtGenParticleFile(const char *particleFile)
Float_t GetLifetime(Int_t kf) override
TString fDecayFile
TClonesArray * fEvtGenProducts
void Decay(Int_t pdg, TLorentzVector *p) override
void Init() override
void ForceDecay() override
Float_t GetPartialBranchingRatio(Int_t ipart) override
void ConvertEvtGenDecay(EvtParticle *parent)
void SetEvtGenDecayFile(const char *decayFile)
~TEvtGenDecayer() override
void DecayWithEvtGen(Int_t pdg, TLorentzVector *p)
TPythia8Decayer * fPythia8Decayer
Bool_t UseEvtGenForParticle(Int_t pdg)