Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/examples/extended/electromagnetic/TestEm7/src/G4ScreenedNuclearRecoil.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

Diff markup

Differences between /examples/extended/electromagnetic/TestEm7/src/G4ScreenedNuclearRecoil.cc (Version 11.3.0) and /examples/extended/electromagnetic/TestEm7/src/G4ScreenedNuclearRecoil.cc (Version 10.1)


  1 //                                                  1 //
  2 // *******************************************      2 // ********************************************************************
  3 // * License and Disclaimer                         3 // * License and Disclaimer                                           *
  4 // *                                                4 // *                                                                  *
  5 // * The  Geant4 software  is  copyright of th      5 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
  6 // * the Geant4 Collaboration.  It is provided      6 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
  7 // * conditions of the Geant4 Software License      7 // * conditions of the Geant4 Software License,  included in the file *
  8 // * LICENSE and available at  http://cern.ch/      8 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
  9 // * include a list of copyright holders.           9 // * include a list of copyright holders.                             *
 10 // *                                               10 // *                                                                  *
 11 // * Neither the authors of this software syst     11 // * Neither the authors of this software system, nor their employing *
 12 // * institutes,nor the agencies providing fin     12 // * institutes,nor the agencies providing financial support for this *
 13 // * work  make  any representation or  warran     13 // * work  make  any representation or  warranty, express or implied, *
 14 // * regarding  this  software system or assum     14 // * regarding  this  software system or assume any liability for its *
 15 // * use.  Please see the license in the file      15 // * use.  Please see the license in the file  LICENSE  and URL above *
 16 // * for the full disclaimer and the limitatio     16 // * for the full disclaimer and the limitation of liability.         *
 17 // *                                               17 // *                                                                  *
 18 // * This  code  implementation is the result      18 // * This  code  implementation is the result of  the  scientific and *
 19 // * technical work of the GEANT4 collaboratio     19 // * technical work of the GEANT4 collaboration.                      *
 20 // * By using,  copying,  modifying or  distri     20 // * By using,  copying,  modifying or  distributing the software (or *
 21 // * any work based  on the software)  you  ag     21 // * any work based  on the software)  you  agree  to acknowledge its *
 22 // * use  in  resulting  scientific  publicati     22 // * use  in  resulting  scientific  publications,  and indicate your *
 23 // * acceptance of all terms of the Geant4 Sof     23 // * acceptance of all terms of the Geant4 Software license.          *
 24 // *******************************************     24 // ********************************************************************
 25 //                                                 25 //
 26 /// \file electromagnetic/TestEm7/src/G4Screen     26 /// \file electromagnetic/TestEm7/src/G4ScreenedNuclearRecoil.cc
 27 /// \brief Implementation of the G4ScreenedNuc     27 /// \brief Implementation of the G4ScreenedNuclearRecoil class
 28 //                                                 28 //
                                                   >>  29 // $Id: G4ScreenedNuclearRecoil.cc 84270 2014-10-13 07:11:34Z gcosmo $
 29 //                                                 30 //
 30 //                                                 31 //
 31 // Class Description                               32 // Class Description
 32 // Process for screened electromagnetic nuclea <<  33 // Process for screened electromagnetic nuclear elastic scattering; 
 33 // Physics comes from:                             34 // Physics comes from:
 34 // Marcus H. Mendenhall and Robert A. Weller,  <<  35 // Marcus H. Mendenhall and Robert A. Weller, 
 35 // "Algorithms  for  the rapid  computation  o <<  36 // "Algorithms  for  the rapid  computation  of  classical  cross  
 36 // sections  for  screened  Coulomb  collision     37 // sections  for  screened  Coulomb  collisions  "
 37 // Nuclear  Instruments  and  Methods  in  Phy <<  38 // Nuclear  Instruments  and  Methods  in  Physics  Research B58 (1991)  11-17  
 38 // The only input required is a screening func     39 // The only input required is a screening function phi(r/a) which is the ratio
 39 // of the actual interatomic potential for two <<  40 // of the actual interatomic potential for two atoms with atomic 
 40 // numbers Z1 and Z2,                              41 // numbers Z1 and Z2,
 41 // to the unscreened potential Z1*Z2*e^2/r whe <<  42 // to the unscreened potential Z1*Z2*e^2/r where e^2 is elm_coupling in 
 42 // Geant4 units                                    43 // Geant4 units
 43 //                                                 44 //
 44 // First version, April 2004, Marcus H. Menden     45 // First version, April 2004, Marcus H. Mendenhall, Vanderbilt University
 45 //                                                 46 //
 46 // 5 May, 2004, Marcus Mendenhall                  47 // 5 May, 2004, Marcus Mendenhall
 47 // Added an option for enhancing hard collisio <<  48 // Added an option for enhancing hard collisions statistically, to allow 
 48 // backscattering calculations to be carried o     49 // backscattering calculations to be carried out with much improved event rates,
 49 // without distorting the multiple-scattering      50 // without distorting the multiple-scattering broadening too much.
 50 // the method SetCrossSectionHardening(G4doubl <<  51 // the method SetCrossSectionHardening(G4double fraction, G4double 
 51 //                                     Hardeni     52 //                                     HardeningFactor)
 52 // sets what fraction of the events will be ra     53 // sets what fraction of the events will be randomly hardened,
 53 // and the factor by which the impact area is      54 // and the factor by which the impact area is reduced for such selected events.
 54 //                                                 55 //
 55 // 21 November, 2004, Marcus Mendenhall            56 // 21 November, 2004, Marcus Mendenhall
 56 // added static_nucleus to IsApplicable            57 // added static_nucleus to IsApplicable
 57 //                                             <<  58 // 
 58 // 7 December, 2004, Marcus Mendenhall             59 // 7 December, 2004, Marcus Mendenhall
 59 // changed mean free path of stopping particle     60 // changed mean free path of stopping particle from 0.0 to 1.0*nanometer
 60 // to avoid new verbose warning about 0 MFP in     61 // to avoid new verbose warning about 0 MFP in 4.6.2p02
 61 //                                             <<  62 // 
 62 // 17 December, 2004, Marcus Mendenhall            63 // 17 December, 2004, Marcus Mendenhall
 63 // added code to permit screening out overly c <<  64 // added code to permit screening out overly close collisions which are 
 64 // expected to be hadronic, not Coulombic          65 // expected to be hadronic, not Coulombic
 65 //                                                 66 //
 66 // 19 December, 2004, Marcus Mendenhall            67 // 19 December, 2004, Marcus Mendenhall
 67 // massive rewrite to add modular physics stag     68 // massive rewrite to add modular physics stages and plug-in cross section table
 68 // computation.  This allows one to select (e. <<  69 // computation.  This allows one to select (e.g.) between the normal external 
 69 // python process and an embedded python inter <<  70 // python process and an embedded python interpreter (which is much faster) 
 70 // for generating the tables.                      71 // for generating the tables.
 71 // It also allows one to switch between sub-sa <<  72 // It also allows one to switch between sub-sampled scattering (event biasing) 
 72 // and normal scattering, and between non-rela <<  73 // and normal scattering, and between non-relativistic kinematics and 
 73 // relativistic kinematic approximations, with <<  74 // relativistic kinematic approximations, without having a class for every 
 74 // combination. Further, one can add extra sta <<  75 // combination. Further, one can add extra stages to the scattering, which can 
 75 // implement various book-keeping processes.       76 // implement various book-keeping processes.
 76 //                                             <<  77 // 
 77 // January 2007, Marcus Mendenhall                 78 // January 2007, Marcus Mendenhall
 78 // Reorganized heavily for inclusion in Geant4 <<  79 // Reorganized heavily for inclusion in Geant4 Core.  All modules merged into 
 79 // one source and header, all historic code re     80 // one source and header, all historic code removed.
 80 //                                             <<  81 // 
 81 // Class Description - End                         82 // Class Description - End
 82                                                    83 
 83 //....oooOO0OOooo........oooOO0OOooo........oo     84 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
 84                                                    85 
 85 #include "G4ScreenedNuclearRecoil.hh"          <<  86 #include <stdio.h>
 86                                                    87 
 87 #include "globals.hh"                              88 #include "globals.hh"
 88                                                    89 
 89 #include <stdio.h>                             <<  90 #include "G4ScreenedNuclearRecoil.hh"
 90                                                    91 
 91 const char* G4ScreenedCoulombCrossSectionInfo: <<  92 const char* G4ScreenedCoulombCrossSectionInfo::CVSFileVers() { return 
 92 {                                              <<  93  "G4ScreenedNuclearRecoil.cc,v 1.57 2008/05/07 11:51:26 marcus Exp GEANT4 tag ";
 93   return "G4ScreenedNuclearRecoil.cc,v 1.57 20 << 
 94 }                                                  94 }
 95                                                    95 
 96 #include "c2_factory.hh"                       <<  96 #include "G4ParticleTypes.hh"
 97                                                <<  97 #include "G4ParticleTable.hh"
                                                   >>  98 #include "G4IonTable.hh"
                                                   >>  99 #include "G4VParticleChange.hh"
                                                   >> 100 #include "G4ParticleChangeForLoss.hh"
 98 #include "G4DataVector.hh"                        101 #include "G4DataVector.hh"
 99 #include "G4DynamicParticle.hh"                << 102 #include "G4Track.hh"
                                                   >> 103 #include "G4Step.hh"
                                                   >> 104 
                                                   >> 105 #include "G4Material.hh"
100 #include "G4Element.hh"                           106 #include "G4Element.hh"
101 #include "G4ElementVector.hh"                  << 
102 #include "G4EmProcessSubType.hh"               << 
103 #include "G4IonTable.hh"                       << 
104 #include "G4Isotope.hh"                           107 #include "G4Isotope.hh"
105 #include "G4IsotopeVector.hh"                  << 
106 #include "G4LindhardPartition.hh"              << 
107 #include "G4Material.hh"                       << 
108 #include "G4MaterialCutsCouple.hh"                108 #include "G4MaterialCutsCouple.hh"
109 #include "G4ParticleChangeForLoss.hh"          << 109 #include "G4ElementVector.hh"
                                                   >> 110 #include "G4IsotopeVector.hh"
                                                   >> 111 
                                                   >> 112 #include "G4EmProcessSubType.hh"
                                                   >> 113 
110 #include "G4ParticleDefinition.hh"                114 #include "G4ParticleDefinition.hh"
111 #include "G4ParticleTable.hh"                  << 115 #include "G4DynamicParticle.hh"
112 #include "G4ParticleTypes.hh"                  << 
113 #include "G4ProcessManager.hh"                    116 #include "G4ProcessManager.hh"
114 #include "G4StableIsotopes.hh"                    117 #include "G4StableIsotopes.hh"
115 #include "G4Step.hh"                           << 118 #include "G4LindhardPartition.hh"
116 #include "G4Track.hh"                          << 119 
117 #include "G4VParticleChange.hh"                << 120 #include "G4PhysicalConstants.hh"
                                                   >> 121 #include "G4SystemOfUnits.hh"
118 #include "Randomize.hh"                           122 #include "Randomize.hh"
119                                                   123 
120 #include <iomanip>                             << 
121 #include <iostream>                               124 #include <iostream>
122 static c2_factory<G4double> c2;  // this makes << 125 #include <iomanip>
                                                   >> 126 
                                                   >> 127 #include "c2_factory.hh"
                                                   >> 128 static c2_factory<G4double> c2; // this makes a lot of notation shorter
123 typedef c2_ptr<G4double> c2p;                     129 typedef c2_ptr<G4double> c2p;
124                                                   130 
125 G4ScreenedCoulombCrossSection::~G4ScreenedCoul    131 G4ScreenedCoulombCrossSection::~G4ScreenedCoulombCrossSection()
126 {                                                 132 {
127   screeningData.clear();                       << 133         screeningData.clear();
128   MFPTables.clear();                           << 134         MFPTables.clear();        
129 }                                                 135 }
130                                                   136 
131 const G4double G4ScreenedCoulombCrossSection:: << 137 const G4double G4ScreenedCoulombCrossSection::massmap[nMassMapElements+1]={
132   0,          1.007940,   4.002602,   6.941000 << 138   0, 1.007940, 4.002602, 6.941000, 9.012182, 10.811000, 12.010700, 
133   15.999400,  18.998403,  20.179700,  22.98977 << 139   14.006700, 15.999400, 18.998403, 20.179700, 22.989770, 24.305000, 26.981538, 
134   32.065000,  35.453000,  39.948000,  39.09830 << 140   28.085500, 
135   51.996100,  54.938049,  55.845000,  58.93320 << 141   30.973761, 32.065000, 35.453000, 39.948000, 39.098300, 40.078000, 44.955910, 
136   72.640000,  74.921600,  78.960000,  79.90400 << 142   47.867000, 
137   91.224000,  92.906380,  95.940000,  98.00000 << 143   50.941500, 51.996100, 54.938049, 55.845000, 58.933200, 58.693400, 63.546000, 
138   112.411000, 114.818000, 118.710000, 121.7600 << 144   65.409000, 
139   137.327000, 138.905500, 140.116000, 140.9076 << 145   69.723000, 72.640000, 74.921600, 78.960000, 79.904000, 83.798000, 85.467800, 
140   157.250000, 158.925340, 162.500000, 164.9303 << 146   87.620000, 
141   178.490000, 180.947900, 183.840000, 186.2070 << 147   88.905850, 91.224000, 92.906380, 95.940000, 98.000000, 101.070000, 102.905500,
142   200.590000, 204.383300, 207.200000, 208.9803 << 148   106.420000, 
143   226.000000, 227.000000, 232.038100, 231.0358 << 149   107.868200, 112.411000, 114.818000, 118.710000, 121.760000, 127.600000, 
144   247.000000, 247.000000, 251.000000, 252.0000 << 150   126.904470, 131.293000, 
145   261.000000, 262.000000, 266.000000, 264.0000 << 151   132.905450, 137.327000, 138.905500, 140.116000, 140.907650, 144.240000, 
146   285.000000, 282.500000, 289.000000, 287.5000 << 152   145.000000, 150.360000, 
147                                                << 153   151.964000, 157.250000, 158.925340, 162.500000, 164.930320, 167.259000, 
148 G4ParticleDefinition*                          << 154   168.934210, 173.040000, 
149 G4ScreenedCoulombCrossSection::SelectRandomUnw << 155   174.967000, 178.490000, 180.947900, 183.840000, 186.207000, 190.230000, 
150 {                                              << 156   192.217000, 195.078000, 
151   // Select randomly an element within the mat << 157   196.966550, 200.590000, 204.383300, 207.200000, 208.980380, 209.000000, 
152   // density only                              << 158   210.000000, 222.000000, 
153   const G4Material* material = couple->GetMate << 159   223.000000, 226.000000, 227.000000, 232.038100, 231.035880, 238.028910, 
154   G4int nMatElements = material->GetNumberOfEl << 160   237.000000, 244.000000, 
155   const G4ElementVector* elementVector = mater << 161   243.000000, 247.000000, 247.000000, 251.000000, 252.000000, 257.000000, 
156   const G4Element* element = 0;                << 162   258.000000, 259.000000, 
157   G4ParticleDefinition* target = 0;            << 163   262.000000, 261.000000, 262.000000, 266.000000, 264.000000, 277.000000, 
158                                                << 164   268.000000, 281.000000, 
159   // Special case: the material consists of on << 165   272.000000, 285.000000, 282.500000, 289.000000, 287.500000, 292.000000};
160   if (nMatElements == 1) {                     << 166 
161     element = (*elementVector)[0];             << 167 G4ParticleDefinition* 
162   }                                            << 168 G4ScreenedCoulombCrossSection::SelectRandomUnweightedTarget(
163   else {                                       << 169   const G4MaterialCutsCouple* couple)
164     // Composite material                      << 170 {
165     G4double random = G4UniformRand() * materi << 171   // Select randomly an element within the material, according to number 
166     G4double nsum = 0.0;                       << 172   // density only        
167     const G4double* atomDensities = material-> << 173         const G4Material* material = couple->GetMaterial();
168                                                << 174         G4int nMatElements = material->GetNumberOfElements();
169     for (G4int k = 0; k < nMatElements; k++) { << 175         const G4ElementVector* elementVector = material->GetElementVector();
170       nsum += atomDensities[k];                << 176         const G4Element *element=0;
171       element = (*elementVector)[k];           << 177         G4ParticleDefinition*target=0;
172       if (nsum >= random) break;               << 178         
173     }                                          << 179         // Special case: the material consists of one element
174   }                                            << 180         if (nMatElements == 1)
175                                                << 181     {
176   G4int N = 0;                                 << 182                 element= (*elementVector)[0];
177   G4int Z = element->GetZasInt();              << 
178                                                << 
179   G4int nIsotopes = element->GetNumberOfIsotop << 
180   if (0 < nIsotopes) {                         << 
181     if (Z <= 92) {                             << 
182       // we have no detailed material isotopic << 
183       // so use G4StableIsotopes table up to Z << 
184       static G4StableIsotopes theIso;          << 
185       // get a stable isotope table for defaul << 
186       nIsotopes = theIso.GetNumberOfIsotopes(Z << 
187       G4double random = 100.0 * G4UniformRand( << 
188       // values are expressed as percent, sum  << 
189       G4int tablestart = theIso.GetFirstIsotop << 
190       G4double asum = 0.0;                     << 
191       for (G4int i = 0; i < nIsotopes; i++) {  << 
192         asum += theIso.GetAbundance(i + tables << 
193         N = theIso.GetIsotopeNucleonCount(i +  << 
194         if (asum >= random) break;             << 
195       }                                        << 
196     }                                             183     }
197     else {                                     << 184         else
198       // too heavy for stable isotope table, j << 185     {
199       N = (G4int)std::floor(element->GetN() +  << 186       // Composite material
200     }                                          << 187       G4double random = G4UniformRand() * material->GetTotNbOfAtomsPerVolume();
201   }                                            << 188       G4double nsum=0.0;
202   else {                                       << 189       const G4double *atomDensities=material->GetVecNbOfAtomsPerVolume();
203     G4int i;                                   << 190                 
204     const G4IsotopeVector* isoV = element->Get << 191                 for (G4int k=0 ; k < nMatElements ; k++ )
205     G4double random = G4UniformRand();         << 192         {
206     G4double* abundance = element->GetRelative << 193                         nsum+=atomDensities[k];
207     G4double asum = 0.0;                       << 194                         element= (*elementVector)[k];
208     for (i = 0; i < nIsotopes; i++) {          << 195                         if (nsum >= random) break;
209       asum += abundance[i];                    << 196         }
210       N = (*isoV)[i]->GetN();                  << 
211       if (asum >= random) break;               << 
212     }                                             197     }
213   }                                            << 
214                                                   198 
215   // get the official definition of this nucle << 199         G4int N=0;
216   // value of A note that GetIon is very slow, << 200         G4int Z=(G4int)std::floor(element->GetZ()+0.5);
217   // we have already found ourselves.          << 201         
218   ParticleCache::iterator p = targetMap.find(Z << 202         G4int nIsotopes=element->GetNumberOfIsotopes();
219   if (p != targetMap.end()) {                  << 203         if(!nIsotopes) {
220     target = (*p).second;                      << 204           if(Z<=92) {
221   }                                            << 205             // we have no detailed material isotopic info available, 
222   else {                                       << 206             // so use G4StableIsotopes table up to Z=92
223     target = G4IonTable::GetIonTable()->GetIon << 207             static G4StableIsotopes theIso; 
224     targetMap[Z * 1000 + N] = target;          << 208             // get a stable isotope table for default results
225   }                                            << 209             nIsotopes=theIso.GetNumberOfIsotopes(Z);
226   return target;                               << 210             G4double random = 100.0*G4UniformRand(); 
                                                   >> 211             // values are expressed as percent, sum is 100
                                                   >> 212             G4int tablestart=theIso.GetFirstIsotope(Z);
                                                   >> 213             G4double asum=0.0;
                                                   >> 214             for(G4int i=0; i<nIsotopes; i++) {
                                                   >> 215               asum+=theIso.GetAbundance(i+tablestart);
                                                   >> 216               N=theIso.GetIsotopeNucleonCount(i+tablestart);
                                                   >> 217               if(asum >= random) break;
                                                   >> 218             }
                                                   >> 219           } else {
                                                   >> 220             // too heavy for stable isotope table, just use mean mass
                                                   >> 221             N=(G4int)std::floor(element->GetN()+0.5);
                                                   >> 222           }
                                                   >> 223         } else {
                                                   >> 224                 G4int i;
                                                   >> 225                 const G4IsotopeVector *isoV=element->GetIsotopeVector();
                                                   >> 226                 G4double random = G4UniformRand();
                                                   >> 227                 G4double *abundance=element->GetRelativeAbundanceVector();
                                                   >> 228                 G4double asum=0.0;
                                                   >> 229                 for(i=0; i<nIsotopes; i++) {
                                                   >> 230                         asum+=abundance[i];
                                                   >> 231                         N=(*isoV)[i]->GetN();
                                                   >> 232                         if(asum >= random) break;
                                                   >> 233                 }
                                                   >> 234         }
                                                   >> 235         
                                                   >> 236         // get the official definition of this nucleus, to get the correct 
                                                   >> 237         // value of A note that GetIon is very slow, so we will cache ones 
                                                   >> 238         // we have already found ourselves.
                                                   >> 239         ParticleCache::iterator p=targetMap.find(Z*1000+N);
                                                   >> 240         if (p != targetMap.end()) {
                                                   >> 241                 target=(*p).second;
                                                   >> 242         } else{
                                                   >> 243                 target=G4IonTable::GetIonTable()->GetIon(Z, N, 0.0); 
                                                   >> 244                 targetMap[Z*1000+N]=target;
                                                   >> 245         }
                                                   >> 246         return target;
227 }                                                 247 }
228                                                   248 
229 void G4ScreenedCoulombCrossSection::BuildMFPTa    249 void G4ScreenedCoulombCrossSection::BuildMFPTables()
230 {                                                 250 {
231   const G4int nmfpvals = 200;                  << 251         const G4int nmfpvals=200;
232                                                << 
233   std::vector<G4double> evals(nmfpvals), mfpva << 
234                                                   252 
235   // sum up inverse MFPs per element for each  << 253         std::vector<G4double> evals(nmfpvals), mfpvals(nmfpvals);
236   const G4MaterialTable* materialTable = G4Mat << 
237   if (materialTable == 0) {                    << 
238     return;                                    << 
239   }                                            << 
240   // G4Exception("G4ScreenedCoulombCrossSectio << 
241   //- no MaterialTable found)");               << 
242                                                << 
243   G4int nMaterials = G4Material::GetNumberOfMa << 
244                                                   254 
245   for (G4int matidx = 0; matidx < nMaterials;  << 255         // sum up inverse MFPs per element for each material        
246     const G4Material* material = (*materialTab << 256         const G4MaterialTable* materialTable = G4Material::GetMaterialTable();
247     const G4ElementVector& elementVector = *(m << 257         if (materialTable == 0) { return; }
248     const G4int nMatElements = material->GetNu << 258         //G4Exception("G4ScreenedCoulombCrossSection::BuildMFPTables 
249                                                << 259         //- no MaterialTable found)");
250     const G4Element* element = 0;              << 260         
251     const G4double* atomDensities = material-> << 261         G4int nMaterials = G4Material::GetNumberOfMaterials();
252                                                << 262 
253     G4double emin = 0, emax = 0;               << 263         for (G4int matidx=0; matidx < nMaterials; matidx++) {
254     // find innermost range of cross section f << 264 
255     for (G4int kel = 0; kel < nMatElements; ke << 265           const G4Material* material= (*materialTable)[matidx];
256       element = elementVector[kel];            << 266           const G4ElementVector &elementVector = 
257       G4int Z = (G4int)std::floor(element->Get << 267             *(material->GetElementVector());
258       const G4_c2_function& ifunc = sigmaMap[Z << 268           const G4int nMatElements = material->GetNumberOfElements();
259       if (!kel || ifunc.xmin() > emin) emin =  << 269 
260       if (!kel || ifunc.xmax() < emax) emax =  << 270           const G4Element *element=0;
261     }                                          << 271           const G4double *atomDensities=material->GetVecNbOfAtomsPerVolume();
262                                                << 272                 
263     G4double logint = std::log(emax / emin) /  << 273           G4double emin=0, emax=0; 
264     // logarithmic increment for tables        << 274           // find innermost range of cross section functions
265                                                << 275           for (G4int kel=0 ; kel < nMatElements ; kel++ )
266     // compute energy scale for interpolator.  << 276             {
267     // both ends to avoid range errors         << 277                         element=elementVector[kel];
268     for (G4int i = 1; i < nmfpvals - 1; i++)   << 278                         G4int Z=(G4int)std::floor(element->GetZ()+0.5);
269       evals[i] = emin * std::exp(logint * i);  << 279                         const G4_c2_function &ifunc=sigmaMap[Z];
270     evals.front() = emin;                      << 280                         if(!kel || ifunc.xmin() > emin) emin=ifunc.xmin();
271     evals.back() = emax;                       << 281                         if(!kel || ifunc.xmax() < emax) emax=ifunc.xmax();
272                                                << 282             }
273     // zero out the inverse mfp sums to start  << 283                 
274     for (G4int eidx = 0; eidx < nmfpvals; eidx << 284           G4double logint=std::log(emax/emin) / (nmfpvals-1) ; 
275       mfpvals[eidx] = 0.0;                     << 285           // logarithmic increment for tables
276                                                << 286                 
277     // sum inverse mfp for each element in thi << 287           // compute energy scale for interpolator.  Force exact values at 
278     // energy                                  << 288           // both ends to avoid range errors
279     for (G4int kel = 0; kel < nMatElements; ke << 289           for (G4int i=1; i<nmfpvals-1; i++) evals[i]=emin*std::exp(logint*i);
280       element = elementVector[kel];            << 290           evals.front()=emin;
281       G4int Z = (G4int)std::floor(element->Get << 291           evals.back()=emax;
282       const G4_c2_function& sigma = sigmaMap[Z << 292                 
283       G4double ndens = atomDensities[kel];     << 293           // zero out the inverse mfp sums to start
284       // compute atom fraction for this elemen << 294           for (G4int eidx=0; eidx < nmfpvals; eidx++) mfpvals[eidx] = 0.0; 
285                                                << 295                 
286       for (G4int eidx = 0; eidx < nmfpvals; ei << 296           // sum inverse mfp for each element in this material and for each 
287         mfpvals[eidx] += ndens * sigma(evals[e << 297           // energy
288       }                                        << 298           for (G4int kel=0 ; kel < nMatElements ; kel++ )
289     }                                          << 299             {
290                                                << 300               element=elementVector[kel];
291     // convert inverse mfp to regular mfp      << 301               G4int Z=(G4int)std::floor(element->GetZ()+0.5);
292     for (G4int eidx = 0; eidx < nmfpvals; eidx << 302               const G4_c2_function &sigma=sigmaMap[Z];
293       mfpvals[eidx] = 1.0 / mfpvals[eidx];     << 303               G4double ndens = atomDensities[kel]; 
294     }                                          << 304               // compute atom fraction for this element in this material
295     // and make a new interpolating function o << 305                                                 
296     MFPTables[matidx] = c2.log_log_interpolati << 306               for (G4int eidx=0; eidx < nmfpvals; eidx++) {
297   }                                            << 307                 mfpvals[eidx] += ndens*sigma(evals[eidx]);
                                                   >> 308               }
                                                   >> 309             }
                                                   >> 310                 
                                                   >> 311           // convert inverse mfp to regular mfp
                                                   >> 312           for (G4int eidx=0; eidx < nmfpvals; eidx++) {
                                                   >> 313             mfpvals[eidx] = 1.0/mfpvals[eidx];
                                                   >> 314           }
                                                   >> 315           // and make a new interpolating function out of the sum
                                                   >> 316           MFPTables[matidx] = c2.log_log_interpolating_function().load(evals, 
                                                   >> 317                               mfpvals,true,0,true,0);
                                                   >> 318         }
298 }                                                 319 }
299                                                   320 
300 G4ScreenedNuclearRecoil::G4ScreenedNuclearReco << 321 G4ScreenedNuclearRecoil::
301                                                << 322 G4ScreenedNuclearRecoil(const G4String& processName, 
302                                                << 323                         const G4String &ScreeningKey,
303                                                << 324                         G4bool GenerateRecoils, 
304   : G4VDiscreteProcess(processName, fElectroma << 325                         G4double RecoilCutoff, G4double PhysicsCutoff) : 
305     screeningKey(ScreeningKey),                << 326   G4VDiscreteProcess(processName, fElectromagnetic),
306     generateRecoils(GenerateRecoils),          << 327         screeningKey(ScreeningKey),
307     avoidReactions(1),                         << 328         generateRecoils(GenerateRecoils), avoidReactions(1), 
308     recoilCutoff(RecoilCutoff),                << 329         recoilCutoff(RecoilCutoff), physicsCutoff(PhysicsCutoff),
309     physicsCutoff(PhysicsCutoff),              << 330         hardeningFraction(0.0), hardeningFactor(1.0),
310     hardeningFraction(0.0),                    << 331         externalCrossSectionConstructor(0),
311     hardeningFactor(1.0),                      << 332         NIELPartitionFunction(new G4LindhardRobinsonPartition)
312     externalCrossSectionConstructor(0),        << 
313     NIELPartitionFunction(new G4LindhardRobins << 
314 {                                                 333 {
315   // for now, point to class instance of this. << 334   // for now, point to class instance of this. Doing it by creating a new 
316   // one fails                                    335   // one fails
317   // to correctly update NIEL                     336   // to correctly update NIEL
318   // not even this is needed... done in G4VPro    337   // not even this is needed... done in G4VProcess().
319   // pParticleChange=&aParticleChange;         << 338   // pParticleChange=&aParticleChange; 
320   processMaxEnergy = 50000.0 * MeV;            << 339   processMaxEnergy=50000.0*MeV;
321   highEnergyLimit = 100.0 * MeV;               << 340   highEnergyLimit=100.0*MeV;
322   lowEnergyLimit = physicsCutoff;              << 341   lowEnergyLimit=physicsCutoff;
323   registerDepositedEnergy = 1;  // by default, << 342   registerDepositedEnergy=1; // by default, don't hide NIEL
324   MFPScale = 1.0;                              << 343   MFPScale=1.0;
325   // SetVerboseLevel(2);                          344   // SetVerboseLevel(2);
326   AddStage(new G4ScreenedCoulombClassicalKinem    345   AddStage(new G4ScreenedCoulombClassicalKinematics);
327   AddStage(new G4SingleScatter);               << 346   AddStage(new G4SingleScatter); 
328   SetProcessSubType(fCoulombScattering);          347   SetProcessSubType(fCoulombScattering);
329 }                                                 348 }
330                                                   349 
331 void G4ScreenedNuclearRecoil::ResetTables()       350 void G4ScreenedNuclearRecoil::ResetTables()
332 {                                                 351 {
333   std::map<G4int, G4ScreenedCoulombCrossSectio << 352         
334   for (; xt != crossSectionHandlers.end(); xt+ << 353   std::map<G4int, G4ScreenedCoulombCrossSection*>::iterator xt=
335     delete (*xt).second;                       << 354     crossSectionHandlers.begin();
336   }                                            << 355         for(;xt != crossSectionHandlers.end(); xt++) {
337   crossSectionHandlers.clear();                << 356                 delete (*xt).second;
                                                   >> 357         }
                                                   >> 358         crossSectionHandlers.clear();
338 }                                                 359 }
339                                                   360 
340 void G4ScreenedNuclearRecoil::ClearStages()       361 void G4ScreenedNuclearRecoil::ClearStages()
341 {                                                 362 {
342   // I don't think I like deleting the process << 363   // I don't think I like deleting the processes here... they are better 
343   // abandoned                                    364   // abandoned
344   // if the creator doesn't get rid of them       365   // if the creator doesn't get rid of them
345   // std::vector<G4ScreenedCollisionStage *>::    366   // std::vector<G4ScreenedCollisionStage *>::iterator stage=
346   // collisionStages.begin();                  << 367   //collisionStages.begin();
347   // for(; stage != collisionStages.end(); sta << 368   //for(; stage != collisionStages.end(); stage++) delete (*stage);
348                                                   369 
349   collisionStages.clear();                     << 370         collisionStages.clear();
350 }                                                 371 }
351                                                   372 
352 void G4ScreenedNuclearRecoil::SetNIELPartition << 373 void G4ScreenedNuclearRecoil::SetNIELPartitionFunction(
                                                   >> 374      const G4VNIELPartition *part)
353 {                                                 375 {
354   if (NIELPartitionFunction) delete NIELPartit << 376         if(NIELPartitionFunction) delete NIELPartitionFunction;
355   NIELPartitionFunction = part;                << 377         NIELPartitionFunction=part;
356 }                                                 378 }
357                                                   379 
358 void G4ScreenedNuclearRecoil::DepositEnergy(G4 << 380 void G4ScreenedNuclearRecoil::DepositEnergy(G4int z1, G4double a1, 
359                                             G4 << 381   const G4Material *material, G4double energy)
360 {                                                 382 {
361   if (!NIELPartitionFunction) {                << 383         if(!NIELPartitionFunction) {
362     IonizingLoss += energy;                    << 384                 IonizingLoss+=energy;
363   }                                            << 385         } else {
364   else {                                       << 386           G4double part=NIELPartitionFunction->PartitionNIEL(z1, a1, 
365     G4double part = NIELPartitionFunction->Par << 387             material, energy);
366     IonizingLoss += energy * (1 - part);       << 388           IonizingLoss+=energy*(1-part);
367     NIEL += energy * part;                     << 389           NIEL += energy*part;
368   }                                            << 390         }
369 }                                                 391 }
370                                                   392 
371 G4ScreenedNuclearRecoil::~G4ScreenedNuclearRec    393 G4ScreenedNuclearRecoil::~G4ScreenedNuclearRecoil()
372 {                                                 394 {
373   ResetTables();                               << 395         ResetTables();
374 }                                                 396 }
375                                                   397 
376 // returns true if it appears the nuclei colli << 398 // returns true if it appears the nuclei collided, and we are interested 
377 // in checking                                    399 // in checking
378 G4bool G4ScreenedNuclearRecoil::CheckNuclearCo << 400 G4bool G4ScreenedNuclearRecoil::CheckNuclearCollision(
379 {                                              << 401                         G4double A, G4double a1, G4double apsis) {
380   return avoidReactions                        << 402   return avoidReactions && (apsis < (1.1*(std::pow(A,1.0/3.0)+
381          && (apsis < (1.1 * (std::pow(A, 1.0 / << 403                                           std::pow(a1,1.0/3.0)) + 1.4)*fermi);
382   // nuclei are within 1.4 fm (reduced pion Co << 404   // nuclei are within 1.4 fm (reduced pion Compton wavelength) of each 
383   // other at apsis,                           << 405   // other at apsis, 
384   // this is hadronic, skip it                    406   // this is hadronic, skip it
385 }                                                 407 }
386                                                   408 
387 G4ScreenedCoulombCrossSection* G4ScreenedNucle << 409 G4ScreenedCoulombCrossSection 
388 {                                              << 410 *G4ScreenedNuclearRecoil::GetNewCrossSectionHandler(void) {
389   G4ScreenedCoulombCrossSection* xc;           << 411   G4ScreenedCoulombCrossSection *xc;
390   if (!externalCrossSectionConstructor)        << 412   if(!externalCrossSectionConstructor) 
391     xc = new G4NativeScreenedCoulombCrossSecti << 413     xc=new G4NativeScreenedCoulombCrossSection;
392   else                                         << 414         else xc=externalCrossSectionConstructor->create();
393     xc = externalCrossSectionConstructor->crea << 415         xc->SetVerbosity(verboseLevel);
394   xc->SetVerbosity(verboseLevel);              << 416         return xc;
395   return xc;                                   << 
396 }                                                 417 }
397                                                   418 
398 G4double G4ScreenedNuclearRecoil::GetMeanFreeP << 419 G4double G4ScreenedNuclearRecoil::GetMeanFreePath(const G4Track& track,
                                                   >> 420                                                   G4double, 
399                                                   421                                                   G4ForceCondition* cond)
400 {                                                 422 {
401   const G4DynamicParticle* incoming = track.Ge << 423         const G4DynamicParticle* incoming = track.GetDynamicParticle();
402   G4double energy = incoming->GetKineticEnergy << 424         G4double energy = incoming->GetKineticEnergy();
403   G4double a1 = incoming->GetDefinition()->Get << 425         G4double a1=incoming->GetDefinition()->GetPDGMass()/amu_c2;
404                                                << 426         
405   G4double meanFreePath;                       << 427         G4double meanFreePath;
406   *cond = NotForced;                           << 428         *cond=NotForced;
407                                                << 429         
408   if (energy < lowEnergyLimit || energy < reco << 430         if (energy < lowEnergyLimit || energy < recoilCutoff*a1) {
409     *cond = Forced;                            << 431                 *cond=Forced;
410     return 1.0 * nm;                           << 432                 return 1.0*nm; 
411     /* catch and stop slow particles to collec << 433 /* catch and stop slow particles to collect their NIEL! */
412   }                                            << 434         } else if (energy > processMaxEnergy*a1) {
413   else if (energy > processMaxEnergy * a1) {   << 435                 return DBL_MAX; // infinite mean free path
414     return DBL_MAX;  // infinite mean free pat << 436         } else if (energy > highEnergyLimit*a1) energy=highEnergyLimit*a1; 
415   }                                            << 437 /* constant MFP at high energy */
416   else if (energy > highEnergyLimit * a1)      << 438 
417     energy = highEnergyLimit * a1;             << 439         G4double fz1=incoming->GetDefinition()->GetPDGCharge();
418   /* constant MFP at high energy */            << 440         G4int z1=(G4int)(fz1/eplus + 0.5);
419                                                << 441 
420   G4double fz1 = incoming->GetDefinition()->Ge << 442         std::map<G4int, G4ScreenedCoulombCrossSection*>::iterator xh=
421   G4int z1 = (G4int)(fz1 / eplus + 0.5);       << 443                 crossSectionHandlers.find(z1);
422                                                << 444         G4ScreenedCoulombCrossSection *xs;
423   std::map<G4int, G4ScreenedCoulombCrossSectio << 445         
424   G4ScreenedCoulombCrossSection* xs;           << 446         if (xh==crossSectionHandlers.end()) {
425                                                << 447                 xs =crossSectionHandlers[z1]=GetNewCrossSectionHandler();
426   if (xh == crossSectionHandlers.end()) {      << 448                 xs->LoadData(screeningKey, z1, a1, physicsCutoff);
427     xs = crossSectionHandlers[z1] = GetNewCros << 449                 xs->BuildMFPTables();
428     xs->LoadData(screeningKey, z1, a1, physics << 450         } else xs=(*xh).second;
429     xs->BuildMFPTables();                      << 451         
430   }                                            << 452         const G4MaterialCutsCouple* materialCouple = 
431   else                                         << 453           track.GetMaterialCutsCouple();
432     xs = (*xh).second;                         << 454         size_t materialIndex = materialCouple->GetMaterial()->GetIndex();
433                                                << 455 
434   const G4MaterialCutsCouple* materialCouple = << 456         const G4_c2_function &mfp=*(*xs)[materialIndex];
435   size_t materialIndex = materialCouple->GetMa << 457         
436                                                << 458         // make absolutely certain we don't get an out-of-range energy
437   const G4_c2_function& mfp = *(*xs)[materialI << 459         meanFreePath = mfp(std::min(std::max(energy, mfp.xmin()), mfp.xmax()));
438                                                << 460         
439   // make absolutely certain we don't get an o << 461         // G4cout << "MFP: " << meanFreePath << " index " << materialIndex 
440   meanFreePath = mfp(std::min(std::max(energy, << 462         //<< " energy " << energy << " MFPScale " << MFPScale << G4endl;
441                                                << 463         
442   // G4cout << "MFP: " << meanFreePath << " in << 464         return meanFreePath*MFPScale;
443   //<< " energy " << energy << " MFPScale " << << 465 }
                                                   >> 466 
                                                   >> 467 G4VParticleChange* G4ScreenedNuclearRecoil::PostStepDoIt(
                                                   >> 468   const G4Track& aTrack, const G4Step& aStep)
                                                   >> 469 {
                                                   >> 470         validCollision=1;
                                                   >> 471         pParticleChange->Initialize(aTrack);
                                                   >> 472         NIEL=0.0; // default is no NIEL deposited
                                                   >> 473         IonizingLoss=0.0;
                                                   >> 474         
                                                   >> 475         // do universal setup
                                                   >> 476         
                                                   >> 477         const G4DynamicParticle* incidentParticle = aTrack.GetDynamicParticle();
                                                   >> 478         G4ParticleDefinition *baseParticle=aTrack.GetDefinition();
                                                   >> 479         
                                                   >> 480         G4double fz1=baseParticle->GetPDGCharge()/eplus;
                                                   >> 481         G4int z1=(G4int)(fz1+0.5);
                                                   >> 482         G4double a1=baseParticle->GetPDGMass()/amu_c2;
                                                   >> 483         G4double incidentEnergy = incidentParticle->GetKineticEnergy();
                                                   >> 484                 
                                                   >> 485         // Select randomly one element and (possibly) isotope in the 
                                                   >> 486         // current material.
                                                   >> 487         const G4MaterialCutsCouple* couple = aTrack.GetMaterialCutsCouple();
                                                   >> 488         
                                                   >> 489         const G4Material* mat = couple->GetMaterial();
                                                   >> 490 
                                                   >> 491         G4double P=0.0; // the impact parameter of this collision
                                                   >> 492 
                                                   >> 493         if(incidentEnergy < GetRecoilCutoff()*a1) { 
                                                   >> 494           // check energy sanity on entry
                                                   >> 495           DepositEnergy(z1, baseParticle->GetPDGMass()/amu_c2, mat, 
                                                   >> 496                         incidentEnergy);
                                                   >> 497           GetParticleChange().ProposeEnergy(0.0);
                                                   >> 498           // stop the particle and bail out
                                                   >> 499           validCollision=0;
                                                   >> 500         } else {
                                                   >> 501                 
                                                   >> 502                 G4double numberDensity=mat->GetTotNbOfAtomsPerVolume();
                                                   >> 503                 G4double lattice=0.5/std::pow(numberDensity,1.0/3.0); 
                                                   >> 504                 // typical lattice half-spacing
                                                   >> 505                 G4double length=GetCurrentInteractionLength();
                                                   >> 506                 G4double sigopi=1.0/(CLHEP::pi*numberDensity*length);  
                                                   >> 507                 // this is sigma0/pi
                                                   >> 508                 
                                                   >> 509                 // compute the impact parameter very early, so if is rejected 
                                                   >> 510                 // as too far away, little effort is wasted
                                                   >> 511                 // this is the TRIM method for determining an impact parameter 
                                                   >> 512                 // based on the flight path
                                                   >> 513                 // this gives a cumulative distribution of 
                                                   >> 514                 // N(P)= 1-exp(-pi P^2 n l)
                                                   >> 515                 // which says the probability of NOT hitting a disk of area 
                                                   >> 516                 // sigma= pi P^2 =exp(-sigma N l) 
                                                   >> 517                 // which may be reasonable
                                                   >> 518                 if(sigopi < lattice*lattice) { 
                                                   >> 519                         // normal long-flight approximation
                                                   >> 520                         P = std::sqrt(-std::log(G4UniformRand()) *sigopi);
                                                   >> 521                 } else {
                                                   >> 522                         // short-flight limit
                                                   >> 523                         P = std::sqrt(G4UniformRand())*lattice;
                                                   >> 524                 }
                                                   >> 525                         
                                                   >> 526                 G4double fraction=GetHardeningFraction();
                                                   >> 527                 if(fraction && G4UniformRand() < fraction) { 
                                                   >> 528                   // pick out some events, and increase the central cross 
                                                   >> 529                   // section by reducing the impact parameter
                                                   >> 530                   P /= std::sqrt(GetHardeningFactor());
                                                   >> 531                 }
                                                   >> 532                 
                                                   >> 533                 
                                                   >> 534                 // check if we are far enough away that the energy transfer 
                                                   >> 535                 // must be below cutoff, 
                                                   >> 536                 // and leave everything alone if so, saving a lot of time.
                                                   >> 537                 if(P*P > sigopi) {
                                                   >> 538                   if(GetVerboseLevel() > 1) 
                                                   >> 539     printf("ScreenedNuclear impact reject: length=%.3f P=%.4f limit=%.4f\n",
                                                   >> 540            length/angstrom, P/angstrom,std::sqrt(sigopi)/angstrom);
                                                   >> 541                   // no collision, don't follow up with anything
                                                   >> 542                   validCollision=0;
                                                   >> 543                 }
                                                   >> 544         }
                                                   >> 545         
                                                   >> 546         // find out what we hit, and record it in our kinematics block.
                                                   >> 547         kinematics.targetMaterial=mat;
                                                   >> 548         kinematics.a1=a1;
                                                   >> 549         
                                                   >> 550         if(validCollision) {
                                                   >> 551                 G4ScreenedCoulombCrossSection *xsect=
                                                   >> 552                   GetCrossSectionHandlers()[z1];
                                                   >> 553                 G4ParticleDefinition *recoilIon=
                                                   >> 554                         xsect->SelectRandomUnweightedTarget(couple);
                                                   >> 555                 kinematics.crossSection=xsect;
                                                   >> 556                 kinematics.recoilIon=recoilIon;
                                                   >> 557                 kinematics.impactParameter=P;
                                                   >> 558                 kinematics.a2=recoilIon->GetPDGMass()/amu_c2;
                                                   >> 559         } else {
                                                   >> 560                 kinematics.recoilIon=0;
                                                   >> 561                 kinematics.impactParameter=0;
                                                   >> 562                 kinematics.a2=0;
                                                   >> 563         }
                                                   >> 564         
                                                   >> 565         std::vector<G4ScreenedCollisionStage *>::iterator stage=
                                                   >> 566           collisionStages.begin();
                                                   >> 567         
                                                   >> 568         for(; stage != collisionStages.end(); stage++) 
                                                   >> 569                 (*stage)->DoCollisionStep(this,aTrack, aStep);
                                                   >> 570         
                                                   >> 571         if(registerDepositedEnergy) {
                                                   >> 572                 pParticleChange->ProposeLocalEnergyDeposit(IonizingLoss+NIEL);
                                                   >> 573                 pParticleChange->ProposeNonIonizingEnergyDeposit(NIEL);
                                                   >> 574                 //MHM G4cout << "depositing energy, total = " 
                                                   >> 575                 //<< IonizingLoss+NIEL << " NIEL = " << NIEL << G4endl;
                                                   >> 576         }
444                                                   577 
445   return meanFreePath * MFPScale;              << 578         return G4VDiscreteProcess::PostStepDoIt( aTrack, aStep );
446 }                                                 579 }
447                                                   580 
448 G4VParticleChange* G4ScreenedNuclearRecoil::Po << 581 G4ScreenedCoulombClassicalKinematics::G4ScreenedCoulombClassicalKinematics() :
                                                   >> 582 // instantiate all the needed functions statically, so no allocation is 
                                                   >> 583 // done at run time
                                                   >> 584 // we will be solving x^2 - x phi(x*au)/eps - beta^2 == 0.0
                                                   >> 585 // or, for easier scaling, x'^2 - x' au phi(x')/eps - beta^2 au^2
                                                   >> 586 // note that only the last of these gets deleted, since it owns the rest
                                                   >> 587   phifunc(c2.const_plugin_function()),
                                                   >> 588   xovereps(c2.linear(0., 0., 0.)), 
                                                   >> 589   // will fill this in with the right slope at run time
                                                   >> 590   diff(c2.quadratic(0., 0., 0., 1.)-xovereps*phifunc)
449 {                                                 591 {
450   validCollision = 1;                          << 
451   pParticleChange->Initialize(aTrack);         << 
452   NIEL = 0.0;  // default is no NIEL deposited << 
453   IonizingLoss = 0.0;                          << 
454                                                << 
455   // do universal setup                        << 
456                                                << 
457   const G4DynamicParticle* incidentParticle =  << 
458   G4ParticleDefinition* baseParticle = aTrack. << 
459                                                << 
460   G4double fz1 = baseParticle->GetPDGCharge()  << 
461   G4int z1 = (G4int)(fz1 + 0.5);               << 
462   G4double a1 = baseParticle->GetPDGMass() / a << 
463   G4double incidentEnergy = incidentParticle-> << 
464                                                << 
465   // Select randomly one element and (possibly << 
466   // current material.                         << 
467   const G4MaterialCutsCouple* couple = aTrack. << 
468                                                << 
469   const G4Material* mat = couple->GetMaterial( << 
470                                                << 
471   G4double P = 0.0;  // the impact parameter o << 
472                                                << 
473   if (incidentEnergy < GetRecoilCutoff() * a1) << 
474     // check energy sanity on entry            << 
475     DepositEnergy(z1, baseParticle->GetPDGMass << 
476     GetParticleChange().ProposeEnergy(0.0);    << 
477     // stop the particle and bail out          << 
478     validCollision = 0;                        << 
479   }                                            << 
480   else {                                       << 
481     G4double numberDensity = mat->GetTotNbOfAt << 
482     G4double lattice = 0.5 / std::pow(numberDe << 
483     // typical lattice half-spacing            << 
484     G4double length = GetCurrentInteractionLen << 
485     G4double sigopi = 1.0 / (pi * numberDensit << 
486     // this is sigma0/pi                       << 
487                                                << 
488     // compute the impact parameter very early << 
489     // as too far away, little effort is waste << 
490     // this is the TRIM method for determining << 
491     // based on the flight path                << 
492     // this gives a cumulative distribution of << 
493     // N(P)= 1-exp(-pi P^2 n l)                << 
494     // which says the probability of NOT hitti << 
495     // sigma= pi P^2 =exp(-sigma N l)          << 
496     // which may be reasonable                 << 
497     if (sigopi < lattice * lattice) {          << 
498       // normal long-flight approximation      << 
499       P = std::sqrt(-std::log(G4UniformRand()) << 
500     }                                          << 
501     else {                                     << 
502       // short-flight limit                    << 
503       P = std::sqrt(G4UniformRand()) * lattice << 
504     }                                          << 
505                                                << 
506     G4double fraction = GetHardeningFraction() << 
507     if (fraction && G4UniformRand() < fraction << 
508       // pick out some events, and increase th << 
509       // section by reducing the impact parame << 
510       P /= std::sqrt(GetHardeningFactor());    << 
511     }                                          << 
512                                                << 
513     // check if we are far enough away that th << 
514     // must be below cutoff,                   << 
515     // and leave everything alone if so, savin << 
516     if (P * P > sigopi) {                      << 
517       if (GetVerboseLevel() > 1)               << 
518         printf("ScreenedNuclear impact reject: << 
519                P / angstrom, std::sqrt(sigopi) << 
520       // no collision, don't follow up with an << 
521       validCollision = 0;                      << 
522     }                                          << 
523   }                                            << 
524                                                << 
525   // find out what we hit, and record it in ou << 
526   kinematics.targetMaterial = mat;             << 
527   kinematics.a1 = a1;                          << 
528                                                << 
529   if (validCollision) {                        << 
530     G4ScreenedCoulombCrossSection* xsect = Get << 
531     G4ParticleDefinition* recoilIon = xsect->S << 
532     kinematics.crossSection = xsect;           << 
533     kinematics.recoilIon = recoilIon;          << 
534     kinematics.impactParameter = P;            << 
535     kinematics.a2 = recoilIon->GetPDGMass() /  << 
536   }                                            << 
537   else {                                       << 
538     kinematics.recoilIon = 0;                  << 
539     kinematics.impactParameter = 0;            << 
540     kinematics.a2 = 0;                         << 
541   }                                            << 
542                                                << 
543   std::vector<G4ScreenedCollisionStage*>::iter << 
544                                                << 
545   for (; stage != collisionStages.end(); stage << 
546     (*stage)->DoCollisionStep(this, aTrack, aS << 
547                                                << 
548   if (registerDepositedEnergy) {               << 
549     pParticleChange->ProposeLocalEnergyDeposit << 
550     pParticleChange->ProposeNonIonizingEnergyD << 
551     // MHM G4cout << "depositing energy, total << 
552     //<< IonizingLoss+NIEL << " NIEL = " << NI << 
553   }                                            << 
554                                                << 
555   return G4VDiscreteProcess::PostStepDoIt(aTra << 
556 }                                                 592 }
557                                                   593 
558 G4ScreenedCoulombClassicalKinematics::G4Screen << 594 G4bool G4ScreenedCoulombClassicalKinematics::DoScreeningComputation(
559   :  // instantiate all the needed functions s << 595   G4ScreenedNuclearRecoil *master,
560      // done at run time                       << 596   const G4ScreeningTables *screen, G4double eps, G4double beta)
561      // we will be solving x^2 - x phi(x*au)/e << 597 {
562      // or, for easier scaling, x'^2 - x' au p << 598   G4double au=screen->au;
563      // note that only the last of these gets  << 599   G4CoulombKinematicsInfo &kin=master->GetKinematics();
564     phifunc(c2.const_plugin_function()),       << 600   G4double A=kin.a2;
565     xovereps(c2.linear(0., 0., 0.)),           << 601   G4double a1=kin.a1;
566     // will fill this in with the right slope  << 602         
567     diff(c2.quadratic(0., 0., 0., 1.) - xovere << 603   G4double xx0; // first estimate of closest approach
568 {}                                             << 604   if(eps < 5.0) {
569                                                << 605     G4double y=std::log(eps);
570 G4bool G4ScreenedCoulombClassicalKinematics::D << 606     G4double mlrho4=((((3.517e-4*y+1.401e-2)*y+2.393e-1)*y+2.734)*y+2.220);
571                                                << 607     G4double rho4=std::exp(-mlrho4); // W&M eq. 18
572                                                << 608     G4double bb2=0.5*beta*beta;
573 {                                              << 609     xx0=std::sqrt(bb2+std::sqrt(bb2*bb2+rho4)); // W&M eq. 17
574   G4double au = screen->au;                    << 610   } else {
575   G4CoulombKinematicsInfo& kin = master->GetKi << 611     G4double ee=1.0/(2.0*eps);
576   G4double A = kin.a2;                         << 612     xx0=ee+std::sqrt(ee*ee+beta*beta); // W&M eq. 15 (Rutherford value)  
577   G4double a1 = kin.a1;                        << 613     if(master->CheckNuclearCollision(A, a1, xx0*au)) return 0; 
578                                                << 
579   G4double xx0;  // first estimate of closest  << 
580   if (eps < 5.0) {                             << 
581     G4double y = std::log(eps);                << 
582     G4double mlrho4 = ((((3.517e-4 * y + 1.401 << 
583     G4double rho4 = std::exp(-mlrho4);  // W&M << 
584     G4double bb2 = 0.5 * beta * beta;          << 
585     xx0 = std::sqrt(bb2 + std::sqrt(bb2 * bb2  << 
586   }                                            << 
587   else {                                       << 
588     G4double ee = 1.0 / (2.0 * eps);           << 
589     xx0 = ee + std::sqrt(ee * ee + beta * beta << 
590     if (master->CheckNuclearCollision(A, a1, x << 
591     // nuclei too close                           614     // nuclei too close
                                                   >> 615                 
592   }                                               616   }
593                                                << 617         
594   // we will be solving x^2 - x phi(x*au)/eps     618   // we will be solving x^2 - x phi(x*au)/eps - beta^2 == 0.0
595   // or, for easier scaling, x'^2 - x' au phi(    619   // or, for easier scaling, x'^2 - x' au phi(x')/eps - beta^2 au^2
596   xovereps.reset(0., 0.0, au / eps);  // slope << 620   xovereps.reset(0., 0.0, au/eps); // slope of x*au/eps term
597   phifunc.set_function(&(screen->EMphiData.get << 621   phifunc.set_function(&(screen->EMphiData.get())); 
598   // install interpolating table                  622   // install interpolating table
599   G4double xx1, phip, phip2;                      623   G4double xx1, phip, phip2;
600   G4int root_error;                            << 624   G4int root_error;        
601   xx1 = diff->find_root(phifunc.xmin(), std::m << 625   xx1=diff->find_root(phifunc.xmin(), std::min(10*xx0*au,phifunc.xmax()), 
602                         std::min(xx0 * au, phi << 626                       std::min(xx0*au, phifunc.xmax()), beta*beta*au*au, 
603                         &phip, &phip2)         << 627                       &root_error, &phip, &phip2)/au; 
604         / au;                                  << 628         
605                                                << 629         if(root_error) {
606   if (root_error) {                            << 630                 G4cout << "Screened Coulomb Root Finder Error" << G4endl;
607     G4cout << "Screened Coulomb Root Finder Er << 631                 G4cout << "au " << au << " A " << A << " a1 " << a1 
608     G4cout << "au " << au << " A " << A << " a << 632                        << " xx1 " << xx1 << " eps " << eps 
609            << " beta " << beta << G4endl;      << 633                        << " beta " << beta << G4endl;
610     G4cout << " xmin " << phifunc.xmin() << "  << 634                 G4cout << " xmin " << phifunc.xmin() << " xmax " 
611     G4cout << " f(xmin) " << phifunc(phifunc.x << 635                        << std::min(10*xx0*au,phifunc.xmax()) ;
612            << phifunc(std::min(10 * xx0 * au,  << 636                 G4cout << " f(xmin) " << phifunc(phifunc.xmin()) 
613     G4cout << " xstart " << std::min(xx0 * au, << 637                        <<  " f(xmax) " 
614            << beta * beta * au * au;           << 638                        << phifunc(std::min(10*xx0*au,phifunc.xmax())) ;
615     G4cout << G4endl;                          << 639                 G4cout << " xstart " << std::min(xx0*au, phifunc.xmax()) 
616     throw c2_exception("Failed root find");    << 640                        <<  " target " <<  beta*beta*au*au ;
617   }                                            << 641                 G4cout << G4endl;
618                                                << 642                 throw c2_exception("Failed root find");
619   // phiprime is scaled by one factor of au be << 643         }
620   // at (xx0*au),                              << 644         
621   G4double phiprime = phip * au;               << 645         // phiprime is scaled by one factor of au because phi is evaluated 
622                                                << 646         // at (xx0*au),
623   // lambda0 is from W&M 19                    << 647         G4double phiprime=phip*au;
624   G4double lambda0 =                           << 648         
625     1.0 / std::sqrt(0.5 + beta * beta / (2.0 * << 649         //lambda0 is from W&M 19
626                                                << 650         G4double lambda0=1.0/std::sqrt(0.5+beta*beta/(2.0*xx1*xx1)
627   // compute the 6-term Lobatto integral alpha << 651                                        -phiprime/(2.0*eps));
628   // different coefficients)                   << 652         
629   // this is probably completely un-needed but << 653         // compute the 6-term Lobatto integral alpha (per W&M 21, with 
630   // quality results,                          << 654         // different coefficients)
631   G4double alpha = (1.0 + lambda0) / 30.0;     << 655         // this is probably completely un-needed but gives the highest 
632   G4double xvals[] = {0.98302349, 0.84652241,  << 656         // quality results,
633   G4double weights[] = {0.03472124, 0.14769029 << 657         G4double alpha=(1.0+ lambda0)/30.0;
634   for (G4int k = 0; k < 4; k++) {              << 658         G4double xvals[]={0.98302349, 0.84652241, 0.53235309, 0.18347974};
635     G4double x, ff;                            << 659         G4double weights[]={0.03472124, 0.14769029, 0.23485003, 0.18602489};
636     x = xx1 / xvals[k];                        << 660         for(G4int k=0; k<4; k++) {
637     ff = 1.0 / std::sqrt(1.0 - phifunc(x * au) << 661                 G4double x, ff;
638     alpha += weights[k] * ff;                  << 662                 x=xx1/xvals[k];
639   }                                            << 663                 ff=1.0/std::sqrt(1.0-phifunc(x*au)/(x*eps)-beta*beta/(x*x));
640                                                << 664                 alpha+=weights[k]*ff;
641   phifunc.unset_function();                    << 665         }
642   // throws an exception if used without setti << 666         
643                                                << 667         phifunc.unset_function(); 
644   G4double thetac1 = pi * beta * alpha / xx1;  << 668         // throws an exception if used without setting again
645   // complement of CM scattering angle         << 669 
646   G4double sintheta = std::sin(thetac1);  // n << 670         G4double thetac1=CLHEP::pi*beta*alpha/xx1; 
647   G4double costheta = -std::cos(thetac1);  //  << 671         // complement of CM scattering angle
648   // G4double psi=std::atan2(sintheta, costhet << 672         G4double sintheta=std::sin(thetac1); //note sin(pi-theta)=sin(theta)
649   // lab scattering angle (M&T 3rd eq. 8.69)   << 673         G4double costheta=-std::cos(thetac1); // note cos(pi-theta)=-cos(theta)
650                                                << 674         // G4double psi=std::atan2(sintheta, costheta+a1/A); 
651   // numerics note:  because we checked above  << 675         // lab scattering angle (M&T 3rd eq. 8.69)
652   // of beta which give real recoils,          << 676         
653   // we don't have to look too closely for the << 677         // numerics note:  because we checked above for reasonable values 
654   // (which would cause sin(theta)             << 678         // of beta which give real recoils,
655   // and 1-cos(theta) to both vanish and make  << 679         // we don't have to look too closely for theta -> 0 here 
656   G4double zeta = std::atan2(sintheta, 1 - cos << 680         // (which would cause sin(theta)
657   // lab recoil angle (M&T 3rd eq. 8.73)       << 681         // and 1-cos(theta) to both vanish and make the atan2 ill behaved).
658   G4double coszeta = std::cos(zeta);           << 682         G4double zeta=std::atan2(sintheta, 1-costheta); 
659   G4double sinzeta = std::sin(zeta);           << 683         // lab recoil angle (M&T 3rd eq. 8.73)
660                                                << 684         G4double coszeta=std::cos(zeta);
661   kin.sinTheta = sintheta;                     << 685         G4double sinzeta=std::sin(zeta);
662   kin.cosTheta = costheta;                     << 686 
663   kin.sinZeta = sinzeta;                       << 687         kin.sinTheta=sintheta;
664   kin.cosZeta = coszeta;                       << 688         kin.cosTheta=costheta;
665   return 1;  // all OK, collision is valid     << 689         kin.sinZeta=sinzeta;
666 }                                              << 690         kin.cosZeta=coszeta;
667                                                << 691         return 1; // all OK, collision is valid
668 void G4ScreenedCoulombClassicalKinematics::DoC << 692 }
669                                                << 693 
670 {                                              << 694 void G4ScreenedCoulombClassicalKinematics::DoCollisionStep(
671   if (!master->GetValidCollision()) return;    << 695   G4ScreenedNuclearRecoil *master,
672                                                << 696   const G4Track& aTrack, const G4Step&) {
673   G4ParticleChange& aParticleChange = master-> << 697         
674   G4CoulombKinematicsInfo& kin = master->GetKi << 698         if(!master->GetValidCollision()) return;
675                                                << 699         
676   const G4DynamicParticle* incidentParticle =  << 700         G4ParticleChange &aParticleChange=master->GetParticleChange();
677   G4ParticleDefinition* baseParticle = aTrack. << 701         G4CoulombKinematicsInfo &kin=master->GetKinematics();
678                                                << 702         
679   G4double incidentEnergy = incidentParticle-> << 703         const G4DynamicParticle* incidentParticle = aTrack.GetDynamicParticle();
680                                                << 704         G4ParticleDefinition *baseParticle=aTrack.GetDefinition();
681   // this adjustment to a1 gives the right res << 705         
682   // (constant gamma)                          << 706         G4double incidentEnergy = incidentParticle->GetKineticEnergy();
683   // relativistic collisions.  Hard collisions << 707         
684   // Coulombic and hadronic terms interfere an << 708         // this adjustment to a1 gives the right results for soft 
685   G4double gamma = (1.0 + incidentEnergy / bas << 709         // (constant gamma)
686   G4double a1 = kin.a1 * gamma;  // relativist << 710         // relativistic collisions.  Hard collisions are wrong anyway, since the
687                                                << 711         // Coulombic and hadronic terms interfere and cannot be added.
688   G4ParticleDefinition* recoilIon = kin.recoil << 712         G4double gamma=(1.0+incidentEnergy/baseParticle->GetPDGMass());
689   G4double A = recoilIon->GetPDGMass() / amu_c << 713         G4double a1=kin.a1*gamma; // relativistic gamma correction
690   G4int Z = (G4int)((recoilIon->GetPDGCharge() << 714         
691                                                << 715         G4ParticleDefinition *recoilIon=kin.recoilIon;
692   G4double Ec = incidentEnergy * (A / (A + a1) << 716         G4double A=recoilIon->GetPDGMass()/amu_c2;
693   // energy in CM frame (non-relativistic!)    << 717         G4int Z=(G4int)((recoilIon->GetPDGCharge()/eplus)+0.5);
694   const G4ScreeningTables* screen = kin.crossS << 718         
695   G4double au = screen->au;  // screening leng << 719         G4double Ec = incidentEnergy*(A/(A+a1)); 
696                                                << 720         // energy in CM frame (non-relativistic!)
697   G4double beta = kin.impactParameter / au;    << 721         const G4ScreeningTables *screen=kin.crossSection->GetScreening(Z);
698   // dimensionless impact parameter            << 722         G4double au=screen->au; // screening length
699   G4double eps = Ec / (screen->z1 * Z * elm_co << 723         
700   // dimensionless energy                      << 724         G4double beta = kin.impactParameter/au; 
701                                                << 725         // dimensionless impact parameter
702   G4bool ok = DoScreeningComputation(master, s << 726         G4double eps = Ec/(screen->z1*Z*elm_coupling/au); 
703   if (!ok) {                                   << 727         // dimensionless energy
704     master->SetValidCollision(0);  // flag bad << 728         
705     return;  // just bail out without setting  << 729         G4bool ok=DoScreeningComputation(master, screen, eps, beta);        
706   }                                            << 730         if(!ok) {
707                                                << 731                 master->SetValidCollision(0); // flag bad collision
708   G4double eRecoil =                           << 732                 return; // just bail out without setting valid flag
709     4 * incidentEnergy * a1 * A * kin.cosZeta  << 733         }
710   kin.eRecoil = eRecoil;                       << 734         
711                                                << 735         G4double eRecoil=4*incidentEnergy*a1*A*kin.cosZeta*kin.cosZeta
712   if (incidentEnergy - eRecoil < master->GetRe << 736           /((a1+A)*(a1+A));
713     aParticleChange.ProposeEnergy(0.0);        << 737         kin.eRecoil=eRecoil;
714     master->DepositEnergy(int(screen->z1), a1, << 738         
715   }                                            << 739         if(incidentEnergy-eRecoil < master->GetRecoilCutoff()*a1) {
716                                                << 740                 aParticleChange.ProposeEnergy(0.0);
717   if (master->GetEnableRecoils() && eRecoil >  << 741                 master->DepositEnergy(int(screen->z1), a1, kin.targetMaterial, 
718     kin.recoilIon = recoilIon;                 << 742                                       incidentEnergy-eRecoil);
719   }                                            << 743         } 
720   else {                                       << 744         
721     kin.recoilIon = 0;  // this flags no recoi << 745         if(master->GetEnableRecoils() && 
722     master->DepositEnergy(Z, A, kin.targetMate << 746            eRecoil > master->GetRecoilCutoff() * kin.a2) {
723   }                                            << 747                 kin.recoilIon=recoilIon;                
724 }                                              << 748         } else {
725                                                << 749                 kin.recoilIon=0; // this flags no recoil to be generated
726 void G4SingleScatter::DoCollisionStep(G4Screen << 750                 master->DepositEnergy(Z, A, kin.targetMaterial, eRecoil) ;
727                                       const G4 << 751         }        
728 {                                              << 752 }
729   if (!master->GetValidCollision()) return;    << 753 
730                                                << 754 void G4SingleScatter::DoCollisionStep(G4ScreenedNuclearRecoil *master,
731   G4CoulombKinematicsInfo& kin = master->GetKi << 755                                       const G4Track& aTrack, const G4Step&) {
732   G4ParticleChange& aParticleChange = master-> << 756         
733                                                << 757         if(!master->GetValidCollision()) return;
734   const G4DynamicParticle* incidentParticle =  << 758 
735   G4double incidentEnergy = incidentParticle-> << 759         G4CoulombKinematicsInfo &kin=master->GetKinematics();
736   G4double eRecoil = kin.eRecoil;              << 760         G4ParticleChange &aParticleChange=master->GetParticleChange();
737                                                << 761 
738   G4double azimuth = G4UniformRand() * (2.0 *  << 762         const G4DynamicParticle* incidentParticle = aTrack.GetDynamicParticle();
739   G4double sa = std::sin(azimuth);             << 763         G4double incidentEnergy = incidentParticle->GetKineticEnergy();
740   G4double ca = std::cos(azimuth);             << 764         G4double eRecoil=kin.eRecoil;
741                                                << 765         
742   G4ThreeVector recoilMomentumDirection(kin.si << 766         G4double azimuth=G4UniformRand()*(2.0*CLHEP::pi);
743   G4ParticleMomentum incidentDirection = incid << 767         G4double sa=std::sin(azimuth);
744   recoilMomentumDirection = recoilMomentumDire << 768         G4double ca=std::cos(azimuth);
745   G4ThreeVector recoilMomentum =               << 769 
746     recoilMomentumDirection * std::sqrt(2.0 *  << 770         G4ThreeVector recoilMomentumDirection(kin.sinZeta*ca, 
747                                                << 771                                               kin.sinZeta*sa, kin.cosZeta);
748   if (aParticleChange.GetEnergy() != 0.0) {    << 772         G4ParticleMomentum incidentDirection = 
749     // DoKinematics hasn't stopped it!         << 773           incidentParticle->GetMomentumDirection();
750     G4ThreeVector beamMomentum = incidentParti << 774         recoilMomentumDirection=
751     aParticleChange.ProposeMomentumDirection(b << 775           recoilMomentumDirection.rotateUz(incidentDirection);
752     aParticleChange.ProposeEnergy(incidentEner << 776         G4ThreeVector recoilMomentum=
753   }                                            << 777           recoilMomentumDirection*std::sqrt(2.0*eRecoil*kin.a2*amu_c2);
754                                                << 778         
755   if (kin.recoilIon) {                         << 779         if(aParticleChange.GetEnergy() != 0.0) { 
756     G4DynamicParticle* recoil =                << 780           // DoKinematics hasn't stopped it!
757       new G4DynamicParticle(kin.recoilIon, rec << 781           G4ThreeVector beamMomentum=
758                                                << 782             incidentParticle->GetMomentum()-recoilMomentum;
759     aParticleChange.SetNumberOfSecondaries(1); << 783           aParticleChange.ProposeMomentumDirection(beamMomentum.unit()) ;
760     aParticleChange.AddSecondary(recoil);      << 784           aParticleChange.ProposeEnergy(incidentEnergy-eRecoil);
761   }                                            << 785         }
                                                   >> 786         
                                                   >> 787         if(kin.recoilIon) {
                                                   >> 788                 G4DynamicParticle* recoil = 
                                                   >> 789                   new G4DynamicParticle (kin.recoilIon,
                                                   >> 790                                 recoilMomentumDirection,eRecoil) ;
                                                   >> 791                 
                                                   >> 792                 aParticleChange.SetNumberOfSecondaries(1);
                                                   >> 793                 aParticleChange.AddSecondary(recoil);   
                                                   >> 794         }
762 }                                                 795 }
763                                                   796 
764 G4bool G4ScreenedNuclearRecoil::IsApplicable(c << 797 G4bool G4ScreenedNuclearRecoil::
                                                   >> 798 IsApplicable(const G4ParticleDefinition& aParticleType)
765 {                                                 799 {
766   return aParticleType == *(G4Proton::Proton() << 800         return  aParticleType == *(G4Proton::Proton()) ||
767          || aParticleType.GetParticleType() == << 801         aParticleType.GetParticleType() == "nucleus" ||
                                                   >> 802         aParticleType.GetParticleType() == "static_nucleus";
768 }                                                 803 }
769                                                   804 
770 void G4ScreenedNuclearRecoil::BuildPhysicsTabl << 805 void 
                                                   >> 806 G4ScreenedNuclearRecoil::
                                                   >> 807 BuildPhysicsTable(const G4ParticleDefinition& aParticleType)
771 {                                                 808 {
772   G4String nam = aParticleType.GetParticleName    809   G4String nam = aParticleType.GetParticleName();
773   if (nam == "GenericIon" || nam == "proton" | << 810   if(nam == "GenericIon" || nam == "proton" 
774       || nam == "alpha" || nam == "He3")       << 811      || nam == "deuteron" || nam == "triton" 
775   {                                            << 812      || nam == "alpha" || nam == "He3") {
776     G4cout << G4endl << GetProcessName() << ":    813     G4cout << G4endl << GetProcessName() << ":   for  " << nam
777            << "    SubType= " << GetProcessSub << 814            << "    SubType= " << GetProcessSubType() 
778            << "    maxEnergy(MeV)= " << proces << 815            << "    maxEnergy(MeV)= " << processMaxEnergy/MeV << G4endl;
779   }                                               816   }
780 }                                                 817 }
781                                                   818 
782 void G4ScreenedNuclearRecoil::DumpPhysicsTable << 819 void 
                                                   >> 820 G4ScreenedNuclearRecoil::
                                                   >> 821 DumpPhysicsTable(const G4ParticleDefinition&)
                                                   >> 822 {
                                                   >> 823 }
783                                                   824 
784 // This used to be the file mhmScreenedNuclear    825 // This used to be the file mhmScreenedNuclearRecoil_native.cc
785 // it has been included here to collect this f << 826 // it has been included here to collect this file into a smaller 
786 // number of packages                             827 // number of packages
787                                                   828 
788 #include "G4DataVector.hh"                        829 #include "G4DataVector.hh"
                                                   >> 830 #include "G4Material.hh"
789 #include "G4Element.hh"                           831 #include "G4Element.hh"
790 #include "G4ElementVector.hh"                  << 
791 #include "G4Isotope.hh"                           832 #include "G4Isotope.hh"
792 #include "G4Material.hh"                       << 
793 #include "G4MaterialCutsCouple.hh"                833 #include "G4MaterialCutsCouple.hh"
794                                                << 834 #include "G4ElementVector.hh"
795 #include <vector>                                 835 #include <vector>
796                                                   836 
797 G4_c2_function& ZBLScreening(G4int z1, G4int z << 837 G4_c2_function &ZBLScreening(G4int z1, G4int z2, size_t npoints, 
                                                   >> 838                              G4double rMax, G4double *auval)
798 {                                                 839 {
799   static const size_t ncoef = 4;               << 840         static const size_t ncoef=4;
800   static G4double scales[ncoef] = {-3.2, -0.94 << 841         static G4double scales[ncoef]={-3.2, -0.9432, -0.4028, -0.2016};
801   static G4double coefs[ncoef] = {0.1818, 0.50 << 842         static G4double coefs[ncoef]={0.1818,0.5099,0.2802,0.0281};
802                                                << 843         
803   G4double au = 0.8854 * angstrom * 0.529 / (s << 844         G4double au=
804   std::vector<G4double> r(npoints), phi(npoint << 845           0.8854*angstrom*0.529/(std::pow(z1, 0.23)+std::pow(z2,0.23));
805                                                << 846         std::vector<G4double> r(npoints), phi(npoints);
806   for (size_t i = 0; i < npoints; i++) {       << 847         
807     G4double rr = (float)i / (float)(npoints - << 848         for(size_t i=0; i<npoints; i++) {
808     r[i] = rr * rr * rMax;                     << 849                 G4double rr=(float)i/(float)(npoints-1);
809     // use quadratic r scale to make sampling  << 850                 r[i]=rr*rr*rMax; 
810     G4double sum = 0.0;                        << 851                 // use quadratic r scale to make sampling fine near the center
811     for (size_t j = 0; j < ncoef; j++)         << 852                 G4double sum=0.0;
812       sum += coefs[j] * std::exp(scales[j] * r << 853                 for(size_t j=0; j<ncoef; j++) 
813     phi[i] = sum;                              << 854                   sum+=coefs[j]*std::exp(scales[j]*r[i]/au);
814   }                                            << 855                 phi[i]=sum;
815                                                << 856         }
816   // compute the derivative at the origin for  << 
817   G4double phiprime0 = 0.0;                    << 
818   for (size_t j = 0; j < ncoef; j++)           << 
819     phiprime0 += scales[j] * coefs[j] * std::e << 
820   phiprime0 *= (1.0 / au);  // put back in nat << 
821                                                << 
822   *auval = au;                                 << 
823   return c2.lin_log_interpolating_function().l << 
824 }                                              << 
825                                                << 
826 G4_c2_function& MoliereScreening(G4int z1, G4i << 
827 {                                              << 
828   static const size_t ncoef = 3;               << 
829   static G4double scales[ncoef] = {-6.0, -1.2, << 
830   static G4double coefs[ncoef] = {0.10, 0.55,  << 
831                                                << 
832   G4double au = 0.8853 * 0.529 * angstrom / st << 
833   std::vector<G4double> r(npoints), phi(npoint << 
834                                                << 
835   for (size_t i = 0; i < npoints; i++) {       << 
836     G4double rr = (float)i / (float)(npoints - << 
837     r[i] = rr * rr * rMax;                     << 
838     // use quadratic r scale to make sampling  << 
839     G4double sum = 0.0;                        << 
840     for (size_t j = 0; j < ncoef; j++)         << 
841       sum += coefs[j] * std::exp(scales[j] * r << 
842     phi[i] = sum;                              << 
843   }                                            << 
844                                                << 
845   // compute the derivative at the origin for  << 
846   G4double phiprime0 = 0.0;                    << 
847   for (size_t j = 0; j < ncoef; j++)           << 
848     phiprime0 += scales[j] * coefs[j] * std::e << 
849   phiprime0 *= (1.0 / au);  // put back in nat << 
850                                                << 
851   *auval = au;                                 << 
852   return c2.lin_log_interpolating_function().l << 
853 }                                              << 
854                                                << 
855 G4_c2_function& LJScreening(G4int z1, G4int z2 << 
856 {                                              << 
857   // from Loftager, Besenbacher, Jensen & Sore << 
858   // PhysRev A20, 1443++, 1979                 << 
859   G4double au = 0.8853 * 0.529 * angstrom / st << 
860   std::vector<G4double> r(npoints), phi(npoint << 
861                                                << 
862   for (size_t i = 0; i < npoints; i++) {       << 
863     G4double rr = (float)i / (float)(npoints - << 
864     r[i] = rr * rr * rMax;                     << 
865     // use quadratic r scale to make sampling  << 
866                                                << 
867     G4double y = std::sqrt(9.67 * r[i] / au);  << 
868     G4double ysq = y * y;                      << 
869     G4double phipoly = 1 + y + 0.3344 * ysq +  << 
870     phi[i] = phipoly * std::exp(-y);           << 
871     // G4cout << r[i] << " " << phi[i] << G4en << 
872   }                                            << 
873                                                << 
874   // compute the derivative at the origin for  << 
875   G4double logphiprime0 = (9.67 / 2.0) * (2 *  << 
876   // #avoid 0/0 on first element               << 
877   logphiprime0 *= (1.0 / au);  // #put back in << 
878                                                << 
879   *auval = au;                                 << 
880   return c2.lin_log_interpolating_function().l << 
881 }                                              << 
882                                                << 
883 G4_c2_function& LJZBLScreening(G4int z1, G4int << 
884 {                                              << 
885   // hybrid of LJ and ZBL, uses LJ if x < 0.25 << 
886   /// connector in between.  These numbers are << 
887   // is very near the point where the function << 
888   G4double auzbl, aulj;                        << 
889                                                << 
890   c2p zbl = ZBLScreening(z1, z2, npoints, rMax << 
891   c2p lj = LJScreening(z1, z2, npoints, rMax,  << 
892                                                << 
893   G4double au = (auzbl + aulj) * 0.5;          << 
894   lj->set_domain(lj->xmin(), 0.25 * au);       << 
895   zbl->set_domain(1.5 * au, zbl->xmax());      << 
896                                                << 
897   c2p conn = c2.connector_function(lj->xmax(), << 
898   c2_piecewise_function_p<G4double>& pw = c2.p << 
899   c2p keepit(pw);                              << 
900   pw.append_function(lj);                      << 
901   pw.append_function(conn);                    << 
902   pw.append_function(zbl);                     << 
903                                                << 
904   *auval = au;                                 << 
905   keepit.release_for_return();                 << 
906   return pw;                                   << 
907 }                                              << 
908                                                   857 
909 G4NativeScreenedCoulombCrossSection::~G4Native << 858         // compute the derivative at the origin for the spline
                                                   >> 859         G4double phiprime0=0.0;
                                                   >> 860         for(size_t j=0; j<ncoef; j++) 
                                                   >> 861           phiprime0+=scales[j]*coefs[j]*std::exp(scales[j]*r[0]/au);
                                                   >> 862         phiprime0*=(1.0/au); // put back in natural units;
                                                   >> 863         
                                                   >> 864         *auval=au;
                                                   >> 865         return c2.lin_log_interpolating_function().load(r, phi, false, 
                                                   >> 866                                                         phiprime0,true,0);
                                                   >> 867 }
                                                   >> 868 
                                                   >> 869 G4_c2_function &MoliereScreening(G4int z1, G4int z2, size_t npoints, 
                                                   >> 870                                  G4double rMax, G4double *auval)
                                                   >> 871 {        
                                                   >> 872         static const size_t ncoef=3;
                                                   >> 873         static G4double scales[ncoef]={-6.0, -1.2, -0.3};
                                                   >> 874         static G4double coefs[ncoef]={0.10, 0.55, 0.35};
                                                   >> 875         
                                                   >> 876         G4double au=0.8853*0.529*angstrom/std::sqrt(std::pow(z1, 0.6667)
                                                   >> 877                                                     +std::pow(z2,0.6667));
                                                   >> 878         std::vector<G4double> r(npoints), phi(npoints);
                                                   >> 879         
                                                   >> 880         for(size_t i=0; i<npoints; i++) {
                                                   >> 881                 G4double rr=(float)i/(float)(npoints-1);
                                                   >> 882                 r[i]=rr*rr*rMax; 
                                                   >> 883                 // use quadratic r scale to make sampling fine near the center
                                                   >> 884                 G4double sum=0.0;
                                                   >> 885                 for(size_t j=0; j<ncoef; j++) 
                                                   >> 886                   sum+=coefs[j]*std::exp(scales[j]*r[i]/au);
                                                   >> 887                 phi[i]=sum;
                                                   >> 888         }
                                                   >> 889         
                                                   >> 890         // compute the derivative at the origin for the spline
                                                   >> 891         G4double phiprime0=0.0;
                                                   >> 892         for(size_t j=0; j<ncoef; j++) 
                                                   >> 893           phiprime0+=scales[j]*coefs[j]*std::exp(scales[j]*r[0]/au);
                                                   >> 894         phiprime0*=(1.0/au); // put back in natural units;
                                                   >> 895         
                                                   >> 896         *auval=au;
                                                   >> 897         return c2.lin_log_interpolating_function().load(r, phi, false, 
                                                   >> 898                                                         phiprime0,true,0);
                                                   >> 899 }
                                                   >> 900 
                                                   >> 901 G4_c2_function &LJScreening(G4int z1, G4int z2, size_t npoints, 
                                                   >> 902                             G4double rMax, G4double *auval)
                                                   >> 903 {        
                                                   >> 904 //from Loftager, Besenbacher, Jensen & Sorensen
                                                   >> 905 //PhysRev A20, 1443++, 1979
                                                   >> 906         G4double au=0.8853*0.529*angstrom/std::sqrt(std::pow(z1, 0.6667)
                                                   >> 907                                                     +std::pow(z2,0.6667));
                                                   >> 908         std::vector<G4double> r(npoints), phi(npoints);
                                                   >> 909         
                                                   >> 910         for(size_t i=0; i<npoints; i++) {
                                                   >> 911                 G4double rr=(float)i/(float)(npoints-1);
                                                   >> 912                 r[i]=rr*rr*rMax; 
                                                   >> 913                 // use quadratic r scale to make sampling fine near the center
                                                   >> 914 
                                                   >> 915                 G4double y=std::sqrt(9.67*r[i]/au);
                                                   >> 916                 G4double ysq=y*y;
                                                   >> 917                 G4double phipoly=1+y+0.3344*ysq+0.0485*y*ysq+0.002647*ysq*ysq;
                                                   >> 918                 phi[i]=phipoly*std::exp(-y);
                                                   >> 919                 // G4cout << r[i] << " " << phi[i] << G4endl;
                                                   >> 920         }
910                                                   921 
911 G4NativeScreenedCoulombCrossSection::G4NativeS << 922         // compute the derivative at the origin for the spline
912 {                                              << 923         G4double logphiprime0=(9.67/2.0)*(2*0.3344-1.0); 
913   AddScreeningFunction("zbl", ZBLScreening);   << 924         // #avoid 0/0 on first element
914   AddScreeningFunction("lj", LJScreening);     << 925         logphiprime0 *= (1.0/au); // #put back in natural units
915   AddScreeningFunction("mol", MoliereScreening << 926         
916   AddScreeningFunction("ljzbl", LJZBLScreening << 927         *auval=au;
                                                   >> 928         return c2.lin_log_interpolating_function().load(r, phi, false, 
                                                   >> 929                                                         logphiprime0*phi[0],
                                                   >> 930                                                         true,0);
                                                   >> 931 }
                                                   >> 932 
                                                   >> 933 G4_c2_function &LJZBLScreening(G4int z1, G4int z2, size_t npoints, 
                                                   >> 934                                G4double rMax, G4double *auval)
                                                   >> 935 {        
                                                   >> 936 // hybrid of LJ and ZBL, uses LJ if x < 0.25*auniv, ZBL if x > 1.5*auniv, and 
                                                   >> 937 /// connector in between.  These numbers are selected so the switchover
                                                   >> 938 // is very near the point where the functions naturally cross.
                                                   >> 939         G4double auzbl, aulj;
                                                   >> 940         
                                                   >> 941         c2p zbl=ZBLScreening(z1, z2, npoints, rMax, &auzbl);
                                                   >> 942         c2p lj=LJScreening(z1, z2, npoints, rMax, &aulj);
                                                   >> 943 
                                                   >> 944         G4double au=(auzbl+aulj)*0.5;
                                                   >> 945         lj->set_domain(lj->xmin(), 0.25*au);
                                                   >> 946         zbl->set_domain(1.5*au,zbl->xmax());
                                                   >> 947         
                                                   >> 948         c2p conn=
                                                   >> 949           c2.connector_function(lj->xmax(), lj, zbl->xmin(), zbl, true,0);
                                                   >> 950         c2_piecewise_function_p<G4double> &pw=c2.piecewise_function();
                                                   >> 951         c2p keepit(pw);
                                                   >> 952         pw.append_function(lj);
                                                   >> 953         pw.append_function(conn);
                                                   >> 954         pw.append_function(zbl);
                                                   >> 955         
                                                   >> 956         *auval=au;
                                                   >> 957         keepit.release_for_return();
                                                   >> 958         return pw;
                                                   >> 959 }
                                                   >> 960 
                                                   >> 961 G4NativeScreenedCoulombCrossSection::~G4NativeScreenedCoulombCrossSection() {
                                                   >> 962 }
                                                   >> 963 
                                                   >> 964 G4NativeScreenedCoulombCrossSection::G4NativeScreenedCoulombCrossSection() {
                                                   >> 965         AddScreeningFunction("zbl", ZBLScreening);
                                                   >> 966         AddScreeningFunction("lj", LJScreening);        
                                                   >> 967         AddScreeningFunction("mol", MoliereScreening);        
                                                   >> 968         AddScreeningFunction("ljzbl", LJZBLScreening);        
917 }                                                 969 }
918                                                   970 
919 std::vector<G4String> G4NativeScreenedCoulombC << 971 std::vector<G4String> 
920 {                                              << 972 G4NativeScreenedCoulombCrossSection::GetScreeningKeys() const {
921   std::vector<G4String> keys;                     973   std::vector<G4String> keys;
922   // find the available screening keys            974   // find the available screening keys
923   std::map<std::string, ScreeningFunc>::const_ << 975   std::map<std::string, ScreeningFunc>::const_iterator sfunciter=phiMap.begin();
924   for (; sfunciter != phiMap.end(); sfunciter+ << 976   for(; sfunciter != phiMap.end(); sfunciter++) 
925     keys.push_back((*sfunciter).first);           977     keys.push_back((*sfunciter).first);
926   return keys;                                    978   return keys;
927 }                                                 979 }
928                                                   980 
929 static inline G4double cm_energy(G4double a1,  << 981 static inline G4double cm_energy(G4double a1, G4double a2, G4double t0) {
930 {                                              << 982         // "relativistically correct energy in CM frame"
931   // "relativistically correct energy in CM fr << 983         G4double m1=a1*amu_c2, mass2=a2*amu_c2;
932   G4double m1 = a1 * amu_c2, mass2 = a2 * amu_ << 984         G4double mc2=(m1+mass2);
933   G4double mc2 = (m1 + mass2);                 << 985         G4double f=2.0*mass2*t0/(mc2*mc2);
934   G4double f = 2.0 * mass2 * t0 / (mc2 * mc2); << 986         // old way: return (f < 1e-6) ?  0.5*mc2*f : mc2*(std::sqrt(1.0+f)-1.0);
935   // old way: return (f < 1e-6) ?  0.5*mc2*f : << 987         // formally equivalent to previous, but numerically stable for all 
936   // formally equivalent to previous, but nume << 988         // f without conditional
937   // f without conditional                     << 989         // uses identity (sqrt(1+x) - 1)(sqrt(1+x) + 1) = x
938   // uses identity (sqrt(1+x) - 1)(sqrt(1+x) + << 990         return mc2*f/(std::sqrt(1.0+f)+1.0); 
939   return mc2 * f / (std::sqrt(1.0 + f) + 1.0); << 991 }
940 }                                              << 992 
941                                                << 993 static inline G4double  thetac(G4double m1, G4double mass2, G4double eratio) {
942 static inline G4double thetac(G4double m1, G4d << 994         G4double s2th2=eratio*( (m1+mass2)*(m1+mass2)/(4.0*m1*mass2) );
943 {                                              << 995         G4double sth2=std::sqrt(s2th2);
944   G4double s2th2 = eratio * ((m1 + mass2) * (m << 996         return 2.0*std::asin(sth2);
945   G4double sth2 = std::sqrt(s2th2);            << 
946   return 2.0 * std::asin(sth2);                << 
947 }                                                 997 }
948                                                   998 
949 void G4NativeScreenedCoulombCrossSection::Load << 999 void G4NativeScreenedCoulombCrossSection::LoadData(G4String screeningKey, 
                                                   >> 1000                                                    G4int z1, G4double a1, 
950                                                   1001                                                    G4double recoilCutoff)
951 {                                              << 1002 {                        
952   static const size_t sigLen = 200;            << 1003         static const size_t sigLen=200; 
953   // since sigma doesn't matter much, a very c << 1004         // since sigma doesn't matter much, a very coarse table will do      
954   G4DataVector energies(sigLen);               << 1005         G4DataVector energies(sigLen);
955   G4DataVector data(sigLen);                   << 1006         G4DataVector data(sigLen);
956                                                << 1007         
957   a1 = standardmass(z1);                       << 1008         a1=standardmass(z1); 
958   // use standardized values for mass for buil << 1009         // use standardized values for mass for building tables
959                                                << 1010         
960   const G4MaterialTable* materialTable = G4Mat << 1011         const G4MaterialTable* materialTable = G4Material::GetMaterialTable();
961   G4int nMaterials = G4Material::GetNumberOfMa << 1012         if (materialTable == 0) { return; }
962                                                << 1013   //G4Exception("mhmNativeCrossSection::LoadData - no MaterialTable found)");
963   for (G4int im = 0; im < nMaterials; im++) {  << 1014         
964     const G4Material* material = (*materialTab << 1015         G4int nMaterials = G4Material::GetNumberOfMaterials();
965     const G4ElementVector* elementVector = mat << 1016         
966     const G4int nMatElements = material->GetNu << 1017         for (G4int im=0; im<nMaterials; im++)
967                                                << 1018           {
968     for (G4int iEl = 0; iEl < nMatElements; iE << 1019             const G4Material* material= (*materialTable)[im];
969       const G4Element* element = (*elementVect << 1020             const G4ElementVector* elementVector = material->GetElementVector();
970       G4int Z = element->GetZasInt();          << 1021             const G4int nMatElements = material->GetNumberOfElements();
971       G4double a2 = element->GetA() * (mole /  << 1022                 
972                                                << 1023             for (G4int iEl=0; iEl<nMatElements; iEl++)
973       if (sigmaMap.find(Z) != sigmaMap.end())  << 1024               {
974       // we've already got this element        << 1025                 G4Element* element = (*elementVector)[iEl];
975                                                << 1026                 G4int Z = (G4int) element->GetZ();
976       // find the screening function generator << 1027                 G4double a2=element->GetA()*(mole/gram);
977       std::map<std::string, ScreeningFunc>::it << 1028                         
978       if (sfunciter == phiMap.end()) {         << 1029                 if(sigmaMap.find(Z)!=sigmaMap.end()) continue; 
979         G4ExceptionDescription ed;             << 1030                 // we've already got this element
980         ed << "No such screening key <" << scr << 1031                         
981         G4Exception("G4NativeScreenedCoulombCr << 1032                 // find the screening function generator we need
982       }                                        << 1033                 std::map<std::string, ScreeningFunc>::iterator sfunciter=
983       ScreeningFunc sfunc = (*sfunciter).secon << 1034                   phiMap.find(screeningKey);
984                                                << 1035                 if(sfunciter==phiMap.end()) {
985       G4double au;                             << 1036                   G4ExceptionDescription ed;
986       G4_c2_ptr screen = sfunc(z1, Z, 200, 50. << 1037                   ed << "No such screening key <" 
987       // generate the screening data           << 1038                      << screeningKey << ">"; 
988       G4ScreeningTables st;                    << 1039                   G4Exception("G4NativeScreenedCoulombCrossSection::LoadData",
989                                                << 1040                               "em0003",FatalException,ed);
990       st.EMphiData = screen;  // save our phi  << 1041                 }
991       st.z1 = z1;                              << 1042                 ScreeningFunc sfunc=(*sfunciter).second;
992       st.m1 = a1;                              << 1043                         
993       st.z2 = Z;                               << 1044                 G4double au; 
994       st.m2 = a2;                              << 1045                 G4_c2_ptr screen=sfunc(z1, Z, 200, 50.0*angstrom, &au); 
995       st.emin = recoilCutoff;                  << 1046                 // generate the screening data
996       st.au = au;                              << 1047                 G4ScreeningTables st;
997                                                << 1048         
998       // now comes the hard part... build the  << 1049                 st.EMphiData=screen; //save our phi table
999       // tables from the phi table             << 1050                 st.z1=z1; st.m1=a1; st.z2=Z; st.m2=a2; st.emin=recoilCutoff;
1000       // based on (pi-thetac) = pi*beta*alpha << 1051                 st.au=au;
1001       // alpha is very nearly unity, always   << 1052 
1002       // so just solve it wth alpha=1, which  << 1053                 // now comes the hard part... build the total cross section
1003       // much easier                          << 1054                 // tables from the phi table                        
1004       // this function returns an approximati << 1055                 // based on (pi-thetac) = pi*beta*alpha/x0, but noting that 
1005       // (beta/x0)^2=phi(x0)/(eps*x0)-1 ~ ((p << 1056                 // alpha is very nearly unity, always
1006       // Since we don't need exact sigma valu << 1057                 // so just solve it wth alpha=1, which makes the solution 
1007       // (within a factor of 2 almost always) << 1058                 // much easier
1008       // this rearranges to phi(x0)/(x0*eps)  << 1059                 // this function returns an approximation to 
1009       // 2*theta/pi - theta^2/pi^2            << 1060                 // (beta/x0)^2=phi(x0)/(eps*x0)-1 ~ ((pi-thetac)/pi)^2
1010                                               << 1061                 // Since we don't need exact sigma values, this is good enough 
1011       c2_linear_p<G4double>& c2eps = c2.linea << 1062                 // (within a factor of 2 almost always)
1012       // will store an appropriate eps inside << 1063                 // this rearranges to phi(x0)/(x0*eps) = 
1013       G4_c2_ptr phiau = screen(c2.linear(0.0, << 1064                 // 2*theta/pi - theta^2/pi^2
1014       G4_c2_ptr x0func(phiau / c2eps);        << 1065                         
1015       // this will be phi(x)/(x*eps) when c2e << 1066                 c2_linear_p<G4double> &c2eps=c2.linear(0.0, 0.0, 1.0); 
1016       x0func->set_domain(1e-6 * angstrom / au << 1067                 // will store an appropriate eps inside this in loop
1017       // needed for inverse function          << 1068                 G4_c2_ptr phiau=screen(c2.linear(0.0, 0.0, au));
1018       // use the c2_inverse_function interfac << 1069                 G4_c2_ptr x0func(phiau/c2eps); 
1019       // it is more efficient for an ordered  << 1070                 // this will be phi(x)/(x*eps) when c2eps is correctly set
1020       // computation of values.               << 1071                 x0func->set_domain(1e-6*angstrom/au, 0.9999*screen->xmax()/au); 
1021       G4_c2_ptr x0_solution(c2.inverse_functi << 1072                 // needed for inverse function
1022                                               << 1073                 // use the c2_inverse_function interface for the root finder...
1023       G4double m1c2 = a1 * amu_c2;            << 1074                 // it is more efficient for an ordered 
1024       G4double escale = z1 * Z * elm_coupling << 1075                 // computation of values.
1025       // energy at screening distance         << 1076                 G4_c2_ptr x0_solution(c2.inverse_function(x0func));
1026       G4double emax = m1c2;                   << 1077                         
1027       // model is doubtful in very relativist << 1078                 G4double m1c2=a1*amu_c2;
1028       G4double eratkin = 0.9999 * (4 * a1 * a << 1079                 G4double escale=z1*Z*elm_coupling/au; 
1029       // #maximum kinematic ratio possible at << 1080                 // energy at screening distance
1030       G4double cmfact0 = st.emin / cm_energy( << 1081                 G4double emax=m1c2; 
1031       G4double l1 = std::log(emax);           << 1082                 // model is doubtful in very relativistic range
1032       G4double l0 = std::log(st.emin * cmfact << 1083                 G4double eratkin=0.9999*(4*a1*a2)/((a1+a2)*(a1+a2)); 
1033                                               << 1084                 // #maximum kinematic ratio possible at 180 degrees
1034       if (verbosity >= 1)                     << 1085                 G4double cmfact0=st.emin/cm_energy(a1, a2, st.emin);
1035         G4cout << "Native Screening: " << scr << 1086                 G4double l1=std::log(emax);
1036                << a2 << " " << recoilCutoff < << 1087                 G4double l0=std::log(st.emin*cmfact0/eratkin);
1037                                               << 1088 
1038       for (size_t idx = 0; idx < sigLen; idx+ << 1089                 if(verbosity >=1) 
1039         G4double ee = std::exp(idx * ((l1 - l << 1090                   G4cout << "Native Screening: " << screeningKey << " " 
1040         G4double gamma = 1.0 + ee / m1c2;     << 1091                          << z1 << " " << a1 << " " << 
1041         G4double eratio = (cmfact0 * st.emin) << 1092                     Z << " " << a2 << " " << recoilCutoff << G4endl;
1042         // factor by which ee needs to be red << 1093                         
1043         G4double theta = thetac(gamma * a1, a << 1094                 for(size_t idx=0; idx<sigLen; idx++) {
1044                                               << 1095                   G4double ee=std::exp(idx*((l1-l0)/sigLen)+l0);
1045         G4double eps = cm_energy(a1, a2, ee)  << 1096                   G4double gamma=1.0+ee/m1c2;
1046         // #make sure lab energy is converted << 1097                   G4double eratio=(cmfact0*st.emin)/ee; 
1047         // calculations                       << 1098                   // factor by which ee needs to be reduced to get emin
1048         c2eps.reset(0.0, 0.0, eps);           << 1099                   G4double theta=thetac(gamma*a1, a2, eratio);
1049         // set correct slope in this function << 1100                         
1050                                               << 1101                   G4double eps=cm_energy(a1, a2, ee)/escale; 
1051         G4double q = theta / pi;              << 1102                   // #make sure lab energy is converted to CM for these 
1052         // G4cout << ee << " " << m1c2 << " " << 1103                   // calculations
1053         // << eps << " " << theta << " " << q << 1104                   c2eps.reset(0.0, 0.0, eps); 
1054         // old way using root finder          << 1105                   // set correct slope in this function
1055         // G4double x0= x0func->find_root(1e- << 1106                                 
1056         // 0.9999*screen.xmax()/au, 1.0, 2*q- << 1107                   G4double q=theta/pi;
1057         // new way using c2_inverse_function  << 1108                   // G4cout << ee << " " << m1c2 << " " << gamma << " " 
1058         // useful information so should be a  << 1109                   // << eps << " " << theta << " " << q << G4endl;
1059         // since we are scanning this in stri << 1110                   // old way using root finder
1060         G4double x0 = 0;                      << 1111                   // G4double x0= x0func->find_root(1e-6*angstrom/au, 
1061         try {                                 << 1112                   // 0.9999*screen.xmax()/au, 1.0, 2*q-q*q);
1062           x0 = x0_solution(2 * q - q * q);    << 1113                   // new way using c2_inverse_function which caches 
1063         }                                     << 1114                   // useful information so should be a bit faster
1064         catch (c2_exception&) {               << 1115                   // since we are scanning this in strict order.
1065           G4Exception("G4ScreenedNuclearRecoi << 1116                   G4double x0=0;
1066                       "failure in inverse sol << 1117                   try {
1067         }                                     << 1118                     x0=x0_solution(2*q-q*q);
1068         G4double betasquared = x0 * x0 - x0 * << 1119                   } catch(c2_exception e) {
1069         G4double sigma = pi * betasquared * a << 1120                     //G4Exception(G4String("G4ScreenedNuclearRecoil: failure 
1070         energies[idx] = ee;                   << 1121                     //in inverse solution to generate MFP Tables: ")+e.what());
1071         data[idx] = sigma;                    << 1122                   }
1072       }                                       << 1123                   G4double betasquared=x0*x0 - x0*phiau(x0)/eps;        
1073       screeningData[Z] = st;                  << 1124                   G4double sigma=pi*betasquared*au*au;
1074       sigmaMap[Z] = c2.log_log_interpolating_ << 1125                   energies[idx]=ee;
1075     }                                         << 1126                   data[idx]=sigma;
1076   }                                           << 1127                 }
                                                   >> 1128                 screeningData[Z]=st;
                                                   >> 1129                 sigmaMap[Z] = 
                                                   >> 1130                   c2.log_log_interpolating_function().load(energies, data, 
                                                   >> 1131                                                            true,0,true,0);
                                                   >> 1132               }
                                                   >> 1133           }
1077 }                                                1134 }
1078                                                  1135