Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4ChargeExchange.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26// G4 Model: Charge and strangness exchange based on G4LightMedia model
27// 28 May 2006 V.Ivanchenko
28//
29// Modified:
30// 07-Jun-06 V.Ivanchenko fix problem of rotation of final state
31// 25-Jul-06 V.Ivanchenko add 19 MeV low energy, below which S-wave is sampled
32// 12-Jun-12 A.Ribon fix warnings of shadowed variables
33// 06-Aug-15 A.Ribon migrating to G4Exp, G4Log and G4Pow
34//
35
36#include "G4ChargeExchange.hh"
37#include "G4ChargeExchangeXS.hh"
39#include "G4SystemOfUnits.hh"
40#include "G4ParticleTable.hh"
42#include "G4IonTable.hh"
43#include "Randomize.hh"
44#include "G4NucleiProperties.hh"
45#include "G4DecayTable.hh"
46#include "G4VDecayChannel.hh"
47#include "G4DecayProducts.hh"
48#include "G4NistManager.hh"
49#include "G4Fragment.hh"
52
53#include "G4Exp.hh"
54#include "G4Log.hh"
55#include "G4Pow.hh"
56
59
60namespace
61{
62 constexpr G4int maxN = 1000;
63}
64
66 : G4HadronicInteraction("ChargeExchange"),
67 fXSection(ptr), fXSWeightFactor(1.0)
68{
69 lowEnergyLimit = 1.*CLHEP::MeV;
70 secID = G4PhysicsModelCatalog::GetModelID( "model_ChargeExchange" );
72 fHandler = new G4ExcitationHandler();
73 if (nullptr != fXSection) {
74 fXSWeightFactor = 1.0/fXSection->GetCrossSectionFactor();
75 }
76}
77
79{
80 delete fHandler;
81}
82
84 const G4HadProjectile& aTrack, G4Nucleus& targetNucleus)
85{
86 theParticleChange.Clear();
87 auto part = aTrack.GetDefinition();
88 G4double ekin = aTrack.GetKineticEnergy();
89
90 G4int A = targetNucleus.GetA_asInt();
91 G4int Z = targetNucleus.GetZ_asInt();
92
93 if (ekin <= lowEnergyLimit) {
94 return &theParticleChange;
95 }
96 theParticleChange.SetWeightChange(fXSWeightFactor);
97
98 G4int projPDG = part->GetPDGEncoding();
99 // for hydrogen targets and positive projectile change exchange
100 // is not possible on proton, only on deuteron
101 if (1 == Z && (211 == projPDG || 321 == projPDG)) { A = 2; }
102
103 if (verboseLevel > 1) {
104 G4cout << "G4ChargeExchange for " << part->GetParticleName()
105 << " PDGcode= " << projPDG << " on nucleus Z= " << Z
106 << " A= " << A << " N= " << A - Z
107 << G4endl;
108 }
109
111 G4LorentzVector lv0 = aTrack.Get4Momentum();
112
113 // select final state
114 const G4ParticleDefinition* theSecondary =
115 fXSection->SampleSecondaryType(part, aTrack.GetMaterial(),
116 Z, A, aTrack.GetTotalEnergy());
117 G4int pdg = theSecondary->GetPDGEncoding();
118
119 if (verboseLevel > 1)
120 G4cout << " Secondary " << theSecondary->GetParticleName() << " pdg=" << pdg << G4endl;
121
122 // omega(782) and f2(1270)
123 G4bool isShortLived = (pdg == 223 || pdg == 225);
124
125 // atomic number of the recoil nucleus
126 if (projPDG == -211) { --Z; }
127 else if (projPDG == 211) { ++Z; }
128 else if (projPDG == -321) { --Z; }
129 else if (projPDG == 321) { ++Z; }
130 else if (projPDG == 130) {
131 if (theSecondary->GetPDGCharge() > 0.0) { --Z; }
132 else { ++Z; }
133 } else {
134 // not ready for other projectile
135 return &theParticleChange;
136 }
137
138 // recoil nucleus
139 const G4ParticleDefinition* theRecoil = nullptr;
140 if (Z == 0 && A == 1) { theRecoil = G4Neutron::Neutron(); }
141 else if (Z == 1 && A == 1) { theRecoil = G4Proton::Proton(); }
142 else if (Z == 1 && A == 2) { theRecoil = G4Deuteron::Deuteron(); }
143 else if (Z == 1 && A == 3) { theRecoil = G4Triton::Triton(); }
144 else if (Z == 2 && A == 3) { theRecoil = G4He3::He3(); }
145 else if (Z == 2 && A == 4) { theRecoil = G4Alpha::Alpha(); }
146
147 // check if there is enough energy for the final state
148 // and sample mass of produced state
149 // sample kinematics
150 G4LorentzVector lv1(0.0, 0.0, 0.0, mass1);
151 G4LorentzVector lv = lv0 + lv1;
152 G4double m0 = lv.mag();
153 const G4double mass0 = theSecondary->GetPDGMass();
154 G4double mass2 = mass0;
155 G4double mass3;
156 G4bool ok = false;
157
158 if (verboseLevel > 1) {
159 G4cout << " Secondary meson " << theSecondary->GetParticleName()
160 << " mass(MeV)=" << mass2 << " pdg=" << pdg
161 << " Final Z=" << Z << " isShortLived=" << isShortLived
162 << " " << lv
163 << G4endl;
164 }
165 // fixed recoil mass
166 if (nullptr != theRecoil) {
167 mass3 = theRecoil->GetPDGMass();
168 ok = (m0 > mass2 + mass3);
169
170 // excited nuclear state
171 } else {
173 const G4double eFermi = 10*CLHEP::MeV;
174 for (G4int i=0; i<10; ++i) {
175 mass3 = mass30 + eFermi*G4UniformRand();
176 if (m0 > mass2 + mass3) {
177 ok = true;
178 break;
179 }
180 }
181 }
182 if (isShortLived) {
183 const G4double elim = 300*CLHEP::MeV;
184 ok = false;
185 for (G4int i=0; i<10; ++i) {
186 if (SampleMass(mass2, theSecondary->GetPDGWidth(), elim)) {
187 if (m0 > mass2 + mass3) {
188 ok = true;
189 break;
190 }
191 }
192 }
193 }
194
195 // not possible kinematically
196 if (!ok) { return &theParticleChange; }
197
198 G4double e2 = (m0*m0 + mass2*mass2 - mass3*mass3)/(2*m0);
199 G4double momentumCMS = std::sqrt(e2*e2 - mass2*mass2);
200 G4double tmax = 4*momentumCMS*momentumCMS;
201
202 // for projectile pion t depends on final state
203 G4double t;
204 if (fXSection->isPion()) {
205 t = fXSection->SampleTforPion(aTrack.GetTotalEnergy(), tmax);
206 }
207 else {
208 t = SampleT(theSecondary, A, tmax);
209 }
210
211 G4double phi = G4UniformRand()*CLHEP::twopi;
212 G4double cost = 1. - 2.0*t/tmax;
213
214 // if cos(theta) negative, there is a numerical problem
215 // instead of making scattering backward, make in this case
216 // no scattering
217 if (std::abs(cost) > 1.0) { cost = 1.0; }
218
219 G4double sint = std::sqrt((1.0 - cost)*(1.0 + cost));
220
221 if (verboseLevel > 1) {
222 G4cout << " t= " << t << " tmax(GeV^2)= " << tmax/(GeV*GeV)
223 << " cos(t)=" << cost << " sin(t)=" << sint << G4endl;
224 }
225 G4LorentzVector lv2(momentumCMS*sint*std::cos(phi),
226 momentumCMS*sint*std::sin(phi),
227 momentumCMS*cost, e2);
228
229 // kinematics in the final state, may be a warning should be added if
230 G4ThreeVector bst = lv.boostVector();
231 lv2.boost(bst);
232 lv -= lv2;
233 if (lv.e() < mass3) {
234 lv.setE(mass3);
235 }
236
237 // prepare secondary particles
238 theParticleChange.SetStatusChange(stopAndKill);
239 theParticleChange.SetEnergyChange(0.0);
240 theParticleChange.SetWeightChange(fXSWeightFactor);
241
242 if (!isShortLived) {
243 auto aSec = new G4DynamicParticle(theSecondary, lv2);
244 theParticleChange.AddSecondary(aSec, secID);
245 } else {
246 auto channel = theSecondary->GetDecayTable()->SelectADecayChannel(mass2);
247 auto products = channel->DecayIt(mass2);
248 G4ThreeVector bst1 = lv2.boostVector();
249 G4int N = products->entries();
250 for (G4int i=0; i<N; ++i) {
251 auto p = (*products)[i];
252 auto lvp = p->Get4Momentum();
253 lvp.boost(bst1);
254 auto pnew = new G4DynamicParticle(*p);
255 pnew->Set4Momentum(lvp);
256 theParticleChange.AddSecondary(pnew, secID);
257 }
258 delete products;
259 }
260
261 // recoil is a stable isotope
262 if (nullptr != theRecoil) {
263 auto aRec = new G4DynamicParticle(theRecoil, lv);
264 theParticleChange.AddSecondary(aRec, secID);
265 } else {
266 // recoil is a fragment, which may be unstable
267 G4Fragment frag(A, Z, lv);
268 auto products = fHandler->BreakItUp(frag);
269 for (auto & prod : *products) {
270 auto dp = new G4DynamicParticle(prod->GetDefinition(), prod->GetMomentum());
271 theParticleChange.AddSecondary(dp, secID);
272 delete prod;
273 }
274 delete products;
275 }
276 return &theParticleChange;
277}
278
280 const G4int A, const G4double ltmax) const
281{
282 const G4double GeV2 = CLHEP::GeV*CLHEP::GeV;
283 const G4double numLimit = 18.;
284
285 G4double tmax = ltmax/GeV2;
286 if (verboseLevel > 1) {
287 G4cout << "G4ChargeExchange::SampleT tmax(GeV^2)=" << tmax << G4endl;
288 }
289
290 G4double aa, bb, cc, dd;
291 G4Pow* g4pow = G4Pow::GetInstance();
292 G4double a13 = g4pow->Z13(A);
293 if (A <= 62) {
294 aa = (A*A);
295 bb = 14.5*a13*a13;
296 cc = 1.4*a13;
297 dd = 10.;
298 } else {
299 aa = g4pow->powZ(A, 1.33);
300 bb = 60.*a13;
301 cc = 0.4*g4pow->powZ(A, 0.40);
302 dd = 10.;
303 }
304 G4double q1 = 1.0 - G4Exp(-std::min(bb*tmax, numLimit));
305 G4double q2 = 1.0 - G4Exp(-std::min(dd*tmax, numLimit));
306 G4double s1 = q1*aa;
307 G4double s2 = q2*cc;
308 if ((s1 + s2)*G4UniformRand() < s2) {
309 q1 = q2;
310 bb = dd;
311 }
312 return -GeV2*G4Log(1.0 - G4UniformRand()*q1)/bb;
313}
314
315G4bool G4ChargeExchange::SampleMass(G4double& M, const G4double G,
316 const G4double elim)
317{
318 // +- 4 width but above 2 pion mass
319 G4double e1 = std::max(M - 4*G, elim);
320 G4double e2 = M + 4*G - e1;
321 if (e2 <= 0.0) { return false; }
322 G4double M2 = M*M;
323 G4double MG2 = M2*G*G;
324
325 // sampling Breit-Wigner function
326 for (G4int i=0; i<maxN; ++i) {
327 G4double e = e1 + e2*G4UniformRand();
328 G4double x = e*e - M2;
329 G4double y = MG2/(x*x + MG2);
330 if (y >= G4UniformRand()) {
331 M = e;
332 return true;
333 }
334 }
335 return false;
336}
const G4double GeV2
G4double G4Exp(G4double initial_x)
Exponential Function double precision.
Definition G4Exp.hh:132
@ stopAndKill
G4double G4Log(G4double x)
Definition G4Log.hh:169
CLHEP::HepLorentzVector G4LorentzVector
#define M(row, col)
CLHEP::Hep3Vector G4ThreeVector
double G4double
Definition G4Types.hh:83
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
const G4double A[17]
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
#define G4UniformRand()
Definition Randomize.hh:52
Hep3Vector boostVector() const
HepLorentzVector & boost(double, double, double)
static G4Alpha * Alpha()
Definition G4Alpha.cc:83
G4HadFinalState * ApplyYourself(const G4HadProjectile &aTrack, G4Nucleus &targetNucleus) override
G4ChargeExchange(G4ChargeExchangeXS *)
G4double SampleT(const G4ParticleDefinition *theSec, const G4int A, const G4double tmax) const
~G4ChargeExchange() override
G4VDecayChannel * SelectADecayChannel(G4double parentMass=-1.)
static G4Deuteron * Deuteron()
Definition G4Deuteron.cc:90
const G4Material * GetMaterial() const
const G4ParticleDefinition * GetDefinition() const
G4double GetKineticEnergy() const
const G4LorentzVector & Get4Momentum() const
G4double GetTotalEnergy() const
G4HadronicInteraction(const G4String &modelName="HadronicModel")
static G4He3 * He3()
Definition G4He3.cc:90
static G4Neutron * Neutron()
Definition G4Neutron.cc:101
static G4NistManager * Instance()
static G4double GetNuclearMass(const G4double A, const G4double Z)
G4int GetA_asInt() const
Definition G4Nucleus.hh:78
G4int GetZ_asInt() const
Definition G4Nucleus.hh:84
G4DecayTable * GetDecayTable() const
const G4String & GetParticleName() const
static G4int GetModelID(const G4int modelIndex)
Definition G4Pow.hh:49
static G4Pow * GetInstance()
Definition G4Pow.cc:41
G4double powZ(G4int Z, G4double y) const
Definition G4Pow.hh:225
G4double Z13(G4int Z) const
Definition G4Pow.hh:123
static G4Proton * Proton()
Definition G4Proton.cc:90
static G4Triton * Triton()
Definition G4Triton.cc:90
virtual G4DecayProducts * DecayIt(G4double parentMass=-1.0)=0
#define N
Definition crc32.c:57