Geant4 9.6.0
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
G4NonEquilibriumEvaporator.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// $Id$
27//
28// 20100114 M. Kelsey -- Remove G4CascadeMomentum, use G4LorentzVector directly
29// 20100309 M. Kelsey -- Use new generateWithRandomAngles for theta,phi stuff;
30// eliminate some unnecessary std::pow()
31// 20100412 M. Kelsey -- Pass G4CollisionOutput by ref to ::collide()
32// 20100413 M. Kelsey -- Pass buffers to paraMaker[Truncated]
33// 20100517 M. Kelsey -- Inherit from common base class
34// 20100617 M. Kelsey -- Remove "RUN" preprocessor flag and all "#else" code
35// 20100622 M. Kelsey -- Use local "bindingEnergy()" function to call through.
36// 20100701 M. Kelsey -- Don't need to add excitation to nuclear mass; compute
37// new excitation energies properly (mass differences)
38// 20100713 M. Kelsey -- Add conservation checking, diagnostic messages.
39// 20100714 M. Kelsey -- Move conservation checking to base class
40// 20100719 M. Kelsey -- Simplify EEXS calculations with particle evaporation.
41// 20100724 M. Kelsey -- Replace std::vector<> D with trivial D[3] array.
42// 20100914 M. Kelsey -- Migrate to integer A and Z: this involves replacing
43// a number of G4double terms with G4int, with consequent casts.
44// 20110214 M. Kelsey -- Follow G4InuclParticle::Model enumerator migration
45// 20110922 M. Kelsey -- Follow G4InuclParticle::print(ostream&) migration
46// 20120608 M. Kelsey -- Fix variable-name "shadowing" compiler warnings.
47// 20121009 M. Kelsey -- Add some high-verbosity debugging output
48
49#include <cmath>
50
52#include "G4SystemOfUnits.hh"
53#include "G4CollisionOutput.hh"
55#include "G4InuclNuclei.hh"
57#include "G4LorentzConvertor.hh"
58
59using namespace G4InuclSpecialFunctions;
60
61
63 : G4CascadeColliderBase("G4NonEquilibriumEvaporator") {}
64
65
67 G4InuclParticle* target,
68 G4CollisionOutput& output) {
69
70 if (verboseLevel) {
71 G4cout << " >>> G4NonEquilibriumEvaporator::collide" << G4endl;
72 }
73
74 // Sanity check
75 G4InuclNuclei* nuclei_target = dynamic_cast<G4InuclNuclei*>(target);
76 if (!nuclei_target) {
77 G4cerr << " NonEquilibriumEvaporator -> target is not nuclei " << G4endl;
78 return;
79 }
80
81 if (verboseLevel > 2) G4cout << " evaporating target:\n" << *target << G4endl;
82
83 const G4int a_cut = 5;
84 const G4int z_cut = 3;
85
86 const G4double eexs_cut = 0.1;
87
88 const G4double coul_coeff = 1.4;
89 const G4int itry_max = 1000;
90 const G4double small_ekin = 1.0e-6;
91 const G4double width_cut = 0.005;
92
93 G4int A = nuclei_target->getA();
94 G4int Z = nuclei_target->getZ();
95
96 G4LorentzVector PEX = nuclei_target->getMomentum();
97 G4LorentzVector pin = PEX; // Save original four-vector for later
98
99 G4double EEXS = nuclei_target->getExitationEnergy();
100
102
103 G4int QPP = config.protonQuasiParticles;
104 G4int QNP = config.neutronQuasiParticles;
105 G4int QPH = config.protonHoles;
106 G4int QNH = config.neutronHoles;
107
108 G4int QP = QPP + QNP;
109 G4int QH = QPH + QNH;
110 G4int QEX = QP + QH;
111
112 G4InuclElementaryParticle dummy(small_ekin, 1);
113 G4LorentzConvertor toTheExitonSystemRestFrame;
114 //*** toTheExitonSystemRestFrame.setVerbose(verboseLevel);
115 toTheExitonSystemRestFrame.setBullet(dummy);
116
117 G4double EFN = FermiEnergy(A, Z, 0);
118 G4double EFP = FermiEnergy(A, Z, 1);
119
120 G4int AR = A - QP;
121 G4int ZR = Z - QPP;
122 G4int NEX = QEX;
123 G4LorentzVector ppout;
124 G4bool try_again = (NEX > 0);
125
126 // Buffer for parameter sets
127 std::pair<G4double, G4double> parms;
128
129 while (try_again) {
130 if (A >= a_cut && Z >= z_cut && EEXS > eexs_cut) { // ok
131 // update exiton system (include excitation energy!)
132 G4double nuc_mass = G4InuclNuclei::getNucleiMass(A, Z, EEXS);
133 PEX.setVectM(PEX.vect(), nuc_mass);
134 toTheExitonSystemRestFrame.setTarget(PEX);
135 toTheExitonSystemRestFrame.toTheTargetRestFrame();
136
137 if (verboseLevel > 2) {
138 G4cout << " A " << A << " Z " << Z << " mass " << nuc_mass
139 << " EEXS " << EEXS << G4endl;
140 }
141
142 G4double MEL = getMatrixElement(A);
143 G4double E0 = getE0(A);
144 G4double PL = getParLev(A, Z);
145 G4double parlev = PL / A;
146 G4double EG = PL * EEXS;
147
148 if (QEX < std::sqrt(2.0 * EG)) { // ok
149 if (verboseLevel > 3)
150 G4cout << " QEX " << QEX << " < sqrt(2*EG) " << std::sqrt(2.*EG)
151 << " NEX " << NEX << G4endl;
152
153 paraMakerTruncated(Z, parms);
154 const G4double& AK1 = parms.first;
155 const G4double& CPA1 = parms.second;
156
157 G4double VP = coul_coeff * Z * AK1 / (G4cbrt(A-1) + 1.0) /
158 (1.0 + EEXS / E0);
159 G4double DM1 = bindingEnergy(A,Z);
160 G4double BN = DM1 - bindingEnergy(A-1,Z);
161 G4double BP = DM1 - bindingEnergy(A-1,Z-1);
162 G4double EMN = EEXS - BN;
163 G4double EMP = EEXS - BP - VP * A / (A-1);
164 G4double ESP = 0.0;
165
166 if (verboseLevel > 3) {
167 G4cout << " AK1 " << AK1 << " CPA1 " << " VP " << VP
168 << "\n bind(A,Z) " << DM1 << " dBind(N) " << BN
169 << " dBind(P) " << BP
170 << "\n EMN " << EMN << " EMP " << EMP << G4endl;
171 }
172
173 if (EMN > eexs_cut) { // ok
174 G4int icase = 0;
175
176 if (NEX > 1) {
177 G4double APH = 0.25 * (QP * QP + QH * QH + QP - 3 * QH);
178 G4double APH1 = APH + 0.5 * (QP + QH);
179 ESP = EEXS / QEX;
180 G4double MELE = MEL / ESP / (A*A*A);
181
182 if (verboseLevel > 3)
183 G4cout << " APH " << APH << " APH1 " << APH1 << " ESP " << ESP
184 << G4endl;
185
186 if (ESP > 15.0) {
187 MELE *= std::sqrt(15.0 / ESP);
188 } else if(ESP < 7.0) {
189 MELE *= std::sqrt(ESP / 7.0);
190 if (ESP < 2.0) MELE *= std::sqrt(ESP / 2.0);
191 };
192
193 G4double F1 = EG - APH;
194 G4double F2 = EG - APH1;
195
196 if (verboseLevel > 3)
197 G4cout << " MELE " << MELE << " F1 " << F1 << " F2 " << F2
198 << G4endl;
199
200 if (F1 > 0.0 && F2 > 0.0) {
201 G4double F = F2 / F1;
202 G4double M1 = 2.77 * MELE * PL;
203 G4double D[3] = { 0., 0., 0. };
204 D[0] = M1 * F2 * F2 * std::pow(F, NEX-1) / (QEX+1);
205
206 if (D[0] > 0.0) {
207
208 if (NEX >= 2) {
209 D[1] = 0.0462 / parlev / G4cbrt(A) * QP * EEXS / QEX;
210
211 if (EMP > eexs_cut)
212 D[2] = D[1] * std::pow(EMP / EEXS, NEX) * (1.0 + CPA1);
213 D[1] *= std::pow(EMN / EEXS, NEX) * getAL(A);
214
215 if (QNP < 1) D[1] = 0.0;
216 if (QPP < 1) D[2] = 0.0;
217
218 try_again = NEX > 1 && (D[1] > width_cut * D[0] ||
219 D[2] > width_cut * D[0]);
220
221 if (try_again) {
222 G4double D5 = D[0] + D[1] + D[2];
223 G4double SL = D5 * inuclRndm();
224 G4double S1 = 0.;
225
226 if (verboseLevel > 3)
227 G4cout << " D5 " << D5 << " SL " << SL << G4endl;
228
229 for (G4int i = 0; i < 3; i++) {
230 S1 += D[i];
231 if (SL <= S1) {
232 icase = i;
233 break;
234 }
235 }
236
237 if (verboseLevel > 3)
238 G4cout << " got icase " << icase << G4endl;
239 } // if (try_again)
240 } // if (NEX >= 2)
241 } else try_again = false; // if (D[0] > 0)
242 } else try_again = false; // if (F1>0 && F2>0)
243 } // if (NEX > 1)
244
245 if (try_again) {
246 if (icase > 0) { // N -> N-1 with particle escape
247 if (verboseLevel > 3)
248 G4cout << " try_again icase " << icase << G4endl;
249
250 G4double V = 0.0;
251 G4int ptype = 0;
252 G4double B = 0.0;
253
254 if (A < 3.0) try_again = false;
255
256 if (try_again) {
257
258 if (icase == 1) { // neutron escape
259 if (verboseLevel > 3)
260 G4cout << " trying neutron escape" << G4endl;
261
262 if (QNP < 1) icase = 0;
263 else {
264 B = BN;
265 V = 0.0;
266 ptype = 2;
267 };
268 } else { // proton esape
269 if (verboseLevel > 3)
270 G4cout << " trying proton escape" << G4endl;
271
272 if (QPP < 1) icase = 0;
273 else {
274 B = BP;
275 V = VP;
276 ptype = 1;
277
278 if (Z-1 < 1) try_again = false;
279 };
280 };
281
282 if (try_again && icase != 0) {
283 if (verboseLevel > 3)
284 G4cout << " ptype " << ptype << " B " << B << " V " << V
285 << G4endl;
286
287 G4double EB = EEXS - B;
288 G4double E = EB - V * A / (A-1);
289
290 if (E < 0.0) icase = 0;
291 else {
292 G4double E1 = EB - V;
293 G4double EEXS_new = -1.;
294 G4double EPART = 0.0;
295 G4int itry1 = 0;
296 G4bool bad = true;
297
298 while (itry1 < itry_max && icase > 0 && bad) {
299 itry1++;
300 G4int itry = 0;
301
302 while (EEXS_new < 0.0 && itry < itry_max) {
303 itry++;
304 G4double R = inuclRndm();
305 G4double X;
306
307 if (NEX == 2) {
308 X = 1.0 - std::sqrt(R);
309
310 } else {
311 G4double QEX2 = 1.0 / QEX;
312 G4double QEX1 = 1.0 / (QEX-1);
313 X = std::pow(0.5 * R, QEX2);
314
315 for (G4int i = 0; i < 1000; i++) {
316 G4double DX = X * QEX1 *
317 (1.0 + QEX2 * X * (1.0 - R / std::pow(X, NEX)) / (1.0 - X));
318 X -= DX;
319
320 if (std::fabs(DX / X) < 0.01) break;
321
322 };
323 };
324 EPART = EB - X * E1;
325 EEXS_new = EB - EPART * A / (A-1);
326 } // while (EEXS_new < 0.0...
327
328 if (itry == itry_max || EEXS_new < 0.0) {
329 icase = 0;
330 continue;
331 }
332
333 if (verboseLevel > 2)
334 G4cout << " particle " << ptype << " escape " << G4endl;
335
336 EPART /= GeV; // From MeV to GeV
337
338 G4InuclElementaryParticle particle(ptype);
340
341 // generate particle momentum
342 G4double mass = particle.getMass();
343 G4double pmod = std::sqrt(EPART * (2.0 * mass + EPART));
345
346 // Push evaporated paricle into current rest frame
347 mom = toTheExitonSystemRestFrame.backToTheLab(mom);
348
349 // Adjust quasiparticle and nucleon counts
350 G4int QPP_new = QPP;
351 G4int QNP_new = QNP;
352
353 G4int A_new = A-1;
354 G4int Z_new = Z;
355
356 if (ptype == 1) {
357 QPP_new--;
358 Z_new--;
359 };
360
361 if (ptype == 2) QNP_new--;
362
363 if (verboseLevel > 3) {
364 G4cout << " nucleus px " << PEX.px() << " py " << PEX.py()
365 << " pz " << PEX.pz() << " E " << PEX.e() << G4endl
366 << " evaporate px " << mom.px() << " py " << mom.py()
367 << " pz " << mom.pz() << " E " << mom.e() << G4endl;
368 }
369
370 // New excitation energy depends on residual nuclear state
371 G4double mass_new = G4InuclNuclei::getNucleiMass(A_new, Z_new);
372
373 EEXS_new = ((PEX-mom).m() - mass_new)*GeV;
374 if (EEXS_new < 0.) continue; // Sanity check for new nucleus
375
376 if (verboseLevel > 3)
377 G4cout << " EEXS_new " << EEXS_new << G4endl;
378
379 PEX -= mom;
380 EEXS = EEXS_new;
381
382 A = A_new;
383 Z = Z_new;
384
385 NEX--;
386 QEX--;
387 QP--;
388 QPP = QPP_new;
389 QNP = QNP_new;
390
391 particle.setMomentum(mom);
392 output.addOutgoingParticle(particle);
393 ppout += mom;
394 if (verboseLevel > 3) {
395 G4cout << particle << G4endl
396 << " ppout px " << ppout.px() << " py " << ppout.py()
397 << " pz " << ppout.pz() << " E " << ppout.e() << G4endl;
398 }
399
400 bad = false;
401 } // while (itry1<itry_max && icase>0
402
403 if (itry1 == itry_max) icase = 0;
404 } // if (E < 0.) [else]
405 } // if (try_again && icase != 0)
406 } // if (try_again)
407 } // if (icase > 0)
408
409 if (icase == 0 && try_again) { // N -> N + 2
410 if (verboseLevel > 3) G4cout << " adding excitons" << G4endl;
411
412 G4double TNN = 1.6 * EFN + ESP;
413 G4double TNP = 1.6 * EFP + ESP;
414 G4double XNUN = 1.0 / (1.6 + ESP / EFN);
415 G4double XNUP = 1.0 / (1.6 + ESP / EFP);
416 G4double SNN1 = csNN(TNP) * XNUP;
417 G4double SNN2 = csNN(TNN) * XNUN;
418 G4double SPN1 = csPN(TNP) * XNUP;
419 G4double SPN2 = csPN(TNN) * XNUN;
420 G4double PP = (QPP * SNN1 + QNP * SPN1) * ZR;
421 G4double PN = (QPP * SPN2 + QNP * SNN2) * (AR - ZR);
422 G4double PW = PP + PN;
423 NEX += 2;
424 QEX += 2;
425 QP++;
426 QH++;
427 AR--;
428
429 if (AR > 1) {
430 G4double SL = PW * inuclRndm();
431
432 if (SL > PP) {
433 QNP++;
434 QNH++;
435 } else {
436 QPP++;
437 QPH++;
438 ZR--;
439 if (ZR < 2) try_again = false;
440 }
441 } else try_again = false;
442 } // if (icase==0 && try_again)
443 } // if (try_again)
444 } else try_again = false; // if (EMN > eexs_cut)
445 } else try_again = false; // if (QEX < sqrg(2*EG)
446 } else try_again = false; // if (A > a_cut ...
447 } // while (try_again)
448
449 // everything finished, set output nuclei
450
451 if (output.numberOfOutgoingParticles() == 0) {
452 output.addOutgoingNucleus(*nuclei_target);
453 } else {
454 G4LorentzVector pnuc = pin - ppout;
455 G4InuclNuclei nuclei(pnuc, A, Z, EEXS, G4InuclParticle::NonEquilib);
456
457 if (verboseLevel > 3) G4cout << " remaining nucleus\n" << nuclei << G4endl;
458 output.addOutgoingNucleus(nuclei);
459 }
460
461 validateOutput(0, target, output); // Check energy conservation, etc.
462 return;
463}
464
465G4double G4NonEquilibriumEvaporator::getMatrixElement(G4int A) const {
466
467 if (verboseLevel > 3) {
468 G4cout << " >>> G4NonEquilibriumEvaporator::getMatrixElement" << G4endl;
469 }
470
471 G4double me;
472
473 if (A > 150) me = 100.0;
474 else if (A > 20) me = 140.0;
475 else me = 70.0;
476
477 return me;
478}
479
480G4double G4NonEquilibriumEvaporator::getE0(G4int ) const {
481 if (verboseLevel > 3) {
482 G4cout << " >>> G4NonEquilibriumEvaporator::getEO" << G4endl;
483 }
484
485 const G4double e0 = 200.0;
486
487 return e0;
488}
489
490G4double G4NonEquilibriumEvaporator::getParLev(G4int A,
491 G4int ) const {
492
493 if (verboseLevel > 3) {
494 G4cout << " >>> G4NonEquilibriumEvaporator::getParLev" << G4endl;
495 }
496
497 // const G4double par = 0.125;
498 G4double pl = 0.125 * A;
499
500 return pl;
501}
double G4double
Definition: G4Types.hh:64
int G4int
Definition: G4Types.hh:66
bool G4bool
Definition: G4Types.hh:67
#define G4endl
Definition: G4ios.hh:52
G4DLLIMPORT std::ostream G4cerr
G4DLLIMPORT std::ostream G4cout
void setVectM(const Hep3Vector &spatial, double mass)
Hep3Vector vect() const
virtual G4bool validateOutput(G4InuclParticle *bullet, G4InuclParticle *target, G4CollisionOutput &output)
G4int numberOfOutgoingParticles() const
void addOutgoingParticle(const G4InuclElementaryParticle &particle)
void addOutgoingNucleus(const G4InuclNuclei &nuclei)
const G4ExitonConfiguration & getExitonConfiguration() const
G4double getNucleiMass() const
G4int getZ() const
G4double getExitationEnergy() const
G4int getA() const
G4double getMass() const
G4LorentzVector getMomentum() const
void setMomentum(const G4LorentzVector &mom)
void setModel(Model model)
void setBullet(const G4InuclParticle *bullet)
G4LorentzVector backToTheLab(const G4LorentzVector &mom) const
void setTarget(const G4InuclParticle *target)
void collide(G4InuclParticle *bullet, G4InuclParticle *target, G4CollisionOutput &output)
G4double bindingEnergy(G4int A, G4int Z)
void paraMakerTruncated(G4double Z, std::pair< G4double, G4double > &parms)
Definition: paraMaker.cc:83
G4LorentzVector generateWithRandomAngles(G4double p, G4double mass=0.)
G4double FermiEnergy(G4int A, G4int Z, G4int ntype)