Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4GEMChannelVI.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// GEM de-excitation model
27// by V. Ivanchenko (July 2019)
28//
29
30#include "G4GEMChannelVI.hh"
31#include "G4GEMProbabilityVI.hh"
32#include "G4VCoulombBarrier.hh"
33#include "G4CoulombBarrier.hh"
34#include "G4DeexPrecoUtility.hh"
36#include "G4NuclearLevelData.hh"
37#include "G4LevelManager.hh"
38#include "G4NucleiProperties.hh"
39#include "G4RandomDirection.hh"
41#include "Randomize.hh"
42#include "G4Exp.hh"
43#include "G4Log.hh"
44#include "G4Pow.hh"
45
46#include "G4Neutron.hh"
47#include "G4Proton.hh"
48#include "G4Deuteron.hh"
49#include "G4Triton.hh"
50#include "G4He3.hh"
51#include "G4Alpha.hh"
52#include "G4InterfaceToXS.hh"
53#include "G4IsotopeList.hh"
54#include "G4NuclearRadii.hh"
55
56namespace
57{
58 const G4double dExc = 1.0*CLHEP::MeV;
59 const G4double limE = 1.0*CLHEP::MeV; // low-energy limit for neutrons
60 const G4double kmin = 20*CLHEP::keV; // low-energy limit on primary kinetic energy
61 const G4int nProbMax = 10;
62 G4double prob[nProbMax] = {0.0};
63}
64
66 : evapA(theA), evapZ(theZ)
67{
69 pairingCorrection = nData->GetPairingCorrection();
70 if (evapZ > 2) { lManagerEvap = nData->GetLevelManager(evapZ, evapA); }
71 fEvapMass = G4NucleiProperties::GetNuclearMass(evapA, evapZ);
72 fEvapMass2 = fEvapMass*fEvapMass;
73
74 cBarrier = new G4CoulombBarrier(evapA, evapZ);
75
76 fTolerance = 10*CLHEP::keV;
77 fCoeff = fEvapMass/((CLHEP::pi*CLHEP::hbarc)*(CLHEP::pi*CLHEP::hbarc));
78
79 std::ostringstream ss;
80 ss << "GEMVI_" << "Z" << evapZ << "_A" << evapA;
81 fModelName = ss.str();
82
83 fNeutron = G4Neutron::Neutron();
84 fProton = G4Proton::Proton();
85
86 secID = G4PhysicsModelCatalog::GetModelID("model_G4GEMChannelVI");
87 const G4ParticleDefinition* part = nullptr;
88 if (evapZ == 0 && evapA == 1) {
89 indexC = 0;
90 fCoeff *= 2.0;
91 part = fNeutron;
92 } else if (evapZ == 1 && evapA == 1) {
93 indexC = 1;
94 fCoeff *= 2.0;
95 part = fProton;
96 } else if (evapZ == 1 && evapA == 2) {
97 indexC = 2;
98 fCoeff *= 3.0;
99 part = G4Deuteron::Deuteron();
100 } else if (evapZ == 1 && evapA == 3) {
101 indexC = 3;
102 fCoeff *= 2.0;
103 part = G4Triton::Triton();
104 } else if (evapZ == 2 && evapA == 3) {
105 indexC = 4;
106 fCoeff *= 2.0;
107 part = G4He3::He3();
108 } else if (evapZ == 2 && evapA == 4) {
109 indexC = 5;
110 part = G4Alpha::Alpha();
111 } else {
112 G4int N = evapA - evapZ;
113 fCoeff *= (1 + (evapZ - 2*(evapZ/2)))*(1 + (N - 2*(N/2)));
114 }
115 g4pow = G4Pow::GetInstance();
116
117 G4double de = (0 == indexC) ? 0.15*CLHEP::MeV : 0.25*CLHEP::MeV;
118 InitialiseIntegrator(0.01, 0.25, 1.3, de, 0.1*CLHEP::MeV, 2*CLHEP::MeV);
119
120 if (indexC <= 6) { fXSection = new G4InterfaceToXS(part, indexC); }
121}
122
124{
125 delete cBarrier;
126 delete fXSection;
127}
128
133
135{
136 fragZ = fragment->GetZ_asInt();
137 fragA = fragment->GetA_asInt();
138 resZ = fragZ - evapZ;
139 resA = fragA - evapA;
140 // G4cout << "G4GEMChannelVI::GetEmissionProbability Z=" << evapZ << " A=" << evapA << " resZ=" << resZ << " resA=" << resA << G4endl;
141 // to avoid double counting
142 if (resA < evapA || resA < resZ || resZ < 1 ||
143 (resA == evapA && resZ < evapZ)) { return 0.0; }
144
145 fFragExc = fragment->GetExcitationEnergy();
146 fMass = fragment->GetGroundStateMass() + fFragExc;
147 fResMass = G4NucleiProperties::GetNuclearMass(resA, resZ);
148 fResA13 = g4pow->Z13(resA);
149 xsfactor = g4pow->Z23(fragA)/g4pow->Z23(resA);
150
151 // limit for the case when both evaporation and residual
152 // fragments are in ground states
153 if (fMass <= fEvapMass + fResMass) { return 0.0; }
154
155 a0 = G4DeexPrecoUtility::LevelDensity(fragZ, fragA, indexC);
156 delta0 = nData->GetPairingCorrection(fragZ, fragA);
157 delta1 = nData->GetPairingCorrection(resZ, resA);
158 fE0 = std::max(fFragExc - delta0, 0.0);
159
160 if (indexC > 0) {
161 bCoulomb = cBarrier->GetCoulombBarrier(resA, resZ, fFragExc);
162 }
163 G4double elim = 0.5*bCoulomb;
164 G4double de = fMass - fEvapMass - fResMass - elim;
165 if (de < fTolerance) { return 0.0; }
166 nProbEvap = 1;
167 fDeltaEvap = de;
168 if (7 == indexC) {
169 G4int n = (G4int)(de/dExc) + 1;
170 nProbEvap = std::min(n, nProbMax);
171 if (nProbEvap > 1) { fDeltaEvap /= (G4double)(nProbEvap - 1); }
172 }
173
174 if (2 < fVerbose) {
175 G4cout << "## G4GEMChannelVI::GetEmissionProbability fragZ="
176 << fragZ << " fragA=" << fragA << " Z=" << evapZ << " A=" << evapA
177 << " Eex(MeV)=" << fFragExc << " nProbEvap=" << nProbEvap
178 << " nProbRes=" << nProbRes << " CB=" << bCoulomb
179 << " Elim=" << fEnergyLimitXS << " XSfac=" << xsfactor << G4endl;
180 }
181
182 // m1 is the mass of emitted excited fragment
183 // e2 - free energy in the 2-body decay
184 G4double sump = 0.0;
185 for (G4int i = 0; i < nProbEvap; ++i) {
186 fEvapExc = fDeltaEvap*i;
187 G4double m1 = fEvapMass + fEvapExc;
188 G4double e2 = fMass - m1 - fResMass;
189 e2 = std::max(e2, 0.0);
190 if (e2 <= elim + fTolerance) {
191 nProbEvap = i + 1;
192 prob[i] = sump;
193 break;
194 }
195 G4double p = ComputeIntegral(elim, e2);
196 sump += p;
197 prob[i] = sump;
198 if (2 < fVerbose) {
199 G4cout << i << ". e1=" << elim << " e2=" << e2 << " e2-e1="
200 << e2 - elim << " fEvapExc=" << fEvapExc
201 << " Probability=" << p << G4endl;
202 }
203 }
204 if (nProbEvap > 1) { sump /= (G4double)nProbEvap; }
205 return sump;
206}
207
209{
210 // e is free energy
211 G4double m1 = fEvapMass + fEvapExc;
212 fResExc = fMass - m1 - fResMass - e;
213 if (fResExc < 0.0 || 0.0 == e) { return 0.0; }
214 fE1 = std::max(fResExc - delta1, 0.0);
215 a1 = G4DeexPrecoUtility::LevelDensity(resZ, resA, indexC);
216 G4double m2 = fResMass + fResExc;
217 G4double elab = 0.5*(fMass + m1 + m2)*(fMass - m1 - m2)/m2;
218 G4double xs = CrossSection(elab);
219 G4double res =
220 fCoeff*G4Exp(2.0*(std::sqrt(a1*fE1) - std::sqrt(a0*fE0)))*e*xs;
221
222 //G4cout << "e=" << e << " elab=" << elab << " xs(mb)="
223 // << xs/CLHEP::millibarn << " prob=" << res << G4endl;
224 return res;
225}
226
227G4double G4GEMChannelVI::CrossSection(G4double e)
228{
229 G4int Z = std::min(resZ, ZMAXNUCLEARDATA);
230 G4double corr;
231 G4double e1 = std::max(e, kmin);
232 if (e1 < 0.5*bCoulomb) {
233 recentXS = 0.0;
234 return recentXS;
235 }
236 if (indexC <= 5) {
237 G4double e2 = 2*bCoulomb;
238 if (0 == indexC) {
239 e2 = lowEnergyLimitMeV[Z];
240 if (e2 == 0.0) { e2 = limE; }
241 }
242 e1 = std::max(e1, e2);
243 corr = G4DeexPrecoUtility::CorrectionFactor(indexC, evapZ, fResA13, bCoulomb, e);
244 recentXS = fXSection->GetElementCrossSection(e1, Z)/CLHEP::millibarn;
245 } else {
246 G4double tR = G4NuclearRadii::Radius(resZ, resA);
247 G4double pR = G4NuclearRadii::Radius(evapZ, evapA);
248 corr = G4DeexPrecoUtility::CorrectionFactor(indexC, Z, fResA13, bCoulomb, e);
249
250 // geometrical x-section
251 recentXS = CLHEP::pi*(pR + tR)*(pR + tR);
252 }
253 recentXS *= corr;
254 return recentXS;
255}
256
258{
259 // assumed, that TotalProbability(...) was already called
260 // if value iz zero no possiblity to sample final state
261 G4Fragment* evFragment = nullptr;
262 lManagerRes = nData->GetLevelManager(resZ, resA);
263 G4double e2 = fMass - fEvapMass - fResMass;
264 fEvapExc = 0.0;
265
266 // sample excitation of the evaporation fragment
267 if (nProbEvap > 1) {
268 G4double q = prob[nProbEvap - 1];
269 if (q > 0.0) {
270 q *= G4UniformRand();
271 for (G4int i=0; i < nProbEvap; ++i) {
272 if (q <= prob[i]) {
273 if (0 == i) { break; }
274 G4double e1 = fDeltaEvap*((i - 1) + (q - prob[i - 1])/(prob[i] - prob[i - 1]));
275 fEvapExc = CorrectExcitation(e1, lManagerEvap);
276 e2 -= fEvapExc;
277 e2 = std::max(e2, 0.0);
278 }
279 }
280 }
281 }
282 if (ComputeIntegral(0.5*bCoulomb, e2) <= 0.0) { return evFragment; }
283
284 // sample free energy
285 G4double e = SampleValue();
286 // compute excitation of the residual fragment
287 fResExc = CorrectExcitation(e2 - e, lManagerRes);
288
289 // final kinematics
290 G4double m1 = fEvapMass + fEvapExc;
291 G4double m2 = fResMass + fResExc;
292
293 G4double ekin = 0.5*e*(e + 2*m2)/(e + m1 + m2);
294 G4LorentzVector lv(std::sqrt(ekin*(ekin + 2.0*m1))
295 *G4RandomDirection(), ekin + m1);
296 G4LorentzVector lv0 = theNucleus->GetMomentum();
297 lv.boost(lv0.boostVector());
298 evFragment = new G4Fragment(evapA, evapZ, lv);
299 evFragment->SetCreatorModelID(secID);
300
301 // residual
302 lv0 -= lv;
303 theNucleus->SetZandA_asInt(resZ, resA);
304 theNucleus->SetMomentum(lv0);
305 theNucleus->SetCreatorModelID(secID);
306
307 return evFragment;
308}
309
311G4GEMChannelVI::CorrectExcitation(G4double exc, const G4LevelManager* man)
312{
313 if (exc <= 0.0 || nullptr == man) { return 0.0; }
314 std::size_t idx = man->NearestLevelIndex(exc);
315
316 // choose ground state
317 if (0 == idx) { return 0.0; }
318
319 // possible discrete level
320 G4double elevel = man->LevelEnergy(idx);
321 std::size_t ntrans{0};
322 if (std::abs(elevel - exc) < fTolerance) {
323 auto level = man->GetLevel(idx);
324 if (nullptr != level) {
325 ntrans = level->NumberOfTransitions();
326 G4int idxfl = man->FloatingLevel(idx);
327 // for floating level check levels with the same energy
328 if (idxfl > 0) {
329 auto newlevel = man->GetLevel(idx - 1);
330 G4double newenergy = man->LevelEnergy(idx - 1);
331 if (nullptr != newlevel && std::abs(elevel - newenergy) < fTolerance) {
332 std::size_t newntrans = newlevel->NumberOfTransitions();
333 if (newntrans > 0) {
334 elevel = newenergy;
335 ntrans = newntrans;
336 }
337 }
338 }
339 if (0 < ntrans) { return elevel; }
340 }
341 }
342 return exc;
343}
344
346{
347 return fModelName;
348}
349
351{}
352
353
354
G4double G4Exp(G4double initial_x)
Exponential Function double precision.
Definition G4Exp.hh:132
CLHEP::HepLorentzVector G4LorentzVector
G4ThreeVector G4RandomDirection()
double G4double
Definition G4Types.hh:83
int G4int
Definition G4Types.hh:85
#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
static G4double LevelDensity(const G4int Z, const G4int A, const G4int index)
static G4double CorrectionFactor(const G4int index, const G4int Z, const G4double A13, const G4double bCoulomb, const G4double ekin)
static G4Deuteron * Deuteron()
Definition G4Deuteron.cc:90
G4double GetGroundStateMass() const
void SetZandA_asInt(G4int Znew, G4int Anew, G4int Lnew=0)
G4double GetExcitationEnergy() const
const G4LorentzVector & GetMomentum() const
void SetCreatorModelID(G4int value)
G4int GetZ_asInt() const
void SetMomentum(const G4LorentzVector &value)
G4int GetA_asInt() const
G4GEMChannelVI(G4int theA, G4int theZ)
void Dump() const override
~G4GEMChannelVI() override
G4double ProbabilityDensityFunction(G4double ekin) override
G4double GetEmissionProbability(G4Fragment *theNucleus) override
void Initialise() override
G4Fragment * EmittedFragment(G4Fragment *theNucleus) override
const G4String & ModelName() const override
static G4He3 * He3()
Definition G4He3.cc:90
const G4NucLevel * GetLevel(const std::size_t i) const
std::size_t NearestLevelIndex(const G4double energy, const std::size_t index=0) const
G4int FloatingLevel(const std::size_t i) const
G4double LevelEnergy(const std::size_t i) const
static G4Neutron * Neutron()
Definition G4Neutron.cc:101
static G4NuclearLevelData * GetInstance()
static G4double Radius(G4int Z, G4int A)
static G4double GetNuclearMass(const G4double A, const G4double Z)
static G4int GetModelID(const G4int modelIndex)
static G4Pow * GetInstance()
Definition G4Pow.cc:41
static G4Proton * Proton()
Definition G4Proton.cc:90
static G4Triton * Triton()
Definition G4Triton.cc:90
G4double ComputeIntegral(const G4double emin, const G4double emax)
void InitialiseIntegrator(G4double accuracy, G4double fact1, G4double fact2, G4double de, G4double dmin, G4double dmax)
#define N
Definition crc32.c:57