Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-31 09:22:07

0001 //
0002 // ********************************************************************
0003 // * License and Disclaimer                                           *
0004 // *                                                                  *
0005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
0006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
0007 // * conditions of the Geant4 Software License,  included in the file *
0008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
0009 // * include a list of copyright holders.                             *
0010 // *                                                                  *
0011 // * Neither the authors of this software system, nor their employing *
0012 // * institutes,nor the agencies providing financial support for this *
0013 // * work  make  any representation or  warranty, express or implied, *
0014 // * regarding  this  software system or assume any liability for its *
0015 // * use.  Please see the license in the file  LICENSE  and URL above *
0016 // * for the full disclaimer and the limitation of liability.         *
0017 // *                                                                  *
0018 // * This  code  implementation is the result of  the  scientific and *
0019 // * technical work of the GEANT4 collaboration.                      *
0020 // * By using,  copying,  modifying or  distributing the software (or *
0021 // * any work based  on the software)  you  agree  to acknowledge its *
0022 // * use  in  resulting  scientific  publications,  and indicate your *
0023 // * acceptance of all terms of the Geant4 Software license.          *
0024 // ********************************************************************
0025 //
0026 //
0027 // -------------------------------------------------------------------
0028 //
0029 // GEANT4 Class file
0030 //
0031 //
0032 // File name:     G4RDeIonisationSpectrum
0033 //
0034 // Author:        V.Ivanchenko (Vladimir.Ivanchenko@cern.ch)
0035 // 
0036 // Creation date: 29 September 2001
0037 //
0038 // Modifications: 
0039 // 10.10.2001 MGP           Revision to improve code quality and 
0040 //                          consistency with design
0041 // 02.11.2001 VI            Optimize sampling of energy 
0042 // 29.11.2001 VI            New parametrisation 
0043 // 19.04.2002 VI            Add protection in case of energy below binding  
0044 // 30.05.2002 VI            Update to 24-parameters data
0045 // 11.07.2002 VI            Fix in integration over spectrum
0046 //
0047 // -------------------------------------------------------------------
0048 //
0049 
0050 #include "G4RDeIonisationSpectrum.hh"
0051 #include "G4RDAtomicTransitionManager.hh"
0052 #include "G4RDAtomicShell.hh"
0053 #include "G4PhysicalConstants.hh"
0054 #include "G4SystemOfUnits.hh"
0055 #include "G4DataVector.hh"
0056 #include "Randomize.hh"
0057 
0058 
0059 G4RDeIonisationSpectrum::G4RDeIonisationSpectrum():G4RDVEnergySpectrum(),
0060   lowestE(0.1*eV),
0061   factor(1.3),
0062   iMax(24),
0063   verbose(0)
0064 {
0065   theParam = new G4RDeIonisationParameters();
0066 }
0067 
0068 
0069 G4RDeIonisationSpectrum::~G4RDeIonisationSpectrum() 
0070 {
0071   delete theParam;
0072 }
0073 
0074 
0075 G4double G4RDeIonisationSpectrum::Probability(G4int Z, 
0076                             G4double tMin, 
0077                         G4double tMax, 
0078                         G4double e,
0079                         G4int shell,
0080                         const G4ParticleDefinition* ) const
0081 {
0082   // Please comment what Probability does and what are the three 
0083   // functions mentioned below
0084   // Describe the algorithms used
0085 
0086   G4double eMax = MaxEnergyOfSecondaries(e);
0087   G4double t0 = std::max(tMin, lowestE);
0088   G4double tm = std::min(tMax, eMax);
0089   if(t0 >= tm) return 0.0;
0090 
0091   G4double bindingEnergy = (G4RDAtomicTransitionManager::Instance())->
0092                            Shell(Z, shell)->BindingEnergy();
0093 
0094   if(e <= bindingEnergy) return 0.0;
0095 
0096   G4double energy = e + bindingEnergy;
0097 
0098   G4double x1 = std::min(0.5,(t0 + bindingEnergy)/energy);
0099   G4double x2 = std::min(0.5,(tm + bindingEnergy)/energy);
0100 
0101   if(verbose > 1 || (Z==4 && e>= 1.0 && e<= 0.0)) {
0102     G4cout << "G4RDeIonisationSpectrum::Probability: Z= " << Z
0103            << "; shell= " << shell
0104            << "; E(keV)= " << e/keV
0105            << "; Eb(keV)= " << bindingEnergy/keV
0106            << "; x1= " << x1 
0107            << "; x2= " << x2 
0108            << G4endl;
0109      
0110   }
0111 
0112   G4DataVector p;
0113 
0114   // Access parameters
0115   for (G4int i=0; i<iMax; i++) 
0116   {
0117     G4double x = theParam->Parameter(Z, shell, i, e);
0118     if(i<4) x /= energy; 
0119     p.push_back(x); 
0120   }
0121 
0122   if(p[3] > 0.5) p[3] = 0.5;
0123   
0124   G4double g = energy/electron_mass_c2 + 1.;
0125   p.push_back((2.0*g - 1.0)/(g*g));
0126   
0127   p[iMax-1] = Function(p[3], p);
0128 
0129   if(e >= 1. && e <= 0. && Z == 4) p.push_back(0.0);
0130 
0131   
0132   G4double val = IntSpectrum(x1, x2, p);
0133   G4double x0  = (lowestE + bindingEnergy)/energy;
0134   G4double nor = IntSpectrum(x0, 0.5, p);
0135   
0136   if(verbose > 1 || (Z==4 && e>= 1.0 && e<= 0.0)) {
0137     G4cout << "tcut= " << tMin 
0138            << "; tMax= " << tMax 
0139            << "; x0= " << x0 
0140            << "; x1= " << x1 
0141            << "; x2= " << x2 
0142            << "; val= " << val 
0143            << "; nor= " << nor 
0144            << "; sum= " << p[0] 
0145            << "; a= " << p[1] 
0146            << "; b= " << p[2] 
0147            << "; c= " << p[3] 
0148            << G4endl;
0149     if(shell == 1) G4cout << "============" << G4endl; 
0150   }
0151 
0152   p.clear();
0153 
0154   if(nor > 0.0) val /= nor;
0155   else          val  = 0.0;
0156 
0157   return val; 
0158 }
0159 
0160 
0161 G4double G4RDeIonisationSpectrum::AverageEnergy(G4int Z,
0162                               G4double tMin, 
0163                           G4double tMax, 
0164                           G4double e,
0165                           G4int shell,
0166                           const G4ParticleDefinition* ) const
0167 {
0168   // Please comment what AverageEnergy does and what are the three 
0169   // functions mentioned below
0170   // Describe the algorithms used
0171 
0172   G4double eMax = MaxEnergyOfSecondaries(e);
0173   G4double t0 = std::max(tMin, lowestE);
0174   G4double tm = std::min(tMax, eMax);
0175   if(t0 >= tm) return 0.0;
0176 
0177   G4double bindingEnergy = (G4RDAtomicTransitionManager::Instance())->
0178                            Shell(Z, shell)->BindingEnergy();
0179 
0180   if(e <= bindingEnergy) return 0.0;
0181 
0182   G4double energy = e + bindingEnergy;
0183 
0184   G4double x1 = std::min(0.5,(t0 + bindingEnergy)/energy);
0185   G4double x2 = std::min(0.5,(tm + bindingEnergy)/energy);
0186 
0187   if(verbose > 1) {
0188     G4cout << "G4RDeIonisationSpectrum::AverageEnergy: Z= " << Z
0189            << "; shell= " << shell
0190            << "; E(keV)= " << e/keV
0191            << "; bindingE(keV)= " << bindingEnergy/keV
0192            << "; x1= " << x1 
0193            << "; x2= " << x2 
0194            << G4endl;
0195   }
0196 
0197   G4DataVector p;
0198 
0199   // Access parameters
0200   for (G4int i=0; i<iMax; i++) 
0201   {
0202     G4double x = theParam->Parameter(Z, shell, i, e);
0203     if(i<4) x /= energy; 
0204     p.push_back(x);
0205   }
0206 
0207   if(p[3] > 0.5) p[3] = 0.5;
0208 
0209   G4double g = energy/electron_mass_c2 + 1.;
0210   p.push_back((2.0*g - 1.0)/(g*g));
0211 
0212   p[iMax-1] = Function(p[3], p);
0213     
0214   G4double val = AverageValue(x1, x2, p);
0215   G4double x0  = (lowestE + bindingEnergy)/energy;
0216   G4double nor = IntSpectrum(x0, 0.5, p);
0217   val *= energy;
0218 
0219   if(verbose > 1) {
0220     G4cout << "tcut(MeV)= " << tMin/MeV 
0221            << "; tMax(MeV)= " << tMax/MeV 
0222            << "; x0= " << x0 
0223            << "; x1= " << x1 
0224            << "; x2= " << x2 
0225            << "; val= " << val 
0226            << "; nor= " << nor 
0227            << "; sum= " << p[0] 
0228            << "; a= " << p[1] 
0229            << "; b= " << p[2] 
0230            << "; c= " << p[3] 
0231            << G4endl;
0232   }
0233 
0234   p.clear();
0235 
0236   if(nor > 0.0) val /= nor;
0237   else          val  = 0.0;
0238 
0239   return val; 
0240 }
0241 
0242 
0243 G4double G4RDeIonisationSpectrum::SampleEnergy(G4int Z,
0244                          G4double tMin, 
0245                          G4double tMax, 
0246                              G4double e,
0247                              G4int shell,
0248                          const G4ParticleDefinition* ) const
0249 {
0250   // Please comment what SampleEnergy does
0251   G4double tDelta = 0.0;
0252   G4double t0 = std::max(tMin, lowestE);
0253   G4double tm = std::min(tMax, MaxEnergyOfSecondaries(e));
0254   if(t0 > tm) return tDelta;
0255 
0256   G4double bindingEnergy = (G4RDAtomicTransitionManager::Instance())->
0257                            Shell(Z, shell)->BindingEnergy();
0258 
0259   if(e <= bindingEnergy) return 0.0;
0260 
0261   G4double energy = e + bindingEnergy;
0262 
0263   G4double x1 = std::min(0.5,(t0 + bindingEnergy)/energy);
0264   G4double x2 = std::min(0.5,(tm + bindingEnergy)/energy);
0265   if(x1 >= x2) return tDelta;
0266 
0267   if(verbose > 1) {
0268     G4cout << "G4RDeIonisationSpectrum::SampleEnergy: Z= " << Z
0269            << "; shell= " << shell
0270            << "; E(keV)= " << e/keV
0271            << G4endl;
0272   }
0273 
0274   // Access parameters
0275   G4DataVector p;
0276 
0277   // Access parameters
0278   for (G4int i=0; i<iMax; i++) 
0279   {
0280     G4double x = theParam->Parameter(Z, shell, i, e);
0281     if(i<4) x /= energy; 
0282     p.push_back(x);
0283   }
0284 
0285   if(p[3] > 0.5) p[3] = 0.5;
0286 
0287   G4double g = energy/electron_mass_c2 + 1.;
0288   p.push_back((2.0*g - 1.0)/(g*g));
0289 
0290   p[iMax-1] = Function(p[3], p);
0291 
0292   G4double aria1 = 0.0;
0293   G4double a1 = std::max(x1,p[1]);
0294   G4double a2 = std::min(x2,p[3]);
0295   if(a1 < a2) aria1 = IntSpectrum(a1, a2, p);
0296   G4double aria2 = 0.0;
0297   G4double a3 = std::max(x1,p[3]);
0298   G4double a4 = x2;
0299   if(a3 < a4) aria2 = IntSpectrum(a3, a4, p);
0300 
0301   G4double aria = (aria1 + aria2)*G4UniformRand();
0302   G4double amaj, fun, q, x, z1, z2, dx, dx1;
0303 
0304   //======= First aria to sample =====
0305 
0306   if(aria <= aria1) { 
0307 
0308     amaj = p[4];
0309     for (G4int j=5; j<iMax; j++) {
0310       if(p[j] > amaj) amaj = p[j];
0311     }
0312 
0313     a1 = 1./a1;
0314     a2 = 1./a2;
0315 
0316     G4int i;
0317     do {
0318 
0319       x = 1./(a2 + G4UniformRand()*(a1 - a2));
0320       z1 = p[1];
0321       z2 = p[3];
0322       dx = (p[2] - p[1]) / 3.0;
0323       dx1= std::exp(std::log(p[3]/p[2]) / 16.0);
0324       for (i=4; i<iMax-1; i++) {
0325 
0326         if (i < 7) {
0327           z2 = z1 + dx;
0328         } else if(iMax-2 == i) {
0329           z2 = p[3];
0330           break;
0331         } else {
0332           z2 = z1*dx1;
0333         }
0334         if(x >= z1 && x <= z2) break;
0335         z1 = z2;
0336       }
0337       fun = p[i] + (x - z1) * (p[i+1] - p[i])/(z2 - z1);
0338 
0339       if(fun > amaj) {
0340           G4cout << "WARNING in G4RDeIonisationSpectrum::SampleEnergy:" 
0341                  << " Majoranta " << amaj 
0342                  << " < " << fun
0343                  << " in the first aria at x= " << x
0344                  << G4endl;
0345       }
0346 
0347       q = amaj*G4UniformRand();
0348 
0349     } while (q >= fun);
0350 
0351   //======= Second aria to sample =====
0352 
0353   } else {
0354 
0355     amaj = std::max(p[iMax-1], Function(0.5, p)) * factor;
0356     a1 = 1./a3;
0357     a2 = 1./a4;
0358 
0359     do {
0360 
0361       x = 1./(a2 + G4UniformRand()*(a1 - a2));
0362       fun = Function(x, p);
0363 
0364       if(fun > amaj) {
0365           G4cout << "WARNING in G4RDeIonisationSpectrum::SampleEnergy:" 
0366                  << " Majoranta " << amaj 
0367                  << " < " << fun
0368                  << " in the second aria at x= " << x
0369                  << G4endl;
0370       }
0371 
0372       q = amaj*G4UniformRand();
0373 
0374     } while (q >= fun);
0375 
0376   }
0377 
0378   p.clear();
0379 
0380   tDelta = x*energy - bindingEnergy;
0381 
0382   if(verbose > 1) {
0383     G4cout << "tcut(MeV)= " << tMin/MeV 
0384            << "; tMax(MeV)= " << tMax/MeV 
0385            << "; x1= " << x1 
0386            << "; x2= " << x2 
0387            << "; a1= " << a1 
0388            << "; a2= " << a2 
0389            << "; x= " << x 
0390            << "; be= " << bindingEnergy 
0391            << "; e= " << e 
0392            << "; tDelta= " << tDelta 
0393            << G4endl;
0394   }
0395 
0396 
0397   return tDelta; 
0398 }
0399 
0400 
0401 G4double G4RDeIonisationSpectrum::IntSpectrum(G4double xMin, 
0402                         G4double xMax,
0403                       const G4DataVector& p) const
0404 {
0405   // Please comment what IntSpectrum does
0406   G4double sum = 0.0;
0407   if(xMin >= xMax) return sum;
0408 
0409   G4double x1, x2, xs1, xs2, y1, y2, ys1, ys2, q;
0410 
0411   // Integral over interpolation aria
0412   if(xMin < p[3]) {
0413 
0414     x1 = p[1];
0415     y1 = p[4];
0416 
0417     G4double dx = (p[2] - p[1]) / 3.0;
0418     G4double dx1= std::exp(std::log(p[3]/p[2]) / 16.0);
0419 
0420     for (size_t i=0; i<19; i++) {
0421 
0422       q = 0.0;
0423       if (i < 3) {
0424         x2 = x1 + dx;
0425       } else if(18 == i) {
0426         x2 = p[3];
0427       } else {
0428         x2 = x1*dx1;
0429       }
0430 
0431       y2 = p[5 + i];
0432 
0433       if (xMax <= x1) {
0434         break;
0435       } else if (xMin < x2) {
0436 
0437         xs1 = x1;
0438         xs2 = x2;
0439         ys1 = y1;
0440         ys2 = y2;
0441 
0442         if (x2 > x1) {
0443           if (xMin > x1) {
0444             xs1 = xMin;
0445             ys1 += (xs1 - x1)*(y2 - y1)/(x2 - x1);
0446       } 
0447           if (xMax < x2) {
0448             xs2 = xMax;
0449             ys2 += (xs2 - x2)*(y1 - y2)/(x1 - x2);
0450       } 
0451           if (xs2 > xs1) {
0452             q = (ys1*xs2 - ys2*xs1)/(xs1*xs2) 
0453               +  std::log(xs2/xs1)*(ys2 - ys1)/(xs2 - xs1);
0454             sum += q;
0455             if(p.size() == 26) G4cout << "i= " << i << "  q= " << q << " sum= " << sum << G4endl;
0456       }
0457     }  
0458       }
0459       x1 = x2;
0460       y1 = y2;
0461     }
0462   }
0463 
0464   // Integral over aria with parametrised formula 
0465 
0466   x1 = std::max(xMin, p[3]);
0467   if(x1 >= xMax) return sum;
0468   x2 = xMax;
0469 
0470   xs1 = 1./x1;
0471   xs2 = 1./x2;
0472   q = (xs1 - xs2)*(1.0 - p[0]) 
0473        - p[iMax]*std::log(x2/x1) 
0474        + (1. - p[iMax])*(x2 - x1)
0475        + 1./(1. - x2) - 1./(1. - x1) 
0476        + p[iMax]*std::log((1. - x2)/(1. - x1))
0477        + 0.25*p[0]*(xs1*xs1 - xs2*xs2);
0478   sum += q;
0479   if(p.size() == 26) G4cout << "param...  q= " << q <<  " sum= " << sum << G4endl;
0480 
0481   return sum;
0482 } 
0483 
0484 
0485 G4double G4RDeIonisationSpectrum::AverageValue(G4double xMin, 
0486                              G4double xMax,
0487                        const G4DataVector& p) const
0488 {
0489   G4double sum = 0.0;
0490   if(xMin >= xMax) return sum;
0491 
0492   G4double x1, x2, xs1, xs2, y1, y2, ys1, ys2;
0493 
0494   // Integral over interpolation aria
0495   if(xMin < p[3]) {
0496 
0497     x1 = p[1];
0498     y1 = p[4];
0499 
0500     G4double dx = (p[2] - p[1]) / 3.0;
0501     G4double dx1= std::exp(std::log(p[3]/p[2]) / 16.0);
0502 
0503     for (size_t i=0; i<19; i++) {
0504 
0505       if (i < 3) {
0506         x2 = x1 + dx;
0507       } else if(18 == i) {
0508         x2 = p[3];
0509       } else {
0510         x2 = x1*dx1;
0511       }
0512 
0513       y2 = p[5 + i];
0514 
0515       if (xMax <= x1) {
0516         break;
0517       } else if (xMin < x2) {
0518 
0519         xs1 = x1;
0520         xs2 = x2;
0521         ys1 = y1;
0522         ys2 = y2;
0523 
0524         if (x2 > x1) {
0525           if (xMin > x1) {
0526             xs1 = xMin;
0527             ys1 += (xs1 - x1)*(y2 - y1)/(x2 - x1);
0528       } 
0529           if (xMax < x2) {
0530             xs2 = xMax;
0531             ys2 += (xs2 - x2)*(y1 - y2)/(x1 - x2);
0532       } 
0533           if (xs2 > xs1) {
0534             sum += std::log(xs2/xs1)*(ys1*xs2 - ys2*xs1)/(xs2 - xs1) 
0535                 +  ys2 - ys1;
0536       }
0537     }  
0538       }
0539       x1 = x2;
0540       y1 = y2;
0541 
0542     }
0543   }
0544 
0545   // Integral over aria with parametrised formula 
0546 
0547   x1 = std::max(xMin, p[3]);
0548   if(x1 >= xMax) return sum;
0549   x2 = xMax;
0550 
0551   xs1 = 1./x1;
0552   xs2 = 1./x2;
0553 
0554   sum  += std::log(x2/x1)*(1.0 - p[0]) 
0555         + 0.5*(1. - p[iMax])*(x2*x2 - x1*x1)
0556         + 1./(1. - x2) - 1./(1. - x1) 
0557         + (1. + p[iMax])*std::log((1. - x2)/(1. - x1))
0558         + 0.5*p[0]*(xs1 - xs2);
0559 
0560   return sum;
0561 } 
0562 
0563 
0564 void G4RDeIonisationSpectrum::PrintData() const 
0565 {
0566   theParam->PrintData();
0567 }
0568 
0569 G4double G4RDeIonisationSpectrum::MaxEnergyOfSecondaries(G4double kineticEnergy,
0570                                G4int, // Z = 0,
0571                                const G4ParticleDefinition* ) const
0572 {
0573   return 0.5 * kineticEnergy;
0574 }