Garfield++ 3.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 Iprint(mcout, felectron_energy);
746 Iprint(mcout, fphoton_energy);
747#endif
748
749 if (is != 0) {
750 // Generate photo-electron and just copy all what is proposed by
751 // get_channel with corrections by hdist.
752 el_energy.resize(1 + felectron_energy.size());
753 el_energy[0] = en;
754 long q = felectron_energy.size();
755 for (long n = 0; n < q; ++n) {
756 check_econd21(felectron_energy[n], < 0 ||, > thrShell, mcerr);
757 el_energy[1 + n] = felectron_energy[n] - hdist;
758 if (el_energy[1 + n] < 0) {
759 hdist = -el_energy[1 + n];
760 el_energy[1 + n] = 0.0;
761 } else {
762 hdist = 0.0;
763 }
764 }
765 ph_energy.resize(fphoton_energy.size());
766 q = fphoton_energy.size();
767 for (long n = 0; n < q; ++n) {
768 check_econd21(fphoton_energy[n], < 0 ||, > thrShell, mcerr);
769 ph_energy[n] = fphoton_energy[n] - hdist;
770 if (ph_energy[n] < 0) {
771 hdist = -ph_energy[n];
772 ph_energy[n] = 0.0;
773 } else {
774 hdist = 0.0;
775 }
776 }
777 return;
778 }
779
780 // Generate default channel.
781 if (main_n <= 0) {
782 // Principal numbers are not available. Generate Auger to outmost shell.
783 const double en1 = thrShell - hdist - 2 * thrMin;
784 el_energy.push_back(en);
785 if (en1 >= 0.0) el_energy.push_back(en1);
786 return;
787 }
788 // First find the principal quantum number of the deepest shell.
789 int main_n_largest = 0;
790 for (int n = 0; n < qshell; ++n) {
791 main_n_largest = std::max(main_n_largest, get_main_shell_number(n));
792 }
793#ifdef DEBUG_PRINT_get_escape_particles
794 Iprintn(mcout, main_n_largest);
795#endif
796 if (main_n_largest - main_n < 2) {
797 // Generate Auger from the outermost shell.
798 double en1 = thrShell - hdist - 2 * thrMin;
799 el_energy.push_back(en);
800 if (en1 >= 0.0) el_energy.push_back(en1);
801 return;
802 }
803 // At least K, l, M shells exist.
804 // In this case we use more advanced scheme.
805 // Look for shell with larger main number and with less energy
806 int n_chosen = -1;
807 double thr = DBL_MAX; // this will be the least threshold
808 // among the shells with next principal number
809 for (int n = 0; n < qshell; ++n) {
810 // currently the minimal shell is the last,
811 // but to avoid this assumption we check all
812 int main_n_t = get_main_shell_number(n);
813 if (main_n_t > 0 && main_n_t == main_n + 1) {
814 if (thr > get_threshold(n)) {
815 n_chosen = n;
816 thr = get_threshold(n);
817 }
818 }
819 }
820#ifdef DEBUG_PRINT_get_escape_particles
821 Iprint2n(mcout, n_chosen, thr);
822#endif
823 check_econd11(n_chosen, < 0, mcerr);
824 double en1 = thrShell - hdist - 2 * get_threshold(n_chosen);
825 if (en1 > 0.) {
826 // Photo-electron
827 el_energy.push_back(en);
828 // First Auger from chosen shell
829 el_energy.push_back(en1);
830 // Then filling two vacancies at the next (chosen) shell
831 // from the outermost one
832 const double en2 = get_threshold(n_chosen) - 2 * thrMin;
833 if (en2 > 0.) {
834 el_energy.push_back(en2);
835 el_energy.push_back(en2);
836 check_econd11(el_energy[2], < 0.0, mcerr);
837 }
838 return;
839 }
840 en1 = thrShell - hdist - get_threshold(n_chosen) - thrMin;
841 if (en1 > 0.) {
842 // Photo-electron
843 el_energy.push_back(en);
844 el_energy.push_back(en1);
845 // Filling initially ionized level from chosen
846 // and emittance of Auger from outermost.
847 check_econd11(el_energy[1], < 0.0, mcerr);
848 const double en2 = get_threshold(n_chosen) - 2 * thrMin;
849 if (en2 > 0.) el_energy.push_back(en2);
850 }
851}
852
854 mfunnamep("AtomicSecondaryProducts* AtomPhotoAbsCS::get_asp(int nshell)");
855 check_econd21(nshell, < 0 ||, >= qshell, mcerr);
856 return &(asp[nshell]);
857}
858
860
862 const std::string& ffile_name)
863 : file_name(ffile_name) {
864 mfunnamep("SimpleAtomPhotoAbsCS::SimpleAtomPhotoAbsCS(...)");
865 check_econd11(fZ, < 1, mcerr);
866 std::ifstream file(file_name.c_str());
867 if (!file) {
868 funnw.ehdr(mcerr);
869 mcerr << "cannot open file " << file_name << std::endl;
870 spexit(mcerr);
871 }
872 while (findmark(file, "#") == 1) {
873 file >> Z;
874 if (Z != fZ) continue;
875 file >> qshell;
876 check_econd21(qshell, < 1 ||, > 10000, mcerr);
877 s_ignore_shell.resize(qshell, false);
878 file >> name;
879 m_acs.resize(qshell);
880 asp.resize(qshell);
881 std::vector<double> fl(qshell);
882 int sZshell = 0;
883 for (int nshell = 0; nshell < qshell; ++nshell) {
884 double thr = 0.0;
885 int Zshell = 0;
886 std::string shell_name;
887 file >> thr;
888 check_econd11(thr, <= 0.0, mcerr);
889 file >> Zshell;
890 check_econd11(Zshell, <= 0, mcerr);
891 sZshell += Zshell;
892 file >> fl[nshell];
893 findmark(file, "!");
894 file >> shell_name;
895 m_acs[nshell].reset(new PhenoPhotoAbsCS(shell_name, Zshell, thr * 1.0e-6));
896 }
897 check_econd12(sZshell, !=, Z, mcerr);
898
899 int n_min = 0;
900 double st = DBL_MAX;
901 for (int nshell = 0; nshell < qshell; ++nshell) {
902 // currently the minimal shell is the last,
903 // but to avoid this assumption we check all
904 if (get_threshold(nshell) < st) n_min = nshell;
905 }
906 for (int nshell = 0; nshell < qshell; ++nshell) {
907 if (fl[nshell] <= 0) continue;
908 check_econd12(nshell, ==, n_min, mcerr);
909 std::vector<double> felectron_energy;
910 std::vector<double> fphoton_energy;
911 fphoton_energy.push_back(get_threshold(nshell) - get_threshold(n_min));
912 asp[nshell].add_channel(fl[nshell], felectron_energy, fphoton_energy);
913 }
914 return;
915 }
916 funnw.ehdr(mcerr);
917 mcerr << "there is no element Z=" << fZ << " in file " << file_name << '\n';
918 spexit(mcerr);
919}
920
921SimpleAtomPhotoAbsCS::SimpleAtomPhotoAbsCS(int fZ, std::shared_ptr<PhotoAbsCS> facs) {
922 mfunname("SimpleAtomPhotoAbsCS::SimpleAtomPhotoAbsCS(...)");
923 check_econd11(facs, == nullptr, mcerr);
924 check_econd11(fZ, <= 0, mcerr);
925 check_econd12(fZ, !=, facs->get_Z(), mcerr);
926 Z = fZ;
927 qshell = 1;
928 s_ignore_shell.resize(qshell, false);
929 name = facs->get_name();
930 m_acs.resize(1);
931 m_acs[0] = std::move(facs);
932}
933
934double SimpleAtomPhotoAbsCS::get_threshold(int nshell) const {
935 mfunname("double SimpleAtomPhotoAbsCS::get_threshold(int nshell) const");
936 check_econd21(nshell, < 0 ||, > qshell, mcerr);
937 return m_acs[nshell]->get_threshold();
938}
939
940double SimpleAtomPhotoAbsCS::get_ACS(double energy) const {
941 mfunname("double SimpleAtomPhotoAbsCS::get_ACS(double energy) const");
942 double s = 0.0;
943 for (int n = 0; n < qshell; ++n) {
944 if (!s_ignore_shell[n]) s += m_acs[n]->get_CS(energy);
945 }
946 return s;
947}
949 double energy2) const {
950 mfunnamep("double SimpleAtomPhotoAbsCS::get_integral_ACS(...) const");
951 double s = 0.0;
952 for (int n = 0; n < qshell; ++n) {
953 if (s_ignore_shell[n]) continue;
954 const double t = m_acs[n]->get_integral_CS(energy1, energy2);
955 if (t < 0) {
956 funnw.ehdr(mcout);
957 mcout << "t < 0\n";
958 Iprintn(mcout, t);
959 print(mcout, 4);
960 spexit(mcout);
961 }
962 s += t;
963 }
964 return s;
965}
966
967double SimpleAtomPhotoAbsCS::get_ACS(int nshell, double energy) const {
968 mfunname("double SimpleAtomPhotoAbsCS::get_ACS(int nshell, double energy)");
969 check_econd21(nshell, < 0 ||, > qshell, mcerr);
970 return s_ignore_shell[nshell] ? 0. : m_acs[nshell]->get_CS(energy);
971}
972
973double SimpleAtomPhotoAbsCS::get_integral_ACS(int nshell, double en1,
974 double en2) const {
975 mfunname("double SimpleAtomPhotoAbsCS::get_integral_ACS(...) const");
976 check_econd21(nshell, < 0 ||, > qshell, mcerr);
977 return s_ignore_shell[nshell] ? 0. : m_acs[nshell]->get_integral_CS(en1, en2);
978}
979
980double SimpleAtomPhotoAbsCS::get_ICS(double energy) const {
981 mfunname("double SimpleAtomPhotoAbsCS::get_ICS(double energy) const");
982 double s = 0.0;
983 for (int n = 0; n < qshell; ++n) {
984 if (!s_ignore_shell[n]) s += m_acs[n]->get_CS(energy);
985 }
986 return s;
987}
988
990 double energy2) const {
991 mfunname("double SimpleAtomPhotoAbsCS::get_integral_ICS(...) const");
992 double s = 0.0;
993 for (int n = 0; n < qshell; ++n) {
994 if (!s_ignore_shell[n]) s += m_acs[n]->get_integral_CS(energy1, energy2);
995 }
996 return s;
997}
998
999double SimpleAtomPhotoAbsCS::get_ICS(int nshell, double energy) const {
1000 mfunname("double SimpleAtomPhotoAbsCS::get_ICS(int nshell, double energy)");
1001 check_econd21(nshell, < 0 ||, > qshell, mcerr);
1002 return s_ignore_shell[nshell] ? 0. : m_acs[nshell]->get_CS(energy);
1003}
1004
1005double SimpleAtomPhotoAbsCS::get_integral_ICS(int nshell, double en1,
1006 double en2) const {
1007 mfunname("double SimpleAtomPhotoAbsCS::get_integral_ICS(...) const");
1008 check_econd21(nshell, < 0 ||, > qshell, mcerr);
1009 return s_ignore_shell[nshell] ? 0. : m_acs[nshell]->get_integral_CS(en1, en2);
1010}
1011
1012void SimpleAtomPhotoAbsCS::print(std::ostream& file, int l) const {
1013 if (l <= 0) return;
1014 Ifile << "SimpleAtomPhotoAbsCS(l=" << l << "): name=" << name << " Z = " << Z
1015 << " qshell = " << qshell << " file_name=" << file_name << std::endl;
1016 l--;
1017 if (l <= 0) return;
1018 indn.n += 2;
1019 for (int n = 0; n < qshell; ++n) {
1020 Ifile << "nshell=" << n << std::endl;
1021 m_acs[n]->print(file, l);
1022 }
1023 AtomPhotoAbsCS::print(file, l);
1024 indn.n -= 2;
1025}
1026
1027//----------------------------------------------------------------------
1028
1030 const std::string& fthreshold_file_name,
1031 const std::string& fsimple_table_file_name,
1032 const std::string& fname,
1033 double fminimal_threshold)
1034 : threshold_file_name(fthreshold_file_name),
1035 simple_table_file_name(fsimple_table_file_name),
1036 BT_file_name("none"),
1037 minimal_threshold(fminimal_threshold) {
1038 mfunnamep("ExAtomPhotoAbsCS::ExAtomPhotoAbsCS(...) const");
1039 check_econd11(fZ, < 1, mcerr);
1040 std::ifstream threshold_file(threshold_file_name.c_str());
1041 if (!threshold_file) {
1042 funnw.ehdr(mcerr);
1043 mcerr << "cannot open file " << threshold_file_name << std::endl;
1044 spexit(mcerr);
1045 }
1046 std::vector<double> thr;
1047 std::vector<int> Zshell;
1048 std::vector<double> fl;
1049 std::vector<std::string> shell_name;
1050 bool foundZ = false;
1051 while (findmark(threshold_file, "#") == 1) {
1052 threshold_file >> Z;
1053 if (Z != fZ) continue;
1054 threshold_file >> qshell;
1055 check_econd21(qshell, < 1 ||, > 10000, mcerr);
1056 s_ignore_shell.resize(qshell, false);
1057 // Iprintn(mcout, qshell);
1058 thr.resize(qshell, 0.0);
1059 Zshell.resize(qshell, 0);
1060 fl.resize(qshell, 0.0);
1061 shell_name.resize(qshell);
1062 m_acs.resize(qshell);
1063 asp.resize(qshell);
1064 std::string temp_name;
1065 threshold_file >> temp_name;
1066 name = fname == "none" ? temp_name : fname;
1067 int sZshell = 0;
1068 for (int nshell = 0; nshell < qshell; nshell++) {
1069 threshold_file >> thr[nshell];
1070 check_econd11(thr[nshell], <= 0.0, mcerr);
1071 thr[nshell] *= 1.0e-6;
1072 threshold_file >> Zshell[nshell];
1073 check_econd11(Zshell[nshell], <= 0, mcerr);
1074 sZshell += Zshell[nshell];
1075 threshold_file >> fl[nshell];
1076 findmark(threshold_file, "!");
1077 threshold_file >> shell_name[nshell];
1078 }
1079 check_econd12(sZshell, !=, Z, mcerr);
1080 // currently the minimal shell is the last,
1081 // but to avoid this assumption, we check all.
1082 int n_min = 0;
1083 double st = DBL_MAX;
1084 for (int nshell = 0; nshell < qshell; nshell++) {
1085 if (thr[nshell] < st) {
1086 n_min = nshell;
1087 st = thr[nshell];
1088 }
1089 }
1090 for (int nshell = 0; nshell < qshell; nshell++) {
1091 if (fl[nshell] <= 0) continue;
1092 check_econd12(nshell, ==, n_min, mcerr);
1093 std::vector<double> felectron_energy;
1094 std::vector<double> fphoton_energy;
1095 fphoton_energy.push_back(thr[nshell] - thr[n_min]);
1096 asp[nshell].add_channel(fl[nshell], felectron_energy, fphoton_energy);
1097 }
1098 foundZ = true;
1099 break;
1100 }
1101 if (!foundZ) {
1102 funnw.ehdr(mcerr);
1103 mcerr << "there is no element Z=" << fZ << " in file "
1104 << threshold_file_name << std::endl;
1105 spexit(mcerr);
1106 }
1107 // Here it reads the PACS as an one shell curve:
1108 SimpleTablePhotoAbsCS stpacs(name, Z, 0.0, fsimple_table_file_name);
1109 const std::vector<double>& ener = stpacs.get_arr_ener();
1110 const std::vector<double>& CS = stpacs.get_arr_CS();
1111 std::vector<double> left_CS = CS; // used in sequencial algorithm
1112 const long qe = ener.size();
1113 // here cs is saved
1114 std::vector<std::vector<double> > SCS(qshell, std::vector<double>(qe, 0.));
1115 int nct = qshell - 1; // "current" threshold index
1116 unsigned long nce = 0; // "current" energy index
1117 // We ignore values below the lowest threshold.
1118 // It is not clear whether it is right, perhaps this is one of possible ways
1119 if (ener[0] < thr[qshell - 1]) {
1120 for (long ne = 0; ne < qe && (ener[ne] < thr[qshell - 1] ||
1121 (ener[ne] >= thr[qshell - 1] && ne > 1 &&
1122 CS[ne - 1] <= CS[ne - 2]));
1123 ne++) {
1124 if (ne > 0) left_CS[ne - 1] = 0.0;
1125 nce = ne;
1126 }
1127 }
1128 int s_more;
1129 int nt2 = 0; // < nt1
1130 int s_spes = 0;
1131 // Actually this is a loop by the group of thresholds
1132 do {
1133 // Find all thresholds which are less then the current energy
1134 int nt;
1135 // sign that there are thresholds more than the current energy
1136 s_more = 0;
1137 for (nt = nct; nt >= 0; nt--) {
1138 if (s_spes == 0) {
1139 if (thr[nt] > ener[nce]) {
1140 s_more = 1;
1141 break;
1142 }
1143 } else {
1144 if (thr[nt] > ener[nce + 1]) {
1145 s_more = 1;
1146 break;
1147 }
1148 }
1149 }
1150 // nt is now index of the next threshold or -1, if the thresholds are
1151 // made up.
1152 int nt1 = nct;
1153 int nce_next = ener.size();
1154 nt2 = nt + 1;
1155 // mcout<<"nt="<<nt<<" nt1="<<nt1<<" nt2="<<nt2<<" s_more="<<s_more<<'\n';
1156 if (s_more == 1) {
1157 // if(nt >= 0) // so if there are other larger thresholds,
1158 //{ // we should check how far we can pass at this step
1159 unsigned long ne;
1160 // finding energy larger than the next threshold
1161 for (ne = nce; ne < ener.size(); ne++) {
1162 if (thr[nt] <= ener[ne]) {
1163 nce_next = ne;
1164 s_spes = 0;
1165 break;
1166 }
1167 // At the following condition energy could be less than threshold,
1168 // but this point will anyway be associated with the next shell
1169 // corresponding to this threshold.
1170 // This is related to not precise measurement of cross section
1171 // and not precise knowledge of shell energies.
1172 // Occurence of this condition is marked by s_spes = 1.
1173 // At the next passing of this loop the thresholds are compared with
1174 // the next energy.
1175 if (ne > 1 && ne < ener.size() - 1 && ne > nce + 2 &&
1176 thr[nt] <= ener[ne + 1] &&
1177 (thr[nt] - ener[ne]) / (ener[ne + 1] - ener[ne]) < 0.1 &&
1178 CS[ne] > CS[ne - 1]) {
1179 // mcout<<"special condition is satisf.\n";
1180 nce_next = ne;
1181 s_spes = 1;
1182 break;
1183 }
1184 }
1185 if (ne == ener.size()) // threshold is larger then energy mesh
1186 s_more = 0; // to finish the loop
1187 }
1188 // Iprintn(mcout, nce_next);
1189 // Iprintn(mcout, ener[nce_next-1]);
1190 int qt = nt1 - nt2 + 1; // quantity of the new thresholds
1191 // Iprintn(mcout, qt);
1192
1193 // Calculate sum of Z.
1194 int s = 0;
1195 for (nt = 0; nt < qt; nt++) {
1196 const int nshell = nct - nt;
1197 s += Zshell[nshell];
1198 }
1199 // Weights according to charges
1200 std::vector<double> w(qt);
1201 for (nt = 0; nt < qt; nt++) {
1202 const int nshell = nct - nt;
1203 w[nt] = double(Zshell[nshell]) / s;
1204 }
1205 double save_left_CS = left_CS[nce_next - 1];
1206 for (long ne = 0; ne < nce_next; ne++) {
1207 for (nt = 0; nt < qt; nt++) {
1208 int nshell = nct - nt;
1209 SCS[nshell][ne] = left_CS[ne] * w[nt];
1210 }
1211 left_CS[ne] = 0.0;
1212 }
1213 for (unsigned long ne = nce_next; ne < ener.size(); ne++) {
1214 double extrap_CS =
1215 save_left_CS * pow(ener[nce_next - 1], 2.75) / pow(ener[ne], 2.75);
1216 if (extrap_CS > left_CS[ne]) extrap_CS = left_CS[ne];
1217 for (nt = 0; nt < qt; nt++) {
1218 int nshell = nct - nt;
1219 SCS[nshell][ne] = extrap_CS * w[nt];
1220 }
1221 left_CS[ne] -= extrap_CS;
1222 }
1223 nce = nce_next;
1224 nct = nt2 - 1;
1225 } while (s_more != 0);
1226 // now nt2 will be index of last filled shell
1227 // Now to fill the shells which are absent in the input table.
1228 // They will be initialized phenomenologically, based on the sum rule.
1229 for (int ns = 0; ns < nt2; ns++) {
1230 m_acs[ns].reset(new PhenoPhotoAbsCS(shell_name[ns], Zshell[ns], thr[ns]));
1231 }
1232 // Initialization of input shells.
1233 for (int ns = nt2; ns < qshell; ns++) {
1234 auto adr = new SimpleTablePhotoAbsCS(shell_name[ns], Zshell[ns], thr[ns], ener, SCS[ns]);
1235 adr->remove_leading_zeros();
1236 m_acs[ns].reset(adr);
1237 }
1239 exener[0] = exener[1] = 0.0;
1240 double integ = get_integral_ACS(0.0, DBL_MAX);
1241 // Iprintn(mcout, integ);
1242 integ_abs_before_corr = integ;
1243 double pred_integ = Thomas_sum_rule_const_Mb * Z;
1244 // Iprintn(mcout, pred_integ);
1245 if (pred_integ > integ) {
1247 const double threshold = m_acs[qshell - 1]->get_threshold();
1248 // add excitation
1249 exener[0] = low_boundary_of_excitations * threshold;
1250 exener[1] = threshold;
1251 height_of_excitation = (pred_integ - integ) / (exener[1] - exener[0]);
1252 if (minimal_threshold > 0.0) {
1253 if (minimal_threshold > threshold) {
1254 // currently the minimal shell is the last one
1255 exener[0] += minimal_threshold - threshold;
1256 exener[1] += minimal_threshold - threshold;
1257 }
1258 }
1259 }
1260 } else if (pred_integ < integ) {
1262 const double fact = pred_integ / integ;
1263 for (int nshell = 0; nshell < qshell; ++nshell) {
1264 m_acs[nshell]->scale(fact);
1265 }
1266 }
1267 }
1268 integ_abs_after_corr = get_integral_ACS(0.0, DBL_MAX);
1270}
1271
1272ExAtomPhotoAbsCS::ExAtomPhotoAbsCS(int fZ, const std::string& fname,
1273 const std::string& fBT_file_name, int id,
1274 double fminimal_threshold)
1275 : threshold_file_name("none"),
1276 simple_table_file_name("none"),
1277 BT_file_name(fBT_file_name),
1278 minimal_threshold(fminimal_threshold) {
1279 mfunnamep(
1280 "ExAtomPhotoAbsCS::ExAtomPhotoAbsCS(int fZ, const std::string& fname, "
1281 "const std::string& fBT_file_name, int id, double fminimal_threshold)");
1282 check_econd11(fZ, < 1, mcerr);
1283 check_econd21(id, < 1 ||, > 2, mcerr);
1284
1285 name = fname;
1286 std::ifstream BT_file(BT_file_name.c_str());
1287 if (!BT_file) {
1288 funnw.ehdr(mcerr);
1289 mcerr << "cannot open file " << BT_file_name << std::endl;
1290 spexit(mcerr);
1291 }
1292 std::vector<double> thresh;
1293 std::vector<double> fl;
1294 Z = fZ;
1295 int i = findmark(BT_file, "NUCLEAR CHARGE =");
1296 check_econd11a(i, != 1, "wrong file format", mcerr);
1297 int Z_from_file;
1298 BT_file >> Z_from_file;
1299 check_econd12(Z_from_file, !=, Z, mcerr);
1300 qshell = 0;
1301 while ((i = findmark(BT_file, "Z =")) == 1) {
1302 BT_file >> i;
1303 check_econd11(i, != Z, mcerr);
1304 std::string shellname;
1305 BT_file >> shellname;
1306 // Iprintn(mcout, shellname);
1307 i = findmark(BT_file, "$");
1308 check_econd11(i, != 1, mcerr);
1309 long qen;
1310 BT_file >> qen;
1311 check_econd11(qen, <= 0, mcerr);
1312 std::vector<double> fener(qen, 0.0);
1313 std::vector<double> fcs(qen, 0.0);
1314 double thr = 0.0;
1315 BT_file >> thr;
1316 check_econd11(thr, <= 0, mcerr);
1317 thr *= 1.0e-3; // pass from keV to MeV
1318 if (id == 2) {
1319 thresh.push_back(thr);
1320 fl.resize(fl.size() + 1);
1321 BT_file >> fl[qshell];
1322 check_econd21(fl[qshell], < 0.0 ||, > 1.0, mcerr);
1323 // Iprintn(mcout, fl[qshell]);
1324 }
1325 long nen;
1326 for (nen = 0; nen < qen; nen++) {
1327 BT_file >> fener[nen] >> fcs[nen];
1328 check_econd11(fener[nen], <= 0.0, mcerr);
1329 check_econd11(fcs[nen], < 0.0, mcerr);
1330 fener[nen] *= 1.0e-3; // pass from keV to MeV
1331 }
1332 qshell++;
1333 m_acs.resize(qshell);
1334 m_acs.back().reset(new SimpleTablePhotoAbsCS(shellname, 0, thr, fener, fcs));
1335 }
1336 if (id == 2) {
1337 // a copy of similar thing from subroutine above
1338 int n_min = 0;
1339 double st = DBL_MAX;
1340 for (int nshell = 0; nshell < qshell; ++nshell) {
1341 // currently the minimal shell is the last,
1342 // but to avoid this assumption we check all
1343 if (thresh[nshell] < st) {
1344 n_min = nshell;
1345 st = thresh[nshell];
1346 }
1347 }
1348 asp.resize(qshell);
1349 for (int nshell = 0; nshell < qshell; ++nshell) {
1350 if (fl[nshell] > 0) {
1351 check_econd12(nshell, ==, n_min, mcerr);
1352 std::vector<double> felectron_energy;
1353 std::vector<double> fphoton_energy;
1354 fphoton_energy.push_back(thresh[nshell] - thresh[n_min]);
1355 asp[nshell].add_channel(fl[nshell], felectron_energy, fphoton_energy);
1356 }
1357 }
1358 }
1359
1360 check_econd11(qshell, <= 0, mcerr);
1361 s_ignore_shell.resize(qshell, false);
1363 exener[0] = exener[1] = 0.0;
1364 double integ = get_integral_ACS(0.0, DBL_MAX);
1365 // Iprintn(mcout, integ);
1366 integ_abs_before_corr = integ;
1367 double pred_integ = Thomas_sum_rule_const_Mb * Z;
1368 // Iprintn(mcout, pred_integ);
1369 if (pred_integ > integ) {
1371 const double thr = m_acs[qshell - 1]->get_threshold();
1372 // add excitation
1374 exener[1] = thr;
1375 height_of_excitation = (pred_integ - integ) / (exener[1] - exener[0]);
1376 if (minimal_threshold > 0.0) {
1377 if (minimal_threshold > thr) {
1378 // currently the minimal shell is the last one
1379 exener[0] += minimal_threshold - thr;
1380 exener[1] += minimal_threshold - thr;
1381 }
1382 }
1383 }
1384 } else {
1386 const double fact = pred_integ / integ;
1387 for (int nshell = 0; nshell < qshell; ++nshell) {
1388 m_acs[nshell]->scale(fact);
1389 }
1390 }
1391 }
1392 integ_abs_after_corr = get_integral_ACS(0.0, DBL_MAX);
1394}
1395
1396#define READ_FILE_WITH_PRINCIPAL_NUMBERS
1397
1398ExAtomPhotoAbsCS::ExAtomPhotoAbsCS(int fZ, const std::string& fname,
1399 const std::string& fFitBT_file_name,
1400 int id,
1401 int s_no_scale, double fminimal_threshold)
1402 : threshold_file_name("none"),
1403 simple_table_file_name("none"),
1404 BT_file_name(fFitBT_file_name),
1405 minimal_threshold(fminimal_threshold) {
1406 mfunnamep(
1407 "ExAtomPhotoAbsCS::ExAtomPhotoAbsCS(int fZ, const std::string& fname, "
1408 "const "
1409 "std::string& fFitBT_file_name, int id, int id1, double "
1410 "fminimal_threshold)");
1411 check_econd11(fZ, < 1, mcerr);
1412 check_econd21(id, < 1 ||, > 2, mcerr);
1413 Z = fZ;
1414 name = fname;
1415 std::ifstream BT_file(fFitBT_file_name.c_str());
1416 if (!BT_file) {
1417 funnw.ehdr(mcerr);
1418 mcerr << "cannot open file " << BT_file_name << std::endl;
1419 spexit(mcerr);
1420 }
1421 std::vector<double> thresh;
1422 std::vector<double> fl;
1423 int i = 0;
1424 while ((i = findmark(BT_file, "$")) == 1) {
1425 long iZ;
1426 BT_file >> iZ;
1427 if (iZ != Z) continue;
1428 BT_file >> qshell;
1429 // Iprintn(mcout, qshell);
1430 check_econd11(qshell, <= 0, mcerr);
1431 check_econd11(qshell, > 1000, mcerr);
1432 m_acs.resize(qshell);
1433 if (id == 2) {
1434 thresh.resize(qshell);
1435 fl.resize(qshell);
1436 }
1437 for (int nshell = 0; nshell < qshell; ++nshell) {
1438#ifdef READ_FILE_WITH_PRINCIPAL_NUMBERS
1439 int n_princ = 0;
1440#endif
1441 int l;
1442 double threshold;
1443 double E0;
1444 double yw;
1445 double ya;
1446 double P;
1447 double sigma;
1448 if (BT_file.eof()) {
1449 mcerr << "unexpected end of file " << BT_file_name << '\n';
1450 spexit(mcerr);
1451 }
1452 if (!BT_file.good()) {
1453 mcerr << "bad format of file " << BT_file_name << '\n';
1454 spexit(mcerr);
1455 }
1456#ifdef READ_FILE_WITH_PRINCIPAL_NUMBERS
1457 BT_file >> n_princ;
1458 if (!BT_file.good()) {
1459 mcerr << "bad format of file " << BT_file_name << '\n';
1460 spexit(mcerr);
1461 }
1462 check_econd21(n_princ, < 0 ||, > 10, mcerr);
1463#endif
1464 BT_file >> l >> threshold >> E0 >> sigma >> ya >> P >> yw;
1465 check_econd11(l, < 0, mcerr);
1466 check_econd11(l, > 20, mcerr);
1467 threshold *= 1.0e-6;
1468 E0 *= 1.0e-6;
1469
1470 check_econd11a(threshold, <= 2.0e-6,
1471 "n_princ=" << n_princ << " l=" << l << '\n', mcerr);
1472 check_econd11(E0, <= 0, mcerr);
1473 double flu = 0.0;
1474 if (id == 2) {
1475 if (BT_file.eof()) {
1476 mcerr << "unexpected end of file " << BT_file_name << '\n';
1477 spexit(mcerr);
1478 }
1479 if (!BT_file.good()) {
1480 mcerr << "bad format of file " << BT_file_name << '\n';
1481 spexit(mcerr);
1482 }
1483 BT_file >> flu;
1484 check_econd11(flu, < 0.0, mcerr);
1485 check_econd11(flu, > 1.0, mcerr);
1486 thresh[nshell] = threshold;
1487 fl[nshell] = flu;
1488 }
1489#ifdef READ_FILE_WITH_PRINCIPAL_NUMBERS
1490 // necessary for generation escape products
1491 std::string shellname(std::to_string(n_princ) + " shell number " +
1492 std::to_string(nshell));
1493#else
1494 std::string shellname("shell number " + std::to_string(nshell));
1495#endif
1496 m_acs[nshell].reset(new SimpleTablePhotoAbsCS(shellname, 0, threshold,
1497 l, E0, yw, ya, P, sigma));
1498 // Iprintn(mcout, nshell);
1499 // Iprint3n(mcout, l, threshold, E0);
1500 // Iprint4n(mcout, yw, ya, P, sigma);
1501 // acs[nshell]->print(mcout, 5);
1502 }
1503 goto mark1;
1504 }
1505 funnw.ehdr(mcerr);
1506 mcerr << "there is no element Z=" << fZ << " in file " << fFitBT_file_name
1507 << std::endl;
1508 spexit(mcerr);
1509mark1:
1510 if (id == 2) {
1511 // a copy of similar thing from subroutine above
1512 int n_min = 0;
1513 double st = DBL_MAX;
1514 for (int nshell = 0; nshell < qshell; ++nshell) {
1515 // currently the minimal shell is the last,
1516 // but to avoid this assumption we check all
1517 if (thresh[nshell] < st) {
1518 n_min = nshell;
1519 st = thresh[nshell];
1520 }
1521 }
1522 asp.resize(qshell);
1523 for (int nshell = 0; nshell < qshell; ++nshell) {
1524 if (fl[nshell] > 0) {
1525 check_econd12(nshell, ==, n_min, mcerr);
1526 std::vector<double> felectron_energy;
1527 std::vector<double> fphoton_energy;
1528 fphoton_energy.push_back(thresh[nshell] - thresh[n_min]);
1529 asp[nshell].add_channel(fl[nshell], felectron_energy, fphoton_energy);
1530 }
1531 }
1532 }
1533
1534 check_econd11(qshell, <= 0, mcerr);
1535 s_ignore_shell.resize(qshell, false);
1537 exener[0] = exener[1] = 0.0;
1538 double integ = get_integral_ACS(0.0, DBL_MAX);
1539 // Iprintn(mcout, integ);
1540 integ_abs_before_corr = integ;
1541 double pred_integ = Thomas_sum_rule_const_Mb * Z;
1542 // Iprintn(mcout, pred_integ);
1543 if (pred_integ > integ) {
1545 const double thr = m_acs[qshell - 1]->get_threshold();
1546 // add excitation
1548 exener[1] = thr;
1549 height_of_excitation = (pred_integ - integ) / (exener[1] - exener[0]);
1550 if (minimal_threshold > 0.0) {
1551 if (minimal_threshold > thr) {
1552 // currently the minimal shell is the last one
1553 exener[0] += minimal_threshold - thr;
1554 exener[1] += minimal_threshold - thr;
1555 }
1556 }
1557 }
1558 } else {
1559 if (s_scale_to_normalize_if_more == 1 && s_no_scale == 0) {
1560 const double fact = pred_integ / integ;
1561 for (int nshell = 0; nshell < qshell; ++nshell) {
1562 m_acs[nshell]->scale(fact);
1563 }
1564 }
1565 }
1566 integ_abs_after_corr = get_integral_ACS(0.0, DBL_MAX);
1568}
1569
1571 int fZ, const std::string& fname, const std::string& fFitBT_file_name,
1572 const std::string& fsimple_table_file_name, double emax_repl,
1573 int id, // to distinguish it from constructor above
1574 double fminimal_threshold) {
1575 mfunname("ExAtomPhotoAbsCS::ExAtomPhotoAbsCS(...)");
1576 Z = fZ;
1577 name = fname;
1578 int s_no_scale = 1;
1579 *this = ExAtomPhotoAbsCS(fZ, fname, fFitBT_file_name, id, s_no_scale,
1580 fminimal_threshold);
1581
1583 exener[0] = exener[1] = 0.0;
1584
1585 double thrmin = DBL_MAX;
1586 long nsmin = -1;
1587 // Look for minimal shell (usually the last).
1588 for (long ns = 0; ns < qshell; ++ns) {
1589 if (thrmin > m_acs[ns]->get_threshold()) {
1590 nsmin = ns;
1591 thrmin = m_acs[ns]->get_threshold();
1592 }
1593 }
1594 check_econd11(nsmin, < 0, mcerr);
1595 check_econd11(nsmin, != qshell - 1, mcerr);
1596
1597 PhotoAbsCS* apacs = m_acs[nsmin].get();
1598 auto first_shell = dynamic_cast<SimpleTablePhotoAbsCS*>(apacs);
1599 check_econd11(first_shell, == nullptr, mcerr);
1600
1601 SimpleTablePhotoAbsCS stpacs(name, Z, 0.0, fsimple_table_file_name);
1602 stpacs.remove_leading_tiny(1.0e-10);
1603
1604 // Merging shells:
1605 SimpleTablePhotoAbsCS* merged = new SimpleTablePhotoAbsCS(*first_shell, stpacs, emax_repl);
1606 m_acs[nsmin].reset(merged);
1607
1608 s_ignore_shell.resize(qshell, false);
1610 exener[0] = exener[1] = 0.0;
1611 double integ = get_integral_ACS(0.0, DBL_MAX);
1612 integ_abs_before_corr = integ;
1613 double pred_integ = Thomas_sum_rule_const_Mb * Z;
1614 if (pred_integ > integ) {
1616 const double thr = m_acs[qshell - 1]->get_threshold();
1617 // add excitation
1619 exener[1] = thr;
1620 height_of_excitation = (pred_integ - integ) / (exener[1] - exener[0]);
1621 if (minimal_threshold > 0.0) {
1622 if (minimal_threshold > thr) {
1623 // currently the minimal shell is the last one
1624 exener[0] += minimal_threshold - thr;
1625 exener[1] += minimal_threshold - thr;
1626 }
1627 }
1628 }
1629 } else {
1631 const double fact = pred_integ / integ;
1632 for (int nshell = 0; nshell < qshell; ++nshell) {
1633 m_acs[nshell]->scale(fact);
1634 }
1635 }
1636 }
1637 integ_abs_after_corr = get_integral_ACS(0.0, DBL_MAX);
1639}
1640
1641double ExAtomPhotoAbsCS::get_threshold(int nshell) const {
1642 mfunname("double ExAtomPhotoAbsCS::get_threshold(int nshell) const");
1643 check_econd21(nshell, < 0 ||, > qshell, mcerr);
1644 double r = m_acs[nshell]->get_threshold();
1645 if (minimal_threshold > 0.0) {
1647 }
1648 return r;
1649}
1650
1651double ExAtomPhotoAbsCS::get_ICS(double energy) const {
1652 mfunname("double ExAtomPhotoAbsCS::get_ACS(double energy) const");
1653 double s = 0.0;
1654 for (int n = 0; n < qshell; ++n) {
1655 if (s_ignore_shell[n]) continue;
1656 double shift = 0.0;
1657 const double t = m_acs[n]->get_threshold();
1658 if (minimal_threshold > 0.0) {
1659 if (t < minimal_threshold) shift = minimal_threshold - t;
1660 }
1661 s += m_acs[n]->get_CS(energy - shift);
1662 }
1663 return s;
1664}
1665
1667 double energy2) const {
1668 mfunname("double ExAtomPhotoAbsCS::get_integral_ICS(double energy) const");
1669 double s = 0.0;
1670 for (int n = 0; n < qshell; ++n) {
1671 if (s_ignore_shell[n]) continue;
1672 double shift = 0.0;
1673 const double t = m_acs[n]->get_threshold();
1674 if (minimal_threshold > 0.0) {
1675 if (t < minimal_threshold) shift = minimal_threshold - t;
1676 }
1677 s += m_acs[n]->get_integral_CS(energy1 - shift, energy2 - shift);
1678 }
1679 return s;
1680}
1681
1682double ExAtomPhotoAbsCS::get_ICS(int nshell, double energy) const {
1683 mfunname("double ExAtomPhotoAbsCS::get_ICS(int nshell, double energy) const");
1684 check_econd21(nshell, < 0 ||, > qshell, mcerr);
1685 if (s_ignore_shell[nshell]) return 0.;
1686 double shift = 0.0;
1687 const double t = m_acs[nshell]->get_threshold();
1688 if (minimal_threshold > 0.0) {
1689 if (t < minimal_threshold) shift = minimal_threshold - t;
1690 }
1691 return m_acs[nshell]->get_CS(energy - shift);
1692}
1693
1694double ExAtomPhotoAbsCS::get_integral_ICS(int nshell, double energy1,
1695 double energy2) const {
1696 mfunname("double ExAtomPhotoAbsCS::get_integral_ICS(int nshell, ...) const");
1697 check_econd21(nshell, < 0 ||, > qshell, mcerr);
1698 if (s_ignore_shell[nshell]) return 0.;
1699 double shift = 0.0;
1700 const double t = m_acs[nshell]->get_threshold();
1701 if (minimal_threshold > 0.0) {
1702 if (t < minimal_threshold) shift = minimal_threshold - t;
1703 }
1704 return m_acs[nshell]->get_integral_CS(energy1 - shift, energy2 - shift);
1705}
1706
1707double ExAtomPhotoAbsCS::get_ACS(double energy) const {
1708 mfunname("double ExAtomPhotoAbsCS::get_ACS(double energy) const");
1709 double s = 0.0;
1710 for (int n = 0; n < qshell; ++n) {
1711 if (s_ignore_shell[n]) continue;
1712 double shift = 0.0;
1713 const double t = m_acs[n]->get_threshold();
1714 if (minimal_threshold > 0.0) {
1715 if (t < minimal_threshold) shift = minimal_threshold - t;
1716 }
1717 s += m_acs[n]->get_CS(energy - shift);
1718 }
1719 if (energy >= exener[0] && energy <= exener[1]) s += height_of_excitation;
1720 return s;
1721}
1722
1724 double energy2) const {
1725 mfunname("double ExAtomPhotoAbsCS::get_integral_ACS(...) const");
1726 double s = 0.0;
1727 for (int n = 0; n < qshell; ++n) {
1728 if (s_ignore_shell[n]) continue;
1729 double shift = 0.0;
1730 const double t = m_acs[n]->get_threshold();
1731 if (minimal_threshold > 0.0) {
1732 if (t < minimal_threshold) shift = minimal_threshold - t;
1733 }
1734 s += m_acs[n]->get_integral_CS(energy1 - shift, energy2 - shift);
1735 }
1736 double b[2] = {std::max(exener[0], energy1), std::min(exener[1], energy2)};
1737 if (b[1] >= b[0]) s += height_of_excitation * (b[1] - b[0]);
1738 return s;
1739}
1740
1741double ExAtomPhotoAbsCS::get_ACS(int nshell, double energy) const {
1742 mfunname("double ExAtomPhotoAbsCS::get_ACS(int nshell, double energy)");
1743 check_econd21(nshell, < 0 ||, > qshell, mcerr);
1744 if (s_ignore_shell[nshell]) return 0.;
1745 double shift = 0.0;
1746 const double t = m_acs[nshell]->get_threshold();
1747 if (minimal_threshold > 0.0) {
1748 if (t < minimal_threshold) shift = minimal_threshold - t;
1749 }
1750 double s = m_acs[nshell]->get_CS(energy - shift);
1751 if (nshell == qshell - 1 && energy >= exener[0] && energy <= exener[1]) {
1753 }
1754 return s;
1755}
1756
1757double ExAtomPhotoAbsCS::get_integral_ACS(int nshell, double energy1,
1758 double energy2) const {
1759 mfunname("double ExAtomPhotoAbsCS::get_integral_ACS(int nshell, ...) const");
1760 check_econd21(nshell, < 0 ||, > qshell, mcerr);
1761 if (s_ignore_shell[nshell]) return 0.;
1762 double shift = 0.0;
1763 const double t = m_acs[nshell]->get_threshold();
1764 if (minimal_threshold > 0.0) {
1765 if (t < minimal_threshold) shift = minimal_threshold - t;
1766 }
1767 double s = m_acs[nshell]->get_integral_CS(energy1 - shift, energy2 - shift);
1768 if (nshell == qshell - 1) {
1769 double b[2] = {std::max(exener[0], energy1), std::min(exener[1], energy2)};
1770 if (b[1] >= b[0]) s += height_of_excitation * (b[1] - b[0]);
1771 }
1772 return s;
1773}
1774
1775void ExAtomPhotoAbsCS::print(std::ostream& file, int l) const {
1776 if (l <= 0) return;
1777 Ifile << "ExAtomPhotoAbsCS(l=" << l << "): name=" << name << " Z = " << Z
1778 << " qshell = " << qshell << std::endl;
1779 indn.n += 2;
1780 Ifile << "threshold_file_name=" << threshold_file_name << '\n';
1781 Ifile << "simple_table_file_name=" << simple_table_file_name << '\n';
1782 Ifile << "BT_file_name=" << BT_file_name << std::endl;
1783 Ifile << "Thomas_sum_rule_const_Mb * Z = " << Thomas_sum_rule_const_Mb* Z
1784 << '\n';
1785 Ifile << "integ_abs_before_corr = " << integ_abs_before_corr << '\n';
1786 Ifile << "integ_abs_after_corr = " << integ_abs_after_corr << '\n';
1787 Ifile << "integ_ioniz_after_corr = " << integ_ioniz_after_corr << '\n';
1788 Ifile << "height_of_excitation=" << height_of_excitation
1789 << " exener=" << exener[0] << ' ' << exener[1] << '\n';
1791 Ifile << "integrals by shells:\n";
1792 Ifile << "nshell, int(acs), int(ics)\n";
1793 for (long n = 0; n < qshell; n++) {
1794 double ainteg = get_integral_ACS(n, 0.0, DBL_MAX);
1795 double iinteg = get_integral_ICS(n, 0.0, DBL_MAX);
1796 Ifile << n << " " << ainteg << " " << iinteg << '\n';
1797 }
1798
1799 if (l > 1) {
1800 l--;
1801 indn.n += 2;
1802 for (long n = 0; n < qshell; ++n) {
1803 Ifile << "nshell=" << n << std::endl;
1804 m_acs[n]->print(file, l);
1805 }
1806 AtomPhotoAbsCS::print(file, l);
1807 indn.n -= 2;
1808 }
1809 indn.n -= 2;
1810}
1811
1812void ExAtomPhotoAbsCS::replace_shells_by_average(double fwidth, double fstep,
1813 long fmax_q_step) {
1814 mfunname("void ExAtomPhotoAbsCS::replace_shells_by_average(...)");
1815 for (long n = 0; n < qshell; n++) {
1816 if (!m_acs[n]) continue;
1817 PhotoAbsCS* a =
1818 new AveragePhotoAbsCS(m_acs[n].get(), fwidth, fstep, fmax_q_step);
1819 m_acs[n].reset(a);
1820 }
1821}
1822
1823//---------------------------------------------------------
1824
1826 double fW, double fF)
1827 : qatom(fqatom), W(fW), F(fF) {
1828 qatom_ps.push_back(qatom);
1829 atom.push_back(fatom);
1830 if (W == 0.0) W = coef_I_to_W * atom[0]->get_I_min();
1831}
1832
1834 const AtomPhotoAbsCS* fatom2, int fqatom_ps2,
1835 double fW, double fF)
1836 : qatom(fqatom_ps1 + fqatom_ps2), W(fW), F(fF) {
1837 qatom_ps.push_back(fqatom_ps1);
1838 qatom_ps.push_back(fqatom_ps2);
1839 atom.push_back(fatom1);
1840 atom.push_back(fatom2);
1841 if (W != 0.0) return;
1842#ifdef CALC_W_USING_CHARGES
1843 W = coef_I_to_W * (qatom_ps[0] * atom[0]->get_Z() * atom[0]->get_I_min() +
1844 qatom_ps[1] * atom[1]->get_Z() * atom[1]->get_I_min()) /
1845 (qatom_ps[0] * atom[0]->get_Z() + qatom_ps[1] * atom[1]->get_Z());
1846#else
1847 W = coef_I_to_W * (qatom_ps[0] * atom[0]->get_I_min() +
1848 qatom_ps[1] * atom[1]->get_I_min()) /
1849 qatom;
1850#endif
1851}
1852
1854 const AtomPhotoAbsCS* fatom2, int fqatom_ps2,
1855 const AtomPhotoAbsCS* fatom3, int fqatom_ps3,
1856 double fW, double fF)
1857 : qatom(fqatom_ps1 + fqatom_ps2 + fqatom_ps3), W(fW), F(fF) {
1858 qatom_ps.push_back(fqatom_ps1);
1859 qatom_ps.push_back(fqatom_ps2);
1860 qatom_ps.push_back(fqatom_ps3);
1861 atom.push_back(fatom1);
1862 atom.push_back(fatom2);
1863 atom.push_back(fatom3);
1864 if (W != 0.0) return;
1865#ifdef CALC_W_USING_CHARGES
1866 W = coef_I_to_W * (qatom_ps[0] * atom[0]->get_Z() * atom[0]->get_I_min() +
1867 qatom_ps[1] * atom[1]->get_Z() * atom[1]->get_I_min() +
1868 qatom_ps[2] * atom[2]->get_Z() * atom[2]->get_I_min()) /
1869 (qatom_ps[0] * atom[0]->get_Z() + qatom_ps[1] * atom[1]->get_Z() +
1870 qatom_ps[2] * atom[2]->get_Z());
1871#else
1872 W = coef_I_to_W *
1873 (qatom_ps[0] * atom[0]->get_I_min() + qatom_ps[1] * atom[1]->get_I_min() +
1874 qatom_ps[2] * atom[2]->get_I_min()) /
1875 qatom;
1876#endif
1877}
1878
1879double MolecPhotoAbsCS::get_ACS(const double energy) const {
1880 mfunname("double MolecPhotoAbsCS::get_ACS(double energy) const");
1881 const long q = qatom_ps.size();
1882 double s = 0.0;
1883 for (long n = 0; n < q; n++) s += qatom_ps[n] * atom[n]->get_ACS(energy);
1884 return s;
1885}
1886
1887double MolecPhotoAbsCS::get_integral_ACS(double en1, double en2) const {
1888 mfunname("double MolecPhotoAbsCS::get_integral_ACS(double e1, double e2)");
1889 const long q = qatom_ps.size();
1890 double s = 0.0;
1891 for (long n = 0; n < q; n++) {
1892 s += qatom_ps[n] * atom[n]->get_integral_ACS(en1, en2);
1893 }
1894 return s;
1895}
1896
1897double MolecPhotoAbsCS::get_ICS(double energy) const {
1898 mfunname("double MolecPhotoAbsCS::get_ICS(double energy) const");
1899 const long q = qatom_ps.size();
1900 double s = 0.0;
1901 for (long n = 0; n < q; n++) s += qatom_ps[n] * atom[n]->get_ICS(energy);
1902 return s;
1903}
1904
1905double MolecPhotoAbsCS::get_integral_ICS(double en1, double en2) const {
1906 mfunname("double MolecPhotoAbsCS::get_integral_ICS(double e1, double e2)");
1907 const long q = qatom_ps.size();
1908 double s = 0.0;
1909 for (long n = 0; n < q; n++) {
1910 s += qatom_ps[n] * atom[n]->get_integral_ICS(en1, en2);
1911 }
1912 return s;
1913}
1914
1916 mfunname("int MolecPhotoAbsCS::get_total_Z() const");
1917 const long q = qatom_ps.size();
1918 int s = 0;
1919 for (long n = 0; n < q; n++) {
1920 s += qatom_ps[n] * atom[n]->get_Z();
1921 }
1922 return s;
1923}
1924
1925void MolecPhotoAbsCS::print(std::ostream& file, int l) const {
1926 Ifile << "MolecPhotoAbsCS (l=" << l << "):\n";
1927 Iprintn(file, qatom);
1928 Iprintn(file, W);
1929 Iprintn(file, F);
1930 const long q = qatom_ps.size();
1931 Ifile << "number of sorts of atoms is " << q << '\n';
1932 indn.n += 2;
1933 for (long n = 0; n < q; n++) {
1934 Ifile << "n=" << n << " qatom_ps[n]=" << qatom_ps[n] << " atom:\n";
1935 atom[n]->print(file, l);
1936 }
1937 indn.n -= 2;
1938}
1939
1940std::ostream& operator<<(std::ostream& file, const MolecPhotoAbsCS& f) {
1941 f.print(file, 1);
1942 return file;
1943}
1944}
#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:853
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
double get_ACS(double energy) const
Photo-absorption cross-section [Mbarn] at a given energy [MeV].
int get_total_Z() const
Sum up the atomic numbers of all atoms in the molecule.
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:859
std::vector< std::shared_ptr< PhotoAbsCS > > m_acs
Definition: PhotoAbsCS.h:424
virtual double get_ACS(double energy) const
Definition: PhotoAbsCS.cpp:940
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:948
virtual double get_integral_ICS(double energy1, double energy2) const
Integrated photo-ionization cross-section over a given interval.
Definition: PhotoAbsCS.cpp:989
virtual double get_threshold(int nshell) const
Get the ionization threshold for a given shell.
Definition: PhotoAbsCS.cpp:934
virtual double get_ICS(double energy) const
Definition: PhotoAbsCS.cpp:980
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:1509
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:1543
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:1823
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:1606
#define mcout
Definition: prstream.h:126
#define Ifile
Definition: prstream.h:196
#define Iprint(file, name)
Definition: prstream.h:198
#define mcerr
Definition: prstream.h:128
#define Iprintn(file, name)
Definition: prstream.h:205
#define Iprint2n(file, name1, name2)
Definition: prstream.h:220