View | Details | Raw Unified | Return to problem 2121 | Differences between
and this patch

Collapse All | Expand All

(-)a/source/materials/include/G4DensityEffectCalc.hh (+132 lines)
Line 0 Link Here
1
//
2
// ********************************************************************
3
// * License and Disclaimer                                           *
4
// *                                                                  *
5
// * The  Geant4 software  is  copyright of the Copyright Holders  of *
6
// * the Geant4 Collaboration.  It is provided  under  the terms  and *
7
// * conditions of the Geant4 Software License,  included in the file *
8
// * LICENSE and available at  http://cern.ch/geant4/license .  These *
9
// * include a list of copyright holders.                             *
10
// *                                                                  *
11
// * Neither the authors of this software system, nor their employing *
12
// * institutes,nor the agencies providing financial support for this *
13
// * work  make  any representation or  warranty, express or implied, *
14
// * regarding  this  software system or assume any liability for its *
15
// * use.  Please see the license in the file  LICENSE  and URL above *
16
// * for the full disclaimer and the limitation of liability.         *
17
// *                                                                  *
18
// * This  code  implementation is the result of  the  scientific and *
19
// * technical work of the GEANT4 collaboration.                      *
20
// * By using,  copying,  modifying or  distributing the software (or *
21
// * any work based  on the software)  you  agree  to acknowledge its *
22
// * use  in  resulting  scientific  publications,  and indicate your *
23
// * acceptance of all terms of the Geant4 Software license.          *
24
// ********************************************************************
25
//
26
27
/*
28
 * Interface to calculation of the Fermi density effect as per the method
29
 * described in:
30
 *
31
 *   R. M. Sternheimer, M. J. Berger, and S. M. Seltzer. Density
32
 *   effect for the ionization loss of charged particles in various sub-
33
 *   stances. Atom. Data Nucl. Data Tabl., 30:261, 1984.
34
 *
35
 * Which (among other Sternheimer references) builds on:
36
 *
37
 *   R. M. Sternheimer. The density effect for ionization loss in
38
 *   materials. Phys. Rev., 88:851­859, 1952.
39
 *
40
 * The returned values of delta are directly from the Sternheimer calculation,
41
 * and not Sternheimer's popular three-part approximate parameterization
42
 * introduced in the same paper.
43
 *
44
 * Author: Matthew Strait <straitm@umn.edu> 2019
45
 */
46
47
#ifndef G4DensityEffectCalc_HH
48
#define G4DensityEffectCalc_HH
49
50
/*
51
 * Holds the user input and intermediate steps for calculation of
52
 * the Fermi density effect parameter delta, a term in the Bethe
53
 * energy loss formula.
54
 */
55
struct G4DensityEffectCalcData{
56
  /***** User set *****/
57
58
  // Number of energy levels.  If a single element, this is the number
59
  // of subshells.  If several elements, this is the sum of the number
60
  // of subshells.  In principle, could include levels for molecular
61
  // orbitals or other non-atomic states.  The last level is always
62
  // the conduction band.  If the material is an insulator, set the
63
  // oscillator strength for that level to zero and the energy to
64
  // any value.
65
  int nlev;
66
67
  // Sternheimer's "oscillator strengths", which are simply the fraction
68
  // of electrons in a given energy level.  For a single element, this is
69
  // the fraction of electrons in a subshell.  For a compound or mixture,
70
  // it is weighted by the number fraction of electrons contributed by
71
  // each element, e.g. for water, oxygen's electrons are given 8/10 of the
72
  // weight.
73
  double * sternf;
74
75
  // Energy levels.  Can be found for free atoms in, e.g., T. A. Carlson.
76
  // Photoelectron and Auger Spectroscopy. Plenum Press, New York and London,
77
  // 1985. Available in a convenient form in G4AtomicShells.cc.
78
  //
79
  // Sternheimer 1984 implies that the energy level for conduction electrons
80
  // (the final element of this array) should be set to zero, although the
81
  // computation could be run with other values.
82
  double * levE;
83
84
  // The plasma energy of the material in eV, which is simply
85
  // 28.816 sqrt(density Z/A), with density in g/cc.
86
  double plasmaE;
87
88
  // The mean excitation energy of the material in eV, i.e. the 'I' in the
89
  // Bethe energy loss formula.
90
  double meanexcite;
91
92
93
  /***** Results of intermediate calculations *****/
94
95
  // The Sternheimer parameters l_i which appear in Sternheimer 1984 eq(1).
96
  double * sternl;
97
98
  // The adjusted energy levels, as found using Sternheimer 1984 eq(8).
99
  double * sternEbar;
100
101
102
  /***** Packaged for convenience *****/
103
104
  // The Sternheimer 'x' defined as log10(p/m) == log10(beta*gamma).
105
  // This is packaged with the rest of the data for convenience.
106
  // Any value set here is overwritten when the user calls DoFermiDeltaCalc().
107
  double sternx;
108
};
109
110
/**
111
 * Given a material defined in 'par' with a plasma energy, mean excitation
112
 * energy, and set of atomic energy levels ("oscillator frequencies") with
113
 * occupation fractions ("oscillation strengths"), solve for the Sternheimer
114
 * adjustment factor (Sternheimer 1984 eq 8) and record (into 'par') the values
115
 * of the adjusted oscillator frequencies and Sternheimer constants l_i.
116
 * After doing this, 'par' is ready for a calculation of delta for an
117
 * arbitrary particle energy.  Returns true on success, false on failure.
118
 */
119
bool SetupFermiDeltaCalc(G4DensityEffectCalcData * par);
120
121
/**
122
 * Given that SetupFermiDeltaCalc() has already been called, calculate
123
 * the Fermi density effect delta for a given Sternheimer x, defined as
124
 * log10(beta * gamma).  This can be called any number of times without
125
 * rerunning SetupFermiDeltaCalc().
126
 *
127
 * Physically, delta is always non-negative.  Returns -1 on failure.
128
 */
129
double DoFermiDeltaCalc(G4DensityEffectCalcData * par,
130
                        const double sternx);
131
132
#endif
(-)a/source/materials/include/G4IonisParamMat.hh (-19 / +50 lines)
Lines 50-55 Link Here
50
#include "G4Log.hh"
50
#include "G4Log.hh"
51
#include "G4Exp.hh"
51
#include "G4Exp.hh"
52
#include "G4Threading.hh"
52
#include "G4Threading.hh"
53
#include "G4DensityEffectCalc.hh"
53
54
54
class G4Material;                        // forward declaration
55
class G4Material;                        // forward declaration
55
class G4DensityEffectData;
56
class G4DensityEffectData;
Lines 77-83 public: Link Here
77
  inline
78
  inline
78
  G4double  GetTaul()                   const {return fTaul;};
79
  G4double  GetTaul()                   const {return fTaul;};
79
    
80
    
80
  // parameters of the density correction:
81
  // parameters of the Sternheimer 3-part approximate density correction:
81
  inline
82
  inline
82
  G4double  GetPlasmaEnergy()           const {return fPlasmaEnergy;};
83
  G4double  GetPlasmaEnergy()           const {return fPlasmaEnergy;};
83
  inline
84
  inline
Lines 95-110 public: Link Here
95
  inline
96
  inline
96
  G4double  GetD0density()              const {return fD0density;};
97
  G4double  GetD0density()              const {return fD0density;};
97
98
98
  // user defined density correction parameterisation
99
  // user defined density correction parameterisation.  These values are
100
  // only used if the more precise Sternheimer exact form cannot be
101
  // calculated.
99
  void SetDensityEffectParameters(G4double cd, G4double md, G4double ad,
102
  void SetDensityEffectParameters(G4double cd, G4double md, G4double ad,
100
                                  G4double x0, G4double x1, G4double d0);
103
                                  G4double x0, G4double x1, G4double d0);
101
104
102
  // defined density correction parameterisation via base material
105
  // defined density correction parameterisation via base material.
106
  // These values are only used if the more precise Sternheimer exact form
107
  // cannot be calculated.
103
  void SetDensityEffectParameters(const G4Material* bmat);
108
  void SetDensityEffectParameters(const G4Material* bmat);
104
    
109
110
  /// Use the exact form of the density effect intead of the parameterization
111
  ///
112
  /// The "Sternheimer exact" form is calculated as described in
113
  ///
114
  /// R.M. Sternheimer et al. "Density Effect For The Ionization Loss
115
  /// of Charged Particles in Various Substances"
116
  /// Atom. Data Nucl. Data Tabl. 30 (1984) 261-271.
117
  ///
118
  /// It is not really the exact form, which requires detailed optical
119
  /// data to compute, but it is a better approximation than the popular
120
  /// parameterization introduced in Sternheimer's 1952 paper and used
121
  /// in the 1984 paper (among others).  If there were a significant
122
  /// number of substances for which the truly exact form could be
123
  /// calculated, I'd add another function SetExactDensityEffect().
124
  /// Alas, the list is only perhaps aluminum, water, and silicon.
125
  ///
126
  /// When this function is called, the atomic data for the material is
127
  /// used to set up the calculation. This involves finding a root of an
128
  /// equation and can fail. If it fails, this function returns false,
129
  /// a warning message will be printed, and we will fall back to the
130
  /// parameterization as though this function had not been called.
131
  ///
132
  /// Important for users:
133
  /// The effect is different for insulators and conductors. Materials are
134
  /// assumed to be non-conductors by default. To make a conductor:
135
  /// GetMaterialPropertiesTable()->AddConstProperty("conductor", 1)
136
  void SetSternheimerExactDensityEffect();
137
105
  // compute density correction as a function of the kinematic variable
138
  // compute density correction as a function of the kinematic variable
106
  // x = log10(beta*gamma)  
139
  // x = log10(beta*gamma)  
107
  inline G4double DensityCorrection(G4double x);
140
  G4double DensityCorrection(G4double x);
108
141
109
  static G4DensityEffectData* GetDensityEffectData();
142
  static G4DensityEffectData* GetDensityEffectData();
110
143
Lines 158-164 private: Link Here
158
  // Compute mean parameters : ExcitationEnergy,Shell corretion vector ...
191
  // Compute mean parameters : ExcitationEnergy,Shell corretion vector ...
159
  void ComputeMeanParameters();
192
  void ComputeMeanParameters();
160
193
161
  // Compute parameters for the density effect
194
  // Compute Sternheimer 3-part approximation parameters for the density
195
  // effect.  These are only used if the more precise Sternheimer exact form
196
  // cannot be used.
162
  void ComputeDensityEffect();
197
  void ComputeDensityEffect();
163
198
164
  // Compute parameters for the energy fluctuation model
199
  // Compute parameters for the energy fluctuation model
Lines 184-190 private: Link Here
184
  G4double* fShellCorrectionVector;         // shell correction coefficients
219
  G4double* fShellCorrectionVector;         // shell correction coefficients
185
  G4double  fTaul;                          // lower limit of Bethe-Bloch formula
220
  G4double  fTaul;                          // lower limit of Bethe-Bloch formula
186
221
187
  // parameters of the density correction
222
  // parameters of the Sternheimer approximate 3-part density correction
188
  G4double fCdensity;                      // mat.constant
223
  G4double fCdensity;                      // mat.constant
189
  G4double fMdensity;                      // exponent
224
  G4double fMdensity;                      // exponent
190
  G4double fAdensity;                      //
225
  G4double fAdensity;                      //
Lines 192-197 private: Link Here
192
  G4double fX1density;                     //
227
  G4double fX1density;                     //
193
  G4double fD0density;
228
  G4double fD0density;
194
229
230
  // Stores atomic data necessary for computing the Sternheimer exact
231
  // density effect, as well as intermediate stages of the computation.
232
  G4DensityEffectCalcData * fCalcDensity;
233
234
  // If the computation of the Sternheimer exact density effect fails,
235
  // this flag is set to prevent wasting time on repeated failures.
236
  G4bool fCalcDensityFailure = false;
237
195
  G4double fPlasmaEnergy;
238
  G4double fPlasmaEnergy;
196
  G4double fAdjustmentFactor;
239
  G4double fAdjustmentFactor;
197
240
Lines 225-240 private: Link Here
225
};
268
};
226
269
227
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... ....oooOO0OOooo....
270
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... ....oooOO0OOooo....
228
229
inline G4double G4IonisParamMat::DensityCorrection(G4double x)
230
{
231
  // x = log10(beta*gamma)  
232
  G4double y = 0.0;
233
  if(x < fX0density) {
234
    if(fD0density > 0.0) { y = fD0density*G4Exp(twoln10*(x - fX0density)); }
235
  } else if(x >= fX1density) { y = twoln10*x - fCdensity; }
236
  else {y = twoln10*x - fCdensity + fAdensity*G4Exp(G4Log(fX1density - x)*fMdensity);}
237
  return y;
238
}
239
240
#endif
271
#endif
(-)a/source/materials/sources.cmake (+2 lines)
Lines 73-78 GEANT4_DEFINE_MODULE(NAME G4materials Link Here
73
			G4UCNMicroRoughnessHelper.hh
73
			G4UCNMicroRoughnessHelper.hh
74
			G4VIonDEDXTable.hh
74
			G4VIonDEDXTable.hh
75
			G4VMaterialExtension.hh
75
			G4VMaterialExtension.hh
76
			G4DensityEffectCalc.hh
76
    SOURCES
77
    SOURCES
77
			G4AtomicBond.cc
78
			G4AtomicBond.cc
78
			G4AtomicFormFactor.cc
79
			G4AtomicFormFactor.cc
Lines 105-110 GEANT4_DEFINE_MODULE(NAME G4materials Link Here
105
			G4UCNMaterialPropertiesTable.cc
106
			G4UCNMaterialPropertiesTable.cc
106
			G4UCNMicroRoughnessHelper.cc
107
			G4UCNMicroRoughnessHelper.cc
107
			G4VIonDEDXTable.cc
108
			G4VIonDEDXTable.cc
109
			G4DensityEffectCalc.cc
108
    GRANULAR_DEPENDENCIES
110
    GRANULAR_DEPENDENCIES
109
        G4globman
111
        G4globman
110
        G4intercoms
112
        G4intercoms
(-)a/source/materials/src/G4DensityEffectCalc.cc (+267 lines)
Line 0 Link Here
1
//
2
// ********************************************************************
3
// * License and Disclaimer                                           *
4
// *                                                                  *
5
// * The  Geant4 software  is  copyright of the Copyright Holders  of *
6
// * the Geant4 Collaboration.  It is provided  under  the terms  and *
7
// * conditions of the Geant4 Software License,  included in the file *
8
// * LICENSE and available at  http://cern.ch/geant4/license .  These *
9
// * include a list of copyright holders.                             *
10
// *                                                                  *
11
// * Neither the authors of this software system, nor their employing *
12
// * institutes,nor the agencies providing financial support for this *
13
// * work  make  any representation or  warranty, express or implied, *
14
// * regarding  this  software system or assume any liability for its *
15
// * use.  Please see the license in the file  LICENSE  and URL above *
16
// * for the full disclaimer and the limitation of liability.         *
17
// *                                                                  *
18
// * This  code  implementation is the result of  the  scientific and *
19
// * technical work of the GEANT4 collaboration.                      *
20
// * By using,  copying,  modifying or  distributing the software (or *
21
// * any work based  on the software)  you  agree  to acknowledge its *
22
// * use  in  resulting  scientific  publications,  and indicate your *
23
// * acceptance of all terms of the Geant4 Software license.          *
24
// ********************************************************************
25
//
26
27
/*
28
 * Implements calculation of the Fermi density effect as per the method
29
 * described in:
30
 *
31
 *   R. M. Sternheimer, M. J. Berger, and S. M. Seltzer. Density
32
 *   effect for the ionization loss of charged particles in various sub-
33
 *   stances. Atom. Data Nucl. Data Tabl., 30:261, 1984.
34
 *
35
 * Which (among other Sternheimer references) builds on:
36
 *
37
 *   R. M. Sternheimer. The density effect for ionization loss in
38
 *   materials. Phys. Rev., 88:851­859, 1952.
39
 *
40
 * The returned values of delta are directly from the Sternheimer calculation,
41
 * and not Sternheimer's popular three-part approximate parameterization
42
 * introduced in the same paper.
43
 *
44
 * Author: Matthew Strait <straitm@umn.edu> 2019
45
 */
46
47
#include "G4ios.hh"
48
#include "G4DensityEffectCalc.hh"
49
#include <stdio.h>
50
#include <stdlib.h>
51
#include <math.h>
52
53
/* Newton's method for finding roots.  Adapted from G4PolynominalSolver, but
54
 * without the assumption that the input is a polynomial.  Also, here we
55
 * always expect the roots to be positive, so return -1 as an error value. */
56
static double newton(const double start,
57
                     double(*Function)(double, G4DensityEffectCalcData *),
58
                     double(*Derivative)(double, G4DensityEffectCalcData *),
59
                     G4DensityEffectCalcData * par)
60
{
61
  const int maxIter = 100;
62
63
  int nbad = 0, ngood = 0;
64
65
  double Lambda = start;
66
67
  while(true){
68
    const double Value = Function(Lambda, par);
69
    const double Gradient = Derivative(Lambda, par);
70
    Lambda -= Value/Gradient;
71
72
    if(std::fabs((Value/Gradient)/Lambda) <= 1e-12) {
73
      ngood++;
74
      if(ngood == 2) return Lambda;
75
    } else {
76
      nbad++;
77
      if(nbad > maxIter || isnan(Value) || isinf(Value)) return -1;
78
    }
79
  }
80
}
81
82
/* Return the derivative of the equation used
83
 * to solve for the Sternheimer parameter rho. */
84
static double dfrho(double rho, G4DensityEffectCalcData * p)
85
{
86
  double ans = 0;
87
  for(int i = 0; i < p->nlev-1; i++)
88
    if(p->sternf[i] > 0)
89
      ans += p->sternf[i] * pow(p->levE[i], 2) * rho /
90
        (pow(p->levE[i] * rho, 2) + 2./3. * p->sternf[i] * pow(p->plasmaE, 2));
91
92
  return ans;
93
}
94
95
/* Return the functional value for the equation used
96
 * to solve for the Sternheimer parameter rho. */
97
static double frho(double rho, G4DensityEffectCalcData * p)
98
{
99
  double ans = 0;
100
  for(int i = 0; i < p->nlev-1; i++)
101
    if(p->sternf[i] > 0)
102
      ans += p->sternf[i] * log(pow(p->levE[i]*rho, 2) +
103
        2./3. * p->sternf[i]*pow(p->plasmaE, 2));
104
105
  ans *= 0.5; // pulled out of loop for efficiency
106
107
  if(p->sternf[p->nlev-1] > 0)
108
    ans += p->sternf[p->nlev-1] * log(p->plasmaE * sqrt(p->sternf[p->nlev-1]));
109
110
  ans -= log(p->meanexcite);
111
112
  return ans;
113
}
114
115
/* Return the derivative for the equation used to
116
 * solve for the Sternheimer parameter l, called 'L' here. */
117
static double dell(double L, G4DensityEffectCalcData * p)
118
{
119
  double ans = 0;
120
  for(int i = 0; i < p->nlev; i++)
121
    if(p->sternf[i] > 0 && (p->sternEbar[i] > 0 || L != 0))
122
      ans += p->sternf[i]/pow(pow(p->sternEbar[i], 2) + L*L, 2);
123
124
  ans *= -2*L; // pulled out of the loop for efficiency
125
126
  return ans;
127
}
128
129
/* Return the functional value for the equation used to
130
 * solve for the Sternheimer parameter l, called 'L' here. */
131
static double ell(double L, G4DensityEffectCalcData * p)
132
{
133
  double ans = 0;
134
  for(int i = 0; i < p->nlev; i++)
135
    if(p->sternf[i] > 0 && (p->sternEbar[i] > 0 || L != 0))
136
      ans += p->sternf[i]/(pow(p->sternEbar[i], 2) + L*L);
137
138
  ans -= pow(10, - 2 * p->sternx);
139
140
  return ans;
141
}
142
143
/**
144
 * Given the Sternheimer parameter l^2 (called 'sternL' here), and that
145
 * the l_i and adjusted energies have been found with SetupFermiDeltaCalc(),
146
 * return the value of delta.  Helper function for DoFermiDeltaCalc().
147
 */
148
static double delta_once_solved(G4DensityEffectCalcData * p,
149
                                const double sternL)
150
{
151
  double ans = 0;
152
  for(int i = 0; i < p->nlev; i++)
153
    if(p->sternf[i] > 0)
154
      ans += p->sternf[i] *
155
        log((pow(p->sternl[i], 2) + pow(sternL, 2))/pow(p->sternl[i], 2));
156
157
  ans -= pow(sternL, 2)/(1 + pow(10, 2 * p->sternx));
158
  return ans;
159
}
160
161
/**
162
 * Calculate the Sternheimer adjusted energy levels and parameters l_i given
163
 * the Sternheimer parameter rho.  Helper function for SetupFermiDeltaCalc().
164
 */
165
static void calc_Ebarl(G4DensityEffectCalcData * par,
166
                       const double sternrho)
167
{
168
  par->sternl    = (double *)malloc(sizeof(double)*par->nlev);
169
  par->sternEbar = (double *)malloc(sizeof(double)*par->nlev);
170
  for(int i = 0; i < par->nlev; i++){
171
    par->sternEbar[i] = par->levE[i] * sternrho/par->plasmaE;
172
    par->sternl[i] = i < par->nlev-1?
173
      sqrt(pow(par->sternEbar[i], 2) + 2./3. * par->sternf[i])
174
      : sqrt(par->sternf[i]);
175
  }
176
}
177
178
/**
179
 * If the "oscillator strengths" par->sternf do not add up to 1,
180
 * normalize them so that they do.
181
 */
182
static void normalize_sternf(G4DensityEffectCalcData * par)
183
{
184
  double sum = 0;
185
  for(int i = 0; i < par->nlev; i++) sum += par->sternf[i];
186
  for(int i = 0; i < par->nlev; i++) par->sternf[i] /= sum;
187
}
188
189
/**
190
 * At sufficiently high energy, the density effect takes on a simple
191
 * form.  Also at sufficiently high energy, we run into numerical problems
192
 * doing the full calculation.  In that case, return this.
193
 */
194
static double delta_limiting_case(G4DensityEffectCalcData * par,
195
                                  const double sternx)
196
{
197
  return 2 * (log(par->plasmaE/par->meanexcite) + log(10.)*sternx) - 1;
198
}
199
200
201
/********************/
202
/* Public functions */
203
/********************/
204
205
bool SetupFermiDeltaCalc(G4DensityEffectCalcData * par)
206
{
207
  normalize_sternf(par);
208
209
  const double sternrho = newton(1.5, frho, dfrho, par);
210
211
  // Negative values, and values much larger than unity are non-physical.
212
  // Values between zero and one are also suspect, but not as clearly wrong.
213
  if(sternrho <= 0 || sternrho > 100){
214
    G4cerr <<
215
    "*********************************************************************\n"
216
    "* Warning: Could not solve for Sternheimer rho. Probably you have a *\n"
217
    "* mean ionization energy which is incompatible with your            *\n"
218
    "* distribution of energy levels, or an unusually dense material.    *\n"
219
    "* Falling back to parameterization.                                 *\n"
220
    "*********************************************************************"
221
    << G4endl
222
    << "Number of levels: " << par->nlev << G4endl
223
    << "Mean ionization energy: " << par->meanexcite << "eV" << G4endl
224
    << "Plasma energy: " << par->plasmaE << "eV" << G4endl;
225
    for(int i = 0; i < par->nlev; i++)
226
      G4cerr << "Level " << i
227
             << ": strength " << par->sternf[i]
228
             << ": energy " << par->levE[i] << "eV" << G4endl;
229
    return false;
230
  }
231
232
  calc_Ebarl(par, sternrho);
233
  return true;
234
}
235
236
double DoFermiDeltaCalc(G4DensityEffectCalcData * par,
237
                        const double sternx)
238
{
239
  // Above beta*gamma of 10^10, the exact treatment is within machine
240
  // precision of the limiting case, for ordinary solids, at least. The
241
  // convergence goes up as the density goes down, but even in a pretty
242
  // hard vacuum it converges by 10^20. Also, it's hard to imagine how
243
  // this energy is relevant (x = 20 -> 10^19 GeV for muons). So this
244
  // is mostly not here for physical reasons, but rather to avoid ugly
245
  // discontinuities in the return value.
246
  if(sternx > 20) return delta_limiting_case(par, sternx);
247
248
  par->sternx = sternx;
249
250
  // The derivative of the function we are solving for is strictly
251
  // negative for positive (physical) values, so if the value at
252
  // zero is less than zero, it has no solution, and there is no
253
  // density effect in the Sternheimer "exact" treatment (which is
254
  // still an approximation).
255
  if(ell(0, par) <= 0) return 0;
256
257
  // Increase initial guess until it converges.
258
  int startLi;
259
  for(startLi = -10; startLi < 30; startLi++){
260
    const double sternL = newton(pow(2, startLi), &ell, &dell, par);
261
    if(sternL != -1)
262
      return delta_once_solved(par, sternL);
263
  }
264
265
  return -1; // Signal the caller to use the Sternheimer approximation,
266
             // because we have been unable to solve the exact form.
267
}
(-)a/source/materials/src/G4IonisParamMat.cc (-24 / +134 lines)
Lines 38-43 Link Here
38
// 27-09-07, add computation of parameters for ions (V.Ivanchenko)
38
// 27-09-07, add computation of parameters for ions (V.Ivanchenko)
39
// 04-03-08, remove reference to G4NistManager. Add fBirks constant (mma)
39
// 04-03-08, remove reference to G4NistManager. Add fBirks constant (mma)
40
// 30-10-09, add G4DensityEffectData class and density effect computation (VI)
40
// 30-10-09, add G4DensityEffectData class and density effect computation (VI)
41
// 16-01-19, add exact computation of the density effect (M. Strait)
41
42
42
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... ....oooOO0OOooo....
43
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... ....oooOO0OOooo....
43
44
Lines 48-53 Link Here
48
#include "G4Pow.hh"
49
#include "G4Pow.hh"
49
#include "G4PhysicalConstants.hh"
50
#include "G4PhysicalConstants.hh"
50
#include "G4SystemOfUnits.hh"
51
#include "G4SystemOfUnits.hh"
52
#include "G4DensityEffectCalc.hh"
53
#include "G4AtomicShells.hh"
51
54
52
G4DensityEffectData* G4IonisParamMat::fDensityData = nullptr;
55
G4DensityEffectData* G4IonisParamMat::fDensityData = nullptr;
53
56
Lines 69-74 G4IonisParamMat::G4IonisParamMat(const G4Material* material) Link Here
69
  fD0density = 0.0;
72
  fD0density = 0.0;
70
  fAdjustmentFactor = 1.0;
73
  fAdjustmentFactor = 1.0;
71
  if(fDensityData == nullptr) { fDensityData = new G4DensityEffectData(); }
74
  if(fDensityData == nullptr) { fDensityData = new G4DensityEffectData(); }
75
  fCalcDensity = nullptr;
72
76
73
  // compute parameters
77
  // compute parameters
74
  ComputeMeanParameters();
78
  ComputeMeanParameters();
Lines 113-118 G4IonisParamMat::G4IonisParamMat(__void__&) Link Here
113
  twoln10 = 2.*G4Pow::GetInstance()->logZ(10);
117
  twoln10 = 2.*G4Pow::GetInstance()->logZ(10);
114
118
115
  if(fDensityData == nullptr) { fDensityData = new G4DensityEffectData(); }
119
  if(fDensityData == nullptr) { fDensityData = new G4DensityEffectData(); }
120
  fCalcDensity = nullptr;
116
}
121
}
117
122
118
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... ....oooOO0OOooo....
123
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... ....oooOO0OOooo....
Lines 213-220 void G4IonisParamMat::ComputeDensityEffect() Link Here
213
    }
218
    }
214
  }
219
  }
215
220
216
  //G4cout<<"DensityEffect for "<<fMaterial->GetName()<<"  "<< idx << G4endl; 
217
218
  if(idx >= 0) {
221
  if(idx >= 0) {
219
222
220
    // Take parameters for the density effect correction from
223
    // Take parameters for the density effect correction from
Lines 231-241 void G4IonisParamMat::ComputeDensityEffect() Link Here
231
    fPlasmaEnergy = fDensityData->GetPlasmaEnergy(idx);
234
    fPlasmaEnergy = fDensityData->GetPlasmaEnergy(idx);
232
    fAdjustmentFactor = fDensityData->GetAdjustmentFactor(idx);
235
    fAdjustmentFactor = fDensityData->GetAdjustmentFactor(idx);
233
236
234
    // parameter C is computed and not taken from Sternheimer tables
235
    //fCdensity = 1. + 2*G4Log(fMeanExcitationEnergy/fPlasmaEnergy);
236
    //G4cout << "IonisParamMat: " << fMaterial->GetName() 
237
    //	   << "  Cst= " << Cdensity << " C= " << fCdensity << G4endl;
238
239
    // correction on nominal density
237
    // correction on nominal density
240
    fCdensity  += corr;
238
    fCdensity  += corr;
241
    fX0density += corr/twoln10;
239
    fX0density += corr/twoln10;
Lines 279-287 void G4IonisParamMat::ComputeDensityEffect() Link Here
279
      //
277
      //
280
      fMdensity = 3.;
278
      fMdensity = 3.;
281
      fX1density = 4.0;
279
      fX1density = 4.0;
282
      //static const G4double ClimiG[] = {10.,10.5,11.,11.5,12.25,13.804};
283
      //static const G4double X0valG[] = {1.6,1.7,1.8,1.9,2.0,2.0};
284
      //static const G4double X1valG[] = {4.0,4.0,4.0,4.0,4.0,5.0};
285
280
286
      if(fCdensity < 10.) {
281
      if(fCdensity < 10.) {
287
	fX0density = 1.6; 
282
	fX0density = 1.6; 
Lines 311-317 void G4IonisParamMat::ComputeDensityEffect() Link Here
311
  // change parameters if the gas is not in STP.
306
  // change parameters if the gas is not in STP.
312
  // For the correction the density(STP) is needed. 
307
  // For the correction the density(STP) is needed. 
313
  // Density(STP) is calculated here : 
308
  // Density(STP) is calculated here : 
314
  
315
    
309
    
316
  if (State == kStateGas) { 
310
  if (State == kStateGas) { 
317
    G4double Density  = fMaterial->GetDensity();
311
    G4double Density  = fMaterial->GetDensity();
Lines 333-351 void G4IonisParamMat::ComputeDensityEffect() Link Here
333
    fAdensity = twoln10*(Xa-fX0density)
327
    fAdensity = twoln10*(Xa-fX0density)
334
      /std::pow((fX1density-fX0density),fMdensity);
328
      /std::pow((fX1density-fX0density),fMdensity);
335
  }
329
  }
336
  /*  
337
  G4cout << "G4IonisParamMat: density effect data for <" 
338
         << fMaterial->GetName() 
339
	 << "> " << G4endl;
340
  G4cout << "Eplasma(eV)= " << fPlasmaEnergy/eV
341
	 << " rho= " << fAdjustmentFactor
342
	 << " -C= " << fCdensity 
343
	 << " x0= " << fX0density
344
	 << " x1= " << fX1density
345
	 << " a= " << fAdensity
346
	 << " m= " << fMdensity
347
	 << G4endl;
348
  */
349
}
330
}
350
331
351
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... ....oooOO0OOooo....
332
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... ....oooOO0OOooo....
Lines 488-493 void G4IonisParamMat::SetDensityEffectParameters(const G4Material* bmat) Link Here
488
#endif
469
#endif
489
}
470
}
490
471
472
void G4IonisParamMat::SetSternheimerExactDensityEffect()
473
{
474
  std::vector<G4int> Z;
475
  std::vector<double> numberfracs;
476
477
  const bool isconductor =
478
       fMaterial->GetMaterialPropertiesTable() != nullptr
479
   && fMaterial->GetMaterialPropertiesTable()->ConstPropertyExists("conductor")
480
   && fMaterial->GetMaterialPropertiesTable()->GetConstProperty("conductor");
481
482
  if(fCalcDensity != nullptr) delete fCalcDensity;
483
  fCalcDensity = new G4DensityEffectCalcData;
484
  memset(fCalcDensity, 0, sizeof(G4DensityEffectCalcData));
485
486
  fCalcDensity->nlev = 0;
487
  for(unsigned int i = 0; i < fMaterial->GetNumberOfElements(); i++){
488
    Z.push_back(fMaterial->GetElement(i)->GetZ());
489
    fCalcDensity->nlev += G4AtomicShells::GetNumberOfShells(Z[i]);
490
  }
491
492
  // The last level is the conduction level.  If this is *not* a conductor,
493
  // make a dummy conductor level with zero electrons in it.
494
  if(!isconductor) fCalcDensity->nlev++;
495
496
  for(unsigned int i = 0; i < fMaterial->GetNumberOfElements(); i++)
497
    numberfracs.push_back(fMaterial->GetVecNbOfAtomsPerVolume()[i]/
498
                          fMaterial->GetTotNbOfAtomsPerVolume());
499
500
  fCalcDensity->sternf = (double *)malloc(sizeof(double) * fCalcDensity->nlev);
501
  fCalcDensity->levE   = (double *)malloc(sizeof(double) * fCalcDensity->nlev);
502
  memset(fCalcDensity->sternf, 0, sizeof(double)*fCalcDensity->nlev);
503
  memset(fCalcDensity->levE, 0, sizeof(double)*fCalcDensity->nlev);
504
505
  int sh = 0;
506
  for(unsigned int j = 0; j < fMaterial->GetNumberOfElements(); j++){
507
    // The last subshell is considered to contain the conduction
508
    // electrons. Sternheimer 1984 says "the lowest chemical valance of
509
    // the element" is used to set the number of conduction electrons.
510
    // I'm not sure if that means the highest subshell or the whole
511
    // shell, but in any case, he also says that the choice is arbitrary
512
    // and offers a possible alternative. This is one of the sources of
513
    // uncertainty in the model.
514
    const int nshell = G4AtomicShells::GetNumberOfShells(Z[j]);
515
    for(int i = 0; i < nshell; i++){
516
      // For conductors, put *all* top shell electrons into the conduction
517
      // band, regardless of element.
518
      const int lev = i < nshell-1 || !isconductor? sh: fCalcDensity->nlev-1;
519
      fCalcDensity->sternf[lev] += numberfracs[j] *
520
        double(G4AtomicShells::GetNumberOfElectrons(Z[j], i));
521
      fCalcDensity->levE[lev] = G4AtomicShells::GetBindingEnergy(Z[j], i)/eV;
522
      sh++;
523
    }
524
  }
525
526
  if(!isconductor){
527
    fCalcDensity->sternf[fCalcDensity->nlev-1] = 0; // No electrons
528
    fCalcDensity->levE[fCalcDensity->nlev-1] = 1; // dummy value
529
  }
530
  else{
531
    fCalcDensity->levE[fCalcDensity->nlev-1] = 0;
532
  }
533
534
  double sumZ = 0, sumA = 0;
535
  for(unsigned int i = 0; i < fMaterial->GetNumberOfElements(); i++){
536
    sumA += numberfracs[i] * fMaterial->GetElement(i)->GetAtomicMassAmu();
537
    sumZ += numberfracs[i] * fMaterial->GetElement(i)->GetZ();
538
  }
539
540
  fCalcDensity->plasmaE = 28.816 * sqrt(fMaterial->GetDensity()/(g/cm3)
541
    * sumZ/sumA);
542
  fCalcDensity->meanexcite = fMeanExcitationEnergy/eV;
543
544
  // In case of a fit failure, SetupFermiDeltaCalc prints a warning.
545
  // We then delete fCalcDensity so it won't be used.
546
  if(!SetupFermiDeltaCalc(fCalcDensity)){
547
    free(fCalcDensity->sternf);
548
    free(fCalcDensity->levE);
549
    delete fCalcDensity;
550
    fCalcDensity = nullptr;
551
    fCalcDensityFailure = true;
552
  }
553
}
554
491
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... ....oooOO0OOooo....
555
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... ....oooOO0OOooo....
492
556
493
G4double G4IonisParamMat::FindMeanExcitationEnergy(const G4Material* mat) const
557
G4double G4IonisParamMat::FindMeanExcitationEnergy(const G4Material* mat) const
Lines 574-576 G4double G4IonisParamMat::FindMeanExcitationEnergy(const G4Material* mat) const Link Here
574
638
575
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... ....oooOO0OOooo....
639
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... ....oooOO0OOooo....
576
640
641
G4double G4IonisParamMat::DensityCorrection(G4double x)
642
{
643
  // If we are set up to calculate the density effect precisely,
644
  // do that.  Otherwise, fall back to Sternheimer 3-part approximations.
645
  if(fCalcDensity == nullptr && !fCalcDensityFailure)
646
    SetSternheimerExactDensityEffect();
647
648
  // x = log10(beta*gamma)
649
  G4double approx = 0.0;
650
  if(x < fX0density) {
651
    if(fD0density > 0.0)
652
      approx = fD0density*G4Exp(twoln10*(x - fX0density));
653
  }
654
  else if(x >= fX1density) {
655
    approx = twoln10*x - fCdensity;
656
  }
657
  else{
658
    approx = twoln10*x - fCdensity
659
        + fAdensity*G4Exp(G4Log(fX1density - x)*fMdensity);
660
  }
661
662
  if(fCalcDensity != nullptr){
663
    const double exact = DoFermiDeltaCalc(fCalcDensity, x);
664
    if(approx > 0 && exact < 0){
665
      G4cerr << "Error: Sternheimer fit failed for "
666
        << fMaterial->GetName() << ". x = " << x << ": Delta = "
667
        << exact << " exact " << approx  << " approx" << G4endl;
668
      return approx;
669
    }
670
671
    // Fall back to approx if exact and approx are very different, under the
672
    // assumption that this means the exact calculation has gone haywire
673
    // somehow, with the exception of the case where approx is negative.  I
674
    // have seen this clearly-wrong result occur for substances with extremely
675
    // low density (1e-25 g/cc).
676
    if(approx >= 0 && fabs(exact - approx) > 1){
677
      G4cerr << "Error: Sternheimer exact, " << exact << ", and approx, "
678
        << approx << " are too different for "
679
        << fMaterial->GetName() << ", x = " << x << G4endl;
680
      return approx;
681
    }
682
    return exact;
683
  }
684
685
  return approx;
686
}
(-)a/source/processes/electromagnetic/highenergy/src/G4mplIonisationModel.cc (-1 / +1 lines)
Lines 202-208 G4double G4mplIonisationModel::ComputeDEDXAhlen(const G4Material* material, Link Here
202
202
203
  dedx += 0.5 * k - B[nmpl];
203
  dedx += 0.5 * k - B[nmpl];
204
204
205
  // density effect correction
205
  // Sternheimer 3-part approximate density effect correction
206
  G4double deltam;
206
  G4double deltam;
207
  G4double x = log(bg2) / twoln10;
207
  G4double x = log(bg2) / twoln10;
208
  if ( x >= x0den ) {
208
  if ( x >= x0den ) {

Return to problem 2121