Garfield++ 4.0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
PhotoAbsCS.cpp
Go to the documentation of this file.
1#include <cmath>
2#include <fstream>
3#include <iomanip>
8
9// 2004, I. Smirnov
10
11//#define DEBUG_PRINT_get_escape_particles
12//#define DEBUG_ignore_non_standard_channels
13
14//#define ALWAYS_LINEAR_INTERPOLATION // how the paper was computed
15
16namespace {
17
18/// Determine whether to use linear or nonlinear interpolation.
19/// Usually photoabsorption cross sections decrease as inverse power function
20/// of power like -2.75. Its linear interpolation inside large energy
21/// intervals is remarkably not precise. This function is designed
22/// to determine the cases common for the total program when the inverse power
23/// function is applied in such intervals.
24/// Conditions are empirical.
25/// true - nonlinear, false - linear.
26/// Energies and threshold are given in MeV.
27/// e1 should be < e2.
28bool sign_nonlinear_interpolation(double e1, double cs1, double e2, double cs2,
29 double threshold) {
30#ifdef ALWAYS_LINEAR_INTERPOLATION
31 return false;
32#else
33 // normal case:
34 if (cs2 >= cs1 || cs2 <= 0 || e1 < 300.0e-6 || e1 < 1.5 * threshold) {
35 return false;
36 }
37 const double pw = log(cs1 / cs2) / log(e1 / e2);
38 if (pw >= -1.0) {
39 // good case for linear interpolation
40 return false;
41 } else if (pw < -5.0) {
42 // unclear odd case, power would be dangerous
43 return false;
44 }
45 // non-linear interpolation
46 return true;
47#endif
48}
49
50/// Fit table by a straight line or by inverse power function
51/// (see sign_nonlinear_interpolation) and integrate the area below it.
52/// The function (and the result) are assumed to be non-negative.
53/// The tail is not added right here, but added after the call of this function.
54/// The theshold is used to restrict this function from the left.
55/// If threshold is less than e[0], the function is extrapolated
56/// by the straight line till threshold.
57/// If this line crosses zero, it is extrapolated only till this point.
58double my_integr_fun(double xp1, double yp1, double xp2, double yp2,
59 double xmin, double /*xmax*/, double x1, double x2) {
60 const bool nonlin = sign_nonlinear_interpolation(xp1, yp1, xp2, yp2, xmin);
61 return nonlin ? Heed::t_integ_power_2point<double>(xp1, yp1, xp2, yp2, x1, x2)
62 : Heed::t_integ_straight_2point<double>(xp1, yp1, xp2, yp2, x1,
63 x2, 0, 1);
64}
65
66double my_val_fun(double xp1, double yp1, double xp2, double yp2, double xmin,
67 double /*xmax*/, double x) {
68 const bool nonlin = sign_nonlinear_interpolation(xp1, yp1, xp2, yp2, xmin);
69 return nonlin
70 ? Heed::t_value_power_2point<double>(xp1, yp1, xp2, yp2, x)
71 : Heed::t_value_straight_2point<double>(xp1, yp1, xp2, yp2, x, 1);
72}
73}
74
75namespace Heed {
76
77//---------------------------------------------------------
78
79PhotoAbsCS::PhotoAbsCS() : name(""), number(-1), Z(0), threshold(0.0) {}
80
81PhotoAbsCS::PhotoAbsCS(const std::string& fname, int fZ, double fthreshold)
82 : name(fname), number(-1), Z(fZ), threshold(fthreshold) {
83
84 // Try to get the (shell) number from the name.
85 std::istringstream ss(name);
86 int i = -100;
87 ss >> i;
88 if (i >= 1 && i <= 50) number = i;
89}
90
91void PhotoAbsCS::print(std::ostream& file, int l) const {
92 if (l <= 0) return;
93 Ifile << "PhotoAbsCS: name=" << name << " Z = " << Z
94 << " threshold = " << threshold << std::endl;
95}
96
97//---------------------------------------------------------
98
100 double fstep, long fmax_q_step)
101// : real_pacs(apacs, do_clone),
102 : width(fwidth),
103 max_q_step(fmax_q_step),
104 step(fstep) {
105 mfunname("AveragePhotoAbsCS::AveragePhotoAbsCS(...)");
106 check_econd11(apacs, == nullptr, mcerr);
107 real_pacs.reset(apacs);
108 // Check the parameters (step = 0.5 * width is bad but OK).
109 if (fwidth > 0.0) check_econd11(fstep, >= 0.6 * fwidth, mcerr);
110 // Copy the parameters of the "real" cross-section.
111 name = real_pacs->get_name();
112 number = real_pacs->get_number();
113 Z = real_pacs->get_Z();
114 threshold = real_pacs->get_threshold();
115}
116
117double AveragePhotoAbsCS::get_CS(double energy) const {
118 mfunname("double AveragePhotoAbsCS::get_CS(double energy) const");
119 // In case of zero width, return the unmodified "real" cross-section.
120 if (width == 0.0) return real_pacs->get_CS(energy);
121 const double w2 = width * 0.5;
122 const double e1 = std::max(energy - w2, 0.);
123 return real_pacs->get_integral_CS(e1, energy + w2) / width;
124}
125
127 double energy2) const {
128 mfunname("double AveragePhotoAbsCS::get_integral_CS(...) const");
129 if (width == 0.0 || energy1 >= energy2) {
130 // Return the integral of the unmodified "real" cross-section.
131 return real_pacs->get_integral_CS(energy1, energy2);
132 }
133 long q = long((energy2 - energy1) / step);
134 if (q > max_q_step) {
135 return real_pacs->get_integral_CS(energy1, energy2);
136 }
137 q++;
138 const double rstep = (energy2 - energy1) / q;
139 double x0 = energy1 + 0.5 * rstep;
140 double s = 0.0;
141 for (long n = 0; n < q; n++) s += get_CS(x0 + rstep * n);
142 return s * rstep;
143}
144
145void AveragePhotoAbsCS::scale(double fact) {
146 mfunname("void AveragePhotoAbsCS::scale(double fact)");
147 real_pacs->scale(fact);
148}
149
150void AveragePhotoAbsCS::print(std::ostream& file, int l) const {
151 mfunname("void PhotoAbsCS::print(std::ostream& file, int l) const");
152 Ifile << "AveragePhotoAbsCS: width = " << width << " step=" << step
153 << " max_q_step=" << max_q_step << '\n';
154 indn.n += 2;
155 real_pacs->print(file, l);
156 indn.n -= 2;
157}
158
159//---------------------------------------------------------
160
162 : PhotoAbsCS("H", 1, 15.43e-6) {
163 number = 1;
164}
165
166double HydrogenPhotoAbsCS::get_CS(double energy) const {
167 if (energy < threshold || energy == DBL_MAX) return 0.0;
168 // The factor 0.5 is needed because we have one atom instead of two.
169 return 0.5 * prefactor * 0.0535 * (pow(100.0e-6 / energy, 3.228));
170}
171
173 double e2) const {
174 if (e2 < threshold) return 0.;
175 if (e1 < threshold) e1 = threshold;
176 const double c1 = 0.5 * 0.0535 * pow(100.0e-6, 3.228) / 2.228;
177 if (e2 == DBL_MAX) {
178 return prefactor * c1 * (1. / pow(e1, 2.228));
179 } else {
180 return prefactor * c1 * (1. / pow(e1, 2.228) - 1. / pow(e2, 2.228));
181 }
182}
183
184void HydrogenPhotoAbsCS::scale(double fact) { prefactor = fact; }
185
186void HydrogenPhotoAbsCS::print(std::ostream& file, int l) const {
187 if (l <= 0) return;
188 Ifile << "HydrogenPhotoAbsCS: name=" << name << " Z = " << Z
189 << " threshold = " << threshold << std::endl;
190}
191
192//---------------------------------------------------------
193
194SimpleTablePhotoAbsCS::SimpleTablePhotoAbsCS(const std::string& fname, int fZ,
195 double fthreshold,
196 const std::string& ffile_name)
197 : PhotoAbsCS(fname, fZ, fthreshold), file_name(ffile_name) {
198 mfunnamep("SimpleTablePhotoAbsCS::SimpleTablePhotoAbsCS(...)");
199 std::ifstream file(file_name.c_str());
200 if (!file) {
201 funnw.ehdr(mcerr);
202 mcerr << "cannot open file " << file_name << std::endl;
203 spexit(mcerr);
204 }
205 ener.reserve(20);
206 cs.reserve(20);
207 do {
208 // Read the energy.
209 double x = 0.;
210 file >> x;
211 if (!file.good()) break;
212 // Make sure it is non-negative and in ascending order.
213 check_econd11(x, < 0.0, mcerr);
214 if (!ener.empty()) check_econd12(x, <, ener.back(), mcerr);
215 // Read the cross-section.
216 double y = 0.;
217 file >> y;
218 if (!file.good()) break;
219 check_econd11(y, < 0.0, mcerr);
220 // Add the point to the table.
221 ener.push_back(x * 1.e-6);
222 cs.push_back(y);
223 } while (1);
224}
225
226SimpleTablePhotoAbsCS::SimpleTablePhotoAbsCS(const std::string& fname, int fZ,
227 double fthreshold,
228 const std::vector<double>& fener,
229 const std::vector<double>& fcs)
230 : PhotoAbsCS(fname, fZ, fthreshold),
231 file_name("none"),
232 ener(fener),
233 cs(fcs) {
234 mfunname("SimpleTablePhotoAbsCS::SimpleTablePhotoAbsCS(...)");
235 check_econd12(ener.size(), !=, cs.size(), mcerr);
236}
237
238SimpleTablePhotoAbsCS::SimpleTablePhotoAbsCS(const std::string& fname, int fZ,
239 double fthreshold, int l,
240 double E0, double yw, double ya,
241 double P, double sigma)
242 : PhotoAbsCS(fname, fZ, fthreshold) {
243 mfunname("SimpleTablePhotoAbsCS::SimpleTablePhotoAbsCS(...)");
244 const long q = 1000;
245 // Make a logarithmic energy mesh.
246 ener.resize(q, 0.);
247 const double emin = 2.e-6;
248 const double emax = 2.e-1;
249 const double rk = pow(emax / emin, (1.0 / double(q)));
250 double e2 = emin;
251 for (long n = 0; n < q; n++) {
252 const double e1 = e2;
253 e2 = e2 * rk;
254 ener[n] = (e1 + e2) * 0.5;
255 }
256 cs.assign(q, 0.);
257 for (long n = 0; n < q; n++) {
258 double energy = ener[n];
259 if (energy < threshold) continue;
260 const double Q = 5.5 + l - 0.5 * P;
261 const double y = energy / E0;
262 const double Fpasc = ((y - 1) * (y - 1) + yw * yw) * pow(y, (-Q)) *
263 pow((1.0 + sqrt(y / ya)), (-P));
264 cs[n] = Fpasc * sigma;
265 }
267}
268
270 const SimpleTablePhotoAbsCS& part,
271 double emax_repl) {
272 mfunname(
273 "SimpleTablePhotoAbsCS::SimpleTablePhotoAbsCS(const "
274 "SimpleTablePhotoAbsCS& total,...)");
275
276 *this = total; // to assure that all is preserved
277
278 long qe_i = total.ener.size();
279
280 const std::vector<double>& ener_r = part.get_arr_ener();
281 const std::vector<double>& cs_r = part.get_arr_CS();
282 long qe_r = ener_r.size();
283 std::vector<double> new_ener;
284 std::vector<double> new_cs;
285 // first write replacements
286 for (long ne = 0; ne < qe_r; ne++) {
287 if (ener_r[ne] >= total.get_threshold() && ener_r[ne] <= emax_repl) {
288 new_ener.push_back(ener_r[ne]);
289 new_cs.push_back(cs_r[ne]);
290 }
291 }
292 for (long ne = 0; ne < qe_i; ne++) {
293 if (ener[ne] >= total.get_threshold() && ener[ne] > emax_repl) {
294 new_ener.push_back(total.ener[ne]);
295 new_cs.push_back(total.cs[ne]);
296 }
297 }
298 ener.swap(new_ener);
299 cs.swap(new_cs);
300}
301
303 const long q = ener.size();
304 long ne = 0;
305 for (ne = 0; ne < q; ne++) {
306 if (cs[ne] > 0.0) break;
307 }
308 if (ne <= 0) return;
309 const long qn = q - ne;
310 std::vector<double> enern(qn);
311 std::vector<double> csn(qn);
312 for (long nez = ne; nez < q; nez++) {
313 enern[nez - ne] = ener[nez];
314 csn[nez - ne] = cs[nez];
315 }
316 ener = enern;
317 cs = csn;
318}
320 const long q = ener.size();
321 long ne = 0;
322 for (ne = 0; ne < q; ne++) {
323 if (cs[ne] > level) break;
324 }
325 if (ne <= 0) return;
326 const long qn = q - ne;
327 std::vector<double> enern(qn);
328 std::vector<double> csn(qn);
329 for (long nez = ne; nez < q; nez++) {
330 enern[nez - ne] = ener[nez];
331 csn[nez - ne] = cs[nez];
332 }
333 ener = enern;
334 cs = csn;
335}
336
337double SimpleTablePhotoAbsCS::get_CS(double energy) const {
338 mfunname("double SimpleTablePhotoAbsCS::get_CS(double energy) const");
339 long q = ener.size();
340 if (q == 0) return 0.0;
341 check_econd11(q, == 1, mcerr);
342 if (energy < threshold) return 0.;
343 if (energy <= ener[q - 1]) {
346 double, std::vector<double>,
348 pcm, cs, &my_val_fun, energy, 1, threshold, 0, DBL_MAX);
349 } else {
350 if (energy == DBL_MAX)
351 return 0.0;
352 else
353 return cs[q - 1] * pow(energy, -2.75) / pow(ener[q - 1], -2.75);
354 }
355}
356
358 double energy2) const {
359 mfunname("double SimpleTablePhotoAbsCS::get_integral_CS(...)");
360
361 const long q = ener.size();
362 if (q == 0) return 0.0;
363 check_econd11(q, == 1, mcerr);
364 if (energy2 < threshold) return 0.0;
365 if (energy1 < threshold) energy1 = threshold;
366 double s = 0.0;
367 double energy21 = ener[q - 1];
368 if (energy1 < energy21) {
369 if (energy21 > energy2) energy21 = energy2;
370 check_econd12(energy1, >, energy21, mcerr);
373 double, std::vector<double>,
375 pcm, cs, &my_integr_fun, energy1, energy21, 1, threshold, 0, DBL_MAX);
376 }
377 // print(mcout, 3);
378 // mcout << "energy1="<<energy1
379 // << " energy21="<<energy21
380 // << " ener[q-1]="<<ener[q-1]
381 // << " threshold="<<threshold
382 // << " s="<<s<<'\n';
383 check_econd11(s, < 0.0, mcout);
384 if (energy2 > ener[q - 1]) {
385 // add tail
386 if (energy2 == DBL_MAX) {
387 if (energy1 < ener[q - 1]) energy1 = ener[q - 1];
388 double c =
389 cs[q - 1] / (1.75 * pow(ener[q - 1], -2.75)) * pow(energy1, -1.75);
390 // check_econd11(c , < 0.0, mcout);
391 s += c;
392 } else {
393 if (energy1 < ener[q - 1]) energy1 = ener[q - 1];
394 double c = cs[q - 1] / (1.75 * pow(ener[q - 1], -2.75)) *
395 (pow(energy1, -1.75) - pow(energy2, -1.75));
396 // check_econd11(c , < 0.0, mcout);
397 s += c;
398 }
399 }
400 return s;
401}
402
404 mfunnamep("void SimpleTablePhotoAbsCS::scale(double fact)");
405 const long q = ener.size();
406 for (long n = 0; n < q; ++n) cs[n] *= fact;
407}
408
409void SimpleTablePhotoAbsCS::print(std::ostream& file, int l) const {
410 if (l <= 0) return;
411 Ifile << "SimpleTablePhotoAbsCS: name=" << name << " Z = " << Z << "\n";
412 Ifile << " threshold = " << threshold << " file_name=" << file_name << "\n";
413 if (l > 1) {
414 indn.n += 2;
415 const long q = ener.size();
416 for (long n = 0; n < q; ++n) {
417 Ifile << "n=" << n << " ener=" << ener[n] << " cs=" << cs[n] << "\n";
418 }
419 indn.n -= 2;
420 }
421}
422
423//---------------------------------------------------------
424
425PhenoPhotoAbsCS::PhenoPhotoAbsCS() : PhotoAbsCS("none", 0, 0.0), power(0.0) {}
426
427PhenoPhotoAbsCS::PhenoPhotoAbsCS(const std::string& fname, int fZ,
428 double fthreshold, double fpower)
429 : PhotoAbsCS(fname, fZ, fthreshold), power(fpower) {
430 mfunname("PhenoPhotoAbsCS::PhenoPhotoAbsCS(...)");
431 check_econd11a(power, <= 2, " value not allowed, integral would be infinite",
432 mcerr);
433 const double a = power - 1.;
434 factor = pow(threshold, a) * Thomas_sum_rule_const_Mb * Z * a;
435}
436
437double PhenoPhotoAbsCS::get_CS(double energy) const {
438 if (energy < threshold || energy == DBL_MAX) return 0.0;
439 return factor * pow(energy, -power);
440}
441
442double PhenoPhotoAbsCS::get_integral_CS(double energy1, double energy2) const {
443 if (energy2 < threshold) return 0.0;
444 if (energy1 < threshold) energy1 = threshold;
445 const double a = power - 1.;
446 double s;
447 if (energy2 == DBL_MAX) {
448 s = factor / a * (1. / pow(energy1, a));
449 } else {
450 s = factor / a * (1. / pow(energy1, a) - 1. / pow(energy2, a));
451 }
452 return s;
453}
454
455void PhenoPhotoAbsCS::scale(double fact) {
456 mfunnamep("void PhenoPhotoAbsCS::scale(double fact)");
457 factor *= fact;
458}
459
460void PhenoPhotoAbsCS::print(std::ostream& file, int l) const {
461 if (l <= 0) return;
462 Ifile << "PhenoPhotoAbsCS: name=" << name << " Z = " << Z << std::endl;
463 Ifile << " threshold = " << threshold << " power=" << power
464 << " factor=" << factor << std::endl;
465}
466
467//------------------------------------------------------------------------
468
470 double fchannel_prob_dens, const std::vector<double>& felectron_energy,
471 const std::vector<double>& fphoton_energy, int s_all_rest) {
472 mfunnamep("void AtomicSecondaryProducts::add_channel(...)");
473 check_econd21(fchannel_prob_dens, < 0.0 ||, > 1.0, mcerr);
474 long q_old = channel_prob_dens.size();
475 long q_new = q_old + 1;
476 channel_prob_dens.resize(q_new);
477 electron_energy.resize(q_new);
478 photon_energy.resize(q_new);
479 if (s_all_rest == 1) {
480 double s = 0.0;
481 for (long n = 0; n < q_old; ++n) {
482 s += channel_prob_dens[n];
483 }
484 check_econd21(s, < 0.0 ||, > 1.0, mcerr);
485 fchannel_prob_dens = 1.0 - s;
486 }
487 channel_prob_dens[q_old] = fchannel_prob_dens;
488 electron_energy[q_old] = felectron_energy;
489 photon_energy[q_old] = fphoton_energy;
490 double s = 0.0;
491 for (long n = 0; n < q_new; ++n) {
492 s += channel_prob_dens[n];
493 }
494 if (s > 1.0) {
495 funnw.ehdr(mcerr);
496 mcerr << "s > 1.0, s=" << s << '\n';
497 Iprintn(mcerr, q_new);
498 for (long n = 0; n < q_new; ++n) {
499 mcerr << "n=" << n << " channel_prob_dens[n]=" << channel_prob_dens[n]
500 << '\n';
501 }
502 spexit(mcerr);
503 }
504}
505
506int AtomicSecondaryProducts::get_channel(std::vector<double>& felectron_energy,
507 std::vector<double>& fphoton_energy)
508 const {
509 mfunname("int AtomicSecondaryProducts::get_channel(...)");
510#ifdef DEBUG_PRINT_get_escape_particles
511 mcout << "AtomicSecondaryProducts::get_channel is started\n";
513#endif
514 if (channel_prob_dens.empty()) return 0;
515 int ir = 0;
516 double rn = SRANLUX();
517#ifdef DEBUG_PRINT_get_escape_particles
518 Iprintn(mcout, rn);
519#endif
520 if (channel_prob_dens.size() == 1) {
521 if (rn < channel_prob_dens[0]) {
522 felectron_energy = electron_energy[0];
523 fphoton_energy = photon_energy[0];
524 ir = 1;
525 }
526 } else {
527 long q = channel_prob_dens.size();
528 double s = 0.0;
529 for (long n = 0; n < q; ++n) {
530 s += channel_prob_dens[n];
531 if (rn <= s) {
532 felectron_energy = electron_energy[n];
533 fphoton_energy = photon_energy[n];
534 ir = 1;
535#ifdef DEBUG_PRINT_get_escape_particles
536 Iprint2n(mcout, n, s);
537#endif
538 break;
539 }
540 }
541 }
542#ifdef DEBUG_PRINT_get_escape_particles
543 mcout << "AtomicSecondaryProducts::get_channel is finishing\n";
544 Iprintn(mcout, ir);
545#endif
546 return ir;
547}
548
549void AtomicSecondaryProducts::print(std::ostream& file, int l) const {
550 if (l <= 0) return;
551 Ifile << "AtomicSecondaryProducts(l=" << l << "):\n";
552 const long q = channel_prob_dens.size();
553 Ifile << "number of channels=" << q << '\n';
554 indn.n += 2;
555 for (long n = 0; n < q; ++n) {
556 Ifile << "n_channel=" << n << " probability=" << channel_prob_dens[n]
557 << '\n';
558 indn.n += 2;
559 long qel = electron_energy[n].size();
560 Ifile << "number of electrons=" << qel << '\n';
561 indn.n += 2;
562 for (long nel = 0; nel < qel; ++nel) {
563 Ifile << "nel=" << nel << " electron_energy=" << electron_energy[n][nel]
564 << '\n';
565 }
566 indn.n -= 2;
567 long qph = photon_energy[n].size();
568 Ifile << "number of photons=" << qph << '\n';
569 indn.n += 2;
570 for (long nph = 0; nph < qph; ++nph) {
571 Ifile << "nph=" << nph << " photon_energy=" << photon_energy[n][nph]
572 << '\n';
573 }
574 indn.n -= 2;
575 indn.n -= 2;
576 }
577 indn.n -= 2;
578}
579
580AtomPhotoAbsCS::AtomPhotoAbsCS() : name("none"), Z(0), qshell(0) {}
581
582double AtomPhotoAbsCS::get_TICS(double energy,
583 double factual_minimal_threshold) const {
584 mfunname("double AtomPhotoAbsCS::get_TICS(...) const");
585 if (factual_minimal_threshold <= energy) {
586 // Above threshold, the ionization cross-section is assumed to be
587 // idential to the absorption cross-section.
588 return get_ACS(energy);
589 }
590 return 0.0;
591}
592
594 double energy1, double energy2, double factual_minimal_threshold) const {
595 mfunname("double AtomPhotoAbsCS::get_integral_TICS(...) const");
596 if (factual_minimal_threshold > energy2) return 0.;
597 energy1 = std::max(energy1, factual_minimal_threshold);
598 return get_integral_ACS(energy1, energy2);
599}
600
601double AtomPhotoAbsCS::get_TICS(int nshell, double energy,
602 double factual_minimal_threshold) const {
603 mfunname("double AtomPhotoAbsCS::get_TICS(...) const");
604 if (s_ignore_shell[nshell]) return 0.;
605 if (factual_minimal_threshold <= energy) {
606 return get_integral_ACS(nshell, energy);
607 }
608 return 0.;
609}
610
612 int nshell, double energy1, double energy2,
613 double factual_minimal_threshold) const {
614 mfunname("double AtomPhotoAbsCS::get_integral_TICS(...) const");
615 if (s_ignore_shell[nshell]) return 0.;
616 if (factual_minimal_threshold <= energy1) {
617 return get_integral_ACS(nshell, energy1, energy2);
618 }
619 if (factual_minimal_threshold >= energy2) return 0.0;
620 return get_integral_ACS(nshell, factual_minimal_threshold, energy2);
621}
622
624 mfunname("void AtomPhotoAbsCS::remove_shell(int nshell)");
625 check_econd21(nshell, < 0 ||, >= qshell, mcerr);
626 s_ignore_shell[nshell] = true;
627}
628
630 mfunname("void AtomPhotoAbsCS::restore_shell(int nshell)");
631 check_econd21(nshell, < 0 ||, >= qshell, mcerr);
632 s_ignore_shell[nshell] = false;
633}
634
635void AtomPhotoAbsCS::print(std::ostream& file, int l) const {
636 mfunnamep("void AtomPhotoAbsCS::print(std::ostream& file, int l) const");
637 if (l <= 0) return;
638 Ifile << "AtomPhotoAbsCS(l=" << l << "): name=" << name << " Z = " << Z
639 << " qshell = " << qshell << std::endl;
640 Iprintn(mcout, asp.size());
641 long q = asp.size();
642 if (q == 0) {
643 q = s_ignore_shell.size();
644 indn.n += 2;
645 for (long n = 0; n < q; ++n) {
646 Ifile << "n=" << n << " s_ignore_shell[n] = " << s_ignore_shell[n]
647 << '\n';
648 }
649 indn.n -= 2;
650 } else {
651 check_econd12(asp.size(), !=, s_ignore_shell.size(), mcerr);
652 indn.n += 2;
653 for (long n = 0; n < q; ++n) {
654 Ifile << "n=" << n << " s_ignore_shell[n] = " << s_ignore_shell[n]
655 << '\n';
656 asp[n].print(mcout, l);
657 }
658 indn.n -= 2;
659 }
660}
661
662std::ostream& operator<<(std::ostream& file, const AtomPhotoAbsCS& f) {
663 f.print(file, 1);
664 return file;
665}
666
668 mfunname("double AtomPhotoAbsCS::get_I_min() const");
669 double st = DBL_MAX;
670 // The minimal shell is normally the last, but to be safe we check all.
671 for (int n = 0; n < qshell; ++n) st = std::min(st, get_threshold(n));
672 return st;
673}
674
676 const int nshell, double energy, std::vector<double>& el_energy,
677 std::vector<double>& ph_energy) const {
678 mfunname("void AtomPhotoAbsCS::get_escape_particles(...)");
679#ifdef DEBUG_PRINT_get_escape_particles
680 mcout << "AtomPhotoAbsCS::get_escape_particles is started\n";
681 Iprintn(mcout, nshell);
682 Iprintn(mcout, energy);
683#endif
684 // In principle, the energy is allowed to be slightly less than threshold
685 // due to unprecision of definition of point-wise cross sections.
686 // To keep correct norm it is better not to ignore such events.
687 // They usually can be treated quite well.
688 // The factor 0.5 is put there just as arbitrary check for full stupidity.
689 const double thrShell = get_threshold(nshell);
690 check_econd12(energy, <, 0.5 * thrShell, mcerr);
691
692 el_energy.clear();
693 ph_energy.clear();
694
695 // Find the shell with the lowest threshold (should be the last).
696 int n_min = 0;
697 double thrMin = DBL_MAX;
698 for (int n = 0; n < qshell; ++n) {
699 if (get_threshold(n) < thrMin) {
700 n_min = n;
701 thrMin = get_threshold(n);
702 }
703 }
704#ifdef DEBUG_PRINT_get_escape_particles
705 Iprintn(mcout, n_min);
706#endif
707 if (nshell == n_min) {
708 // Outermost (valence) shell. Only generate the delta electron.
709 const double en = std::max(energy - thrMin, 0.);
710 el_energy.push_back(en);
711 return;
712 }
713 // Energy of photo-electron
714 double en = energy - thrShell;
715 double hdist = 0.0; // used to preserve the balance of energy
716 // virtual gamma are generated by energy mesh
717 // and their energy could be little less than the shell energy.
718 // To avoid generation of electrons with negative energy
719 // their energy is corrected. The value of correction is hdist.
720 // To preserve energy this hdist is then distributed over
721 // the other secondary products if they exist.
722 if (en < 0.0) {
723 hdist = -en;
724 en = 0.0;
725 }
726 int is = 0;
727 std::vector<double> felectron_energy;
728 std::vector<double> fphoton_energy;
729#ifdef DEBUG_PRINT_get_escape_particles
730 Iprint2n(mcout, asp.size(), get_qshell());
731#endif
732#ifndef DEBUG_ignore_non_standard_channels
733 if (asp.size() == get_qshell()) {
734 // works only in this case?
735 is = asp[nshell].get_channel(felectron_energy, fphoton_energy);
736 // Here zero can be if the shell is not included in database
737 // or if not standard channel is not chosen by random way.
738 // In both cases the standard way should be invoked.
739 }
740#endif
741 int main_n = get_main_shell_number(nshell);
742#ifdef DEBUG_PRINT_get_escape_particles
743 Iprint2n(mcout, nshell, main_n);
744 Iprintn(mcout, is);
745#endif
746
747 if (is != 0) {
748 // Generate photo-electron and just copy all what is proposed by
749 // get_channel with corrections by hdist.
750 el_energy.resize(1 + felectron_energy.size());
751 el_energy[0] = en;
752 long q = felectron_energy.size();
753 for (long n = 0; n < q; ++n) {
754 check_econd21(felectron_energy[n], < 0 ||, > thrShell, mcerr);
755 el_energy[1 + n] = felectron_energy[n] - hdist;
756 if (el_energy[1 + n] < 0) {
757 hdist = -el_energy[1 + n];
758 el_energy[1 + n] = 0.0;
759 } else {
760 hdist = 0.0;
761 }
762 }
763 ph_energy.resize(fphoton_energy.size());
764 q = fphoton_energy.size();
765 for (long n = 0; n < q; ++n) {
766 check_econd21(fphoton_energy[n], < 0 ||, > thrShell, mcerr);
767 ph_energy[n] = fphoton_energy[n] - hdist;
768 if (ph_energy[n] < 0) {
769 hdist = -ph_energy[n];
770 ph_energy[n] = 0.0;
771 } else {
772 hdist = 0.0;
773 }
774 }
775 return;
776 }
777
778 // Generate default channel.
779 if (main_n <= 0) {
780 // Principal numbers are not available. Generate Auger to outmost shell.
781 const double en1 = thrShell - hdist - 2 * thrMin;
782 el_energy.push_back(en);
783 if (en1 >= 0.0) el_energy.push_back(en1);
784 return;
785 }
786 // First find the principal quantum number of the deepest shell.
787 int main_n_largest = 0;
788 for (int n = 0; n < qshell; ++n) {
789 main_n_largest = std::max(main_n_largest, get_main_shell_number(n));
790 }
791#ifdef DEBUG_PRINT_get_escape_particles
792 Iprintn(mcout, main_n_largest);
793#endif
794 if (main_n_largest - main_n < 2) {
795 // Generate Auger from the outermost shell.
796 double en1 = thrShell - hdist - 2 * thrMin;
797 el_energy.push_back(en);
798 if (en1 >= 0.0) el_energy.push_back(en1);
799 return;
800 }
801 // At least K, l, M shells exist.
802 // In this case we use more advanced scheme.
803 // Look for shell with larger main number and with less energy
804 int n_chosen = -1;
805 double thr = DBL_MAX; // this will be the least threshold
806 // among the shells with next principal number
807 for (int n = 0; n < qshell; ++n) {
808 // currently the minimal shell is the last,
809 // but to avoid this assumption we check all
810 int main_n_t = get_main_shell_number(n);
811 if (main_n_t > 0 && main_n_t == main_n + 1) {
812 if (thr > get_threshold(n)) {
813 n_chosen = n;
814 thr = get_threshold(n);
815 }
816 }
817 }
818#ifdef DEBUG_PRINT_get_escape_particles
819 Iprint2n(mcout, n_chosen, thr);
820#endif
821 check_econd11(n_chosen, < 0, mcerr);
822 double en1 = thrShell - hdist - 2 * get_threshold(n_chosen);
823 if (en1 > 0.) {
824 // Photo-electron
825 el_energy.push_back(en);
826 // First Auger from chosen shell
827 el_energy.push_back(en1);
828 // Then filling two vacancies at the next (chosen) shell
829 // from the outermost one
830 const double en2 = get_threshold(n_chosen) - 2 * thrMin;
831 if (en2 > 0.) {
832 el_energy.push_back(en2);
833 el_energy.push_back(en2);
834 check_econd11(el_energy[2], < 0.0, mcerr);
835 }
836 return;
837 }
838 en1 = thrShell - hdist - get_threshold(n_chosen) - thrMin;
839 if (en1 > 0.) {
840 // Photo-electron
841 el_energy.push_back(en);
842 el_energy.push_back(en1);
843 // Filling initially ionized level from chosen
844 // and emittance of Auger from outermost.
845 check_econd11(el_energy[1], < 0.0, mcerr);
846 const double en2 = get_threshold(n_chosen) - 2 * thrMin;
847 if (en2 > 0.) el_energy.push_back(en2);
848 }
849}
850
852 mfunnamep("AtomicSecondaryProducts* AtomPhotoAbsCS::get_asp(int nshell)");
853 check_econd21(nshell, < 0 ||, >= qshell, mcerr);
854 return &(asp[nshell]);
855}
856
858
860 const std::string& ffile_name)
861 : file_name(ffile_name) {
862 mfunnamep("SimpleAtomPhotoAbsCS::SimpleAtomPhotoAbsCS(...)");
863 check_econd11(fZ, < 1, mcerr);
864 std::ifstream file(file_name.c_str());
865 if (!file) {
866 funnw.ehdr(mcerr);
867 mcerr << "cannot open file " << file_name << std::endl;
868 spexit(mcerr);
869 }
870 while (findmark(file, "#") == 1) {
871 file >> Z;
872 if (Z != fZ) continue;
873 file >> qshell;
874 check_econd21(qshell, < 1 ||, > 10000, mcerr);
875 s_ignore_shell.resize(qshell, false);
876 file >> name;
877 m_acs.resize(qshell);
878 asp.resize(qshell);
879 std::vector<double> fl(qshell);
880 int sZshell = 0;
881 for (int nshell = 0; nshell < qshell; ++nshell) {
882 double thr = 0.0;
883 int Zshell = 0;
884 std::string shell_name;
885 file >> thr;
886 check_econd11(thr, <= 0.0, mcerr);
887 file >> Zshell;
888 check_econd11(Zshell, <= 0, mcerr);
889 sZshell += Zshell;
890 file >> fl[nshell];
891 findmark(file, "!");
892 file >> shell_name;
893 m_acs[nshell].reset(new PhenoPhotoAbsCS(shell_name, Zshell, thr * 1.0e-6));
894 }
895 check_econd12(sZshell, !=, Z, mcerr);
896
897 int n_min = 0;
898 double st = DBL_MAX;
899 for (int nshell = 0; nshell < qshell; ++nshell) {
900 // currently the minimal shell is the last,
901 // but to avoid this assumption we check all
902 if (get_threshold(nshell) < st) n_min = nshell;
903 }
904 for (int nshell = 0; nshell < qshell; ++nshell) {
905 if (fl[nshell] <= 0) continue;
906 check_econd12(nshell, ==, n_min, mcerr);
907 std::vector<double> felectron_energy;
908 std::vector<double> fphoton_energy;
909 fphoton_energy.push_back(get_threshold(nshell) - get_threshold(n_min));
910 asp[nshell].add_channel(fl[nshell], felectron_energy, fphoton_energy);
911 }
912 return;
913 }
914 funnw.ehdr(mcerr);
915 mcerr << "there is no element Z=" << fZ << " in file " << file_name << '\n';
916 spexit(mcerr);
917}
918
919SimpleAtomPhotoAbsCS::SimpleAtomPhotoAbsCS(int fZ, std::shared_ptr<PhotoAbsCS> facs) {
920 mfunname("SimpleAtomPhotoAbsCS::SimpleAtomPhotoAbsCS(...)");
921 check_econd11(facs, == nullptr, mcerr);
922 check_econd11(fZ, <= 0, mcerr);
923 check_econd12(fZ, !=, facs->get_Z(), mcerr);
924 Z = fZ;
925 qshell = 1;
926 s_ignore_shell.resize(qshell, false);
927 name = facs->get_name();
928 m_acs.resize(1);
929 m_acs[0] = std::move(facs);
930}
931
932double SimpleAtomPhotoAbsCS::get_threshold(int nshell) const {
933 mfunname("double SimpleAtomPhotoAbsCS::get_threshold(int nshell) const");
934 check_econd21(nshell, < 0 ||, > qshell, mcerr);
935 return m_acs[nshell]->get_threshold();
936}
937
938double SimpleAtomPhotoAbsCS::get_ACS(double energy) const {
939 mfunname("double SimpleAtomPhotoAbsCS::get_ACS(double energy) const");
940 double s = 0.0;
941 for (int n = 0; n < qshell; ++n) {
942 if (!s_ignore_shell[n]) s += m_acs[n]->get_CS(energy);
943 }
944 return s;
945}
947 double energy2) const {
948 mfunnamep("double SimpleAtomPhotoAbsCS::get_integral_ACS(...) const");
949 double s = 0.0;
950 for (int n = 0; n < qshell; ++n) {
951 if (s_ignore_shell[n]) continue;
952 const double t = m_acs[n]->get_integral_CS(energy1, energy2);
953 if (t < 0) {
954 funnw.ehdr(mcout);
955 mcout << "t < 0\n";
956 Iprintn(mcout, t);
957 print(mcout, 4);
958 spexit(mcout);
959 }
960 s += t;
961 }
962 return s;
963}
964
965double SimpleAtomPhotoAbsCS::get_ACS(int nshell, double energy) const {
966 mfunname("double SimpleAtomPhotoAbsCS::get_ACS(int nshell, double energy)");
967 check_econd21(nshell, < 0 ||, > qshell, mcerr);
968 return s_ignore_shell[nshell] ? 0. : m_acs[nshell]->get_CS(energy);
969}
970
971double SimpleAtomPhotoAbsCS::get_integral_ACS(int nshell, double en1,
972 double en2) const {
973 mfunname("double SimpleAtomPhotoAbsCS::get_integral_ACS(...) const");
974 check_econd21(nshell, < 0 ||, > qshell, mcerr);
975 return s_ignore_shell[nshell] ? 0. : m_acs[nshell]->get_integral_CS(en1, en2);
976}
977
978double SimpleAtomPhotoAbsCS::get_ICS(double energy) const {
979 mfunname("double SimpleAtomPhotoAbsCS::get_ICS(double energy) const");
980 double s = 0.0;
981 for (int n = 0; n < qshell; ++n) {
982 if (!s_ignore_shell[n]) s += m_acs[n]->get_CS(energy);
983 }
984 return s;
985}
986
988 double energy2) const {
989 mfunname("double SimpleAtomPhotoAbsCS::get_integral_ICS(...) const");
990 double s = 0.0;
991 for (int n = 0; n < qshell; ++n) {
992 if (!s_ignore_shell[n]) s += m_acs[n]->get_integral_CS(energy1, energy2);
993 }
994 return s;
995}
996
997double SimpleAtomPhotoAbsCS::get_ICS(int nshell, double energy) const {
998 mfunname("double SimpleAtomPhotoAbsCS::get_ICS(int nshell, double energy)");
999 check_econd21(nshell, < 0 ||, > qshell, mcerr);
1000 return s_ignore_shell[nshell] ? 0. : m_acs[nshell]->get_CS(energy);
1001}
1002
1003double SimpleAtomPhotoAbsCS::get_integral_ICS(int nshell, double en1,
1004 double en2) const {
1005 mfunname("double SimpleAtomPhotoAbsCS::get_integral_ICS(...) const");
1006 check_econd21(nshell, < 0 ||, > qshell, mcerr);
1007 return s_ignore_shell[nshell] ? 0. : m_acs[nshell]->get_integral_CS(en1, en2);
1008}
1009
1010void SimpleAtomPhotoAbsCS::print(std::ostream& file, int l) const {
1011 if (l <= 0) return;
1012 Ifile << "SimpleAtomPhotoAbsCS(l=" << l << "): name=" << name << " Z = " << Z
1013 << " qshell = " << qshell << " file_name=" << file_name << std::endl;
1014 l--;
1015 if (l <= 0) return;
1016 indn.n += 2;
1017 for (int n = 0; n < qshell; ++n) {
1018 Ifile << "nshell=" << n << std::endl;
1019 m_acs[n]->print(file, l);
1020 }
1021 AtomPhotoAbsCS::print(file, l);
1022 indn.n -= 2;
1023}
1024
1025//----------------------------------------------------------------------
1026
1028 const std::string& fthreshold_file_name,
1029 const std::string& fsimple_table_file_name,
1030 const std::string& fname,
1031 double fminimal_threshold)
1032 : threshold_file_name(fthreshold_file_name),
1033 simple_table_file_name(fsimple_table_file_name),
1034 BT_file_name("none"),
1035 minimal_threshold(fminimal_threshold) {
1036 mfunnamep("ExAtomPhotoAbsCS::ExAtomPhotoAbsCS(...) const");
1037 check_econd11(fZ, < 1, mcerr);
1038 std::ifstream threshold_file(threshold_file_name.c_str());
1039 if (!threshold_file) {
1040 funnw.ehdr(mcerr);
1041 mcerr << "cannot open file " << threshold_file_name << std::endl;
1042 spexit(mcerr);
1043 }
1044 std::vector<double> thr;
1045 std::vector<int> Zshell;
1046 std::vector<double> fl;
1047 std::vector<std::string> shell_name;
1048 bool foundZ = false;
1049 while (findmark(threshold_file, "#") == 1) {
1050 threshold_file >> Z;
1051 if (Z != fZ) continue;
1052 threshold_file >> qshell;
1053 check_econd21(qshell, < 1 ||, > 10000, mcerr);
1054 s_ignore_shell.resize(qshell, false);
1055 // Iprintn(mcout, qshell);
1056 thr.resize(qshell, 0.0);
1057 Zshell.resize(qshell, 0);
1058 fl.resize(qshell, 0.0);
1059 shell_name.resize(qshell);
1060 m_acs.resize(qshell);
1061 asp.resize(qshell);
1062 std::string temp_name;
1063 threshold_file >> temp_name;
1064 name = fname == "none" ? temp_name : fname;
1065 int sZshell = 0;
1066 for (int nshell = 0; nshell < qshell; nshell++) {
1067 threshold_file >> thr[nshell];
1068 check_econd11(thr[nshell], <= 0.0, mcerr);
1069 thr[nshell] *= 1.0e-6;
1070 threshold_file >> Zshell[nshell];
1071 check_econd11(Zshell[nshell], <= 0, mcerr);
1072 sZshell += Zshell[nshell];
1073 threshold_file >> fl[nshell];
1074 findmark(threshold_file, "!");
1075 threshold_file >> shell_name[nshell];
1076 }
1077 check_econd12(sZshell, !=, Z, mcerr);
1078 // currently the minimal shell is the last,
1079 // but to avoid this assumption, we check all.
1080 int n_min = 0;
1081 double st = DBL_MAX;
1082 for (int nshell = 0; nshell < qshell; nshell++) {
1083 if (thr[nshell] < st) {
1084 n_min = nshell;
1085 st = thr[nshell];
1086 }
1087 }
1088 for (int nshell = 0; nshell < qshell; nshell++) {
1089 if (fl[nshell] <= 0) continue;
1090 check_econd12(nshell, ==, n_min, mcerr);
1091 std::vector<double> felectron_energy;
1092 std::vector<double> fphoton_energy;
1093 fphoton_energy.push_back(thr[nshell] - thr[n_min]);
1094 asp[nshell].add_channel(fl[nshell], felectron_energy, fphoton_energy);
1095 }
1096 foundZ = true;
1097 break;
1098 }
1099 if (!foundZ) {
1100 funnw.ehdr(mcerr);
1101 mcerr << "there is no element Z=" << fZ << " in file "
1102 << threshold_file_name << std::endl;
1103 spexit(mcerr);
1104 }
1105 // Here it reads the PACS as an one shell curve:
1106 SimpleTablePhotoAbsCS stpacs(name, Z, 0.0, fsimple_table_file_name);
1107 const std::vector<double>& ener = stpacs.get_arr_ener();
1108 const std::vector<double>& CS = stpacs.get_arr_CS();
1109 std::vector<double> left_CS = CS; // used in sequencial algorithm
1110 const long qe = ener.size();
1111 // here cs is saved
1112 std::vector<std::vector<double> > SCS(qshell, std::vector<double>(qe, 0.));
1113 int nct = qshell - 1; // "current" threshold index
1114 unsigned long nce = 0; // "current" energy index
1115 // We ignore values below the lowest threshold.
1116 // It is not clear whether it is right, perhaps this is one of possible ways
1117 if (ener[0] < thr[qshell - 1]) {
1118 for (long ne = 0; ne < qe && (ener[ne] < thr[qshell - 1] ||
1119 (ne > 1 && CS[ne - 1] <= CS[ne - 2]));
1120 ne++) {
1121 if (ne > 0) left_CS[ne - 1] = 0.0;
1122 nce = ne;
1123 }
1124 }
1125 int s_more;
1126 int nt2 = 0; // < nt1
1127 int s_spes = 0;
1128 // Actually this is a loop by the group of thresholds
1129 do {
1130 // Find all thresholds which are less then the current energy
1131 int nt;
1132 // sign that there are thresholds more than the current energy
1133 s_more = 0;
1134 for (nt = nct; nt >= 0; nt--) {
1135 if (s_spes == 0) {
1136 if (thr[nt] > ener[nce]) {
1137 s_more = 1;
1138 break;
1139 }
1140 } else {
1141 if (thr[nt] > ener[nce + 1]) {
1142 s_more = 1;
1143 break;
1144 }
1145 }
1146 }
1147 // nt is now index of the next threshold or -1, if the thresholds are
1148 // made up.
1149 int nt1 = nct;
1150 int nce_next = ener.size();
1151 nt2 = nt + 1;
1152 // mcout<<"nt="<<nt<<" nt1="<<nt1<<" nt2="<<nt2<<" s_more="<<s_more<<'\n';
1153 if (s_more == 1) {
1154 // if(nt >= 0) // so if there are other larger thresholds,
1155 //{ // we should check how far we can pass at this step
1156 unsigned long ne;
1157 // finding energy larger than the next threshold
1158 for (ne = nce; ne < ener.size(); ne++) {
1159 if (thr[nt] <= ener[ne]) {
1160 nce_next = ne;
1161 s_spes = 0;
1162 break;
1163 }
1164 // At the following condition energy could be less than threshold,
1165 // but this point will anyway be associated with the next shell
1166 // corresponding to this threshold.
1167 // This is related to not precise measurement of cross section
1168 // and not precise knowledge of shell energies.
1169 // Occurence of this condition is marked by s_spes = 1.
1170 // At the next passing of this loop the thresholds are compared with
1171 // the next energy.
1172 if (ne > 1 && ne < ener.size() - 1 && ne > nce + 2 &&
1173 thr[nt] <= ener[ne + 1] &&
1174 (thr[nt] - ener[ne]) / (ener[ne + 1] - ener[ne]) < 0.1 &&
1175 CS[ne] > CS[ne - 1]) {
1176 // mcout<<"special condition is satisf.\n";
1177 nce_next = ne;
1178 s_spes = 1;
1179 break;
1180 }
1181 }
1182 if (ne == ener.size()) // threshold is larger then energy mesh
1183 s_more = 0; // to finish the loop
1184 }
1185 // Iprintn(mcout, nce_next);
1186 // Iprintn(mcout, ener[nce_next-1]);
1187 int qt = nt1 - nt2 + 1; // quantity of the new thresholds
1188 // Iprintn(mcout, qt);
1189
1190 // Calculate sum of Z.
1191 int s = 0;
1192 for (nt = 0; nt < qt; nt++) {
1193 const int nshell = nct - nt;
1194 s += Zshell[nshell];
1195 }
1196 // Weights according to charges
1197 std::vector<double> w(qt);
1198 for (nt = 0; nt < qt; nt++) {
1199 const int nshell = nct - nt;
1200 w[nt] = double(Zshell[nshell]) / s;
1201 }
1202 double save_left_CS = left_CS[nce_next - 1];
1203 for (long ne = 0; ne < nce_next; ne++) {
1204 for (nt = 0; nt < qt; nt++) {
1205 int nshell = nct - nt;
1206 SCS[nshell][ne] = left_CS[ne] * w[nt];
1207 }
1208 left_CS[ne] = 0.0;
1209 }
1210 for (unsigned long ne = nce_next; ne < ener.size(); ne++) {
1211 double extrap_CS =
1212 save_left_CS * pow(ener[nce_next - 1], 2.75) / pow(ener[ne], 2.75);
1213 if (extrap_CS > left_CS[ne]) extrap_CS = left_CS[ne];
1214 for (nt = 0; nt < qt; nt++) {
1215 int nshell = nct - nt;
1216 SCS[nshell][ne] = extrap_CS * w[nt];
1217 }
1218 left_CS[ne] -= extrap_CS;
1219 }
1220 nce = nce_next;
1221 nct = nt2 - 1;
1222 } while (s_more != 0);
1223 // now nt2 will be index of last filled shell
1224 // Now to fill the shells which are absent in the input table.
1225 // They will be initialized phenomenologically, based on the sum rule.
1226 for (int ns = 0; ns < nt2; ns++) {
1227 m_acs[ns].reset(new PhenoPhotoAbsCS(shell_name[ns], Zshell[ns], thr[ns]));
1228 }
1229 // Initialization of input shells.
1230 for (int ns = nt2; ns < qshell; ns++) {
1231 auto adr = new SimpleTablePhotoAbsCS(shell_name[ns], Zshell[ns], thr[ns], ener, SCS[ns]);
1232 adr->remove_leading_zeros();
1233 m_acs[ns].reset(adr);
1234 }
1236 exener[0] = exener[1] = 0.0;
1237 double integ = get_integral_ACS(0.0, DBL_MAX);
1238 // Iprintn(mcout, integ);
1239 integ_abs_before_corr = integ;
1240 double pred_integ = Thomas_sum_rule_const_Mb * Z;
1241 // Iprintn(mcout, pred_integ);
1242 if (pred_integ > integ) {
1244 const double threshold = m_acs[qshell - 1]->get_threshold();
1245 // add excitation
1246 exener[0] = low_boundary_of_excitations * threshold;
1247 exener[1] = threshold;
1248 height_of_excitation = (pred_integ - integ) / (exener[1] - exener[0]);
1249 if (minimal_threshold > 0.0) {
1250 if (minimal_threshold > threshold) {
1251 // currently the minimal shell is the last one
1252 exener[0] += minimal_threshold - threshold;
1253 exener[1] += minimal_threshold - threshold;
1254 }
1255 }
1256 }
1257 } else if (pred_integ < integ) {
1259 const double fact = pred_integ / integ;
1260 for (int nshell = 0; nshell < qshell; ++nshell) {
1261 m_acs[nshell]->scale(fact);
1262 }
1263 }
1264 }
1265 integ_abs_after_corr = get_integral_ACS(0.0, DBL_MAX);
1267}
1268
1269ExAtomPhotoAbsCS::ExAtomPhotoAbsCS(int fZ, const std::string& fname,
1270 const std::string& fBT_file_name, int id,
1271 double fminimal_threshold)
1272 : threshold_file_name("none"),
1273 simple_table_file_name("none"),
1274 BT_file_name(fBT_file_name),
1275 minimal_threshold(fminimal_threshold) {
1276 mfunnamep(
1277 "ExAtomPhotoAbsCS::ExAtomPhotoAbsCS(int fZ, const std::string& fname, "
1278 "const std::string& fBT_file_name, int id, double fminimal_threshold)");
1279 check_econd11(fZ, < 1, mcerr);
1280 check_econd21(id, < 1 ||, > 2, mcerr);
1281
1282 name = fname;
1283 std::ifstream BT_file(BT_file_name.c_str());
1284 if (!BT_file) {
1285 funnw.ehdr(mcerr);
1286 mcerr << "cannot open file " << BT_file_name << std::endl;
1287 spexit(mcerr);
1288 }
1289 std::vector<double> thresh;
1290 std::vector<double> fl;
1291 Z = fZ;
1292 int i = findmark(BT_file, "NUCLEAR CHARGE =");
1293 check_econd11a(i, != 1, "wrong file format", mcerr);
1294 int Z_from_file;
1295 BT_file >> Z_from_file;
1296 check_econd12(Z_from_file, !=, Z, mcerr);
1297 qshell = 0;
1298 while ((i = findmark(BT_file, "Z =")) == 1) {
1299 BT_file >> i;
1300 check_econd11(i, != Z, mcerr);
1301 std::string shellname;
1302 BT_file >> shellname;
1303 // Iprintn(mcout, shellname);
1304 i = findmark(BT_file, "$");
1305 check_econd11(i, != 1, mcerr);
1306 long qen;
1307 BT_file >> qen;
1308 check_econd11(qen, <= 0, mcerr);
1309 std::vector<double> fener(qen, 0.0);
1310 std::vector<double> fcs(qen, 0.0);
1311 double thr = 0.0;
1312 BT_file >> thr;
1313 check_econd11(thr, <= 0, mcerr);
1314 thr *= 1.0e-3; // pass from keV to MeV
1315 if (id == 2) {
1316 thresh.push_back(thr);
1317 fl.resize(fl.size() + 1);
1318 BT_file >> fl[qshell];
1319 check_econd21(fl[qshell], < 0.0 ||, > 1.0, mcerr);
1320 // Iprintn(mcout, fl[qshell]);
1321 }
1322 long nen;
1323 for (nen = 0; nen < qen; nen++) {
1324 BT_file >> fener[nen] >> fcs[nen];
1325 check_econd11(fener[nen], <= 0.0, mcerr);
1326 check_econd11(fcs[nen], < 0.0, mcerr);
1327 fener[nen] *= 1.0e-3; // pass from keV to MeV
1328 }
1329 qshell++;
1330 m_acs.resize(qshell);
1331 m_acs.back().reset(new SimpleTablePhotoAbsCS(shellname, 0, thr, fener, fcs));
1332 }
1333 if (id == 2) {
1334 // a copy of similar thing from subroutine above
1335 int n_min = 0;
1336 double st = DBL_MAX;
1337 for (int nshell = 0; nshell < qshell; ++nshell) {
1338 // currently the minimal shell is the last,
1339 // but to avoid this assumption we check all
1340 if (thresh[nshell] < st) {
1341 n_min = nshell;
1342 st = thresh[nshell];
1343 }
1344 }
1345 asp.resize(qshell);
1346 for (int nshell = 0; nshell < qshell; ++nshell) {
1347 if (fl[nshell] > 0) {
1348 check_econd12(nshell, ==, n_min, mcerr);
1349 std::vector<double> felectron_energy;
1350 std::vector<double> fphoton_energy;
1351 fphoton_energy.push_back(thresh[nshell] - thresh[n_min]);
1352 asp[nshell].add_channel(fl[nshell], felectron_energy, fphoton_energy);
1353 }
1354 }
1355 }
1356
1357 check_econd11(qshell, <= 0, mcerr);
1358 s_ignore_shell.resize(qshell, false);
1360 exener[0] = exener[1] = 0.0;
1361 double integ = get_integral_ACS(0.0, DBL_MAX);
1362 // Iprintn(mcout, integ);
1363 integ_abs_before_corr = integ;
1364 double pred_integ = Thomas_sum_rule_const_Mb * Z;
1365 // Iprintn(mcout, pred_integ);
1366 if (pred_integ > integ) {
1368 const double thr = m_acs[qshell - 1]->get_threshold();
1369 // add excitation
1371 exener[1] = thr;
1372 height_of_excitation = (pred_integ - integ) / (exener[1] - exener[0]);
1373 if (minimal_threshold > 0.0) {
1374 if (minimal_threshold > thr) {
1375 // currently the minimal shell is the last one
1376 exener[0] += minimal_threshold - thr;
1377 exener[1] += minimal_threshold - thr;
1378 }
1379 }
1380 }
1381 } else {
1383 const double fact = pred_integ / integ;
1384 for (int nshell = 0; nshell < qshell; ++nshell) {
1385 m_acs[nshell]->scale(fact);
1386 }
1387 }
1388 }
1389 integ_abs_after_corr = get_integral_ACS(0.0, DBL_MAX);
1391}
1392
1393#define READ_FILE_WITH_PRINCIPAL_NUMBERS
1394
1395ExAtomPhotoAbsCS::ExAtomPhotoAbsCS(int fZ, const std::string& fname,
1396 const std::string& fFitBT_file_name,
1397 int id,
1398 int s_no_scale, double fminimal_threshold)
1399 : threshold_file_name("none"),
1400 simple_table_file_name("none"),
1401 BT_file_name(fFitBT_file_name),
1402 minimal_threshold(fminimal_threshold) {
1403 mfunnamep(
1404 "ExAtomPhotoAbsCS::ExAtomPhotoAbsCS(int fZ, const std::string& fname, "
1405 "const "
1406 "std::string& fFitBT_file_name, int id, int id1, double "
1407 "fminimal_threshold)");
1408 check_econd11(fZ, < 1, mcerr);
1409 check_econd21(id, < 1 ||, > 2, mcerr);
1410 Z = fZ;
1411 name = fname;
1412 std::ifstream BT_file(fFitBT_file_name.c_str());
1413 if (!BT_file) {
1414 funnw.ehdr(mcerr);
1415 mcerr << "cannot open file " << BT_file_name << std::endl;
1416 spexit(mcerr);
1417 }
1418 std::vector<double> thresh;
1419 std::vector<double> fl;
1420 int i = 0;
1421 while ((i = findmark(BT_file, "$")) == 1) {
1422 long iZ;
1423 BT_file >> iZ;
1424 if (iZ != Z) continue;
1425 BT_file >> qshell;
1426 // Iprintn(mcout, qshell);
1427 check_econd11(qshell, <= 0, mcerr);
1428 check_econd11(qshell, > 1000, mcerr);
1429 m_acs.resize(qshell);
1430 if (id == 2) {
1431 thresh.resize(qshell);
1432 fl.resize(qshell);
1433 }
1434 for (int nshell = 0; nshell < qshell; ++nshell) {
1435#ifdef READ_FILE_WITH_PRINCIPAL_NUMBERS
1436 int n_princ = 0;
1437#endif
1438 int l;
1439 double threshold;
1440 double E0;
1441 double yw;
1442 double ya;
1443 double P;
1444 double sigma;
1445 if (BT_file.eof()) {
1446 mcerr << "unexpected end of file " << BT_file_name << '\n';
1447 spexit(mcerr);
1448 }
1449 if (!BT_file.good()) {
1450 mcerr << "bad format of file " << BT_file_name << '\n';
1451 spexit(mcerr);
1452 }
1453#ifdef READ_FILE_WITH_PRINCIPAL_NUMBERS
1454 BT_file >> n_princ;
1455 if (!BT_file.good()) {
1456 mcerr << "bad format of file " << BT_file_name << '\n';
1457 spexit(mcerr);
1458 }
1459 check_econd21(n_princ, < 0 ||, > 10, mcerr);
1460#endif
1461 BT_file >> l >> threshold >> E0 >> sigma >> ya >> P >> yw;
1462 check_econd11(l, < 0, mcerr);
1463 check_econd11(l, > 20, mcerr);
1464 threshold *= 1.0e-6;
1465 E0 *= 1.0e-6;
1466
1467 check_econd11a(threshold, <= 2.0e-6,
1468 "n_princ=" << n_princ << " l=" << l << '\n', mcerr);
1469 check_econd11(E0, <= 0, mcerr);
1470 double flu = 0.0;
1471 if (id == 2) {
1472 if (BT_file.eof()) {
1473 mcerr << "unexpected end of file " << BT_file_name << '\n';
1474 spexit(mcerr);
1475 }
1476 if (!BT_file.good()) {
1477 mcerr << "bad format of file " << BT_file_name << '\n';
1478 spexit(mcerr);
1479 }
1480 BT_file >> flu;
1481 check_econd11(flu, < 0.0, mcerr);
1482 check_econd11(flu, > 1.0, mcerr);
1483 thresh[nshell] = threshold;
1484 fl[nshell] = flu;
1485 }
1486#ifdef READ_FILE_WITH_PRINCIPAL_NUMBERS
1487 // necessary for generation escape products
1488 std::string shellname(std::to_string(n_princ) + " shell number " +
1489 std::to_string(nshell));
1490#else
1491 std::string shellname("shell number " + std::to_string(nshell));
1492#endif
1493 m_acs[nshell].reset(new SimpleTablePhotoAbsCS(shellname, 0, threshold,
1494 l, E0, yw, ya, P, sigma));
1495 // Iprintn(mcout, nshell);
1496 // Iprint3n(mcout, l, threshold, E0);
1497 // Iprint4n(mcout, yw, ya, P, sigma);
1498 // acs[nshell]->print(mcout, 5);
1499 }
1500 goto mark1;
1501 }
1502 funnw.ehdr(mcerr);
1503 mcerr << "there is no element Z=" << fZ << " in file " << fFitBT_file_name
1504 << std::endl;
1505 spexit(mcerr);
1506mark1:
1507 if (id == 2) {
1508 // a copy of similar thing from subroutine above
1509 int n_min = 0;
1510 double st = DBL_MAX;
1511 for (int nshell = 0; nshell < qshell; ++nshell) {
1512 // currently the minimal shell is the last,
1513 // but to avoid this assumption we check all
1514 if (thresh[nshell] < st) {
1515 n_min = nshell;
1516 st = thresh[nshell];
1517 }
1518 }
1519 asp.resize(qshell);
1520 for (int nshell = 0; nshell < qshell; ++nshell) {
1521 if (fl[nshell] > 0) {
1522 check_econd12(nshell, ==, n_min, mcerr);
1523 std::vector<double> felectron_energy;
1524 std::vector<double> fphoton_energy;
1525 fphoton_energy.push_back(thresh[nshell] - thresh[n_min]);
1526 asp[nshell].add_channel(fl[nshell], felectron_energy, fphoton_energy);
1527 }
1528 }
1529 }
1530
1531 check_econd11(qshell, <= 0, mcerr);
1532 s_ignore_shell.resize(qshell, false);
1534 exener[0] = exener[1] = 0.0;
1535 double integ = get_integral_ACS(0.0, DBL_MAX);
1536 // Iprintn(mcout, integ);
1537 integ_abs_before_corr = integ;
1538 double pred_integ = Thomas_sum_rule_const_Mb * Z;
1539 // Iprintn(mcout, pred_integ);
1540 if (pred_integ > integ) {
1542 const double thr = m_acs[qshell - 1]->get_threshold();
1543 // add excitation
1545 exener[1] = thr;
1546 height_of_excitation = (pred_integ - integ) / (exener[1] - exener[0]);
1547 if (minimal_threshold > 0.0) {
1548 if (minimal_threshold > thr) {
1549 // currently the minimal shell is the last one
1550 exener[0] += minimal_threshold - thr;
1551 exener[1] += minimal_threshold - thr;
1552 }
1553 }
1554 }
1555 } else {
1556 if (s_scale_to_normalize_if_more == 1 && s_no_scale == 0) {
1557 const double fact = pred_integ / integ;
1558 for (int nshell = 0; nshell < qshell; ++nshell) {
1559 m_acs[nshell]->scale(fact);
1560 }
1561 }
1562 }
1563 integ_abs_after_corr = get_integral_ACS(0.0, DBL_MAX);
1565}
1566
1568 int fZ, const std::string& fname, const std::string& fFitBT_file_name,
1569 const std::string& fsimple_table_file_name, double emax_repl,
1570 int id, // to distinguish it from constructor above
1571 double fminimal_threshold) {
1572 mfunname("ExAtomPhotoAbsCS::ExAtomPhotoAbsCS(...)");
1573 Z = fZ;
1574 name = fname;
1575 int s_no_scale = 1;
1576 *this = ExAtomPhotoAbsCS(fZ, fname, fFitBT_file_name, id, s_no_scale,
1577 fminimal_threshold);
1578
1580 exener[0] = exener[1] = 0.0;
1581
1582 double thrmin = DBL_MAX;
1583 long nsmin = -1;
1584 // Look for minimal shell (usually the last).
1585 for (long ns = 0; ns < qshell; ++ns) {
1586 if (thrmin > m_acs[ns]->get_threshold()) {
1587 nsmin = ns;
1588 thrmin = m_acs[ns]->get_threshold();
1589 }
1590 }
1591 check_econd11(nsmin, < 0, mcerr);
1592 check_econd11(nsmin, != qshell - 1, mcerr);
1593
1594 PhotoAbsCS* apacs = m_acs[nsmin].get();
1595 auto first_shell = dynamic_cast<SimpleTablePhotoAbsCS*>(apacs);
1596 check_econd11(first_shell, == nullptr, mcerr);
1597
1598 SimpleTablePhotoAbsCS stpacs(name, Z, 0.0, fsimple_table_file_name);
1599 stpacs.remove_leading_tiny(1.0e-10);
1600
1601 // Merging shells:
1602 SimpleTablePhotoAbsCS* merged = new SimpleTablePhotoAbsCS(*first_shell, stpacs, emax_repl);
1603 m_acs[nsmin].reset(merged);
1604
1605 s_ignore_shell.resize(qshell, false);
1607 exener[0] = exener[1] = 0.0;
1608 double integ = get_integral_ACS(0.0, DBL_MAX);
1609 integ_abs_before_corr = integ;
1610 double pred_integ = Thomas_sum_rule_const_Mb * Z;
1611 if (pred_integ > integ) {
1613 const double thr = m_acs[qshell - 1]->get_threshold();
1614 // add excitation
1616 exener[1] = thr;
1617 height_of_excitation = (pred_integ - integ) / (exener[1] - exener[0]);
1618 if (minimal_threshold > 0.0) {
1619 if (minimal_threshold > thr) {
1620 // currently the minimal shell is the last one
1621 exener[0] += minimal_threshold - thr;
1622 exener[1] += minimal_threshold - thr;
1623 }
1624 }
1625 }
1626 } else {
1628 const double fact = pred_integ / integ;
1629 for (int nshell = 0; nshell < qshell; ++nshell) {
1630 m_acs[nshell]->scale(fact);
1631 }
1632 }
1633 }
1634 integ_abs_after_corr = get_integral_ACS(0.0, DBL_MAX);
1636}
1637
1638double ExAtomPhotoAbsCS::get_threshold(int nshell) const {
1639 mfunname("double ExAtomPhotoAbsCS::get_threshold(int nshell) const");
1640 check_econd21(nshell, < 0 ||, > qshell, mcerr);
1641 double r = m_acs[nshell]->get_threshold();
1642 if (minimal_threshold > 0.0) {
1644 }
1645 return r;
1646}
1647
1648double ExAtomPhotoAbsCS::get_ICS(double energy) const {
1649 mfunname("double ExAtomPhotoAbsCS::get_ACS(double energy) const");
1650 double s = 0.0;
1651 for (int n = 0; n < qshell; ++n) {
1652 if (s_ignore_shell[n]) continue;
1653 double shift = 0.0;
1654 const double t = m_acs[n]->get_threshold();
1655 if (minimal_threshold > 0.0) {
1656 if (t < minimal_threshold) shift = minimal_threshold - t;
1657 }
1658 s += m_acs[n]->get_CS(energy - shift);
1659 }
1660 return s;
1661}
1662
1664 double energy2) const {
1665 mfunname("double ExAtomPhotoAbsCS::get_integral_ICS(double energy) const");
1666 double s = 0.0;
1667 for (int n = 0; n < qshell; ++n) {
1668 if (s_ignore_shell[n]) continue;
1669 double shift = 0.0;
1670 const double t = m_acs[n]->get_threshold();
1671 if (minimal_threshold > 0.0) {
1672 if (t < minimal_threshold) shift = minimal_threshold - t;
1673 }
1674 s += m_acs[n]->get_integral_CS(energy1 - shift, energy2 - shift);
1675 }
1676 return s;
1677}
1678
1679double ExAtomPhotoAbsCS::get_ICS(int nshell, double energy) const {
1680 mfunname("double ExAtomPhotoAbsCS::get_ICS(int nshell, double energy) const");
1681 check_econd21(nshell, < 0 ||, > qshell, mcerr);
1682 if (s_ignore_shell[nshell]) return 0.;
1683 double shift = 0.0;
1684 const double t = m_acs[nshell]->get_threshold();
1685 if (minimal_threshold > 0.0) {
1686 if (t < minimal_threshold) shift = minimal_threshold - t;
1687 }
1688 return m_acs[nshell]->get_CS(energy - shift);
1689}
1690
1691double ExAtomPhotoAbsCS::get_integral_ICS(int nshell, double energy1,
1692 double energy2) const {
1693 mfunname("double ExAtomPhotoAbsCS::get_integral_ICS(int nshell, ...) const");
1694 check_econd21(nshell, < 0 ||, > qshell, mcerr);
1695 if (s_ignore_shell[nshell]) return 0.;
1696 double shift = 0.0;
1697 const double t = m_acs[nshell]->get_threshold();
1698 if (minimal_threshold > 0.0) {
1699 if (t < minimal_threshold) shift = minimal_threshold - t;
1700 }
1701 return m_acs[nshell]->get_integral_CS(energy1 - shift, energy2 - shift);
1702}
1703
1704double ExAtomPhotoAbsCS::get_ACS(double energy) const {
1705 mfunname("double ExAtomPhotoAbsCS::get_ACS(double energy) const");
1706 double s = 0.0;
1707 for (int n = 0; n < qshell; ++n) {
1708 if (s_ignore_shell[n]) continue;
1709 double shift = 0.0;
1710 const double t = m_acs[n]->get_threshold();
1711 if (minimal_threshold > 0.0) {
1712 if (t < minimal_threshold) shift = minimal_threshold - t;
1713 }
1714 s += m_acs[n]->get_CS(energy - shift);
1715 }
1716 if (energy >= exener[0] && energy <= exener[1]) s += height_of_excitation;
1717 return s;
1718}
1719
1721 double energy2) const {
1722 mfunname("double ExAtomPhotoAbsCS::get_integral_ACS(...) const");
1723 double s = 0.0;
1724 for (int n = 0; n < qshell; ++n) {
1725 if (s_ignore_shell[n]) continue;
1726 double shift = 0.0;
1727 const double t = m_acs[n]->get_threshold();
1728 if (minimal_threshold > 0.0) {
1729 if (t < minimal_threshold) shift = minimal_threshold - t;
1730 }
1731 s += m_acs[n]->get_integral_CS(energy1 - shift, energy2 - shift);
1732 }
1733 double b[2] = {std::max(exener[0], energy1), std::min(exener[1], energy2)};
1734 if (b[1] >= b[0]) s += height_of_excitation * (b[1] - b[0]);
1735 return s;
1736}
1737
1738double ExAtomPhotoAbsCS::get_ACS(int nshell, double energy) const {
1739 mfunname("double ExAtomPhotoAbsCS::get_ACS(int nshell, double energy)");
1740 check_econd21(nshell, < 0 ||, > qshell, mcerr);
1741 if (s_ignore_shell[nshell]) return 0.;
1742 double shift = 0.0;
1743 const double t = m_acs[nshell]->get_threshold();
1744 if (minimal_threshold > 0.0) {
1745 if (t < minimal_threshold) shift = minimal_threshold - t;
1746 }
1747 double s = m_acs[nshell]->get_CS(energy - shift);
1748 if (nshell == qshell - 1 && energy >= exener[0] && energy <= exener[1]) {
1750 }
1751 return s;
1752}
1753
1754double ExAtomPhotoAbsCS::get_integral_ACS(int nshell, double energy1,
1755 double energy2) const {
1756 mfunname("double ExAtomPhotoAbsCS::get_integral_ACS(int nshell, ...) const");
1757 check_econd21(nshell, < 0 ||, > qshell, mcerr);
1758 if (s_ignore_shell[nshell]) return 0.;
1759 double shift = 0.0;
1760 const double t = m_acs[nshell]->get_threshold();
1761 if (minimal_threshold > 0.0) {
1762 if (t < minimal_threshold) shift = minimal_threshold - t;
1763 }
1764 double s = m_acs[nshell]->get_integral_CS(energy1 - shift, energy2 - shift);
1765 if (nshell == qshell - 1) {
1766 double b[2] = {std::max(exener[0], energy1), std::min(exener[1], energy2)};
1767 if (b[1] >= b[0]) s += height_of_excitation * (b[1] - b[0]);
1768 }
1769 return s;
1770}
1771
1772void ExAtomPhotoAbsCS::print(std::ostream& file, int l) const {
1773 if (l <= 0) return;
1774 Ifile << "ExAtomPhotoAbsCS(l=" << l << "): name=" << name << " Z = " << Z
1775 << " qshell = " << qshell << std::endl;
1776 indn.n += 2;
1777 Ifile << "threshold_file_name=" << threshold_file_name << '\n';
1778 Ifile << "simple_table_file_name=" << simple_table_file_name << '\n';
1779 Ifile << "BT_file_name=" << BT_file_name << std::endl;
1780 Ifile << "Thomas_sum_rule_const_Mb * Z = " << Thomas_sum_rule_const_Mb* Z
1781 << '\n';
1782 Ifile << "integ_abs_before_corr = " << integ_abs_before_corr << '\n';
1783 Ifile << "integ_abs_after_corr = " << integ_abs_after_corr << '\n';
1784 Ifile << "integ_ioniz_after_corr = " << integ_ioniz_after_corr << '\n';
1785 Ifile << "height_of_excitation=" << height_of_excitation
1786 << " exener=" << exener[0] << ' ' << exener[1] << '\n';
1788 Ifile << "integrals by shells:\n";
1789 Ifile << "nshell, int(acs), int(ics)\n";
1790 for (long n = 0; n < qshell; n++) {
1791 double ainteg = get_integral_ACS(n, 0.0, DBL_MAX);
1792 double iinteg = get_integral_ICS(n, 0.0, DBL_MAX);
1793 Ifile << n << " " << ainteg << " " << iinteg << '\n';
1794 }
1795
1796 if (l > 1) {
1797 l--;
1798 indn.n += 2;
1799 for (long n = 0; n < qshell; ++n) {
1800 Ifile << "nshell=" << n << std::endl;
1801 m_acs[n]->print(file, l);
1802 }
1803 AtomPhotoAbsCS::print(file, l);
1804 indn.n -= 2;
1805 }
1806 indn.n -= 2;
1807}
1808
1809void ExAtomPhotoAbsCS::replace_shells_by_average(double fwidth, double fstep,
1810 long fmax_q_step) {
1811 mfunname("void ExAtomPhotoAbsCS::replace_shells_by_average(...)");
1812 for (long n = 0; n < qshell; n++) {
1813 if (!m_acs[n]) continue;
1814 PhotoAbsCS* a =
1815 new AveragePhotoAbsCS(m_acs[n].get(), fwidth, fstep, fmax_q_step);
1816 m_acs[n].reset(a);
1817 }
1818}
1819
1820//---------------------------------------------------------
1821
1823 double fW, double fF)
1824 : qatom(fqatom), W(fW), F(fF) {
1825 qatom_ps.push_back(qatom);
1826 atom.push_back(fatom);
1827 if (W == 0.0) W = coef_I_to_W * atom[0]->get_I_min();
1828}
1829
1831 const AtomPhotoAbsCS* fatom2, int fqatom_ps2,
1832 double fW, double fF)
1833 : qatom(fqatom_ps1 + fqatom_ps2), W(fW), F(fF) {
1834 qatom_ps.push_back(fqatom_ps1);
1835 qatom_ps.push_back(fqatom_ps2);
1836 atom.push_back(fatom1);
1837 atom.push_back(fatom2);
1838 if (W != 0.0) return;
1839#ifdef CALC_W_USING_CHARGES
1840 W = coef_I_to_W * (qatom_ps[0] * atom[0]->get_Z() * atom[0]->get_I_min() +
1841 qatom_ps[1] * atom[1]->get_Z() * atom[1]->get_I_min()) /
1842 (qatom_ps[0] * atom[0]->get_Z() + qatom_ps[1] * atom[1]->get_Z());
1843#else
1844 W = coef_I_to_W * (qatom_ps[0] * atom[0]->get_I_min() +
1845 qatom_ps[1] * atom[1]->get_I_min()) /
1846 qatom;
1847#endif
1848}
1849
1851 const AtomPhotoAbsCS* fatom2, int fqatom_ps2,
1852 const AtomPhotoAbsCS* fatom3, int fqatom_ps3,
1853 double fW, double fF)
1854 : qatom(fqatom_ps1 + fqatom_ps2 + fqatom_ps3), W(fW), F(fF) {
1855 qatom_ps.push_back(fqatom_ps1);
1856 qatom_ps.push_back(fqatom_ps2);
1857 qatom_ps.push_back(fqatom_ps3);
1858 atom.push_back(fatom1);
1859 atom.push_back(fatom2);
1860 atom.push_back(fatom3);
1861 if (W != 0.0) return;
1862#ifdef CALC_W_USING_CHARGES
1863 W = coef_I_to_W * (qatom_ps[0] * atom[0]->get_Z() * atom[0]->get_I_min() +
1864 qatom_ps[1] * atom[1]->get_Z() * atom[1]->get_I_min() +
1865 qatom_ps[2] * atom[2]->get_Z() * atom[2]->get_I_min()) /
1866 (qatom_ps[0] * atom[0]->get_Z() + qatom_ps[1] * atom[1]->get_Z() +
1867 qatom_ps[2] * atom[2]->get_Z());
1868#else
1869 W = coef_I_to_W *
1870 (qatom_ps[0] * atom[0]->get_I_min() + qatom_ps[1] * atom[1]->get_I_min() +
1871 qatom_ps[2] * atom[2]->get_I_min()) /
1872 qatom;
1873#endif
1874}
1875
1876double MolecPhotoAbsCS::get_ACS(const double energy) const {
1877 mfunname("double MolecPhotoAbsCS::get_ACS(double energy) const");
1878 const long q = qatom_ps.size();
1879 double s = 0.0;
1880 for (long n = 0; n < q; n++) s += qatom_ps[n] * atom[n]->get_ACS(energy);
1881 return s;
1882}
1883
1884double MolecPhotoAbsCS::get_integral_ACS(double en1, double en2) const {
1885 mfunname("double MolecPhotoAbsCS::get_integral_ACS(double e1, double e2)");
1886 const long q = qatom_ps.size();
1887 double s = 0.0;
1888 for (long n = 0; n < q; n++) {
1889 s += qatom_ps[n] * atom[n]->get_integral_ACS(en1, en2);
1890 }
1891 return s;
1892}
1893
1894double MolecPhotoAbsCS::get_ICS(double energy) const {
1895 mfunname("double MolecPhotoAbsCS::get_ICS(double energy) const");
1896 const long q = qatom_ps.size();
1897 double s = 0.0;
1898 for (long n = 0; n < q; n++) s += qatom_ps[n] * atom[n]->get_ICS(energy);
1899 return s;
1900}
1901
1902double MolecPhotoAbsCS::get_integral_ICS(double en1, double en2) const {
1903 mfunname("double MolecPhotoAbsCS::get_integral_ICS(double e1, double e2)");
1904 const long q = qatom_ps.size();
1905 double s = 0.0;
1906 for (long n = 0; n < q; n++) {
1907 s += qatom_ps[n] * atom[n]->get_integral_ICS(en1, en2);
1908 }
1909 return s;
1910}
1911
1913 mfunname("size_t MolecPhotoAbsCS::get_total_Z() const");
1914 const size_t q = qatom_ps.size();
1915 size_t s = 0;
1916 for (size_t n = 0; n < q; n++) {
1917 s += qatom_ps[n] * atom[n]->get_Z();
1918 }
1919 return s;
1920}
1921
1922void MolecPhotoAbsCS::print(std::ostream& file, int l) const {
1923 Ifile << "MolecPhotoAbsCS (l=" << l << "):\n";
1924 Iprintn(file, qatom);
1925 Iprintn(file, W);
1926 Iprintn(file, F);
1927 const long q = qatom_ps.size();
1928 Ifile << "number of sorts of atoms is " << q << '\n';
1929 indn.n += 2;
1930 for (long n = 0; n < q; n++) {
1931 Ifile << "n=" << n << " qatom_ps[n]=" << qatom_ps[n] << " atom:\n";
1932 atom[n]->print(file, l);
1933 }
1934 indn.n -= 2;
1935}
1936
1937std::ostream& operator<<(std::ostream& file, const MolecPhotoAbsCS& f) {
1938 f.print(file, 1);
1939 return file;
1940}
1941}
#define check_econd21(a, sign1_b1_sign0, sign2_b2, stream)
Definition: FunNameStack.h:191
#define check_econd11(a, signb, stream)
Definition: FunNameStack.h:155
#define check_econd11a(a, signb, add, stream)
Definition: FunNameStack.h:172
#define mfunnamep(string)
Definition: FunNameStack.h:49
#define spexit(stream)
Definition: FunNameStack.h:256
#define check_econd12(a, sign, b, stream)
Definition: FunNameStack.h:163
#define mfunname(string)
Definition: FunNameStack.h:45
Atomic photoabsorption cross-section abstract base class.
Definition: PhotoAbsCS.h:286
AtomPhotoAbsCS()
Default constructor.
Definition: PhotoAbsCS.cpp:580
std::vector< bool > s_ignore_shell
Definition: PhotoAbsCS.h:379
int Z
Atomic number.
Definition: PhotoAbsCS.h:371
virtual void remove_shell(int nshell)
Deactivate a sub-shell. Set s_ignore_shell flag to true.
Definition: PhotoAbsCS.cpp:623
std::string name
Name of the atom.
Definition: PhotoAbsCS.h:369
virtual double get_I_min() const
Get the lowest ionization threshold among all shells.
Definition: PhotoAbsCS.cpp:667
virtual double get_ACS(double energy) const =0
virtual int get_main_shell_number(int nshell) const =0
virtual void print(std::ostream &file, int l) const
Definition: PhotoAbsCS.cpp:635
virtual double get_TICS(double energy, double factual_minimal_threshold) const
Definition: PhotoAbsCS.cpp:582
virtual double get_threshold(int nshell) const =0
Get the ionization threshold for a given shell.
virtual double get_integral_TICS(double energy1, double energy2, double factual_minimal_threshold) const
Integral photo-ionization cross-section with redefined threshold.
Definition: PhotoAbsCS.cpp:593
virtual void restore_shell(int nshell)
Activate a sub-shell. Set s_ignore_shell flag to false.
Definition: PhotoAbsCS.cpp:629
int qshell
Number of shells.
Definition: PhotoAbsCS.h:373
unsigned int get_qshell() const
Get the number of shells.
Definition: PhotoAbsCS.h:294
virtual void get_escape_particles(const int nshell, double energy, std::vector< double > &el_energy, std::vector< double > &ph_energy) const
Definition: PhotoAbsCS.cpp:675
std::vector< AtomicSecondaryProducts > asp
Sampling of relaxation products for each shell.
Definition: PhotoAbsCS.h:381
AtomicSecondaryProducts * get_asp(int nshell)
Definition: PhotoAbsCS.cpp:851
virtual double get_integral_ACS(double energy1, double energy2) const =0
Integrated photo-absorption cross-section overa given interval.
int get_channel(std::vector< double > &felectron_energy, std::vector< double > &fphoton_energy) const
Definition: PhotoAbsCS.cpp:506
void print(std::ostream &file, int l) const
Definition: PhotoAbsCS.cpp:549
std::vector< std::vector< double > > electron_energy
Definition: PhotoAbsCS.h:281
std::vector< std::vector< double > > photon_energy
Definition: PhotoAbsCS.h:282
void add_channel(double fchannel_prob_dens, const std::vector< double > &felectron_energy, const std::vector< double > &fphoton_energy, int s_all_rest=0)
Definition: PhotoAbsCS.cpp:469
std::vector< double > channel_prob_dens
Definition: PhotoAbsCS.h:279
Smoothed/smeared photoabsorption cross-section.
Definition: PhotoAbsCS.h:83
void scale(double fact) override
Multiply by some factor. Can be useful for debugging and other purposes.
Definition: PhotoAbsCS.cpp:145
double get_CS(double energy) const override
Retrieve cross-section [Mb] at a given energy [MeV].
Definition: PhotoAbsCS.cpp:117
AveragePhotoAbsCS()
Default constructor.
Definition: PhotoAbsCS.h:94
void print(std::ostream &file, int l) const override
Definition: PhotoAbsCS.cpp:150
double get_integral_CS(double energy1, double energy2) const override
Retrieve integral cross-section [Mb * MeV] in a given interval [MeV].
Definition: PhotoAbsCS.cpp:126
void replace_shells_by_average(double fwidth, double fstep, long fmax_q_step)
std::string BT_file_name
Definition: PhotoAbsCS.h:543
double height_of_excitation
Excitation cross-section (assumed in the lowest shell).
Definition: PhotoAbsCS.h:553
virtual double get_threshold(int nshell) const
Get the ionization threshold for a given shell.
static const int s_add_excitations_to_normalize
Definition: PhotoAbsCS.h:569
double exener[2]
Boundaries of excitation.
Definition: PhotoAbsCS.h:555
std::vector< std::shared_ptr< PhotoAbsCS > > m_acs
Definition: PhotoAbsCS.h:546
virtual double get_integral_ACS(double energy1, double energy2) const
Integrated photo-absorption cross-section overa given interval.
virtual double get_ACS(double energy) const
static const int s_scale_to_normalize_if_more
Definition: PhotoAbsCS.h:570
std::string threshold_file_name
Definition: PhotoAbsCS.h:541
ExAtomPhotoAbsCS()
Default constructor.
Definition: PhotoAbsCS.h:455
std::string simple_table_file_name
Definition: PhotoAbsCS.h:542
virtual void print(std::ostream &file, int l) const
virtual double get_ICS(double energy) const
virtual double get_integral_ICS(double energy1, double energy2) const
Integrated photo-ionization cross-section over a given interval.
void scale(double fact) override
Multiply by some factor. Can be useful for debugging and other purposes.
Definition: PhotoAbsCS.cpp:184
HydrogenPhotoAbsCS()
Constructor.
Definition: PhotoAbsCS.cpp:161
double get_integral_CS(double energy1, double energy2) const override
Retrieve integral cross-section [Mb * MeV] in a given interval [MeV].
Definition: PhotoAbsCS.cpp:172
double get_CS(double energy) const override
Retrieve cross-section [Mb] at a given energy [MeV].
Definition: PhotoAbsCS.cpp:166
void print(std::ostream &file, int l) const override
Definition: PhotoAbsCS.cpp:186
size_t get_total_Z() const
Sum up the atomic numbers of all atoms in the molecule.
double get_ACS(double energy) const
Photo-absorption cross-section [Mbarn] at a given energy [MeV].
double get_ICS(double energy) const
Photo-ionization cross-section [Mbarn] at a given energy [MeV].
double get_integral_ICS(double energy1, double energy2) const
Integral photo-ionization cross-section.
MolecPhotoAbsCS()=default
Default constructor.
double get_integral_ACS(double energy1, double energy2) const
Integral photo-absorption cross-section.
void print(std::ostream &file, int l) const
Simple phenomenological CS for any shell (analytic formula).
Definition: PhotoAbsCS.h:211
void print(std::ostream &file, int l) const override
Definition: PhotoAbsCS.cpp:460
void scale(double fact) override
Multiply by some factor. Can be useful for debugging and other purposes.
Definition: PhotoAbsCS.cpp:455
double get_integral_CS(double energy1, double energy2) const override
Retrieve integral cross-section [Mb * MeV] in a given interval [MeV].
Definition: PhotoAbsCS.cpp:442
double get_CS(double energy) const override
Retrieve cross-section [Mb] at a given energy [MeV].
Definition: PhotoAbsCS.cpp:437
PhenoPhotoAbsCS()
Default constructor.
Definition: PhotoAbsCS.cpp:425
PhotoAbsCS()
Default constructor.
Definition: PhotoAbsCS.cpp:79
double threshold
Definition: PhotoAbsCS.h:79
double get_threshold() const
Return the threshold energy.
Definition: PhotoAbsCS.h:64
virtual void print(std::ostream &file, int l) const
Definition: PhotoAbsCS.cpp:91
std::string name
Definition: PhotoAbsCS.h:76
SimpleAtomPhotoAbsCS()
Default constructor.
Definition: PhotoAbsCS.cpp:857
std::vector< std::shared_ptr< PhotoAbsCS > > m_acs
Definition: PhotoAbsCS.h:424
virtual double get_ACS(double energy) const
Definition: PhotoAbsCS.cpp:938
virtual void print(std::ostream &file, int l) const
std::string file_name
Filename (saved for printing).
Definition: PhotoAbsCS.h:423
virtual double get_integral_ACS(double energy1, double energy2) const
Integrated photo-absorption cross-section overa given interval.
Definition: PhotoAbsCS.cpp:946
virtual double get_integral_ICS(double energy1, double energy2) const
Integrated photo-ionization cross-section over a given interval.
Definition: PhotoAbsCS.cpp:987
virtual double get_threshold(int nshell) const
Get the ionization threshold for a given shell.
Definition: PhotoAbsCS.cpp:932
virtual double get_ICS(double energy) const
Definition: PhotoAbsCS.cpp:978
void remove_leading_tiny(double level)
Definition: PhotoAbsCS.cpp:319
void print(std::ostream &file, int l) const override
Definition: PhotoAbsCS.cpp:409
double get_integral_CS(double energy1, double energy2) const override
Retrieve integral cross-section [Mb * MeV] in a given interval [MeV].
Definition: PhotoAbsCS.cpp:357
SimpleTablePhotoAbsCS()=default
Default constructor.
void scale(double fact) override
Multiply by some factor. Can be useful for debugging and other purposes.
Definition: PhotoAbsCS.cpp:403
double get_CS(double energy) const override
Retrieve cross-section [Mb] at a given energy [MeV].
Definition: PhotoAbsCS.cpp:337
const std::vector< double > & get_arr_CS() const
Definition: PhotoAbsCS.h:194
const std::vector< double > & get_arr_ener() const
Definition: PhotoAbsCS.h:193
void remove_leading_zeros()
Remove points with zero cross-section from the table.
Definition: PhotoAbsCS.cpp:302
Definition: BGMesh.cpp:6
T t_value_straight_2point(T x1, T y1, T x2, T y2, T x, int s_ban_neg)
Definition: tline.h:1518
constexpr double Thomas_sum_rule_const_Mb
TRK sum rule [Mb * MeV].
Definition: PhotoAbsCS.h:19
std::ostream & operator<<(std::ostream &file, const BGMesh &bgm)
Definition: BGMesh.cpp:37
DoubleAc pow(const DoubleAc &f, double p)
Definition: DoubleAc.cpp:337
T t_integ_straight_2point(T x1, T y1, T x2, T y2, T xl, T xr, int xpower, int s_ban_neg)
Definition: tline.h:1552
T t_integ_generic_point_ar(const M &mesh, const D &y, T(*fun)(T xp1, T yp1, T xp2, T yp2, T xmin, T xmax, T x1, T x2), T x1, T x2, int s_extrap_left, T left_bond, int s_extrap_right, T right_bond)
Definition: tline.h:1832
constexpr double coef_I_to_W
Definition: PhotoAbsCS.h:585
int findmark(std::istream &file, const char *s)
Definition: findmark.cpp:19
constexpr double low_boundary_of_excitations
Definition: PhotoAbsCS.h:427
indentation indn
Definition: prstream.cpp:15
DoubleAc sqrt(const DoubleAc &f)
Definition: DoubleAc.cpp:314
T t_value_generic_point_ar(const M &mesh, const D &y, T(*funval)(T xp1, T yp1, T xp2, T yp2, T xmin, T xmax, T x), T x, int s_extrap_left, T left_bond, int s_extrap_right, T right_bond)
Definition: tline.h:1615
#define mcout
Definition: prstream.h:126
#define Ifile
Definition: prstream.h:195
#define mcerr
Definition: prstream.h:128
#define Iprintn(file, name)
Definition: prstream.h:204
#define Iprint2n(file, name1, name2)
Definition: prstream.h:219