25 <<
"Reading Chi cross section file \"" << file_name <<
"\"\n";
30 if (not file.is_open())
31 throw std::runtime_error(
32 "Failed to open Chi cross section file "
33 "\"" + file_name +
"\" in call to " +
34 std::string(__FUNCTION__));
42 auto ReadGroupStructure =
43 [](
const std::string& keyword,
44 std::vector<std::vector<double>>& destination,
47 std::istringstream& line_stream,
48 unsigned int& line_number)
51 destination.assign(G, std::vector<double>(2, 0.0));
58 unsigned int count = 0;
61 std::getline(file, line);
62 line_stream = std::istringstream(line);
64 while (line != keyword +
"_END")
67 line_stream >> group >> high >> low;
68 destination.at(group).at(0) = high;
69 destination.at(group).at(1) = low;
71 throw std::runtime_error(
72 "Too many entries encountered when parsing "
73 "group structure.\nThe expected number of entries "
74 "is " + std::to_string(G) +
".");
77 std::getline(file, line);
78 line_stream = std::istringstream(line);
86 [](
const std::string& keyword,
87 std::vector<double>& destination,
90 std::istringstream& line_stream,
91 unsigned int& line_number)
94 destination.assign(N, 0.0);
100 unsigned int count = 0;
103 std::getline(file, line);
104 line_stream = std::istringstream(line);
106 while (line != keyword +
"_END")
109 line_stream >> i >> value;
110 destination.at(i) = value;
112 throw std::runtime_error(
113 "To many entries encountered when parsing "
114 "1D data.\nThe expected number of entries is " +
118 std::getline(file, line);
119 line_stream = std::istringstream(line);
127 [](
const std::string& keyword,
128 const std::string& entry_prefix,
129 std::vector<std::vector<double>>& destination,
130 const unsigned int n_rows,
131 const unsigned int n_cols,
133 std::istringstream& line_stream,
134 unsigned int& line_number)
138 for (
unsigned int i = 0; i < n_rows; ++i)
139 destination.emplace_back(n_cols, 0.0);
142 std::string word, line;
148 std::getline(file, line);
149 line_stream = std::istringstream(line);
151 while (line != keyword +
"_END")
155 if (word == entry_prefix)
158 line_stream >> i >> j >> value;
159 if (entry_prefix ==
"G_PRECURSOR_VAL")
160 destination.at(j).at(i) = value;
162 destination.at(i).at(j) = value;
166 std::getline(file, line);
167 line_stream = std::istringstream(line);
175 auto ReadTransferMatrices =
176 [](
const std::string& keyword,
177 std::vector<chi_math::SparseMatrix>& destination,
178 const unsigned int M,
179 const unsigned int G,
181 std::istringstream& line_stream,
182 unsigned int& line_number)
186 for (
unsigned int i = 0; i < M; ++i)
187 destination.emplace_back(G, G);
190 std::string word, line;
197 std::getline(file, line);
198 line_stream = std::istringstream(line);
200 while (line != keyword +
"_END")
204 if (word ==
"M_GPRIME_G_VAL")
207 line_stream >> ell >> gprime >> group >> value;
208 destination.at(ell).Insert(group, gprime, value);
212 std::getline(file, line);
213 line_stream = std::istringstream(line);
221 [](
const std::vector<double>& vec)
223 return not std::any_of(vec.begin(), vec.end(),
224 [](
double x) { return x < 0.0; });
230 [](
const std::vector<double>& vec)
232 return not std::any_of(vec.begin(), vec.end(),
233 [](
double x) { return x <= 0.0; });
239 [](
const std::vector<double> & vec)
241 return std::any_of(vec.begin(), vec.end(),
242 [](
double x) { return x > 0.0; });
254 std::vector<double> decay_constants;
255 std::vector<double> fractional_yields;
256 std::vector<std::vector<double>> emission_spectra;
257 std::vector<double> nu, nu_prompt, nu_delayed, beta;
258 std::vector<double>
chi, chi_prompt;
260 std::string word, line;
261 unsigned int line_number = 0;
262 while (std::getline(file, line))
264 std::istringstream line_stream(line);
268 if (word ==
"NUM_GROUPS")
273 throw std::logic_error(
274 "The specified number of energy groups "
275 "must be strictly positive.");
280 if (word ==
"NUM_MOMENTS")
285 throw std::logic_error(
286 "The specified number of scattering moments "
287 "must be non-negative.");
292 if (word ==
"NUM_PRECURSORS")
297 throw std::logic_error(
298 "The specified number of delayed neutron "
299 "precursors must be non-negative.");
307 auto& ln = line_number;
308 auto& ls = line_stream;
316 if (fw ==
"GROUP_STRUCTURE_BEGIN")
317 ReadGroupStructure(
"GROUP_STRUCTURE",
320 if (fw ==
"INV_VELOCITY_BEGIN")
325 throw std::logic_error(
326 "Invalid inverse velocity value encountered.\n"
327 "Only strictly positive values are permitted.");
334 throw std::logic_error(
335 "Invalid velocity value encountered.\n"
336 "Only strictly positive values are permitted.");
347 if (fw ==
"SIGMA_T_BEGIN")
352 throw std::logic_error(
353 "Invalid total cross section value encountered.\n"
354 "Negative values are not permitted.");
357 if (fw ==
"SIGMA_A_BEGIN")
362 throw std::logic_error(
363 "Invalid absorption cross section value encountered.\n"
364 "Negative values are not permitted.");
367 if (fw ==
"SIGMA_F_BEGIN")
374 <<
"The fission cross section specified in "
375 <<
"\"" << file_name <<
"\" is uniformly zero..."
379 else if (not IsNonNegative(
sigma_f_))
380 throw std::logic_error(
381 "Invalid fission cross section value encountered.\n"
382 "Negative values are not permitted.");
385 if (fw ==
"NU_SIGMA_F_BEGIN")
392 <<
"The production cross-section specified in "
393 <<
"\"" << file_name <<
"\" is uniformly zero..."
398 throw std::logic_error(
399 "Invalid production cross section value encountered.\n"
400 "Negative values are not permitted.");
407 if (fw ==
"NU_BEGIN")
411 if (not HasNonZero(nu))
414 <<
"The total fission neutron yield specified in "
415 <<
"\"" << file_name <<
"\" is uniformly zero..."
419 else if (std::any_of(nu.begin(), nu.end(),
421 { return not (x == 0.0 or x > 1.0); }))
422 throw std::logic_error(
423 "Invalid total fission neutron yield value encountered.\n"
424 "Only values strictly greater than one, or zero, are "
429 not nu.empty() and not beta.empty() and
430 nu_prompt.empty() and nu_delayed.empty())
436 nu_prompt[g] = (1.0 - beta[g]) * nu[g];
437 nu_delayed[g] = beta[g] * nu[g];
442 if (fw ==
"NU_PROMPT_BEGIN")
444 Read1DData(
"NU_PROMPT", nu_prompt,
num_groups_, f, ls, ln);
446 if (not HasNonZero(nu_prompt))
449 <<
"The prompt fission neutron yield specified in "
450 <<
"\"" << file_name <<
"\" is uniformly zero..."
454 else if (std::any_of(nu_prompt.begin(), nu_prompt.end(),
456 { return not (x == 0.0 or x > 1.0); }))
457 throw std::logic_error(
458 "Invalid prompt fission neutron yield value encountered.\n"
459 "Only values strictly greater than one, or zero, are "
463 if (fw ==
"NU_DELAYED_BEGIN")
465 Read1DData(
"NU_DELAYED", nu_delayed,
num_groups_, f, ls, ln);
467 if (not HasNonZero(nu_delayed))
470 <<
"The delayed fission neutron yield specified in "
471 <<
"\"" << file_name <<
"\" is uniformly zero..."
475 else if (not IsNonNegative(nu_delayed))
476 throw std::logic_error(
477 "Invalid delayed fission neutron yield value encountered.\n"
478 "Only non-negative values are permitted.");
481 if (fw ==
"BETA_BEGIN")
485 if (not HasNonZero(beta))
488 <<
"The delayed neutron fraction specified in "
489 <<
"\"" << file_name <<
"\" is uniformly zero..."
493 else if (std::any_of(beta.begin(), beta.end(),
495 { return not (x >= 0.0 and x <= 1.0); }))
496 throw std::logic_error(
497 "Invalid delayed neutron fraction value encountered.\n"
498 "Only values in the range [0.0, 1.0] are permitted.");
502 not nu.empty() and not beta.empty() and
503 nu_prompt.empty() and nu_delayed.empty())
509 nu_prompt[g] = (1.0 - beta[g]) * nu[g];
510 nu_delayed[g] = beta[g] * nu[g];
519 if (fw ==
"CHI_BEGIN")
523 if (not HasNonZero(
chi))
524 throw std::logic_error(
525 "Invalid steady-state fission spectrum encountered.\n"
526 "No non-zero values found.");
527 if (not IsNonNegative(
chi))
528 throw std::logic_error(
529 "Invalid steady-state fission spectrum value encountered.\n"
530 "Only non-negative values are permitted.");
533 double sum = std::accumulate(
chi.begin(),
chi.end(), 0.0);
534 std::transform(
chi.begin(),
chi.end(),
chi.begin(),
535 [sum](
double& x) { return x / sum; });
538 if (fw ==
"CHI_PROMPT_BEGIN")
540 Read1DData(
"CHI_PROMPT", chi_prompt,
num_groups_, f, ls, ln);
542 if (not HasNonZero(chi_prompt))
543 throw std::logic_error(
544 "Invalid prompt fission spectrum encountered.\n"
545 "No non-zero values found.");
546 if (not IsNonNegative(chi_prompt))
547 throw std::logic_error(
548 "Invalid prompt fission spectrum value encountered.\n"
549 "Only non-negative values are permitted.");
552 double sum = std::accumulate(chi_prompt.begin(), chi_prompt.end(), 0.0);
553 std::transform(chi_prompt.begin(),
556 [sum](
double& x) { return x / sum; });
563 Read2DData(
"CHI_DELAYED",
"G_PRECURSOR_VAL",
568 if (not HasNonZero(emission_spectra[j]))
569 throw std::logic_error(
570 "Invalid delayed emission spectrum encountered for "
571 "precursor species " + std::to_string(j) +
".\n" +
572 "No non-zero values found.");
573 if (not IsNonNegative(emission_spectra[j]))
574 throw std::logic_error(
575 "Invalid delayed emission spectrum value encountered "
576 "for precursor species " + std::to_string(j) +
".\n" +
577 "Only non-negative values are permitted.");
580 double sum = std::accumulate(emission_spectra[j].begin(),
581 emission_spectra[j].end(), 0.0);
582 std::transform(emission_spectra[j].begin(),
583 emission_spectra[j].end(),
584 emission_spectra[j].begin(),
585 [sum](
double& x) {
return x / sum; });
595 if (fw ==
"PRECURSOR_DECAY_CONSTANTS_BEGIN")
597 Read1DData(
"PRECURSOR_DECAY_CONSTANTS",
600 if (not IsPositive(decay_constants))
601 throw std::logic_error(
602 "Invalid precursor decay constant value encountered.\n"
603 "Only strictly positive values are permitted.");
606 if (fw ==
"PRECURSOR_FRACTIONAL_YIELDS_BEGIN")
608 Read1DData(
"PRECURSOR_FRACTIONAL_YIELDS",
611 if (not HasNonZero(fractional_yields))
612 throw std::logic_error(
613 "Invalid precursor fractional yields encountered.\n"
614 "No non-zero values found.");
615 if (std::any_of(fractional_yields.begin(),
616 fractional_yields.end(),
617 [](
double x) { return not (x >= 0.0 and x <= 1.0); }))
618 throw std::logic_error(
619 "Invalid precursor fractional yield value encountered.\n"
620 "Only values in the range [0.0, 1.0] are permitted.");
623 double sum = std::accumulate(fractional_yields.begin(),
624 fractional_yields.end(), 0.0);
625 std::transform(fractional_yields.begin(),
626 fractional_yields.end(),
627 fractional_yields.begin(),
628 [sum](
double& x) { return x / sum; });
636 if (fw ==
"TRANSFER_MOMENTS_BEGIN")
640 if (fw ==
"PRODUCTION_MATRIX_BEGIN")
641 Read2DData(
"PRODUCTION_MATRIX",
"GPRIME_G_VAL",
645 catch (
const std::runtime_error& err)
647 throw std::runtime_error(
648 "Error reading Chi cross section file "
649 "\"" + file_name +
"\".\n" +
650 "Line number " + std::to_string(line_number) +
654 catch (
const std::logic_error& err)
656 throw std::logic_error(
657 "Error reading Chi cross section file "
658 "\"" + file_name +
"\".\n" +
659 "Line number " + std::to_string(line_number) +
665 throw std::runtime_error(
666 "Unknown error encountered in " +
667 std::string (__FUNCTION__ ));
703 if (nu.empty() and nu_prompt.empty())
704 throw std::logic_error(
705 "Invalid fission neutron yield specification encountered.\n"
706 "Either the total or prompt fission neutron yield must be "
709 if (not nu.empty() and not nu_prompt.empty())
710 throw std::logic_error(
711 "Ambiguous fission neutron yield data specified.\n"
712 "Either the total or prompt fission neutron yield "
713 "must be specified, not both.");
716 if (
chi.empty() and chi_prompt.empty())
717 throw std::logic_error(
718 "Invalid fission spectrum specification encountered.\n"
719 "Either the steady-state or prompt fission spectrum must be "
722 if (not
chi.empty() and not chi_prompt.empty())
723 throw std::logic_error(
724 "Ambiguous fission spectrum data specified.\n"
725 "Either the steady-state or prompt fission spectrum "
726 "must be specified, not both.");
729 if ((not nu.empty() and
chi.empty()) or
730 (nu.empty() and not
chi.empty()) or
731 (not nu_prompt.empty() and chi_prompt.empty()) or
732 (nu_prompt.empty() and not chi_prompt.empty()))
733 throw std::logic_error(
734 "Ambiguous fission data specified.\n"
735 "Either the total fission neutron yield and steady-state "
736 "fission spectrum or the prompt fission neutron yield and "
737 "prompt fission spectrum must be specified.");
741 if (not nu_prompt.empty())
745 nu[g] = nu_prompt[g];
752 if (chi_prompt.empty() or nu_prompt.empty())
753 throw std::logic_error(
754 "Invalid fission data specification encountered.\n"
755 "When delayed neutron precursors are present, "
756 "prompt fission data must be specified.");
759 if (nu_delayed.empty() or
760 decay_constants.empty() or
761 fractional_yields.empty() or
762 std::any_of(emission_spectra.begin(),
763 emission_spectra.end(),
764 [](
const std::vector<double>& x)
765 { return x.empty(); }))
766 throw std::logic_error(
767 "Invalid fission data specification encountered.\n"
768 "When delayed neutron precursors are present, "
769 "the delayed fission neutron yield, delayed neutron "
770 "precursor decay constants, fractional yields, and "
771 "emission spectra must all be specified.");
775 nu[g] += nu_delayed[g];
780 precursors_[j].decay_constant = decay_constants[j];
781 precursors_[j].fractional_yield = fractional_yields[j];
782 precursors_[j].emission_spectrum = emission_spectra[j];
801 if (not nu_prompt.empty())
809 if (not nu_delayed.empty())
817 const auto chi_ = not chi_prompt.empty()? chi_prompt :
chi;
818 const auto nu_sigma_f =
823 std::vector<double> prod;
824 for (
unsigned int gp = 0.0; gp <
num_groups_; ++gp)
825 prod.push_back(chi_[g] * nu_sigma_f[gp]);
839 throw std::runtime_error(
840 "This setup has not been implemented.\n"
841 "Currently, when a production matrix is specified, "
842 "no delayed neutron precursors are allowed.");
846 throw std::logic_error(
847 "Invalid fission data specification encountered.\n"
848 "When a production matrix is specified, the fission "
849 "cross sections must also be specified.");
863 if (std::any_of(nu.begin(), nu.end(),
865 { return not (x == 0.0 or (x > 1.0 and x < 10.0));}))
866 throw std::logic_error(
867 "Incompatible fission data encountered.\n"
868 "The estimated fission neutron yield must be either zero "
869 "or in the range (1.0, 10.0).");
873 "material's sigma_f is not defined");
#define ChiLogicalErrorIf(condition, message)
LogStream Log(LOG_LVL level=LOG_0)
unsigned int scattering_order_
Legendre scattering order.
std::vector< double > sigma_f_
Fission cross section.
std::vector< std::vector< double > > production_matrix_
std::vector< double > nu_prompt_sigma_f_
unsigned int num_groups_
Total number of groups.
std::vector< std::vector< double > > e_bounds_
Energy bin boundaries in MeV.
unsigned int num_precursors_
Number of precursors.
std::vector< double > sigma_t_
Total cross section.
std::vector< chi_math::SparseMatrix > transfer_matrices_
std::vector< double > inv_velocity_
std::vector< Precursor > precursors_
std::vector< double > nu_sigma_f_
void ComputeDiffusionParameters()
std::vector< double > nu_delayed_sigma_f_
void MakeFromChiXSFile(const std::string &file_name)
std::vector< double > sigma_a_
Absorption cross section.