Geant4 9.6.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4WilsonAblationModel.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// * *
21// * Parts of this code which have been developed by QinetiQ Ltd *
22// * under contract to the European Space Agency (ESA) are the *
23// * intellectual property of ESA. Rights to use, copy, modify and *
24// * redistribute this software for general public use are granted *
25// * in compliance with any licensing, distribution and development *
26// * policy adopted by the Geant4 Collaboration. This code has been *
27// * written by QinetiQ Ltd for the European Space Agency, under ESA *
28// * contract 17191/03/NL/LvH (Aurora Programme). *
29// * *
30// * By using, copying, modifying or distributing the software (or *
31// * any work based on the software) you agree to acknowledge its *
32// * use in resulting scientific publications, and indicate your *
33// * acceptance of all terms of the Geant4 Software license. *
34// ********************************************************************
35//
36// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37//
38// MODULE: G4WilsonAblationModel.cc
39//
40// Version: 1.0
41// Date: 08/12/2009
42// Author: P R Truscott
43// Organisation: QinetiQ Ltd, UK
44// Customer: ESA/ESTEC, NOORDWIJK
45// Contract: 17191/03/NL/LvH
46//
47// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
48//
49// CHANGE HISTORY
50// --------------
51//
52// 6 October 2003, P R Truscott, QinetiQ Ltd, UK
53// Created.
54//
55// 15 March 2004, P R Truscott, QinetiQ Ltd, UK
56// Beta release
57//
58// 08 December 2009, P R Truscott, QinetiQ Ltd, UK
59// Ver 1.0
60// Updated as a result of changes in the G4Evaporation classes. These changes
61// affect mostly SelectSecondariesByEvaporation, and now you have variables
62// associated with the evaporation model which can be changed:
63// OPTxs to select the inverse cross-section
64// OPTxs = 0 => Dostrovski's parameterization
65// OPTxs = 1 or 2 => Chatterjee's paramaterization
66// OPTxs = 3 or 4 => Kalbach's parameterization
67// useSICB => use superimposed Coulomb Barrier for inverse cross
68// sections
69// Other problem found with G4Fragment definition using Lorentz vector and
70// **G4ParticleDefinition**. This does not allow A and Z to be defined for the
71// fragment for some reason. Now the fragment is defined more explicitly:
72// G4Fragment *fragment = new G4Fragment(A, Z, lorentzVector);
73// to avoid this quirk. Bug found in SelectSecondariesByDefault: *type is now
74// equated to evapType[i] whereas previously it was equated to fragType[i].
75//
76// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
77////////////////////////////////////////////////////////////////////////////////
78//
79#include <iomanip>
80#include <numeric>
81
84#include "G4SystemOfUnits.hh"
85#include "Randomize.hh"
86#include "G4ParticleTable.hh"
87#include "G4IonTable.hh"
88#include "G4Alpha.hh"
89#include "G4He3.hh"
90#include "G4Triton.hh"
91#include "G4Deuteron.hh"
92#include "G4Proton.hh"
93#include "G4Neutron.hh"
100#include "G4LorentzVector.hh"
102
103////////////////////////////////////////////////////////////////////////////////
104//
106{
107//
108//
109// Send message to stdout to advise that the G4Abrasion model is being used.
110//
111 PrintWelcomeMessage();
112//
113//
114// Set the default verbose level to 0 - no output.
115//
116 verboseLevel = 0;
117//
118//
119// Set the binding energy per nucleon .... did I mention that this is a crude
120// model for nuclear de-excitation?
121//
122 B = 10.0 * MeV;
123//
124//
125// It is possuble to switch off secondary particle production (other than the
126// final nuclear fragment). The default is on.
127//
128 produceSecondaries = true;
129//
130//
131// Now we need to define the decay modes. We're using the G4Evaporation model
132// to help determine the kinematics of the decay.
133//
134 nFragTypes = 6;
135 fragType[0] = G4Alpha::Alpha();
136 fragType[1] = G4He3::He3();
137 fragType[2] = G4Triton::Triton();
138 fragType[3] = G4Deuteron::Deuteron();
139 fragType[4] = G4Proton::Proton();
140 fragType[5] = G4Neutron::Neutron();
141//
142//
143// Set verboseLevel default to no output.
144//
145 verboseLevel = 0;
146 theChannelFactory = new G4EvaporationFactory();
147 theChannels = theChannelFactory->GetChannel();
148//
149//
150// Set defaults for evaporation classes. These can be overridden by user
151// "set" methods.
152//
153 OPTxs = 3;
154 useSICB = false;
155 fragmentVector = 0;
156}
157////////////////////////////////////////////////////////////////////////////////
158//
160{
161 if (theChannels != 0) theChannels = 0;
162 if (theChannelFactory != 0) delete theChannelFactory;
163}
164////////////////////////////////////////////////////////////////////////////////
165//
167 (const G4Fragment &theNucleus)
168{
169//
170//
171// Initilise the pointer to the G4FragmentVector used to return the information
172// about the breakup.
173//
174 fragmentVector = new G4FragmentVector;
175 fragmentVector->clear();
176//
177//
178// Get the A, Z and excitation of the nucleus.
179//
180 G4int A = theNucleus.GetA_asInt();
181 G4int Z = theNucleus.GetZ_asInt();
182 G4double ex = theNucleus.GetExcitationEnergy();
183 if (verboseLevel >= 2)
184 {
185 G4cout <<"oooooooooooooooooooooooooooooooooooooooo"
186 <<"oooooooooooooooooooooooooooooooooooooooo"
187 <<G4endl;
188 G4cout.precision(6);
189 G4cout <<"IN G4WilsonAblationModel" <<G4endl;
190 G4cout <<"Initial prefragment A=" <<A
191 <<", Z=" <<Z
192 <<", excitation energy = " <<ex/MeV <<" MeV"
193 <<G4endl;
194 }
195//
196//
197// Check that there is a nucleus to speak of. It's possible there isn't one
198// or its just a proton or neutron. In either case, the excitation energy
199// (from the Lorentz vector) is not used.
200//
201 if (A == 0)
202 {
203 if (verboseLevel >= 2)
204 {
205 G4cout <<"No nucleus to decay" <<G4endl;
206 G4cout <<"oooooooooooooooooooooooooooooooooooooooo"
207 <<"oooooooooooooooooooooooooooooooooooooooo"
208 <<G4endl;
209 }
210 return fragmentVector;
211 }
212 else if (A == 1)
213 {
214 G4LorentzVector lorentzVector = theNucleus.GetMomentum();
215 lorentzVector.setE(lorentzVector.e()-ex+10.0*eV);
216 if (Z == 0)
217 {
218 G4Fragment *fragment = new G4Fragment(lorentzVector,G4Neutron::Neutron());
219 fragmentVector->push_back(fragment);
220 }
221 else
222 {
223 G4Fragment *fragment = new G4Fragment(lorentzVector,G4Proton::Proton());
224 fragmentVector->push_back(fragment);
225 }
226 if (verboseLevel >= 2)
227 {
228 G4cout <<"Final fragment is in fact only a nucleon) :" <<G4endl;
229 G4cout <<(*fragmentVector)[0] <<G4endl;
230 G4cout <<"oooooooooooooooooooooooooooooooooooooooo"
231 <<"oooooooooooooooooooooooooooooooooooooooo"
232 <<G4endl;
233 }
234 return fragmentVector;
235 }
236//
237//
238// Then the number of nucleons ablated (either as nucleons or light nuclear
239// fragments) is based on a simple argument for the binding energy per nucleon.
240//
241 G4int DAabl = (G4int) (ex / B);
242 if (DAabl > A) DAabl = A;
243// The following lines are no longer accurate given we now treat the final fragment
244// if (verboseLevel >= 2)
245// G4cout <<"Number of nucleons ejected = " <<DAabl <<G4endl;
246
247//
248//
249// Determine the nuclear fragment from the ablation process by sampling the
250// Rudstam equation.
251//
252 G4int AF = A - DAabl;
253 G4int ZF = 0;
254 if (AF > 0)
255 {
256 G4double AFd = (G4double) AF;
257 G4double R = 11.8 / std::pow(AFd, 0.45);
258 G4int minZ = Z - DAabl;
259 if (minZ <= 0) minZ = 1;
260//
261//
262// Here we define an integral probability distribution based on the Rudstam
263// equation assuming a constant AF.
264//
265 G4double sig[100];
266 G4double sum = 0.0;
267 for (G4int ii=minZ; ii<= Z; ii++)
268 {
269 sum += std::exp(-R*std::pow(std::abs(ii - 0.486*AFd + 3.8E-04*AFd*AFd),1.5));
270 sig[ii] = sum;
271 }
272//
273//
274// Now sample that distribution to determine a value for ZF.
275//
276 G4double xi = G4UniformRand();
277 G4int iz = minZ;
278 G4bool found = false;
279 while (iz <= Z && !found)
280 {
281 found = (xi <= sig[iz]/sum);
282 if (!found) iz++;
283 }
284 if (iz > Z)
285 ZF = Z;
286 else
287 ZF = iz;
288 }
289 G4int DZabl = Z - ZF;
290//
291//
292// Now determine the nucleons or nuclei which have bee ablated. The preference
293// is for the production of alphas, then other nuclei in order of decreasing
294// binding energy. The energies assigned to the products of the decay are
295// provisional for the moment (the 10eV is just to avoid errors with negative
296// excitation energies due to rounding).
297//
298 G4double totalEpost = 0.0;
299 evapType.clear();
300 for (G4int ift=0; ift<nFragTypes; ift++)
301 {
302 G4ParticleDefinition *type = fragType[ift];
303 G4double n = std::floor((G4double) DAabl / type->GetBaryonNumber() + 1.0E-10);
304 G4double n1 = 1.0E+10;
305 if (fragType[ift]->GetPDGCharge() > 0.0)
306 n1 = std::floor((G4double) DZabl / type->GetPDGCharge() + 1.0E-10);
307 if (n > n1) n = n1;
308 if (n > 0.0)
309 {
310 G4double mass = type->GetPDGMass();
311 for (G4int j=0; j<(G4int) n; j++)
312 {
313 totalEpost += mass;
314 evapType.push_back(type);
315 }
316 DAabl -= (G4int) (n * type->GetBaryonNumber() + 1.0E-10);
317 DZabl -= (G4int) (n * type->GetPDGCharge() + 1.0E-10);
318 }
319 }
320//
321//
322// Determine the properties of the final nuclear fragment. Note that if
323// the final fragment is predicted to have a nucleon number of zero, then
324// really it's the particle last in the vector evapType which becomes the
325// final fragment. Therefore delete this from the vector if this is the
326// case.
327//
328 G4double massFinalFrag = 0.0;
329 if (AF > 0)
331 GetIonMass(ZF,AF);
332 else
333 {
334 G4ParticleDefinition *type = evapType[evapType.size()-1];
335 AF = type->GetBaryonNumber();
336 ZF = (G4int) (type->GetPDGCharge() + 1.0E-10);
337 evapType.erase(evapType.end()-1);
338 }
339 totalEpost += massFinalFrag;
340//
341//
342// Provide verbose output on the nuclear fragment if requested.
343//
344 if (verboseLevel >= 2)
345 {
346 G4cout <<"Final fragment A=" <<AF
347 <<", Z=" <<ZF
348 <<G4endl;
349 for (G4int ift=0; ift<nFragTypes; ift++)
350 {
351 G4ParticleDefinition *type = fragType[ift];
352 G4int n = std::count(evapType.begin(),evapType.end(),type);
353 if (n > 0)
354 G4cout <<"Particle type: " <<std::setw(10) <<type->GetParticleName()
355 <<", number of particles emitted = " <<n <<G4endl;
356 }
357 }
358//
359// Add the total energy from the fragment. Note that the fragment is assumed
360// to be de-excited and does not undergo photo-evaporation .... I did mention
361// this is a bit of a crude model?
362//
363 G4double massPreFrag = theNucleus.GetGroundStateMass();
364 G4double totalEpre = massPreFrag + ex;
365 G4double excess = totalEpre - totalEpost;
366// G4Fragment *resultNucleus(theNucleus);
367 G4Fragment *resultNucleus = new G4Fragment(A, Z, theNucleus.GetMomentum());
368 G4ThreeVector boost(0.0,0.0,0.0);
369 G4int nEvap = 0;
370 if (produceSecondaries && evapType.size()>0)
371 {
372 if (excess > 0.0)
373 {
374 SelectSecondariesByEvaporation (resultNucleus);
375 nEvap = fragmentVector->size();
376 boost = resultNucleus->GetMomentum().findBoostToCM();
377 if (evapType.size() > 0)
378 SelectSecondariesByDefault (boost);
379 }
380 else
381 SelectSecondariesByDefault(G4ThreeVector(0.0,0.0,0.0));
382 }
383
384 if (AF > 0)
385 {
387 GetIonMass(ZF,AF);
388 G4double e = mass + 10.0*eV;
389 G4double p = std::sqrt(e*e-mass*mass);
390 G4ThreeVector direction(0.0,0.0,1.0);
391 G4LorentzVector lorentzVector = G4LorentzVector(direction*p, e);
392 lorentzVector.boost(-boost);
393 G4Fragment* frag = new G4Fragment(AF, ZF, lorentzVector);
394 fragmentVector->push_back(frag);
395 }
396 delete resultNucleus;
397//
398//
399// Provide verbose output on the ablation products if requested.
400//
401 if (verboseLevel >= 2)
402 {
403 if (nEvap > 0)
404 {
405 G4cout <<"----------------------" <<G4endl;
406 G4cout <<"Evaporated particles :" <<G4endl;
407 G4cout <<"----------------------" <<G4endl;
408 }
409 G4int ie = 0;
410 G4FragmentVector::iterator iter;
411 for (iter = fragmentVector->begin(); iter != fragmentVector->end(); iter++)
412 {
413 if (ie == nEvap)
414 {
415// G4cout <<*iter <<G4endl;
416 G4cout <<"---------------------------------" <<G4endl;
417 G4cout <<"Particles from default emission :" <<G4endl;
418 G4cout <<"---------------------------------" <<G4endl;
419 }
420 G4cout <<*iter <<G4endl;
421 }
422 G4cout <<"oooooooooooooooooooooooooooooooooooooooo"
423 <<"oooooooooooooooooooooooooooooooooooooooo"
424 <<G4endl;
425 }
426
427 return fragmentVector;
428}
429////////////////////////////////////////////////////////////////////////////////
430//
431void G4WilsonAblationModel::SelectSecondariesByEvaporation
432 (G4Fragment *intermediateNucleus)
433{
434 G4Fragment theResidualNucleus = *intermediateNucleus;
435 G4bool evaporate = true;
436 while (evaporate && evapType.size() != 0)
437 {
438//
439//
440// Here's the cheaky bit. We're hijacking the G4Evaporation model, in order to
441// more accurately sample to kinematics, but the species of the nuclear
442// fragments will be the ones of our choosing as above.
443//
444 std::vector <G4VEvaporationChannel*> theChannels1;
445 theChannels1.clear();
446 std::vector <G4VEvaporationChannel*>::iterator i;
447 VectorOfFragmentTypes::iterator iter;
448 std::vector <VectorOfFragmentTypes::iterator> iters;
449 iters.clear();
450 iter = std::find(evapType.begin(), evapType.end(), G4Alpha::Alpha());
451 if (iter != evapType.end())
452 {
453 theChannels1.push_back(new G4AlphaEvaporationChannel);
454 i = theChannels1.end() - 1;
455 (*i)->SetOPTxs(OPTxs);
456 (*i)->UseSICB(useSICB);
457// (*i)->Initialize(theResidualNucleus);
458 iters.push_back(iter);
459 }
460 iter = std::find(evapType.begin(), evapType.end(), G4He3::He3());
461 if (iter != evapType.end())
462 {
463 theChannels1.push_back(new G4He3EvaporationChannel);
464 i = theChannels1.end() - 1;
465 (*i)->SetOPTxs(OPTxs);
466 (*i)->UseSICB(useSICB);
467// (*i)->Initialize(theResidualNucleus);
468 iters.push_back(iter);
469 }
470 iter = std::find(evapType.begin(), evapType.end(), G4Triton::Triton());
471 if (iter != evapType.end())
472 {
473 theChannels1.push_back(new G4TritonEvaporationChannel);
474 i = theChannels1.end() - 1;
475 (*i)->SetOPTxs(OPTxs);
476 (*i)->UseSICB(useSICB);
477// (*i)->Initialize(theResidualNucleus);
478 iters.push_back(iter);
479 }
480 iter = std::find(evapType.begin(), evapType.end(), G4Deuteron::Deuteron());
481 if (iter != evapType.end())
482 {
483 theChannels1.push_back(new G4DeuteronEvaporationChannel);
484 i = theChannels1.end() - 1;
485 (*i)->SetOPTxs(OPTxs);
486 (*i)->UseSICB(useSICB);
487// (*i)->Initialize(theResidualNucleus);
488 iters.push_back(iter);
489 }
490 iter = std::find(evapType.begin(), evapType.end(), G4Proton::Proton());
491 if (iter != evapType.end())
492 {
493 theChannels1.push_back(new G4ProtonEvaporationChannel);
494 i = theChannels1.end() - 1;
495 (*i)->SetOPTxs(OPTxs);
496 (*i)->UseSICB(useSICB);
497// (*i)->Initialize(theResidualNucleus);
498 iters.push_back(iter);
499 }
500 iter = std::find(evapType.begin(), evapType.end(), G4Neutron::Neutron());
501 if (iter != evapType.end())
502 {
503 theChannels1.push_back(new G4NeutronEvaporationChannel);
504 i = theChannels1.end() - 1;
505 (*i)->SetOPTxs(OPTxs);
506 (*i)->UseSICB(useSICB);
507// (*i)->Initialize(theResidualNucleus);
508 iters.push_back(iter);
509 }
510 G4int nChannels = theChannels1.size();
511
512 G4double totalProb = 0.0;
513 G4int ich = 0;
514 G4double probEvapType[6] = {0.0};
515 std::vector<G4VEvaporationChannel*>::iterator iterEv;
516 for (iterEv=theChannels1.begin(); iterEv!=theChannels1.end(); iterEv++) {
517 totalProb += (*iterEv)->GetEmissionProbability(intermediateNucleus);
518 probEvapType[ich] = totalProb;
519 ++ich;
520 }
521 if (totalProb > 0.0) {
522//
523//
524// The emission probability for at least one of the evaporation channels is
525// positive, therefore work out which one should be selected and decay
526// the nucleus.
527//
528 G4double xi = totalProb*G4UniformRand();
529 G4int ii = 0;
530 for (ii=0; ii<nChannels; ii++) {
531 if (xi < probEvapType[ii]) { break; }
532 }
533 if (ii >= nChannels) { ii = nChannels - 1; }
534 G4FragmentVector *evaporationResult = theChannels1[ii]->
535 BreakUp(*intermediateNucleus);
536 fragmentVector->push_back((*evaporationResult)[0]);
537 *intermediateNucleus = *(*evaporationResult)[1];
538 //delete evaporationResult->back();
539 delete evaporationResult;
540 //evapType.erase(iters[ii]);
541 }
542 else
543 {
544//
545//
546// Probability for further evaporation is nil so have to escape from this
547// routine and set the energies of the secondaries to 10eV.
548//
549 evaporate = false;
550 }
551 }
552
553 return;
554}
555////////////////////////////////////////////////////////////////////////////////
556//
557void G4WilsonAblationModel::SelectSecondariesByDefault (G4ThreeVector boost)
558{
559 for (unsigned i=0; i<evapType.size(); i++)
560 {
561 G4ParticleDefinition *type = evapType[i];
562 G4double mass = type->GetPDGMass();
563 G4double e = mass + 10.0*eV;
564 G4double p = std::sqrt(e*e-mass*mass);
565 G4double costheta = 2.0*G4UniformRand() - 1.0;
566 G4double sintheta = std::sqrt((1.0 - costheta)*(1.0 + costheta));
567 G4double phi = twopi * G4UniformRand() * rad;
568 G4ThreeVector direction(sintheta*std::cos(phi),sintheta*std::sin(phi),costheta);
569 G4LorentzVector lorentzVector = G4LorentzVector(direction*p, e);
570 lorentzVector.boost(-boost);
571// Possibility that the following line is not correctly carrying over A and Z
572// from particle definition. Force values. PRT 03/12/2009.
573// G4Fragment *fragment =
574// new G4Fragment(lorentzVector, type);
575 G4int A = type->GetBaryonNumber();
576 G4int Z = (G4int) (type->GetPDGCharge() + 1.0E-10);
577 G4Fragment *fragment =
578 new G4Fragment(A, Z, lorentzVector);
579
580 fragmentVector->push_back(fragment);
581 }
582}
583////////////////////////////////////////////////////////////////////////////////
584//
585void G4WilsonAblationModel::PrintWelcomeMessage ()
586{
587 G4cout <<G4endl;
588 G4cout <<" *****************************************************************"
589 <<G4endl;
590 G4cout <<" Nuclear ablation model for nuclear-nuclear interactions activated"
591 <<G4endl;
592 G4cout <<" (Written by QinetiQ Ltd for the European Space Agency)"
593 <<G4endl;
594 G4cout <<" *****************************************************************"
595 <<G4endl;
596 G4cout << G4endl;
597
598 return;
599}
600////////////////////////////////////////////////////////////////////////////////
601//
std::vector< G4Fragment * > G4FragmentVector
Definition: G4Fragment.hh:65
CLHEP::HepLorentzVector G4LorentzVector
CLHEP::Hep3Vector G4ThreeVector
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 G4cout
#define G4UniformRand()
Definition: Randomize.hh:53
HepLorentzVector & boost(double, double, double)
Hep3Vector findBoostToCM() const
static G4Alpha * Alpha()
Definition: G4Alpha.cc:89
static G4Deuteron * Deuteron()
Definition: G4Deuteron.cc:94
G4double GetGroundStateMass() const
Definition: G4Fragment.hh:240
G4double GetExcitationEnergy() const
Definition: G4Fragment.hh:235
const G4LorentzVector & GetMomentum() const
Definition: G4Fragment.hh:251
G4int GetZ_asInt() const
Definition: G4Fragment.hh:223
G4int GetA_asInt() const
Definition: G4Fragment.hh:218
static G4He3 * He3()
Definition: G4He3.cc:94
static G4Neutron * Neutron()
Definition: G4Neutron.cc:104
G4double GetPDGCharge() const
const G4String & GetParticleName() const
static G4ParticleTable * GetParticleTable()
G4IonTable * GetIonTable()
static G4Proton * Proton()
Definition: G4Proton.cc:93
static G4Triton * Triton()
Definition: G4Triton.cc:95
virtual std::vector< G4VEvaporationChannel * > * GetChannel()=0
G4FragmentVector * BreakItUp(const G4Fragment &theNucleus)