Geant4-11
G4PhotonEvaporation.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// -------------------------------------------------------------------
27//
28// GEANT4 class file
29//
30// CERN, Geneva, Switzerland
31//
32// File name: G4PhotonEvaporation
33//
34// Author: Vladimir Ivantchenko
35//
36// Creation date: 20 December 2011
37//
38//Modifications:
39//
40//
41// -------------------------------------------------------------------
42//
43
45
47#include "Randomize.hh"
48#include "G4Gamma.hh"
49#include "G4LorentzVector.hh"
50#include "G4FragmentVector.hh"
51#include "G4GammaTransition.hh"
52#include "G4Pow.hh"
56
59
60#ifdef G4MULTITHREADED
61G4Mutex G4PhotonEvaporation::PhotonEvaporationMutex = G4MUTEX_INITIALIZER;
62#endif
63
65 : fLevelManager(nullptr), fTransition(p), fPolarization(nullptr),
66 fVerbose(1), fPoints(0), vShellNumber(-1), fIndex(0), fSecID(-1),
67 fMaxLifeTime(DBL_MAX),
68 fICM(true), fRDM(false), fSampleTime(true),
69 fCorrelatedGamma(false), fIsomerFlag(false), isInitialised(false)
70{
71 //G4cout << "### New G4PhotonEvaporation() " << this << G4endl;
74
76
77 theA = theZ = fCode = 0;
78 fSecID = G4PhysicsModelCatalog::GetModelID("model_G4PhotonEvaporation");
80
81 for(G4int i=0; i<MAXDEPOINT; ++i) { fCummProbability[i] = 0.0; }
82 if(0.0f == GREnergy[1]) { InitialiseGRData(); }
83}
84
86{
87 delete fTransition;
88}
89
91{
92 if(isInitialised) { return; }
93 isInitialised = true;
94
96 Tolerance = param->GetMinExcitation();
100 fIsomerFlag = param->IsomerProduction();
101 if(fRDM) { fIsomerFlag = true; }
102 fVerbose = param->GetVerbose();
103
107 if(fVerbose > 1) {
108 G4cout << "### G4PhotonEvaporation is initialized " << this << G4endl;
109 }
110}
111
113{
114#ifdef G4MULTITHREADED
115 G4MUTEXLOCK(&G4PhotonEvaporation::PhotonEvaporationMutex);
116#endif
117 if(0.0f == GREnergy[1]) {
118 G4Pow* g4calc = G4Pow::GetInstance();
119 const G4float GRWfactor = 0.3f;
120 for (G4int A=1; A<MAXGRDATA; ++A) {
121 GREnergy[A] = (G4float)(40.3*CLHEP::MeV/g4calc->powZ(A,0.2));
122 GRWidth[A] = GRWfactor*GREnergy[A];
123 }
124 }
125#ifdef G4MULTITHREADED
126 G4MUTEXUNLOCK(&G4PhotonEvaporation::PhotonEvaporationMutex);
127#endif
128}
129
132{
133 if(!isInitialised) { Initialise(); }
134 fSampleTime = (fRDM) ? false : true;
135
136 // potentially external code may set initial polarization
137 // but only for radioactive decay nuclear polarization is considered
138 G4NuclearPolarizationStore* fNucPStore = nullptr;
139 if(fCorrelatedGamma && fRDM) {
141 if(nucleus->GetNuclearPolarization()) {
142 fNucPStore->RemoveMe(nucleus->GetNuclearPolarization());
143 delete nucleus->GetNuclearPolarization();
144 }
145 fPolarization = fNucPStore->FindOrBuild(nucleus->GetZ_asInt(),
146 nucleus->GetA_asInt(),
147 nucleus->GetExcitationEnergy());
149 }
150 if(fVerbose > 2) {
151 G4cout << "G4PhotonEvaporation::EmittedFragment: "
152 << *nucleus << G4endl;
153 if(fPolarization) { G4cout << "NucPolar: " << fPolarization << G4endl; }
154 G4cout << " CorrGamma: " << fCorrelatedGamma << " RDM: " << fRDM
155 << " fPolarization: " << fPolarization << G4endl;
156 }
157 G4Fragment* gamma = GenerateGamma(nucleus);
158
159 if(gamma != nullptr) { gamma->SetCreatorModelID(fSecID); }
160
161 // remove G4NuclearPolarizaton when reach ground state
162 if(fNucPStore && fPolarization && 0 == fIndex) {
163 if(fVerbose > 3) {
164 G4cout << "G4PhotonEvaporation::EmittedFragment: remove "
165 << fPolarization << G4endl;
166 }
167 fNucPStore->RemoveMe(fPolarization);
168 fPolarization = nullptr;
170 }
171
172 if(fVerbose > 2) {
173 G4cout << "G4PhotonEvaporation::EmittedFragment: RDM= "
174 << fRDM << " done:" << G4endl;
175 if(gamma) { G4cout << *gamma << G4endl; }
176 G4cout << " Residual: " << *nucleus << G4endl;
177 }
178 return gamma;
179}
180
183{
184 if(fVerbose > 1) {
185 G4cout << "G4PhotonEvaporation::BreakItUp" << G4endl;
186 }
187 G4Fragment* aNucleus = new G4Fragment(nucleus);
188 G4FragmentVector* products = new G4FragmentVector();
189 BreakUpChain(products, aNucleus);
190 aNucleus->SetCreatorModelID(fSecID);
191 products->push_back(aNucleus);
192 return products;
193}
194
196 G4Fragment* nucleus)
197{
198 if(!isInitialised) { Initialise(); }
199 if(fVerbose > 1) {
200 G4cout << "G4PhotonEvaporation::BreakUpChain RDM= " << fRDM << " "
201 << *nucleus << G4endl;
202 }
203 G4Fragment* gamma = nullptr;
204 fSampleTime = !fRDM;
205
206 // start decay chain from unpolarized state
207 if(fCorrelatedGamma) {
209 nucleus->GetA_asInt(),
210 nucleus->GetExcitationEnergy());
212 }
213
214 do {
215 gamma = GenerateGamma(nucleus);
216 if(gamma) {
218 products->push_back(gamma);
219 if(fVerbose > 2) {
220 G4cout << "G4PhotonEvaporation::BreakUpChain: "
221 << *gamma << G4endl;
222 G4cout << " Residual: " << *nucleus << G4endl;
223 }
224 // for next decays in the chain always sample time
225 fSampleTime = true;
226 }
227 // Loop checking, 05-Aug-2015, Vladimir Ivanchenko
228 } while(gamma);
229
230 // clear nuclear polarization end of chain
231 if(fPolarization) {
232 delete fPolarization;
233 fPolarization = nullptr;
235 }
236 return false;
237}
238
241{
242 if(!isInitialised) { Initialise(); }
243 fProbability = 0.0;
244 fExcEnergy = nucleus->GetExcitationEnergy();
245 G4int Z = nucleus->GetZ_asInt();
246 G4int A = nucleus->GetA_asInt();
247 fCode = 1000*Z + A;
248 if(fVerbose > 2) {
249 G4cout << "G4PhotonEvaporation::GetEmissionProbability: Z="
250 << Z << " A=" << A << " Eexc(MeV)= " << fExcEnergy << G4endl;
251 }
252 // ignore gamma de-excitation for exotic fragments
253 // and for very low excitations
254 if(0 >= Z || 1 >= A || Z == A || Tolerance >= fExcEnergy)
255 { return fProbability; }
256
257 // ignore gamma de-excitation for highly excited levels
258 if(A >= MAXGRDATA) { A = MAXGRDATA-1; }
259 //G4cout<<" GREnergy= "<< GREnergy[A]<<" GRWidth= "<<GRWidth[A]<<G4endl;
260
261 static const G4float GREfactor = 5.0f;
262 if(fExcEnergy >= (G4double)(GREfactor*GRWidth[A] + GREnergy[A])) {
263 return fProbability;
264 }
265 // probability computed assuming continium transitions
266 // VI: continium transition are limited only to final states
267 // below Fermi energy (this approach needs further evaluation)
268 G4double emax = std::max(0.0, nucleus->ComputeGroundStateMass(Z, A-1)
270
271 // max energy level for continues transition
273 const G4double eexcfac = 0.99;
274 if(0.0 == emax || fExcEnergy*eexcfac <= emax) { emax = fExcEnergy*eexcfac; }
275
276 fStep = emax;
277 const G4double MaxDeltaEnergy = CLHEP::MeV;
278 fPoints = std::min((G4int)(fStep/MaxDeltaEnergy) + 2, MAXDEPOINT);
279 fStep /= ((G4double)(fPoints - 1));
280 if(fVerbose > 2) {
281 G4cout << "Emax= " << emax << " Npoints= " << fPoints
282 << " Eex= " << fExcEnergy << G4endl;
283 }
284 // integrate probabilities
285 G4double eres = (G4double)GREnergy[A];
286 G4double wres = (G4double)GRWidth[A];
287 G4double eres2= eres*eres;
288 G4double wres2= wres*wres;
290 G4double xsqr = std::sqrt(levelDensity*fExcEnergy);
291
292 G4double egam = fExcEnergy;
293 G4double gammaE2 = egam*egam;
294 G4double gammaR2 = gammaE2*wres2;
295 G4double egdp2 = gammaE2 - eres2;
296
297 G4double p0 = G4Exp(-2.0*xsqr)*gammaR2*gammaE2/(egdp2*egdp2 + gammaR2);
298 G4double p1(0.0);
299
300 for(G4int i=1; i<fPoints; ++i) {
301 egam -= fStep;
302 gammaE2 = egam*egam;
303 gammaR2 = gammaE2*wres2;
304 egdp2 = gammaE2 - eres2;
305 p1 = G4Exp(2.0*(std::sqrt(levelDensity*std::abs(fExcEnergy - egam)) - xsqr))
306 *gammaR2*gammaE2/(egdp2*egdp2 + gammaR2);
307 fProbability += (p1 + p0);
309 if(fVerbose > 3) {
310 G4cout << "Egamma= " << egam << " Eex= " << fExcEnergy
311 << " p0= " << p0 << " p1= " << p1 << " sum= "
312 << fCummProbability[i] <<G4endl;
313 }
314 p0 = p1;
315 }
316
317 static const G4double NormC = 1.25*CLHEP::millibarn
319 fProbability *= fStep*NormC*A;
320 if(fVerbose > 1) { G4cout << "prob= " << fProbability << G4endl; }
321 return fProbability;
322}
323
326{
327 G4double E = energy;
329 if(fLevelManager) {
331 if(E > fLevelEnergyMax + Tolerance) { E = energy; }
332 }
333 return E;
334}
335
337{
339 return fLevelEnergyMax;
340}
341
344{
345 if(!isInitialised) { Initialise(); }
346 G4Fragment* result = nullptr;
347 G4double eexc = nucleus->GetExcitationEnergy();
348 if(eexc <= Tolerance) { return result; }
349
350 InitialiseLevelManager(nucleus->GetZ_asInt(), nucleus->GetA_asInt());
351
352 G4double time = nucleus->GetCreationTime();
353
354 G4double efinal = 0.0;
355 G4double ratio = 0.0;
356 vShellNumber = -1;
357 G4int JP1 = 0;
358 G4int JP2 = 0;
359 G4int multiP = 0;
360 G4bool isGamma = true;
361 G4bool isDiscrete = false;
362
363 const G4NucLevel* level = nullptr;
364 size_t ntrans = 0;
365
366 if(fVerbose > 2) {
367 G4cout << "GenerateGamma: " << " Eex= " << eexc
368 << " Eexmax= " << fLevelEnergyMax << G4endl;
369 }
370 // initial discrete state
371 if(fLevelManager && eexc <= fLevelEnergyMax + Tolerance) {
373 // initial state below 1st level
374 if(0 == fIndex && eexc >= Tolerance
375 && fLevelManager->NumberOfTransitions() > 0) { fIndex = 1; }
376 isDiscrete = true;
377 if(fVerbose > 2) {
378 G4cout << " index= " << fIndex
379 << " lTime= " << fLevelManager->LifeTime(fIndex) << G4endl;
380 }
381 if(0 < fIndex) {
382 // for discrete transition
383 level = fLevelManager->GetLevel(fIndex);
384 if(level) {
385 ntrans = level->NumberOfTransitions();
387 if(fVerbose > 2) {
388 G4cout << " ntrans= " << ntrans << " JP= " << JP1
389 << " RDM: " << fRDM << G4endl;
390 }
391 if(0 == ntrans && fLevelManager->FloatingLevel(fIndex) > 0) {
392 --fIndex;
393 level = fLevelManager->GetLevel(fIndex);
394 ntrans = level->NumberOfTransitions();
396 }
397 }
398 }
399 }
400 // if a level has no defined transitions
401 if(0 == ntrans) { isDiscrete = false; }
402 if(fVerbose > 2) {
403 G4int prec = G4cout.precision(4);
404 G4cout << "GenerateGamma: Z= " << nucleus->GetZ_asInt()
405 << " A= " << nucleus->GetA_asInt()
406 << " Exc= " << eexc << " Emax= "
407 << fLevelEnergyMax << " idx= " << fIndex
408 << " fCode= " << fCode << " fPoints= " << fPoints
409 << " Ntr= " << ntrans << " discrete: " << isDiscrete
410 << " fProb= " << fProbability << G4endl;
411 G4cout.precision(prec);
412 }
413
414 // continues part
415 if(!isDiscrete) {
416 // we compare current excitation versus value used for probability
417 // computation and also Z and A used for probability computation
418 if(fCode != 1000*theZ + theA || eexc != fExcEnergy) {
419 GetEmissionProbability(nucleus);
420 }
421 if(fProbability == 0.0) {
422 fPoints = 1;
423 efinal = 0.0;
424 } else {
426 for(G4int i=1; i<fPoints; ++i) {
427 if(fVerbose > 3) {
428 G4cout << "y= " << y << " cummProb= " << fCummProbability[i]
429 << " fPoints= " << fPoints << " fStep= " << fStep << G4endl;
430 }
431 if(y <= fCummProbability[i]) {
432 efinal = fStep*((i - 1) + (y - fCummProbability[i-1])
434 break;
435 }
436 }
437 }
438 // final discrete level
439 if(fVerbose > 2) {
440 G4cout << "Continues proposes Efinal= " << efinal << G4endl;
441 }
442 if(fLevelManager) {
443 if(efinal < fLevelEnergyMax) {
446 // protection - take level below
447 if(efinal >= eexc && 0 < fIndex) {
448 --fIndex;
450 }
452
453 // not allowed to have final energy above max energy
454 // if G4LevelManager exist
455 } else {
456 efinal = fLevelEnergyMax;
458 }
459 }
460 if(fVerbose > 2) {
461 G4cout << "Continues emission efinal(MeV)= " << efinal << G4endl;
462 }
463 //discrete part ground state
464 } else if(0 == fIndex) {
465 return result;
466
467 //discrete part
468 } else {
469
470 if(fVerbose > 2) {
471 G4cout << "Discrete emission from level Index= " << fIndex
472 << " Elevel= " << fLevelManager->LevelEnergy(fIndex)
473 << " Ltime= " << fLevelManager->LifeTime(fIndex)
474 << " LtimeMax= " << fMaxLifeTime
475 << " RDM= " << fRDM << " ICM= " << fICM << G4endl;
476 }
477
478 // stable fragment has life time -1 or above the limit
479 // if is called from the radioactive decay the life time is not checked
481 if(ltime < 0.0 || (!fRDM && ltime > fMaxLifeTime)) { return result; }
482
483 size_t idx = 0;
484 if(1 < ntrans) {
485 idx = level->SampleGammaTransition(G4UniformRand());
486 }
487 if(fVerbose > 2) {
488 G4cout << "Ntrans= " << ntrans << " idx= " << idx
489 << " ICM= " << fICM << " JP1= " << JP1 << G4endl;
490 }
491 G4double prob = (G4double)level->GammaProbability(idx);
492 // prob = 0 means that there is only internal conversion
493 if(fICM && prob < 1.0) {
494 G4double rndm = G4UniformRand();
495 if(rndm > prob) {
496 isGamma = false;
497 rndm = (rndm - prob)/(1.0 - prob);
498 vShellNumber = level->SampleShell(idx, rndm);
499 }
500 }
501 // it is discrete transition with possible gamma correlation
502 ratio = level->MultipolarityRatio(idx);
503 multiP = level->TransitionType(idx);
504 fIndex = level->FinalExcitationIndex(idx);
506
507 // final energy and time
509 // time is sampled if decay not prompt and this class called not
510 // from radioactive decay and isomer production is enabled
511 if(fSampleTime && fIsomerFlag && ltime > 0.0) {
512 time -= ltime*G4Log(G4UniformRand());
513 }
515 }
516 // protection for floating levels
517 if(std::abs(efinal - eexc) <= Tolerance) { return result; }
518
519 result = fTransition->SampleTransition(nucleus, efinal, ratio, JP1,
520 JP2, multiP, vShellNumber,
521 isDiscrete, isGamma);
522 if(result) { result->SetCreationTime(time); }
523
524 // updated residual nucleus
525 nucleus->SetCreationTime(time);
526 nucleus->SetSpin(0.5*JP2);
528
529 // ignore the floating levels with zero energy and create ground state
530 if(efinal == 0.0 && fIndex > 0) {
531 fIndex = 0;
533 }
534
535 if(fVerbose > 2) {
536 G4cout << "Final level E= " << efinal << " time= " << time
537 << " idxFinal= " << fIndex << " isDiscrete: " << isDiscrete
538 << " isGamma: " << isGamma << " multiP= " << multiP
539 << " shell= " << vShellNumber
540 << " JP1= " << JP1 << " JP2= " << JP2 << G4endl;
541 }
542 return result;
543}
544
546{
547 if(p != fTransition) {
548 delete fTransition;
549 fTransition = p;
550 }
551}
552
554{
555 fICM = val;
556}
557
559{
560 fRDM = val;
561}
562
static const G4double emax
G4double G4Exp(G4double initial_x)
Exponential Function double precision.
Definition: G4Exp.hh:179
std::vector< G4Fragment * > G4FragmentVector
Definition: G4Fragment.hh:64
G4double G4Log(G4double x)
Definition: G4Log.hh:226
const G4int MAXDEPOINT
const G4int MAXGRDATA
#define G4MUTEX_INITIALIZER
Definition: G4Threading.hh:85
#define G4MUTEXLOCK(mutex)
Definition: G4Threading.hh:251
#define G4MUTEXUNLOCK(mutex)
Definition: G4Threading.hh:254
std::mutex G4Mutex
Definition: G4Threading.hh:81
float G4float
Definition: G4Types.hh:84
double G4double
Definition: G4Types.hh:83
bool G4bool
Definition: G4Types.hh:86
int G4int
Definition: G4Types.hh:85
const G4int Z[17]
const G4double A[17]
#define G4endl
Definition: G4ios.hh:57
G4GLOB_DLL std::ostream G4cout
#define G4UniformRand()
Definition: Randomize.hh:52
G4double GetMinExcitation() const
G4bool GetInternalConversionFlag() const
void SetFloatingLevelNumber(G4int value)
Definition: G4Fragment.hh:448
G4double GetGroundStateMass() const
Definition: G4Fragment.hh:304
G4NuclearPolarization * GetNuclearPolarization() const
Definition: G4Fragment.hh:479
G4double ComputeGroundStateMass(G4int Z, G4int A, G4int numberOfLambdas=0) const
Definition: G4Fragment.hh:259
G4double GetExcitationEnergy() const
Definition: G4Fragment.hh:299
void SetCreatorModelID(G4int value)
Definition: G4Fragment.hh:428
G4double GetCreationTime() const
Definition: G4Fragment.hh:464
void SetNuclearPolarization(G4NuclearPolarization *)
Definition: G4Fragment.hh:484
G4int GetZ_asInt() const
Definition: G4Fragment.hh:276
void SetCreationTime(G4double time)
Definition: G4Fragment.hh:469
void SetSpin(G4double value)
Definition: G4Fragment.hh:438
G4int GetA_asInt() const
Definition: G4Fragment.hh:271
void SetPolarizationFlag(G4bool val)
void SetTwoJMAX(G4int val)
void SetVerbose(G4int val)
virtual G4Fragment * SampleTransition(G4Fragment *nucleus, G4double newExcEnergy, G4double mpRatio, G4int JP1, G4int JP2, G4int MP, G4int shell, G4bool isDiscrete, G4bool isGamma)
G4double LifeTime(size_t i) const
const G4NucLevel * GetLevel(size_t i) const
size_t NearestLevelIndex(G4double energy, size_t index=0) const
G4double NearestLevelEnergy(G4double energy, size_t index=0) const
G4int FloatingLevel(size_t i) const
G4int SpinTwo(size_t i) const
size_t NumberOfTransitions() const
G4double LevelEnergy(size_t i) const
G4int TransitionType(size_t idx) const
Definition: G4NucLevel.hh:121
G4float MultipolarityRatio(size_t idx) const
Definition: G4NucLevel.hh:150
G4float GammaProbability(size_t idx) const
Definition: G4NucLevel.hh:134
size_t NumberOfTransitions() const
Definition: G4NucLevel.hh:108
size_t FinalExcitationIndex(size_t idx) const
Definition: G4NucLevel.hh:113
size_t SampleGammaTransition(G4double rndm) const
Definition: G4NucLevel.hh:158
G4int SampleShell(size_t idx, G4double rndm) const
Definition: G4NucLevel.hh:168
G4double GetLevelDensity(G4int Z, G4int A, G4double U)
G4DeexPrecoParameters * GetParameters()
static G4NuclearLevelData * GetInstance()
static G4NuclearPolarizationStore * GetInstance()
void RemoveMe(G4NuclearPolarization *ptr)
G4NuclearPolarization * FindOrBuild(G4int Z, G4int A, G4double Eexc)
void SetExcitationEnergy(G4double val)
virtual G4double GetFinalLevelEnergy(G4int Z, G4int A, G4double energy) final
static G4float GRWidth[MAXGRDATA]
static G4float GREnergy[MAXGRDATA]
G4NuclearLevelData * fNuclearLevelData
virtual G4Fragment * EmittedFragment(G4Fragment *theNucleus) final
void InitialiseLevelManager(G4int Z, G4int A)
virtual G4double GetEmissionProbability(G4Fragment *theNucleus) final
virtual void Initialise() final
G4NuclearPolarization * fPolarization
virtual void SetICM(G4bool)
G4double fCummProbability[MAXDEPOINT]
const G4LevelManager * fLevelManager
G4Fragment * GenerateGamma(G4Fragment *nucleus)
virtual G4double GetUpperLevelEnergy(G4int Z, G4int A) final
void SetGammaTransition(G4GammaTransition *)
G4GammaTransition * fTransition
G4PhotonEvaporation(G4GammaTransition *ptr=nullptr)
G4FragmentVector * BreakItUp(const G4Fragment &theNucleus)
virtual void RDMForced(G4bool)
virtual G4bool BreakUpChain(G4FragmentVector *theResult, G4Fragment *theNucleus) final
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
static const double prec
Definition: RanecuEngine.cc:61
static constexpr double millibarn
Definition: SystemOfUnits.h:87
static constexpr double pi2
Definition: SystemOfUnits.h:58
static constexpr double neutron_mass_c2
static constexpr double MeV
static constexpr double eV
static constexpr double hbarc
G4double energy(const ThreeVector &p, const G4double m)
T max(const T t1, const T t2)
brief Return the largest of the two arguments
T min(const T t1, const T t2)
brief Return the smallest of the two arguments
#define DBL_MAX
Definition: templates.hh:62