Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4PenelopePhotoElectricModel.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// Author: Luciano Pandola
28//
29// History:
30// --------
31// 08 Jan 2010 L Pandola First implementation
32// 01 Feb 2011 L Pandola Suppress fake energy-violation warning when Auger
33// is active.
34// Make sure that fluorescence/Auger is generated
35// only if above threshold
36// 25 May 2011 L Pandola Renamed (make v2008 as default Penelope)
37// 10 Jun 2011 L Pandola Migrate atomic deexcitation interface
38// 07 Oct 2011 L Pandola Bug fix (potential violation of energy conservation)
39// 27 Sep 2013 L Pandola Migrate to MT paradigm, only master model manages
40// tables.
41// 02 Oct 2013 L Pandola Rewrite sampling algorithm of SelectRandomShell()
42// to improve CPU performances
43//
44
47#include "G4SystemOfUnits.hh"
50#include "G4DynamicParticle.hh"
51#include "G4PhysicsTable.hh"
53#include "G4ElementTable.hh"
54#include "G4Element.hh"
56#include "G4AtomicShell.hh"
57#include "G4Gamma.hh"
58#include "G4Electron.hh"
59#include "G4AutoLock.hh"
60#include "G4LossTableManager.hh"
61#include "G4Exp.hh"
62
63//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
64
65const G4int G4PenelopePhotoElectricModel::fMaxZ;
66G4PhysicsTable* G4PenelopePhotoElectricModel::fLogAtomicShellXS[] = {nullptr};
67
68//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
69
71 const G4String& nam)
72 :G4VEmModel(nam),fParticleChange(nullptr),fParticle(nullptr),
73 fAtomDeexcitation(nullptr),fIsInitialised(false),fLocalTable(false)
74{
75 fIntrinsicLowEnergyLimit = 100.0*eV;
76 fIntrinsicHighEnergyLimit = 100.0*GeV;
77 // SetLowEnergyLimit(fIntrinsicLowEnergyLimit);
78 SetHighEnergyLimit(fIntrinsicHighEnergyLimit);
79 //
80
81 if (part)
82 SetParticle(part);
83
84 fVerboseLevel= 0;
85 // Verbosity scale:
86 // 0 = nothing
87 // 1 = warning for energy non-conservation
88 // 2 = details of energy budget
89 // 3 = calculation of cross sections, file openings, sampling of atoms
90 // 4 = entering in methods
91
92 //Mark this model as "applicable" for atomic deexcitation
94
95 fTransitionManager = G4AtomicTransitionManager::Instance();
96}
97
98//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
99
101{
102 if (IsMaster() || fLocalTable)
103 {
104 for(G4int i=0; i<=fMaxZ; ++i)
105 {
106 if(fLogAtomicShellXS[i]) {
107 fLogAtomicShellXS[i]->clearAndDestroy();
108 delete fLogAtomicShellXS[i];
109 fLogAtomicShellXS[i] = nullptr;
110 }
111 }
112 }
113}
114
115//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
116
118 const G4DataVector& cuts)
119{
120 if (fVerboseLevel > 3)
121 G4cout << "Calling G4PenelopePhotoElectricModel::Initialise()" << G4endl;
122
123 fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
124 //Issue warning if the AtomicDeexcitation has not been declared
125 if (!fAtomDeexcitation)
126 {
127 G4cout << G4endl;
128 G4cout << "WARNING from G4PenelopePhotoElectricModel " << G4endl;
129 G4cout << "Atomic de-excitation module is not instantiated, so there will not be ";
130 G4cout << "any fluorescence/Auger emission." << G4endl;
131 G4cout << "Please make sure this is intended" << G4endl;
132 }
133
134 SetParticle(particle);
135
136 //Only the master model creates/fills/destroys the tables
137 if (IsMaster() && particle == fParticle)
138 {
139 G4ProductionCutsTable* theCoupleTable =
141
142 for (G4int i=0;i<(G4int)theCoupleTable->GetTableSize();++i)
143 {
144 const G4Material* material =
145 theCoupleTable->GetMaterialCutsCouple(i)->GetMaterial();
146 const G4ElementVector* theElementVector = material->GetElementVector();
147
148 for (std::size_t j=0;j<material->GetNumberOfElements();++j)
149 {
150 G4int iZ = theElementVector->at(j)->GetZasInt();
151 //read data files only in the master
152 if (!fLogAtomicShellXS[iZ])
153 ReadDataFile(iZ);
154 }
155 }
156
157 InitialiseElementSelectors(particle,cuts);
158
159 if (fVerboseLevel > 0) {
160 G4cout << "Penelope Photo-Electric model v2008 is initialized " << G4endl
161 << "Energy range: "
162 << LowEnergyLimit() / MeV << " MeV - "
163 << HighEnergyLimit() / GeV << " GeV";
164 }
165 }
166
167 if(fIsInitialised) return;
169 fIsInitialised = true;
170
171}
172
174 G4VEmModel *masterModel)
175{
176 if (fVerboseLevel > 3)
177 G4cout << "Calling G4PenelopePhotoElectricModel::InitialiseLocal()" << G4endl;
178 //
179 //Check that particle matches: one might have multiple master models (e.g.
180 //for e+ and e-).
181 //
182 if (part == fParticle)
183 {
185
186 //Get the const table pointers from the master to the workers
187 const G4PenelopePhotoElectricModel* theModel =
188 static_cast<G4PenelopePhotoElectricModel*> (masterModel);
189 for(G4int i=0; i<=fMaxZ; ++i)
190 fLogAtomicShellXS[i] = theModel->fLogAtomicShellXS[i];
191 //Same verbosity for all workers, as the master
192 fVerboseLevel = theModel->fVerboseLevel;
193 }
194
195 return;
196}
197
198//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
199namespace { G4Mutex PenelopePhotoElectricModelMutex = G4MUTEX_INITIALIZER; }
202 G4double energy,
205{
206 //
207 // Penelope model v2008
208 //
209 if (fVerboseLevel > 3)
210 G4cout << "Calling ComputeCrossSectionPerAtom() of G4PenelopePhotoElectricModel" << G4endl;
211
212 G4int iZ = G4int(Z);
213
214 if (!fLogAtomicShellXS[iZ])
215 {
216 //If we are here, it means that Initialize() was inkoved, but the MaterialTable was
217 //not filled up. This can happen in a UnitTest or via G4EmCalculator
218 if (fVerboseLevel > 0)
219 {
220 //Issue a G4Exception (warning) only in verbose mode
222 ed << "Unable to retrieve the shell cross section table for Z=" << iZ << G4endl;
223 ed << "This can happen only in Unit Tests or via G4EmCalculator" << G4endl;
224 G4Exception("G4PenelopePhotoElectricModel::ComputeCrossSectionPerAtom()",
225 "em2038",JustWarning,ed);
226 }
227 //protect file reading via autolock
228 G4AutoLock lock(&PenelopePhotoElectricModelMutex);
229 ReadDataFile(iZ);
230 lock.unlock();
231 }
232
233 G4double cross = 0;
234 G4PhysicsTable* theTable = fLogAtomicShellXS[iZ];
235 G4PhysicsFreeVector* totalXSLog = (G4PhysicsFreeVector*) (*theTable)[0];
236
237 if (!totalXSLog)
238 {
239 G4Exception("G4PenelopePhotoElectricModel::ComputeCrossSectionPerAtom()",
240 "em2039",FatalException,
241 "Unable to retrieve the total cross section table");
242 return 0;
243 }
244 G4double logene = G4Log(energy);
245 G4double logXS = totalXSLog->Value(logene);
246 cross = G4Exp(logXS);
247
248 if (fVerboseLevel > 2)
249 G4cout << "Photoelectric cross section at " << energy/MeV << " MeV for Z=" << Z <<
250 " = " << cross/barn << " barn" << G4endl;
251 return cross;
252}
253
254//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
255
256void G4PenelopePhotoElectricModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
257 const G4MaterialCutsCouple* couple,
258 const G4DynamicParticle* aDynamicGamma,
259 G4double,
260 G4double)
261{
262 //
263 // Photoelectric effect, Penelope model v2008
264 //
265 // The target atom and the target shell are sampled according to the Livermore
266 // database
267 // D.E. Cullen et al., Report UCRL-50400 (1989)
268 // The angular distribution of the electron in the final state is sampled
269 // according to the Sauter distribution from
270 // F. Sauter, Ann. Phys. 11 (1931) 454
271 // The energy of the final electron is given by the initial photon energy minus
272 // the binding energy. Fluorescence de-excitation is subsequently produced
273 // (to fill the vacancy) according to the general Geant4 G4DeexcitationManager:
274 // J. Stepanek, Comp. Phys. Comm. 1206 pp 1-1-9 (1997)
275
276 if (fVerboseLevel > 3)
277 G4cout << "Calling SamplingSecondaries() of G4PenelopePhotoElectricModel" << G4endl;
278
279 G4double photonEnergy = aDynamicGamma->GetKineticEnergy();
280
281 // always kill primary
284
285 if (photonEnergy <= fIntrinsicLowEnergyLimit)
286 {
288 return ;
289 }
290
291 G4ParticleMomentum photonDirection = aDynamicGamma->GetMomentumDirection();
292
293 // Select randomly one element in the current material
294 if (fVerboseLevel > 2)
295 G4cout << "Going to select element in " << couple->GetMaterial()->GetName() << G4endl;
296
297 // atom can be selected efficiently if element selectors are initialised
298 const G4Element* anElement =
299 SelectRandomAtom(couple,G4Gamma::GammaDefinition(),photonEnergy);
300 G4int Z = anElement->GetZasInt();
301 if (fVerboseLevel > 2)
302 G4cout << "Selected " << anElement->GetName() << G4endl;
303
304 // Select the ionised shell in the current atom according to shell cross sections
305 //shellIndex = 0 --> K shell
306 // 1-3 --> L shells
307 // 4-8 --> M shells
308 // 9 --> outer shells cumulatively
309 //
310 std::size_t shellIndex = SelectRandomShell(Z,photonEnergy);
311
312 if (fVerboseLevel > 2)
313 G4cout << "Selected shell " << shellIndex << " of element " << anElement->GetName() << G4endl;
314
315 // Retrieve the corresponding identifier and binding energy of the selected shell
317
318 //The number of shell cross section possibly reported in the Penelope database
319 //might be different from the number of shells in the G4AtomicTransitionManager
320 //(namely, Penelope may contain more shell, especially for very light elements).
321 //In order to avoid a warning message from the G4AtomicTransitionManager, I
322 //add this protection. Results are anyway changed, because when G4AtomicTransitionManager
323 //has a shellID>maxID, it sets the shellID to the last valid shell.
324 std::size_t numberOfShells = (std::size_t) transitionManager->NumberOfShells(Z);
325 if (shellIndex >= numberOfShells)
326 shellIndex = numberOfShells-1;
327
328 const G4AtomicShell* shell = fTransitionManager->Shell(Z,shellIndex);
329 G4double bindingEnergy = shell->BindingEnergy();
330
331 //Penelope considers only K, L and M shells. Cross sections of outer shells are
332 //not included in the Penelope database. If SelectRandomShell() returns
333 //shellIndex = 9, it means that an outer shell was ionized. In this case the
334 //Penelope recipe is to set bindingEnergy = 0 (the energy is entirely assigned
335 //to the electron) and to disregard fluorescence.
336 if (shellIndex == 9)
337 bindingEnergy = 0.*eV;
338
339 G4double localEnergyDeposit = 0.0;
340 G4double cosTheta = 1.0;
341
342 // Primary outcoming electron
343 G4double eKineticEnergy = photonEnergy - bindingEnergy;
344
345 // There may be cases where the binding energy of the selected shell is > photon energy
346 // In such cases do not generate secondaries
347 if (eKineticEnergy > 0.)
348 {
349 // The electron is created
350 // Direction sampled from the Sauter distribution
351 cosTheta = SampleElectronDirection(eKineticEnergy);
352 G4double sinTheta = std::sqrt(1-cosTheta*cosTheta);
353 G4double phi = twopi * G4UniformRand() ;
354 G4double dirx = sinTheta * std::cos(phi);
355 G4double diry = sinTheta * std::sin(phi);
356 G4double dirz = cosTheta ;
357 G4ThreeVector electronDirection(dirx,diry,dirz); //electron direction
358 electronDirection.rotateUz(photonDirection);
360 electronDirection,
361 eKineticEnergy);
362 fvect->push_back(electron);
363 }
364 else
365 bindingEnergy = photonEnergy;
366
367 G4double energyInFluorescence = 0; //testing purposes
368 G4double energyInAuger = 0; //testing purposes
369
370 //Now, take care of fluorescence, if required. According to the Penelope
371 //recipe, I have to skip fluoresence completely if shellIndex == 9
372 //(= sampling of a shell outer than K,L,M)
373 if (fAtomDeexcitation && shellIndex<9)
374 {
375 G4int index = couple->GetIndex();
376 if (fAtomDeexcitation->CheckDeexcitationActiveRegion(index))
377 {
378 std::size_t nBefore = fvect->size();
379 fAtomDeexcitation->GenerateParticles(fvect,shell,Z,index);
380 std::size_t nAfter = fvect->size();
381
382 if (nAfter > nBefore) //actual production of fluorescence
383 {
384 for (std::size_t j=nBefore;j<nAfter;++j) //loop on products
385 {
386 G4double itsEnergy = ((*fvect)[j])->GetKineticEnergy();
387 if (itsEnergy < bindingEnergy) // valid secondary, generate it
388 {
389 bindingEnergy -= itsEnergy;
390 if (((*fvect)[j])->GetParticleDefinition() == G4Gamma::Definition())
391 energyInFluorescence += itsEnergy;
392 else if (((*fvect)[j])->GetParticleDefinition() == G4Electron::Definition())
393 energyInAuger += itsEnergy;
394 }
395 else //invalid secondary: takes more than the available energy: delete it
396 {
397 delete (*fvect)[j];
398 (*fvect)[j] = nullptr;
399 }
400 }
401 }
402 }
403 }
404
405 //Residual energy is deposited locally
406 localEnergyDeposit += bindingEnergy;
407
408 if (localEnergyDeposit < 0) //Should not be: issue a G4Exception (warning)
409 {
410 G4Exception("G4PenelopePhotoElectricModel::SampleSecondaries()",
411 "em2099",JustWarning,"WARNING: Negative local energy deposit");
412 localEnergyDeposit = 0;
413 }
414
415 fParticleChange->ProposeLocalEnergyDeposit(localEnergyDeposit);
416
417 if (fVerboseLevel > 1)
418 {
419 G4cout << "-----------------------------------------------------------" << G4endl;
420 G4cout << "Energy balance from G4PenelopePhotoElectric" << G4endl;
421 G4cout << "Selected shell: " << WriteTargetShell(shellIndex) << " of element " <<
422 anElement->GetName() << G4endl;
423 G4cout << "Incoming photon energy: " << photonEnergy/keV << " keV" << G4endl;
424 G4cout << "-----------------------------------------------------------" << G4endl;
425 if (eKineticEnergy)
426 G4cout << "Outgoing electron " << eKineticEnergy/keV << " keV" << G4endl;
427 if (energyInFluorescence)
428 G4cout << "Fluorescence x-rays: " << energyInFluorescence/keV << " keV" << G4endl;
429 if (energyInAuger)
430 G4cout << "Auger electrons: " << energyInAuger/keV << " keV" << G4endl;
431 G4cout << "Local energy deposit " << localEnergyDeposit/keV << " keV" << G4endl;
432 G4cout << "Total final state: " <<
433 (eKineticEnergy+energyInFluorescence+localEnergyDeposit+energyInAuger)/keV <<
434 " keV" << G4endl;
435 G4cout << "-----------------------------------------------------------" << G4endl;
436 }
437 if (fVerboseLevel > 0)
438 {
439 G4double energyDiff =
440 std::fabs(eKineticEnergy+energyInFluorescence+localEnergyDeposit+energyInAuger-photonEnergy);
441 if (energyDiff > 0.05*keV)
442 {
443 G4cout << "Warning from G4PenelopePhotoElectric: problem with energy conservation: " <<
444 (eKineticEnergy+energyInFluorescence+localEnergyDeposit+energyInAuger)/keV
445 << " keV (final) vs. " <<
446 photonEnergy/keV << " keV (initial)" << G4endl;
447 G4cout << "-----------------------------------------------------------" << G4endl;
448 G4cout << "Energy balance from G4PenelopePhotoElectric" << G4endl;
449 G4cout << "Selected shell: " << WriteTargetShell(shellIndex) << " of element " <<
450 anElement->GetName() << G4endl;
451 G4cout << "Incoming photon energy: " << photonEnergy/keV << " keV" << G4endl;
452 G4cout << "-----------------------------------------------------------" << G4endl;
453 if (eKineticEnergy)
454 G4cout << "Outgoing electron " << eKineticEnergy/keV << " keV" << G4endl;
455 if (energyInFluorescence)
456 G4cout << "Fluorescence x-rays: " << energyInFluorescence/keV << " keV" << G4endl;
457 if (energyInAuger)
458 G4cout << "Auger electrons: " << energyInAuger/keV << " keV" << G4endl;
459 G4cout << "Local energy deposit " << localEnergyDeposit/keV << " keV" << G4endl;
460 G4cout << "Total final state: " <<
461 (eKineticEnergy+energyInFluorescence+localEnergyDeposit+energyInAuger)/keV <<
462 " keV" << G4endl;
463 G4cout << "-----------------------------------------------------------" << G4endl;
464 }
465 }
466}
467
468//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
469
470G4double G4PenelopePhotoElectricModel::SampleElectronDirection(G4double energy)
471{
472 G4double costheta = 1.0;
473 if (energy>1*GeV) return costheta;
474
475 //1) initialize energy-dependent variables
476 // Variable naming according to Eq. (2.24) of Penelope Manual
477 // (pag. 44)
478 G4double gamma = 1.0 + energy/electron_mass_c2;
479 G4double gamma2 = gamma*gamma;
480 G4double beta = std::sqrt((gamma2-1.0)/gamma2);
481
482 // ac corresponds to "A" of Eq. (2.31)
483 //
484 G4double ac = (1.0/beta) - 1.0;
485 G4double a1 = 0.5*beta*gamma*(gamma-1.0)*(gamma-2.0);
486 G4double a2 = ac + 2.0;
487 G4double gtmax = 2.0*(a1 + 1.0/ac);
488
489 G4double tsam = 0;
490 G4double gtr = 0;
491
492 //2) sampling. Eq. (2.31) of Penelope Manual
493 // tsam = 1-std::cos(theta)
494 // gtr = rejection function according to Eq. (2.28)
495 do{
496 G4double rand = G4UniformRand();
497 tsam = 2.0*ac * (2.0*rand + a2*std::sqrt(rand)) / (a2*a2 - 4.0*rand);
498 gtr = (2.0 - tsam) * (a1 + 1.0/(ac+tsam));
499 }while(G4UniformRand()*gtmax > gtr);
500 costheta = 1.0-tsam;
501
502 return costheta;
503}
504
505//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
506
507void G4PenelopePhotoElectricModel::ReadDataFile(G4int Z)
508{
509 if (!IsMaster())
510 //Should not be here!
511 G4Exception("G4PenelopePhotoElectricModel::ReadDataFile()",
512 "em0100",FatalException,"Worker thread in this method");
513
514 if (fVerboseLevel > 2)
515 {
516 G4cout << "G4PenelopePhotoElectricModel::ReadDataFile()" << G4endl;
517 G4cout << "Going to read PhotoElectric data files for Z=" << Z << G4endl;
518 }
519
520 const char* path = G4FindDataDir("G4LEDATA");
521 if(!path)
522 {
523 G4String excep = "G4PenelopePhotoElectricModel - G4LEDATA environment variable not set!";
524 G4Exception("G4PenelopePhotoElectricModel::ReadDataFile()",
525 "em0006",FatalException,excep);
526 return;
527 }
528
529 /*
530 Read the cross section file
531 */
532 std::ostringstream ost;
533 if (Z>9)
534 ost << path << "/penelope/photoelectric/pdgph" << Z << ".p08";
535 else
536 ost << path << "/penelope/photoelectric/pdgph0" << Z << ".p08";
537 std::ifstream file(ost.str().c_str());
538 if (!file.is_open())
539 {
540 G4String excep = "G4PenelopePhotoElectricModel - data file " + G4String(ost.str()) + " not found!";
541 G4Exception("G4PenelopePhotoElectricModel::ReadDataFile()",
542 "em0003",FatalException,excep);
543 }
544 //I have to know in advance how many points are in the data list
545 //to initialize the G4PhysicsFreeVector()
546 std::size_t ndata=0;
547 G4String line;
548 while( getline(file, line) )
549 ndata++;
550 ndata -= 1;
551 //G4cout << "Found: " << ndata << " lines" << G4endl;
552
553 file.clear();
554 file.close();
555 file.open(ost.str().c_str());
556
557 G4int readZ =0;
558 std::size_t nShells= 0;
559 file >> readZ >> nShells;
560
561 if (fVerboseLevel > 3)
562 G4cout << "Element Z=" << Z << " , nShells = " << nShells << G4endl;
563
564 //check the right file is opened.
565 if (readZ != Z || nShells <= 0 || nShells > 50) //protect nShell against large values
566 {
568 ed << "Corrupted data file for Z=" << Z << G4endl;
569 G4Exception("G4PenelopePhotoElectricModel::ReadDataFile()",
570 "em0005",FatalException,ed);
571 return;
572 }
573 G4PhysicsTable* thePhysicsTable = new G4PhysicsTable();
574
575 //the table has to contain nShell+1 G4PhysicsFreeVectors,
576 //(theTable)[0] --> total cross section
577 //(theTable)[ishell] --> cross section for shell (ishell-1)
578
579 //reserve space for the vectors
580 //everything is log-log
581 for (std::size_t i=0;i<nShells+1;++i)
582 thePhysicsTable->push_back(new G4PhysicsFreeVector(ndata));
583
584 std::size_t k =0;
585 for (k=0;k<ndata && !file.eof();++k)
586 {
587 G4double energy = 0;
588 G4double aValue = 0;
589 file >> energy ;
590 energy *= eV;
591 G4double logene = G4Log(energy);
592 //loop on the columns
593 for (std::size_t i=0;i<nShells+1;++i)
594 {
595 file >> aValue;
596 aValue *= barn;
597 G4PhysicsFreeVector* theVec = (G4PhysicsFreeVector*) ((*thePhysicsTable)[i]);
598 if (aValue < 1e-40*cm2) //protection against log(0)
599 aValue = 1e-40*cm2;
600 theVec->PutValue(k,logene,G4Log(aValue));
601 }
602 }
603
604 if (fVerboseLevel > 2)
605 {
606 G4cout << "G4PenelopePhotoElectricModel: read " << k << " points for element Z = "
607 << Z << G4endl;
608 }
609
610 fLogAtomicShellXS[Z] = thePhysicsTable;
611
612 file.close();
613 return;
614}
615
616//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
617
619{
620 if (!IsMaster())
621 //Should not be here!
622 G4Exception("G4PenelopePhotoElectricModel::GetNumberOfShellXS()",
623 "em0100",FatalException,"Worker thread in this method");
624
625 //read data files
626 if (!fLogAtomicShellXS[Z])
627 ReadDataFile(Z);
628 //now it should be ok
629 if (!fLogAtomicShellXS[Z])
630 {
632 ed << "Cannot find shell cross section data for Z=" << Z << G4endl;
633 G4Exception("G4PenelopePhotoElectricModel::GetNumberOfShellXS()",
634 "em2038",FatalException,ed);
635 }
636 //one vector is allocated for the _total_ cross section
637 std::size_t nEntries = fLogAtomicShellXS[Z]->entries();
638 return (nEntries-1);
639}
640
641//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
642
644{
645 //this forces also the loading of the data
646 std::size_t entries = GetNumberOfShellXS(Z);
647
648 if (shellID >= entries)
649 {
650 G4cout << "Element Z=" << Z << " has data for " << entries << " shells only" << G4endl;
651 G4cout << "so shellID should be from 0 to " << entries-1 << G4endl;
652 return 0;
653 }
654
655 G4PhysicsTable* theTable = fLogAtomicShellXS[Z];
656 //[0] is the total XS, shellID is in the element [shellID+1]
657 G4PhysicsFreeVector* totalXSLog = (G4PhysicsFreeVector*) (*theTable)[shellID+1];
658
659 if (!totalXSLog)
660 {
661 G4Exception("G4PenelopePhotoElectricModel::GetShellCrossSection()",
662 "em2039",FatalException,
663 "Unable to retrieve the total cross section table");
664 return 0;
665 }
666 G4double logene = G4Log(energy);
667 G4double logXS = totalXSLog->Value(logene);
668 G4double cross = G4Exp(logXS);
669 if (cross < 2e-40*cm2) cross = 0;
670 return cross;
671}
672
673//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
674
675G4String G4PenelopePhotoElectricModel::WriteTargetShell(std::size_t shellID)
676{
677 G4String theShell = "outer shell";
678 if (shellID == 0)
679 theShell = "K";
680 else if (shellID == 1)
681 theShell = "L1";
682 else if (shellID == 2)
683 theShell = "L2";
684 else if (shellID == 3)
685 theShell = "L3";
686 else if (shellID == 4)
687 theShell = "M1";
688 else if (shellID == 5)
689 theShell = "M2";
690 else if (shellID == 6)
691 theShell = "M3";
692 else if (shellID == 7)
693 theShell = "M4";
694 else if (shellID == 8)
695 theShell = "M5";
696
697 return theShell;
698}
699
700//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...
701
702void G4PenelopePhotoElectricModel::SetParticle(const G4ParticleDefinition* p)
703{
704 if(!fParticle) {
705 fParticle = p;
706 }
707}
708
709//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...
710
711std::size_t G4PenelopePhotoElectricModel::SelectRandomShell(G4int Z,G4double energy)
712{
713 G4double logEnergy = G4Log(energy);
714
715 //Check if data have been read (it should be!)
716 if (!fLogAtomicShellXS[Z])
717 {
719 ed << "Cannot find shell cross section data for Z=" << Z << G4endl;
720 G4Exception("G4PenelopePhotoElectricModel::SelectRandomShell()",
721 "em2038",FatalException,ed);
722 }
723
724 G4PhysicsTable* theTable = fLogAtomicShellXS[Z];
725
726 G4double sum = 0;
727 G4PhysicsFreeVector* totalXSLog = (G4PhysicsFreeVector*) (*theTable)[0];
728 G4double logXS = totalXSLog->Value(logEnergy);
729 G4double totalXS = G4Exp(logXS);
730
731 //Notice: totalXS is the total cross section and it does *not* correspond to
732 //the sum of partialXS's, since these include only K, L and M shells.
733 //
734 // Therefore, here one have to consider the possibility of ionisation of
735 // an outer shell. Conventionally, it is indicated with id=10 in Penelope
736 //
737 G4double random = G4UniformRand()*totalXS;
738
739 for (std::size_t k=1;k<theTable->entries();++k)
740 {
741 //Add one shell
742 G4PhysicsFreeVector* partialXSLog = (G4PhysicsFreeVector*) (*theTable)[k];
743 G4double logXSLocal = partialXSLog->Value(logEnergy);
744 G4double partialXS = G4Exp(logXSLocal);
745 sum += partialXS;
746 if (random <= sum)
747 return k-1;
748 }
749 //none of the shells K, L, M: return outer shell
750 return 9;
751}
std::vector< const G4Element * > G4ElementVector
const char * G4FindDataDir(const char *)
@ JustWarning
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:59
std::ostringstream G4ExceptionDescription
Definition: G4Exception.hh:40
G4double G4Exp(G4double initial_x)
Exponential Function double precision.
Definition: G4Exp.hh:180
G4double G4Log(G4double x)
Definition: G4Log.hh:227
#define G4MUTEX_INITIALIZER
Definition: G4Threading.hh:85
std::mutex G4Mutex
Definition: G4Threading.hh:81
@ fStopAndKill
double G4double
Definition: G4Types.hh:83
int G4int
Definition: G4Types.hh:85
const G4int Z[17]
#define G4endl
Definition: G4ios.hh:57
G4GLOB_DLL std::ostream G4cout
#define G4UniformRand()
Definition: Randomize.hh:52
Hep3Vector & rotateUz(const Hep3Vector &)
Definition: ThreeVector.cc:33
G4double BindingEnergy() const
G4AtomicShell * Shell(G4int Z, size_t shellIndex) const
static G4AtomicTransitionManager * Instance()
const G4ThreeVector & GetMomentumDirection() const
G4double GetKineticEnergy() const
static G4Electron * Definition()
Definition: G4Electron.cc:48
static G4Electron * Electron()
Definition: G4Electron.cc:93
const G4String & GetName() const
Definition: G4Element.hh:127
G4int GetZasInt() const
Definition: G4Element.hh:132
static G4Gamma * GammaDefinition()
Definition: G4Gamma.cc:80
static G4Gamma * Definition()
Definition: G4Gamma.cc:48
static G4LossTableManager * Instance()
G4VAtomDeexcitation * AtomDeexcitation()
const G4Material * GetMaterial() const
const G4ElementVector * GetElementVector() const
Definition: G4Material.hh:185
size_t GetNumberOfElements() const
Definition: G4Material.hh:181
const G4String & GetName() const
Definition: G4Material.hh:172
void SetProposedKineticEnergy(G4double proposedKinEnergy)
void Initialise(const G4ParticleDefinition *, const G4DataVector &) override
void InitialiseLocal(const G4ParticleDefinition *, G4VEmModel *masterModel) override
void SampleSecondaries(std::vector< G4DynamicParticle * > *, const G4MaterialCutsCouple *, const G4DynamicParticle *, G4double tmin, G4double maxEnergy) override
G4PenelopePhotoElectricModel(const G4ParticleDefinition *p=nullptr, const G4String &processName="PenPhotoElec")
G4double GetShellCrossSection(G4int Z, std::size_t shellID, G4double energy)
G4double ComputeCrossSectionPerAtom(const G4ParticleDefinition *, G4double kinEnergy, G4double Z, G4double A=0, G4double cut=0, G4double emax=DBL_MAX) override
G4ParticleChangeForGamma * fParticleChange
const G4ParticleDefinition * fParticle
void PutValue(const std::size_t index, const G4double e, const G4double value)
void push_back(G4PhysicsVector *)
void clearAndDestroy()
std::size_t entries() const
G4double Value(const G4double energy, std::size_t &lastidx) const
const G4MaterialCutsCouple * GetMaterialCutsCouple(G4int i) const
std::size_t GetTableSize() const
static G4ProductionCutsTable * GetProductionCutsTable()
G4bool CheckDeexcitationActiveRegion(G4int coupleIndex)
void GenerateParticles(std::vector< G4DynamicParticle * > *secVect, const G4AtomicShell *, G4int Z, G4int coupleIndex)
void SetHighEnergyLimit(G4double)
Definition: G4VEmModel.hh:746
void SetElementSelectors(std::vector< G4EmElementSelector * > *)
Definition: G4VEmModel.hh:831
G4ParticleChangeForGamma * GetParticleChangeForGamma()
Definition: G4VEmModel.cc:124
G4double LowEnergyLimit() const
Definition: G4VEmModel.hh:641
std::vector< G4EmElementSelector * > * GetElementSelectors()
Definition: G4VEmModel.hh:823
G4bool IsMaster() const
Definition: G4VEmModel.hh:725
G4double HighEnergyLimit() const
Definition: G4VEmModel.hh:634
const G4Element * SelectRandomAtom(const G4MaterialCutsCouple *, const G4ParticleDefinition *, G4double kineticEnergy, G4double cutEnergy=0.0, G4double maxEnergy=DBL_MAX)
Definition: G4VEmModel.hh:561
void SetDeexcitationFlag(G4bool val)
Definition: G4VEmModel.hh:802
void InitialiseElementSelectors(const G4ParticleDefinition *, const G4DataVector &)
Definition: G4VEmModel.cc:139
void ProposeTrackStatus(G4TrackStatus status)
void ProposeLocalEnergyDeposit(G4double anEnergyPart)
G4double energy(const ThreeVector &p, const G4double m)