Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/materials/src/G4DensityEffectCalculator.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 /materials/src/G4DensityEffectCalculator.cc (Version 11.3.0) and /materials/src/G4DensityEffectCalculator.cc (Version 9.4.p1)


  1 //                                                  1 
  2 // *******************************************    
  3 // * License and Disclaimer                       
  4 // *                                              
  5 // * The  Geant4 software  is  copyright of th    
  6 // * the Geant4 Collaboration.  It is provided    
  7 // * conditions of the Geant4 Software License    
  8 // * LICENSE and available at  http://cern.ch/    
  9 // * include a list of copyright holders.         
 10 // *                                              
 11 // * Neither the authors of this software syst    
 12 // * institutes,nor the agencies providing fin    
 13 // * work  make  any representation or  warran    
 14 // * regarding  this  software system or assum    
 15 // * use.  Please see the license in the file     
 16 // * for the full disclaimer and the limitatio    
 17 // *                                              
 18 // * This  code  implementation is the result     
 19 // * technical work of the GEANT4 collaboratio    
 20 // * By using,  copying,  modifying or  distri    
 21 // * any work based  on the software)  you  ag    
 22 // * use  in  resulting  scientific  publicati    
 23 // * acceptance of all terms of the Geant4 Sof    
 24 // *******************************************    
 25 //                                                
 26                                                   
 27 /*                                                
 28  * Implements calculation of the Fermi density    
 29  * described in:                                  
 30  *                                                
 31  *   R. M. Sternheimer, M. J. Berger, and S. M    
 32  *   effect for the ionization loss of charged    
 33  *   stances. Atom. Data Nucl. Data Tabl., 30:    
 34  *                                                
 35  * Which (among other Sternheimer references)     
 36  *                                                
 37  *   R. M. Sternheimer. The density effect for    
 38  *   materials. Phys. Rev., 88:851­859, 1952.    
 39  *                                                
 40  * The returned values of delta are directly f    
 41  * and not Sternheimer's popular three-part ap    
 42  * introduced in the same paper.                  
 43  *                                                
 44  * Author: Matthew Strait <straitm@umn.edu> 20    
 45  */                                               
 46                                                   
 47 #include "G4DensityEffectCalculator.hh"           
 48                                                   
 49 #include "G4AtomicShells.hh"                      
 50 #include "G4NistManager.hh"                       
 51 #include "G4Pow.hh"                               
 52                                                   
 53 static G4Pow* gpow = G4Pow::GetInstance();        
 54                                                   
 55 const G4int maxWarnings = 20;                     
 56                                                   
 57 G4DensityEffectCalculator::G4DensityEffectCalc    
 58   : fMaterial(mat), nlev(n)                       
 59 {                                                 
 60   fVerbose = std::max(fVerbose, G4NistManager:    
 61                                                   
 62   sternf = new G4double[nlev];                    
 63   levE = new G4double[nlev];                      
 64   sternl = new G4double[nlev];                    
 65   sternEbar = new G4double[nlev];                 
 66   for (G4int i = 0; i < nlev; ++i) {              
 67     sternf[i] = 0.0;                              
 68     levE[i] = 0.0;                                
 69     sternl[i] = 0.0;                              
 70     sternEbar[i] = 0.0;                           
 71   }                                               
 72                                                   
 73   fConductivity = sternx = 0.0;                   
 74   G4bool conductor = (fMaterial->GetFreeElectr    
 75                                                   
 76   G4int sh = 0;                                   
 77   G4double sum = 0.;                              
 78   const G4double tot = fMaterial->GetTotNbOfAt    
 79   for (size_t j = 0; j < fMaterial->GetNumberO    
 80     // The last subshell is considered to cont    
 81     // electrons. Sternheimer 1984 says "the l    
 82     // the element" is used to set the number     
 83     // I'm not sure if that means the highest     
 84     // shell, but in any case, he also says th    
 85     // and offers a possible alternative. This    
 86     // uncertainty in the model.                  
 87     const G4double frac = fMaterial->GetVecNbO    
 88     const G4int Z = fMaterial->GetElement((G4i    
 89     const G4int nshell = G4AtomicShells::GetNu    
 90     for (G4int i = 0; i < nshell; ++i) {          
 91       // For conductors, put *all* top shell e    
 92       // band, regardless of element.             
 93       const G4double xx = frac * G4AtomicShell    
 94       if (i < nshell - 1 || ! conductor) {        
 95         sternf[sh] += xx;                         
 96       }                                           
 97       else {                                      
 98         fConductivity += xx;                      
 99       }                                           
100       levE[sh] = G4AtomicShells::GetBindingEne    
101       ++sh;                                       
102     }                                             
103   }                                               
104   for (G4int i = 0; i < nlev; ++i) {              
105     sum += sternf[i];                             
106   }                                               
107   sum += fConductivity;                           
108                                                   
109   const G4double invsum = (sum > 0.0) ? 1. / s    
110   for (G4int i = 0; i < nlev; ++i) {              
111     sternf[i] *= invsum;                          
112   }                                               
113   fConductivity *= invsum;                        
114   plasmaE = fMaterial->GetIonisation()->GetPla    
115   meanexcite = fMaterial->GetIonisation()->Get    
116 }                                                 
117                                                   
118 G4DensityEffectCalculator::~G4DensityEffectCal    
119 {                                                 
120   delete[] sternf;                                
121   delete[] levE;                                  
122   delete[] sternl;                                
123   delete[] sternEbar;                             
124 }                                                 
125                                                   
126 G4double G4DensityEffectCalculator::ComputeDen    
127 {                                                 
128   if (fVerbose > 1) {                             
129     G4cout << "G4DensityEffectCalculator::Comp    
130            << ", x= " << x << G4endl;             
131   }                                               
132   const G4double approx = fMaterial->GetIonisa    
133   const G4double exact = FermiDeltaCalculation    
134                                                   
135   if (fVerbose > 1) {                             
136     G4cout << "   Delta: computed= " << exact     
137   }                                               
138   if (approx >= 0. && exact < 0.) {               
139     if (fVerbose > 0) {                           
140       ++fWarnings;                                
141       if (fWarnings < maxWarnings) {              
142         G4ExceptionDescription ed;                
143         ed << "Sternheimer fit failed for " <<    
144            << ": Delta exact= " << exact << ",    
145         G4Exception("G4DensityEffectCalculator    
146       }                                           
147     }                                             
148     return approx;                                
149   }                                               
150   // Fall back to approx if exact and approx a    
151   // assumption that this means the exact calc    
152   // somehow, with the exception of the case w    
153   // have seen this clearly-wrong result occur    
154   // low density (1e-25 g/cc).                    
155   if (approx >= 0. && std::abs(exact - approx)    
156     if (fVerbose > 0) {                           
157       ++fWarnings;                                
158       if (fWarnings < maxWarnings) {              
159         G4ExceptionDescription ed;                
160         ed << "Sternheimer exact= " << exact <    
161            << " are too different for " << fMa    
162         G4Exception("G4DensityEffectCalculator    
163       }                                           
164     }                                             
165     return approx;                                
166   }                                               
167   return exact;                                   
168 }                                                 
169                                                   
170 G4double G4DensityEffectCalculator::FermiDelta    
171 {                                                 
172   // Above beta*gamma of 10^10, the exact trea    
173   // precision of the limiting case, for ordin    
174   // convergence goes up as the density goes d    
175   // hard vacuum it converges by 10^20. Also,     
176   // this energy is relevant (x = 20 -> 10^19     
177   // is mostly not here for physical reasons,     
178   // discontinuities in the return value.         
179   if (x > 20.) {                                  
180     return -1.;                                   
181   }                                               
182                                                   
183   sternx = x;                                     
184   G4double sternrho = Newton(1.5, true);          
185                                                   
186   // Negative values, and values much larger t    
187   // Values between zero and one are also susp    
188   if (sternrho <= 0. || sternrho > 100.) {        
189     if (fVerbose > 0) {                           
190       ++fWarnings;                                
191       if (fWarnings < maxWarnings) {              
192         G4ExceptionDescription ed;                
193         ed << "Sternheimer computation failed     
194            << ":\n"                               
195            << "Could not solve for Sternheimer    
196            << "mean ionization energy which is    
197            << "distribution of energy levels,     
198            << "Number of levels: " << nlev <<     
199            << " Plasma energy(eV): " << plasma    
200         for (G4int i = 0; i < nlev; ++i) {        
201           ed << "Level " << i << ": strength "    
202         }                                         
203         G4Exception("G4DensityEffectCalculator    
204       }                                           
205     }                                             
206     return -1.;                                   
207   }                                               
208                                                   
209   // Calculate the Sternheimer adjusted energy    
210   // the Sternheimer parameter rho.               
211   for (G4int i = 0; i < nlev; ++i) {              
212     sternEbar[i] = levE[i] * (sternrho / plasm    
213     sternl[i] = std::sqrt(gpow->powN(sternEbar    
214   }                                               
215   // The derivative of the function we are sol    
216   // negative for positive (physical) values,     
217   // zero is less than zero, it has no solutio    
218   // density effect in the Sternheimer "exact"    
219   // still an approximation).                     
220   //                                              
221   // For conductors, this test is not needed,     
222   // the term fConductivity/(L*L), so the valu    
223   // positive infinity. In the code we don't r    
224   // rather set that term to zero, which means    
225   // used, it would give the wrong result for     
226   if (fConductivity == 0 && Ell(0) <= 0) {        
227     return 0;                                     
228   }                                               
229                                                   
230   // Attempt to find the root from 40 starting    
231   // in log space.  Trying a single starting p    
232   // convergence in most cases.                   
233   for (G4int startLi = -10; startLi < 30; ++st    
234     const G4double sternL = Newton(gpow->powN(    
235     if (sternL != -1.) {                          
236       return DeltaOnceSolved(sternL);             
237     }                                             
238   }                                               
239   return -1.;  // Signal the caller to use the    
240                // because we have been unable     
241 }                                                 
242                                                   
243 /* Newton's method for finding roots.  Adapted    
244  * without the assumption that the input is a     
245  * always expect the roots to be positive, so     
246 G4double G4DensityEffectCalculator::Newton(G4d    
247 {                                                 
248   const G4int maxIter = 100;                      
249   G4int nbad = 0, ngood = 0;                      
250                                                   
251   G4double lambda(start), value(0.), dvalue(0.    
252                                                   
253   if (fVerbose > 2) {                             
254     G4cout << "G4DensityEffectCalculator::Newt    
255   }                                               
256   while (true) {                                  
257     if (first) {                                  
258       value = FRho(lambda);                       
259       dvalue = DFRho(lambda);                     
260     }                                             
261     else {                                        
262       value = Ell(lambda);                        
263       dvalue = DEll(lambda);                      
264     }                                             
265     if (dvalue == 0.0) {                          
266       break;                                      
267     }                                             
268     const G4double del = value / dvalue;          
269     lambda -= del;                                
270                                                   
271     const G4double eps = std::abs(del / lambda    
272     if (eps <= 1.e-12) {                          
273       ++ngood;                                    
274       if (ngood == 2) {                           
275         if (fVerbose > 2) {                       
276           G4cout << "  Converged with result=     
277         }                                         
278         return lambda;                            
279       }                                           
280     }                                             
281     else {                                        
282       ++nbad;                                     
283     }                                             
284     if (nbad > maxIter || std::isnan(value) ||    
285       break;                                      
286     }                                             
287   }                                               
288   if (fVerbose > 2) {                             
289     G4cout << "  Failed to converge last value    
290            << " lambda= " << lambda << G4endl;    
291   }                                               
292   return -1.;                                     
293 }                                                 
294                                                   
295 /* Return the derivative of the equation used     
296  * to solve for the Sternheimer parameter rho.    
297 G4double G4DensityEffectCalculator::DFRho(G4do    
298 {                                                 
299   G4double ans = 0.0;                             
300   for (G4int i = 0; i < nlev; ++i) {              
301     if (sternf[i] > 0.) {                         
302       ans += sternf[i] * gpow->powN(levE[i], 2    
303              (gpow->powN(levE[i] * rho, 2) + 2    
304     }                                             
305   }                                               
306   return ans;                                     
307 }                                                 
308                                                   
309 /* Return the functional value for the equatio    
310  * to solve for the Sternheimer parameter rho.    
311 G4double G4DensityEffectCalculator::FRho(G4dou    
312 {                                                 
313   G4double ans = 0.0;                             
314   for (G4int i = 0; i < nlev; ++i) {              
315     if (sternf[i] > 0.) {                         
316       ans += sternf[i] *                          
317              G4Log(gpow->powN(levE[i] * rho, 2    
318     }                                             
319   }                                               
320   ans *= 0.5;  // pulled out of loop for effic    
321                                                   
322   if (fConductivity > 0.) {                       
323     ans += fConductivity * G4Log(plasmaE * std    
324   }                                               
325   ans -= G4Log(meanexcite);                       
326   return ans;                                     
327 }                                                 
328                                                   
329 /* Return the derivative for the equation used    
330  * solve for the Sternheimer parameter l, call    
331 G4double G4DensityEffectCalculator::DEll(G4dou    
332 {                                                 
333   G4double ans = 0.;                              
334   for (G4int i = 0; i < nlev; ++i) {              
335     if (sternf[i] > 0 && (sternEbar[i] > 0. ||    
336       const G4double y = gpow->powN(sternEbar[    
337       ans += sternf[i] / gpow->powN(y + L * L,    
338     }                                             
339   }                                               
340   ans += fConductivity / gpow->powN(L * L, 2);    
341   ans *= (-2 * L);  // pulled out of the loop     
342   return ans;                                     
343 }                                                 
344                                                   
345 /* Return the functional value for the equatio    
346  * solve for the Sternheimer parameter l, call    
347 G4double G4DensityEffectCalculator::Ell(G4doub    
348 {                                                 
349   G4double ans = 0.;                              
350   for (G4int i = 0; i < nlev; ++i) {              
351     if (sternf[i] > 0. && (sternEbar[i] > 0. |    
352       ans += sternf[i] / (gpow->powN(sternEbar    
353     }                                             
354   }                                               
355   if (fConductivity > 0. && L != 0.) {            
356     ans += fConductivity / (L * L);               
357   }                                               
358   ans -= gpow->powZ(10, -2 * sternx);             
359   return ans;                                     
360 }                                                 
361                                                   
362 /**                                               
363  * Given the Sternheimer parameter l (called '    
364  * the l_i and adjusted energies have been fou    
365  * return the value of delta.  Helper function    
366  */                                               
367 G4double G4DensityEffectCalculator::DeltaOnceS    
368 {                                                 
369   G4double ans = 0.;                              
370   for (G4int i = 0; i < nlev; ++i) {              
371     if (sternf[i] > 0.) {                         
372       ans += sternf[i] *                          
373              G4Log((gpow->powN(sternl[i], 2) +    
374     }                                             
375   }                                               
376   // sternl for the conduction electrons is sq    
377   // no factor of 2./3 as with the other level    
378   if (fConductivity > 0) {                        
379     ans += fConductivity * G4Log((fConductivit    
380   }                                               
381   ans -= gpow->powN(sternL, 2) / (1 + gpow->po    
382   return ans;                                     
383 }                                                 
384