45 m_conv = ElectronMass / (2 * Pi2 * FineStructureConstant * pow(HbarC, 3) * m_density);
47 constexpr unsigned int n2 = 64;
48 const double u = log(2.) / n2;
49 const double um = exp(u);
50 constexpr double kEdge = 1839.;
51 const double ken = log(kEdge / 1.5) / u;
52 m_E[0] = kEdge / pow(2, ken / n2);
53 if (
m_debug) std::cout <<
" Bin Energy [eV]\n";
54 for (
size_t j = 0; j < NEnergyBins; ++j) {
55 m_E[j + 1] = m_E[j] * um;
57 if ((j + 1) % 50 == 0) std::printf(
" %4zu %16.8f\n", j + 1, m_E[j]);
62 std::string path =
"";
63 auto installdir = std::getenv(
"GARFIELD_INSTALL");
65 std::cerr <<
" Environment variable GARFIELD_INSTALL not set.\n";
67 path = std::string(installdir) +
"/share/Garfield/Data/";
70 std::cout <<
" Reading dielectric function.\n";
71 infile.open(path +
"heps.tab", std::ios::in);
73 std::cerr <<
" Could not open heps.tab.\n";
77 for (std::string line; std::getline(infile, line);) {
80 if (IsComment(line))
continue;
81 std::istringstream data(line);
83 double energy, eps1, eps2, lossFunction;
84 data >> j >> energy >> eps1 >> eps2 >> lossFunction;
85 if (j < 1 || j > NEnergyBins) {
86 std::cerr <<
" Index out of range.\n";
93 m_dfdE[j] = lossFunction * m_conv * m_E[j];
97 std::cerr <<
" Error reading dielectric function.\n";
107 std::cout <<
" Reading K and L shell calculations.\n";
108 infile.open(path +
"macom.tab", std::ios::in);
110 std::cerr <<
" Could not open macom.tab.\n";
113 for (std::string line; std::getline(infile, line);) {
115 if (IsComment(line))
continue;
116 std::istringstream data(line);
119 data >> j >> energy >> val;
120 if (j < 1 || j > NEnergyBins) {
121 std::cerr <<
" Index out of range.\n";
130 std::cerr <<
" Error reading K/L shell data.\n";
138 std::cout <<
" Reading M shell calculations.\n";
139 infile.open(path +
"emerc.tab", std::ios::in);
141 std::cerr <<
" Could not open emerc.tab.\n";
144 for (std::string line; std::getline(infile, line);) {
146 if (IsComment(line))
continue;
147 std::istringstream data(line);
149 double energy, a, k1;
150 data >> j >> energy >> a >> k1;
151 if (j < 1 || j > NEnergyBins) {
152 std::cerr <<
" Index out of range.\n";
160 if (j < 19 || j > 30)
continue;
161 std::printf(
" %4zu %11.2f %11.2f %12.6f %12.6f\n",
162 j + 1, m_E[j], energy, m_int[j], m_k1[j]);
166 std::cerr <<
" Error reading M shell data.\n";
173 for (
size_t j = 0; j < NEnergyBins; ++j) {
174 const auto logE = log(m_E[j]);
175 const double dE = m_E[j + 1] - m_E[j];
176 s0 += m_dfdE[j] * dE;
177 s1 += m_dfdE[j] * dE * m_E[j];
178 avI += m_dfdE[j] * dE * logE;
181 std::printf(
" S0 = %15.5f\n", s0);
182 std::printf(
" S1 = %15.5f\n", s1);
183 std::printf(
" lnI = %15.5f\n", avI);
185 m_initialised =
true;
191 if (!m_initialised) {
192 std::cerr <<
m_className <<
"::ComputeCrossSection: Not initialised.\n";
198 std::cerr <<
m_className <<
"::ComputeCrossSection:\n"
199 <<
" Calculating differential cross-section for bg = "
202 const double gamma = sqrt(bg * bg + 1.);
204 const double g1 = (gamma - 1.) * (gamma - 1.) / (gamma * gamma);
205 const double g2 = (2. * gamma - 1.) / (gamma * gamma);
208 const double rm = ElectronMass /
m_mass;
210 double emax = 2 * ElectronMass * bg * bg;
214 emax = 2 * ElectronMass * bg * bg / (1. + 2 * gamma * rm + rm * rm);
216 if (
m_debug) std::printf(
" Max. energy transfer: %12.4f eV\n", emax);
217 const double betaSq = bg * bg / (1. + bg * bg);
218 m_speed = SpeedOfLight * sqrt(betaSq);
219 constexpr size_t nTerms = 3;
220 std::array<double, nTerms + 1> m0;
221 std::array<double, nTerms + 1> m1;
222 std::array<double, nTerms + 1> m2;
227 std::array<std::array<double, NEnergyBins>, nTerms + 1> cs;
228 std::vector<double> cdf(NEnergyBins, 0.);
230 const auto betaSqOverEmax = betaSq / emax;
231 const auto twoMeBetaSq = 2 * ElectronMass * betaSq;
234 for (
size_t j = 0; j < NEnergyBins; ++j) {
236 if (m_E[j] > emax)
break;
237 const auto e2 = m_E[j] * m_E[j];
238 double q1 = RydbergEnergy;
241 q1 = m_k1[j] * m_k1[j] * RydbergEnergy;
242 }
else if (m_E[j] < 100.) {
243 constexpr double k1 = 0.025;
244 q1 = k1 * k1 * RydbergEnergy;
246 const auto qmin = e2 / twoMeBetaSq;
247 if (m_E[j] < 11.9 && q1 <= qmin) {
250 cs[0][j] = m_E[j] * m_dfdE[j] * log(q1 / qmin);
253 auto b1 = 1. - betaSq * m_eps1[j];
254 if (b1 == 0.) b1 = 1.e-20;
255 const auto b2 = betaSq * m_eps2[j];
256 const auto g = m_E[j] * m_dfdE[j] * (-0.5) * log(b1 * b1 + b2 * b2);
257 auto theta = atan(b2 / b1);
258 if (theta < 0.) theta += Pi;
259 const auto epsSq = m_eps1[j] * m_eps1[j] + m_eps2[j] * m_eps2[j];
260 const auto h = m_conv * e2 * (betaSq - m_eps1[j] / epsSq) * theta;
263 cs[2][j] = 2 * m_int[j];
266 const double u = m_E[j] / (ek - m_E[j]);
267 const double v = m_E[j] / ek;
268 cs[2][j] *= (1. + u * u + g1 * v * v - g2 * u);
271 cs[2][j] *= (1. - m_E[j] * betaSqOverEmax);
275 const double dE = m_E[j + 1] - m_E[j];
276 for (
size_t k = 0; k < nTerms; ++k) {
277 m0[k] += cs[k][j] * dE / e2;
278 m1[k] += cs[k][j] * dE / m_E[j];
279 m2[k] += cs[k][j] * dE;
280 cs[nTerms][j] += cs[k][j];
282 m0[nTerms] += cs[nTerms][j] * dE / e2;
283 m1[nTerms] += cs[nTerms][j] * dE / m_E[j];
284 m2[nTerms] += cs[nTerms][j] * dE;
287 if ((j + 1) % 10 != 0)
continue;
288 std::printf(
" %4zu %9.1f %9.4f %9.4f %9.4f %9.4f %9.4f %9.4f\n",
289 j + 1, m_E[j], m_dfdE[j], g, h, cs[0][j], cs[1][j], cs[2][j]);
291 if (jmax < NEnergyBins) cdf.resize(jmax);
293 printf(
" M0: %15.4f %15.4f %15.4f %15.4f\n", m0[0], m0[1], m0[2], m0[3]);
294 printf(
" M1: %15.4f %15.4f %15.4f %15.4f\n", m1[0], m1[1], m1[2], m1[3]);
295 printf(
" M2: %15.4f %15.4f %15.4f %15.4f\n", m2[0], m2[1], m2[2], m2[3]);
298 cdf[0] = 0.5 * m_E[0] * cs[nTerms][0];
299 for (
size_t j = 1; j < jmax; ++j) {
300 const double dE = m_E[j] - m_E[j - 1];
301 cdf[j] = cdf[j - 1] + 0.5 * (cs[nTerms][j - 1] + cs[nTerms][j]) * dE;
304 constexpr double ary = BohrRadius * RydbergEnergy;
305 constexpr double prefactor = 8 * Pi * ary * ary / ElectronMass;
306 const double dec =
m_q *
m_q * m_density * prefactor / betaSq;
307 m_imfp = m0.back() * dec;
308 m_dEdx = m1.back() * dec;
310 std::printf(
" M0 = %12.4f cm-1 ... inverse mean free path\n",
312 std::printf(
" M1 = %12.4f keV/cm ... dE/dx\n", m_dEdx * 1.e-3);
313 std::printf(
" M2 = %12.4f keV2/cm\n", m2.back() * dec * 1.e-6);
316 double integral = cdf.back();
317 if (emax > m_E.back()) {
318 const double e1 = m_E.back();
319 const double rm0 = (1. - 720. * betaSqOverEmax) * (
320 (1. / e1 - 1. / emax) +
321 2 * (1. / (e1 * e1) - 1. / (emax * emax))) -
322 betaSqOverEmax * log(emax / e1);
323 if (
m_debug) std::printf(
" Residual M0 = %15.5f\n", rm0 * 14. * dec);
324 m_imfp += rm0 * 14. * dec;
326 integral += 14. * rm0;
328 const double scale = 1. / integral;
329 for (
size_t j = 0; j < jmax; ++j) {
332 if ((j + 1) % 20 != 0)
continue;
333 std::printf(
" %4zu %9.1f %15.6f\n", j + 1, m_E[j], cdf[j]);
336 for (
size_t i = 0; i < NCdfBins; ++i) {
337 constexpr double step = 1. / NCdfBins;
338 const double x = (i + 1) * step;
341 const auto it1 = std::upper_bound(cdf.cbegin(), cdf.cend(), x);
342 if (it1 == cdf.cbegin()) {
343 m_tab[i] = m_E.front();
346 const auto it0 = std::prev(it1);
347 const double x0 = *it0;
348 const double x1 = *it1;
349 const double y0 = m_E[it0 - cdf.cbegin()];
350 const double y1 = m_E[it1 - cdf.cbegin()];
351 const double f0 = (x - x0) / (x1 - x0);
352 const double f1 = 1. - f0;
353 m_tab[i] = f0 * y0 + f1 * y1;