00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include "G4PenelopeComptonModel.hh"
00042 #include "G4PhysicalConstants.hh"
00043 #include "G4SystemOfUnits.hh"
00044 #include "G4ParticleDefinition.hh"
00045 #include "G4MaterialCutsCouple.hh"
00046 #include "G4DynamicParticle.hh"
00047 #include "G4VEMDataSet.hh"
00048 #include "G4PhysicsTable.hh"
00049 #include "G4PhysicsLogVector.hh"
00050 #include "G4AtomicTransitionManager.hh"
00051 #include "G4AtomicShell.hh"
00052 #include "G4Gamma.hh"
00053 #include "G4Electron.hh"
00054 #include "G4PenelopeOscillatorManager.hh"
00055 #include "G4PenelopeOscillator.hh"
00056 #include "G4LossTableManager.hh"
00057
00058
00059
00060
00061 G4PenelopeComptonModel::G4PenelopeComptonModel(const G4ParticleDefinition*,
00062 const G4String& nam)
00063 :G4VEmModel(nam),fParticleChange(0),isInitialised(false),fAtomDeexcitation(0),
00064 oscManager(0)
00065 {
00066 fIntrinsicLowEnergyLimit = 100.0*eV;
00067 fIntrinsicHighEnergyLimit = 100.0*GeV;
00068
00069 SetHighEnergyLimit(fIntrinsicHighEnergyLimit);
00070
00071 oscManager = G4PenelopeOscillatorManager::GetOscillatorManager();
00072
00073 verboseLevel= 0;
00074
00075
00076
00077
00078
00079
00080
00081
00082 SetDeexcitationFlag(true);
00083
00084 fTransitionManager = G4AtomicTransitionManager::Instance();
00085 }
00086
00087
00088
00089 G4PenelopeComptonModel::~G4PenelopeComptonModel()
00090 {;}
00091
00092
00093
00094 void G4PenelopeComptonModel::Initialise(const G4ParticleDefinition*,
00095 const G4DataVector&)
00096 {
00097 if (verboseLevel > 3)
00098 G4cout << "Calling G4PenelopeComptonModel::Initialise()" << G4endl;
00099
00100 fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
00101
00102 if (!fAtomDeexcitation)
00103 {
00104 G4cout << G4endl;
00105 G4cout << "WARNING from G4PenelopeComptonModel " << G4endl;
00106 G4cout << "Atomic de-excitation module is not instantiated, so there will not be ";
00107 G4cout << "any fluorescence/Auger emission." << G4endl;
00108 G4cout << "Please make sure this is intended" << G4endl;
00109 }
00110
00111
00112 if (verboseLevel > 0)
00113 {
00114 G4cout << "Penelope Compton model v2008 is initialized " << G4endl
00115 << "Energy range: "
00116 << LowEnergyLimit() / keV << " keV - "
00117 << HighEnergyLimit() / GeV << " GeV";
00118 }
00119
00120 if(isInitialised) return;
00121 fParticleChange = GetParticleChangeForGamma();
00122 isInitialised = true;
00123
00124 }
00125
00126
00127
00128 G4double G4PenelopeComptonModel::CrossSectionPerVolume(const G4Material* material,
00129 const G4ParticleDefinition* p,
00130 G4double energy,
00131 G4double,
00132 G4double)
00133 {
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145 if (verboseLevel > 3)
00146 G4cout << "Calling CrossSectionPerVolume() of G4PenelopeComptonModel" << G4endl;
00147 SetupForMaterial(p, material, energy);
00148
00149
00150 G4PenelopeOscillatorTable* theTable = oscManager->GetOscillatorTableCompton(material);
00151
00152 G4double cs = 0;
00153
00154 if (energy < 5*MeV)
00155 {
00156 size_t numberOfOscillators = theTable->size();
00157 for (size_t i=0;i<numberOfOscillators;i++)
00158 {
00159 G4PenelopeOscillator* theOsc = (*theTable)[i];
00160
00161 cs += OscillatorTotalCrossSection(energy,theOsc);
00162 }
00163 }
00164 else
00165 cs = KleinNishinaCrossSection(energy,material);
00166
00167
00168 cs *= pi*classic_electr_radius*classic_electr_radius;
00169
00170
00171
00172
00173 G4double atomDensity = material->GetTotNbOfAtomsPerVolume();
00174 G4double atPerMol = oscManager->GetAtomsPerMolecule(material);
00175
00176 if (verboseLevel > 3)
00177 G4cout << "Material " << material->GetName() << " has " << atPerMol <<
00178 "atoms per molecule" << G4endl;
00179
00180 G4double moleculeDensity = 0.;
00181
00182 if (atPerMol)
00183 moleculeDensity = atomDensity/atPerMol;
00184
00185 G4double csvolume = cs*moleculeDensity;
00186
00187 if (verboseLevel > 2)
00188 G4cout << "Compton mean free path at " << energy/keV << " keV for material " <<
00189 material->GetName() << " = " << (1./csvolume)/mm << " mm" << G4endl;
00190 return csvolume;
00191 }
00192
00193
00194
00195
00196
00197
00198 G4double G4PenelopeComptonModel::ComputeCrossSectionPerAtom(const G4ParticleDefinition*,
00199 G4double,
00200 G4double,
00201 G4double,
00202 G4double,
00203 G4double)
00204 {
00205 G4cout << "*** G4PenelopeComptonModel -- WARNING ***" << G4endl;
00206 G4cout << "Penelope Compton model v2008 does not calculate cross section _per atom_ " << G4endl;
00207 G4cout << "so the result is always zero. For physics values, please invoke " << G4endl;
00208 G4cout << "GetCrossSectionPerVolume() or GetMeanFreePath() via the G4EmCalculator" << G4endl;
00209 return 0;
00210 }
00211
00212
00213
00214 void G4PenelopeComptonModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
00215 const G4MaterialCutsCouple* couple,
00216 const G4DynamicParticle* aDynamicGamma,
00217 G4double,
00218 G4double)
00219 {
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241 if (verboseLevel > 3)
00242 G4cout << "Calling SampleSecondaries() of G4PenelopeComptonModel" << G4endl;
00243
00244 G4double photonEnergy0 = aDynamicGamma->GetKineticEnergy();
00245
00246 if (photonEnergy0 <= fIntrinsicLowEnergyLimit)
00247 {
00248 fParticleChange->ProposeTrackStatus(fStopAndKill);
00249 fParticleChange->SetProposedKineticEnergy(0.);
00250 fParticleChange->ProposeLocalEnergyDeposit(photonEnergy0);
00251 return ;
00252 }
00253
00254 G4ParticleMomentum photonDirection0 = aDynamicGamma->GetMomentumDirection();
00255 const G4Material* material = couple->GetMaterial();
00256
00257 G4PenelopeOscillatorTable* theTable = oscManager->GetOscillatorTableCompton(material);
00258
00259 const G4int nmax = 64;
00260 G4double rn[nmax]={0.0};
00261 G4double pac[nmax]={0.0};
00262
00263 G4double S=0.0;
00264 G4double epsilon = 0.0;
00265 G4double cosTheta = 1.0;
00266 G4double hartreeFunc = 0.0;
00267 G4double oscStren = 0.0;
00268 size_t numberOfOscillators = theTable->size();
00269 size_t targetOscillator = 0;
00270 G4double ionEnergy = 0.0*eV;
00271
00272 G4double ek = photonEnergy0/electron_mass_c2;
00273 G4double ek2 = 2.*ek+1.0;
00274 G4double eks = ek*ek;
00275 G4double ek1 = eks-ek2-1.0;
00276
00277 G4double taumin = 1.0/ek2;
00278 G4double a1 = std::log(ek2);
00279 G4double a2 = a1+2.0*ek*(1.0+ek)/(ek2*ek2);
00280
00281 G4double TST = 0;
00282 G4double tau = 0.;
00283
00284
00285
00286 if (photonEnergy0 > 5*MeV)
00287 {
00288 do{
00289 do{
00290 if ((a2*G4UniformRand()) < a1)
00291 tau = std::pow(taumin,G4UniformRand());
00292 else
00293 tau = std::sqrt(1.0+G4UniformRand()*(taumin*taumin-1.0));
00294
00295 TST = (1.0+tau*(ek1+tau*(ek2+tau*eks)))/(eks*tau*(1.0+tau*tau));
00296 }while (G4UniformRand()> TST);
00297 epsilon=tau;
00298 cosTheta = 1.0 - (1.0-tau)/(ek*tau);
00299
00300
00301 TST = oscManager->GetTotalZ(material)*G4UniformRand();
00302 targetOscillator = numberOfOscillators-1;
00303 S=0.0;
00304 G4bool levelFound = false;
00305 for (size_t j=0;j<numberOfOscillators && !levelFound; j++)
00306 {
00307 S += (*theTable)[j]->GetOscillatorStrength();
00308 if (S > TST)
00309 {
00310 targetOscillator = j;
00311 levelFound = true;
00312 }
00313 }
00314
00315 ionEnergy = (*theTable)[targetOscillator]->GetIonisationEnergy();
00316 }while((epsilon*photonEnergy0-photonEnergy0+ionEnergy) >0);
00317 }
00318 else
00319 {
00320
00321 G4double s0=0.0;
00322 G4double pzomc=0.0;
00323 G4double rni=0.0;
00324 G4double aux=0.0;
00325 for (size_t i=0;i<numberOfOscillators;i++)
00326 {
00327 ionEnergy = (*theTable)[i]->GetIonisationEnergy();
00328 if (photonEnergy0 > ionEnergy)
00329 {
00330 G4double aux2 = photonEnergy0*(photonEnergy0-ionEnergy)*2.0;
00331 hartreeFunc = (*theTable)[i]->GetHartreeFactor();
00332 oscStren = (*theTable)[i]->GetOscillatorStrength();
00333 pzomc = hartreeFunc*(aux2-electron_mass_c2*ionEnergy)/
00334 (electron_mass_c2*std::sqrt(2.0*aux2+ionEnergy*ionEnergy));
00335 if (pzomc > 0)
00336 rni = 1.0-0.5*std::exp(0.5-(std::sqrt(0.5)+std::sqrt(2.0)*pzomc)*
00337 (std::sqrt(0.5)+std::sqrt(2.0)*pzomc));
00338 else
00339 rni = 0.5*std::exp(0.5-(std::sqrt(0.5)-std::sqrt(2.0)*pzomc)*
00340 (std::sqrt(0.5)-std::sqrt(2.0)*pzomc));
00341 s0 += oscStren*rni;
00342 }
00343 }
00344
00345 G4double cdt1 = 0.;
00346 do
00347 {
00348 if ((G4UniformRand()*a2) < a1)
00349 tau = std::pow(taumin,G4UniformRand());
00350 else
00351 tau = std::sqrt(1.0+G4UniformRand()*(taumin*taumin-1.0));
00352 cdt1 = (1.0-tau)/(ek*tau);
00353
00354 S = 0.;
00355 for (size_t i=0;i<numberOfOscillators;i++)
00356 {
00357 ionEnergy = (*theTable)[i]->GetIonisationEnergy();
00358 if (photonEnergy0 > ionEnergy)
00359 {
00360 aux = photonEnergy0*(photonEnergy0-ionEnergy)*cdt1;
00361 hartreeFunc = (*theTable)[i]->GetHartreeFactor();
00362 oscStren = (*theTable)[i]->GetOscillatorStrength();
00363 pzomc = hartreeFunc*(aux-electron_mass_c2*ionEnergy)/
00364 (electron_mass_c2*std::sqrt(2.0*aux+ionEnergy*ionEnergy));
00365 if (pzomc > 0)
00366 rn[i] = 1.0-0.5*std::exp(0.5-(std::sqrt(0.5)+std::sqrt(2.0)*pzomc)*
00367 (std::sqrt(0.5)+std::sqrt(2.0)*pzomc));
00368 else
00369 rn[i] = 0.5*std::exp(0.5-(std::sqrt(0.5)-std::sqrt(2.0)*pzomc)*
00370 (std::sqrt(0.5)-std::sqrt(2.0)*pzomc));
00371 S += oscStren*rn[i];
00372 pac[i] = S;
00373 }
00374 else
00375 pac[i] = S-1e-6;
00376 }
00377
00378 TST = S*(1.0+tau*(ek1+tau*(ek2+tau*eks)))/(eks*tau*(1.0+tau*tau));
00379 }while ((G4UniformRand()*s0) > TST);
00380
00381 cosTheta = 1.0 - cdt1;
00382 G4double fpzmax=0.0,fpz=0.0;
00383 G4double A=0.0;
00384
00385 do
00386 {
00387 do
00388 {
00389 TST = S*G4UniformRand();
00390 targetOscillator = numberOfOscillators-1;
00391 G4bool levelFound = false;
00392 for (size_t i=0;i<numberOfOscillators && !levelFound;i++)
00393 {
00394 if (pac[i]>TST)
00395 {
00396 targetOscillator = i;
00397 levelFound = true;
00398 }
00399 }
00400 A = G4UniformRand()*rn[targetOscillator];
00401 hartreeFunc = (*theTable)[targetOscillator]->GetHartreeFactor();
00402 oscStren = (*theTable)[targetOscillator]->GetOscillatorStrength();
00403 if (A < 0.5)
00404 pzomc = (std::sqrt(0.5)-std::sqrt(0.5-std::log(2.0*A)))/
00405 (std::sqrt(2.0)*hartreeFunc);
00406 else
00407 pzomc = (std::sqrt(0.5-std::log(2.0-2.0*A))-std::sqrt(0.5))/
00408 (std::sqrt(2.0)*hartreeFunc);
00409 } while (pzomc < -1);
00410
00411
00412 G4double XQC = 1.0+tau*(tau-2.0*cosTheta);
00413 G4double AF = std::sqrt(XQC)*(1.0+tau*(tau-cosTheta)/XQC);
00414 if (AF > 0)
00415 fpzmax = 1.0+AF*0.2;
00416 else
00417 fpzmax = 1.0-AF*0.2;
00418 fpz = 1.0+AF*std::max(std::min(pzomc,0.2),-0.2);
00419 }while ((fpzmax*G4UniformRand())>fpz);
00420
00421
00422 G4double T = pzomc*pzomc;
00423 G4double b1 = 1.0-T*tau*tau;
00424 G4double b2 = 1.0-T*tau*cosTheta;
00425 if (pzomc > 0.0)
00426 epsilon = (tau/b1)*(b2+std::sqrt(std::abs(b2*b2-b1*(1.0-T))));
00427 else
00428 epsilon = (tau/b1)*(b2-std::sqrt(std::abs(b2*b2-b1*(1.0-T))));
00429 }
00430
00431
00432 G4double sinTheta = std::sqrt(1-cosTheta*cosTheta);
00433 G4double phi = twopi * G4UniformRand() ;
00434 G4double dirx = sinTheta * std::cos(phi);
00435 G4double diry = sinTheta * std::sin(phi);
00436 G4double dirz = cosTheta ;
00437
00438
00439 G4ThreeVector photonDirection1(dirx,diry,dirz);
00440 photonDirection1.rotateUz(photonDirection0);
00441 fParticleChange->ProposeMomentumDirection(photonDirection1) ;
00442
00443 G4double photonEnergy1 = epsilon * photonEnergy0;
00444
00445 if (photonEnergy1 > 0.)
00446 fParticleChange->SetProposedKineticEnergy(photonEnergy1) ;
00447 else
00448 {
00449 fParticleChange->SetProposedKineticEnergy(0.) ;
00450 fParticleChange->ProposeTrackStatus(fStopAndKill);
00451 }
00452
00453
00454 G4double diffEnergy = photonEnergy0*(1-epsilon);
00455 ionEnergy = (*theTable)[targetOscillator]->GetIonisationEnergy();
00456
00457 G4double Q2 =
00458 photonEnergy0*photonEnergy0+photonEnergy1*(photonEnergy1-2.0*photonEnergy0*cosTheta);
00459 G4double cosThetaE = 0.;
00460
00461 if (Q2 > 1.0e-12)
00462 cosThetaE = (photonEnergy0-photonEnergy1*cosTheta)/std::sqrt(Q2);
00463 else
00464 cosThetaE = 1.0;
00465 G4double sinThetaE = std::sqrt(1-cosThetaE*cosThetaE);
00466
00467
00468
00469 G4int shFlag = (*theTable)[targetOscillator]->GetShellFlag();
00470 G4int Z = (G4int) (*theTable)[targetOscillator]->GetParentZ();
00471
00472
00473 G4double bindingEnergy = 0.*eV;
00474 const G4AtomicShell* shell = 0;
00475
00476
00477 if (Z > 0 && shFlag<30)
00478 {
00479 shell = fTransitionManager->Shell(Z,shFlag-1);
00480 bindingEnergy = shell->BindingEnergy();
00481 }
00482
00483 G4double ionEnergyInPenelopeDatabase = ionEnergy;
00484
00485 ionEnergy = std::max(bindingEnergy,ionEnergyInPenelopeDatabase);
00486
00487
00488
00489 G4double eKineticEnergy = diffEnergy - ionEnergy;
00490 G4double localEnergyDeposit = ionEnergy;
00491 G4double energyInFluorescence = 0.;
00492 G4double energyInAuger = 0;
00493
00494 if (eKineticEnergy < 0)
00495 {
00496
00497
00498
00499
00500 localEnergyDeposit = diffEnergy;
00501 eKineticEnergy = 0.0;
00502 }
00503
00504
00505
00506
00507 if (fAtomDeexcitation && shell)
00508 {
00509 G4int index = couple->GetIndex();
00510 if (fAtomDeexcitation->CheckDeexcitationActiveRegion(index))
00511 {
00512 size_t nBefore = fvect->size();
00513 fAtomDeexcitation->GenerateParticles(fvect,shell,Z,index);
00514 size_t nAfter = fvect->size();
00515
00516 if (nAfter > nBefore)
00517 {
00518 for (size_t j=nBefore;j<nAfter;j++)
00519 {
00520 G4double itsEnergy = ((*fvect)[j])->GetKineticEnergy();
00521 localEnergyDeposit -= itsEnergy;
00522 if (((*fvect)[j])->GetParticleDefinition() == G4Gamma::Definition())
00523 energyInFluorescence += itsEnergy;
00524 else if (((*fvect)[j])->GetParticleDefinition() == G4Electron::Definition())
00525 energyInAuger += itsEnergy;
00526
00527 }
00528 }
00529
00530 }
00531 }
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602 G4DynamicParticle* electron = 0;
00603
00604 G4double xEl = sinThetaE * std::cos(phi+pi);
00605 G4double yEl = sinThetaE * std::sin(phi+pi);
00606 G4double zEl = cosThetaE;
00607 G4ThreeVector eDirection(xEl,yEl,zEl);
00608 eDirection.rotateUz(photonDirection0);
00609 electron = new G4DynamicParticle (G4Electron::Electron(),
00610 eDirection,eKineticEnergy) ;
00611 fvect->push_back(electron);
00612
00613
00614 if (localEnergyDeposit < 0)
00615 {
00616 G4cout << "WARNING-"
00617 << "G4PenelopeComptonModel::SampleSecondaries - Negative energy deposit"
00618 << G4endl;
00619 localEnergyDeposit=0.;
00620 }
00621 fParticleChange->ProposeLocalEnergyDeposit(localEnergyDeposit);
00622
00623 G4double electronEnergy = 0.;
00624 if (electron)
00625 electronEnergy = eKineticEnergy;
00626 if (verboseLevel > 1)
00627 {
00628 G4cout << "-----------------------------------------------------------" << G4endl;
00629 G4cout << "Energy balance from G4PenelopeCompton" << G4endl;
00630 G4cout << "Incoming photon energy: " << photonEnergy0/keV << " keV" << G4endl;
00631 G4cout << "-----------------------------------------------------------" << G4endl;
00632 G4cout << "Scattered photon: " << photonEnergy1/keV << " keV" << G4endl;
00633 G4cout << "Scattered electron " << electronEnergy/keV << " keV" << G4endl;
00634 if (energyInFluorescence)
00635 G4cout << "Fluorescence x-rays: " << energyInFluorescence/keV << " keV" << G4endl;
00636 if (energyInAuger)
00637 G4cout << "Auger electrons: " << energyInAuger/keV << " keV" << G4endl;
00638 G4cout << "Local energy deposit " << localEnergyDeposit/keV << " keV" << G4endl;
00639 G4cout << "Total final state: " << (photonEnergy1+electronEnergy+energyInFluorescence+
00640 localEnergyDeposit+energyInAuger)/keV <<
00641 " keV" << G4endl;
00642 G4cout << "-----------------------------------------------------------" << G4endl;
00643 }
00644 if (verboseLevel > 0)
00645 {
00646 G4double energyDiff = std::fabs(photonEnergy1+
00647 electronEnergy+energyInFluorescence+
00648 localEnergyDeposit+energyInAuger-photonEnergy0);
00649 if (energyDiff > 0.05*keV)
00650 G4cout << "Warning from G4PenelopeCompton: problem with energy conservation: " <<
00651 (photonEnergy1+electronEnergy+energyInFluorescence+energyInAuger+localEnergyDeposit)/keV <<
00652 " keV (final) vs. " <<
00653 photonEnergy0/keV << " keV (initial)" << G4endl;
00654 }
00655 }
00656
00657
00658
00659 G4double G4PenelopeComptonModel::DifferentialCrossSection(G4double cosTheta,G4double energy,
00660 G4PenelopeOscillator* osc)
00661 {
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673 G4double ionEnergy = osc->GetIonisationEnergy();
00674 G4double harFunc = osc->GetHartreeFactor();
00675
00676 const G4double k2 = std::sqrt(2.);
00677 const G4double k1 = 1./k2;
00678
00679 if (energy < ionEnergy)
00680 return 0;
00681
00682
00683 G4double cdt1 = 1.0-cosTheta;
00684 G4double EOEC = 1.0+(energy/electron_mass_c2)*cdt1;
00685 G4double ECOE = 1.0/EOEC;
00686
00687
00688 G4double aux = energy*(energy-ionEnergy)*cdt1;
00689 G4double Pzimax =
00690 (aux - electron_mass_c2*ionEnergy)/(electron_mass_c2*std::sqrt(2*aux+ionEnergy*ionEnergy));
00691 G4double sia = 0.0;
00692 G4double x = harFunc*Pzimax;
00693 if (x > 0)
00694 sia = 1.0-0.5*std::exp(0.5-(k1+k2*x)*(k1+k2*x));
00695 else
00696 sia = 0.5*std::exp(0.5-(k1-k2*x)*(k1-k2*x));
00697
00698
00699
00700 G4double pf = 3.0/(4.0*harFunc);
00701 if (std::fabs(Pzimax) < pf)
00702 {
00703 G4double QCOE2 = 1.0+ECOE*ECOE-2.0*ECOE*cosTheta;
00704 G4double p2 = Pzimax*Pzimax;
00705 G4double dspz = std::sqrt(QCOE2)*
00706 (1.0+ECOE*(ECOE-cosTheta)/QCOE2)*harFunc
00707 *0.25*(2*p2-(p2*p2)/(pf*pf)-(pf*pf));
00708 sia += std::max(dspz,-1.0*sia);
00709 }
00710
00711 G4double XKN = EOEC+ECOE-1.0+cosTheta*cosTheta;
00712
00713
00714 G4double diffCS = ECOE*ECOE*XKN*sia;
00715
00716 return diffCS;
00717 }
00718
00719
00720
00721 G4double G4PenelopeComptonModel::OscillatorTotalCrossSection(G4double energy,G4PenelopeOscillator* osc)
00722 {
00723
00724
00725
00726
00727 G4double stre = osc->GetOscillatorStrength();
00728
00729
00730
00731 const G4int npoints=10;
00732 const G4int ncallsmax=20000;
00733 const G4int nst=256;
00734 static G4double Abscissas[10] = {7.652651133497334e-02,2.2778585114164508e-01,3.7370608871541956e-01,
00735 5.1086700195082710e-01,6.3605368072651503e-01,7.4633190646015079e-01,
00736 8.3911697182221882e-01,9.1223442825132591e-01,9.6397192727791379e-01,
00737 9.9312859918509492e-01};
00738 static G4double Weights[10] = {1.5275338713072585e-01,1.4917298647260375e-01,1.4209610931838205e-01,
00739 1.3168863844917663e-01,1.1819453196151842e-01,1.0193011981724044e-01,
00740 8.3276741576704749e-02,6.2672048334109064e-02,4.0601429800386941e-02,
00741 1.7614007139152118e-02};
00742
00743 G4double MaxError = 1e-5;
00744
00745 G4double Ctol = std::min(std::max(MaxError,1e-13),1e-02);
00746 G4double Ptol = 0.01*Ctol;
00747 G4double Err=1e35;
00748
00749
00750 G4double LowPoint = -1.0;
00751 G4double HighPoint = 1.0;
00752
00753 G4double h=HighPoint-LowPoint;
00754 G4double sumga=0.0;
00755 G4double a=0.5*(HighPoint-LowPoint);
00756 G4double b=0.5*(HighPoint+LowPoint);
00757 G4double c=a*Abscissas[0];
00758 G4double d= Weights[0]*
00759 (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
00760 for (G4int i=2;i<=npoints;i++)
00761 {
00762 c=a*Abscissas[i-1];
00763 d += Weights[i-1]*
00764 (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
00765 }
00766 G4int icall = 2*npoints;
00767 G4int LH=1;
00768 G4double S[nst],x[nst],sn[nst],xrn[nst];
00769 S[0]=d*a;
00770 x[0]=LowPoint;
00771
00772 G4bool loopAgain = true;
00773
00774
00775 do{
00776 G4double h0=h;
00777 h=0.5*h;
00778 G4double sumr=0;
00779 G4int LHN=0;
00780 G4double si,xa,xb,xc;
00781 for (G4int i=1;i<=LH;i++){
00782 si=S[i-1];
00783 xa=x[i-1];
00784 xb=xa+h;
00785 xc=xa+h0;
00786 a=0.5*(xb-xa);
00787 b=0.5*(xb+xa);
00788 c=a*Abscissas[0];
00789 G4double dLocal = Weights[0]*
00790 (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
00791
00792 for (G4int j=1;j<npoints;j++)
00793 {
00794 c=a*Abscissas[j];
00795 dLocal += Weights[j]*
00796 (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
00797 }
00798 G4double s1=dLocal*a;
00799 a=0.5*(xc-xb);
00800 b=0.5*(xc+xb);
00801 c=a*Abscissas[0];
00802 dLocal=Weights[0]*
00803 (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
00804
00805 for (G4int j=1;j<npoints;j++)
00806 {
00807 c=a*Abscissas[j];
00808 dLocal += Weights[j]*
00809 (DifferentialCrossSection(b+c,energy,osc)+DifferentialCrossSection(b-c,energy,osc));
00810 }
00811 G4double s2=dLocal*a;
00812 icall=icall+4*npoints;
00813 G4double s12=s1+s2;
00814 if (std::abs(s12-si)<std::max(Ptol*std::abs(s12),1e-35))
00815 sumga += s12;
00816 else
00817 {
00818 sumr += s12;
00819 LHN += 2;
00820 sn[LHN-1]=s2;
00821 xrn[LHN-1]=xb;
00822 sn[LHN-2]=s1;
00823 xrn[LHN-2]=xa;
00824 }
00825
00826 if (icall>ncallsmax || LHN>nst)
00827 {
00828 G4cout << "G4PenelopeComptonModel: " << G4endl;
00829 G4cout << "LowPoint: " << LowPoint << ", High Point: " << HighPoint << G4endl;
00830 G4cout << "Tolerance: " << MaxError << G4endl;
00831 G4cout << "Calls: " << icall << ", Integral: " << sumga << ", Error: " << Err << G4endl;
00832 G4cout << "Number of open subintervals: " << LHN << G4endl;
00833 G4cout << "WARNING: the required accuracy has not been attained" << G4endl;
00834 loopAgain = false;
00835 }
00836 }
00837 Err=std::abs(sumr)/std::max(std::abs(sumr+sumga),1e-35);
00838 if (Err < Ctol || LHN == 0)
00839 loopAgain = false;
00840 LH=LHN;
00841 for (G4int i=0;i<LH;i++)
00842 {
00843 S[i]=sn[i];
00844 x[i]=xrn[i];
00845 }
00846 }while(Ctol < 1.0 && loopAgain);
00847
00848
00849 G4double xs = stre*sumga;
00850
00851 return xs;
00852 }
00853
00854
00855
00856 G4double G4PenelopeComptonModel::KleinNishinaCrossSection(G4double energy,
00857 const G4Material* material)
00858 {
00859
00860
00861
00862 G4double cs = 0;
00863
00864 G4double ek =energy/electron_mass_c2;
00865 G4double eks = ek*ek;
00866 G4double ek2 = 1.0+ek+ek;
00867 G4double ek1 = eks-ek2-1.0;
00868
00869 G4double t0 = 1.0/ek2;
00870 G4double csl = 0.5*eks*t0*t0+ek2*t0+ek1*std::log(t0)-(1.0/t0);
00871
00872 G4PenelopeOscillatorTable* theTable = oscManager->GetOscillatorTableCompton(material);
00873
00874 for (size_t i=0;i<theTable->size();i++)
00875 {
00876 G4PenelopeOscillator* theOsc = (*theTable)[i];
00877 G4double ionEnergy = theOsc->GetIonisationEnergy();
00878 G4double tau=(energy-ionEnergy)/energy;
00879 if (tau > t0)
00880 {
00881 G4double csu = 0.5*eks*tau*tau+ek2*tau+ek1*std::log(tau)-(1.0/tau);
00882 G4double stre = theOsc->GetOscillatorStrength();
00883
00884 cs += stre*(csu-csl);
00885 }
00886 }
00887
00888 cs /= (ek*eks);
00889
00890 return cs;
00891
00892 }
00893