Chi-Tech
single_state_mgxs_00_general.cc
Go to the documentation of this file.
1#include "single_state_mgxs.h"
2
3#include "chi_runtime.h"
4#include "chi_log.h"
5
6#include <algorithm>
7
8
9//######################################################################
11{
12 num_groups_ = 0;
15 is_fissionable_ = false;
16
17 sigma_t_.clear();
18 sigma_f_.clear();
19 sigma_a_.clear();
20
21 nu_sigma_f_.clear();
22 nu_prompt_sigma_f_.clear();
23 nu_delayed_sigma_f_.clear();
24
25 inv_velocity_.clear();
26
27 transfer_matrices_.clear();
28 production_matrix_.clear();
29
30 precursors_.clear();
31
32 //Diffusion quantities
34 diffusion_coeff_.clear();
35 sigma_removal_.clear();
36 sigma_s_gtog_.clear();
37
38 //Monte-Carlo quantities
40 cdf_gprime_g_.clear();
42}
43
44
45//######################################################################
46/** Makes a simple material with no transfer matrix just sigma_t. */
48MakeSimple0(unsigned int num_groups, double sigma_t)
49{
50 Clear();
51
52 num_groups_ = num_groups;
53 sigma_t_.resize(num_groups, sigma_t);
54 sigma_a_.resize(num_groups, sigma_t);
55
56 ComputeDiffusionParameters();
57}
58
59
60//######################################################################
61/**
62 * Makes a simple material with isotropic transfer matrix (L=0)
63 * and mostly down scattering but with a few of the last groups
64 * subject to up-scattering.
65 */
67MakeSimple1(unsigned int num_groups, double sigma_t, double c)
68{
69 Clear();
70
71 num_groups_ = num_groups;
72 sigma_t_.resize(num_groups, sigma_t);
73 transfer_matrices_.emplace_back(num_groups, num_groups);
74
75 // When multi-group, assign half the scattering cross section
76 // to within-group scattering. The other half will be used for
77 // up/down-scattering.
78
79 auto& S = transfer_matrices_.back();
80 double scale = (num_groups_ == 1) ? 1.0 : 0.5;
81 S.SetDiagonal(std::vector<double>(num_groups, sigma_t * c * scale));
82
83 // Set the up/down-scattering cross sections.
84 // Summary:
85 // 1) The half of groups with higher energies down-scatter to the next
86 // lowest energy group half the time and to the same group half the
87 // time.
88 // 2) The half of groups with lower energies less the last group
89 // down-scatter to the next lowest energy group three quarters of the
90 // time and up-scatter to the next highest energy group one quarter
91 // of the time.
92 // 3) The lowest energy group has the same form as 1).
93
94 for (unsigned int g = 0; g < num_groups_; ++g)
95 {
96 //downscattering
97 if (g > 0)
98 S.Insert(g, g - 1, sigma_t * c * 0.5);
99
100 //upscattering
101 if (g > num_groups_ / 2)
102 {
103 if (g < num_groups_ - 1)
104 {
105 S.Insert(g, g - 1, sigma_t * c * 0.25);
106 S.Insert(g, g + 1, sigma_t * c * 0.25);
107 }
108 else
109 S.Insert(g, g - 1, sigma_t * c * 0.5);
110 }
111 }//for g
112
113 ComputeAbsorption();
114 ComputeDiffusionParameters();
115}
116
117
118//######################################################################
119/** Populates the cross section from a combination of others. */
121MakeCombined(std::vector<std::pair<int, double> > &combinations)
122{
123 Clear();
124
125 //pickup all xs and make sure valid
126 std::vector<std::shared_ptr<MultiGroupXS>> xsecs;
127 xsecs.reserve(combinations.size());
128
129 unsigned int n_grps = 0;
130 unsigned int n_precs = 0;
131 double Nf_total = 0.0; //total density of fissile materials
132
133 //loop over cross sections
134 for (auto combo : combinations)
135 {
136 //get the cross section from the lua stack
137 std::shared_ptr<MultiGroupXS> xs;
139 Chi::multigroup_xs_stack, combo.first,
140 std::string(__FUNCTION__));
141 xsecs.push_back(xs);
142
143 //increment densities
144 if (xs->IsFissionable())
145 {
146 is_fissionable_ = true;
147 Nf_total += combo.second;
148 }
149
150 //define and check number of groups
151 if (xsecs.size() == 1)
152 n_grps = xs->NumGroups();
153 else if (xs->NumGroups() != n_grps)
154 throw std::logic_error(
155 "Incompatible cross sections encountered.\n"
156 "All cross sections being combined must have the "
157 "same number of energy groups.");
158
159 //increment number of precursors
160 n_precs += xs->NumPrecursors();
161 }//for cross section
162
163 // Check that the fissile and precursor densities are greater than
164 // machine precision. If this condition is not met, the material is assumed
165 // to be either not fissile, have zero precursors, or both.
166 if (Nf_total < 1.0e-12)
167 is_fissionable_ = false;
168
169 // Check to ensure that all fissionable cross sections contain either
170 // prompt/delayed fission data or total fission data
171 if (n_precs > 0)
172 for (const auto& xs : xsecs)
173 if (xs->IsFissionable() and xs->NumPrecursors() == 0)
174 throw std::logic_error(
175 "Incompatible cross sections encountered.\n"
176 "If any fissionable cross sections specify delayed neutron "
177 "data, all fissionable cross sections must specify delayed "
178 "neutron data.");
179
180 //============================================================
181 // Initialize the data
182 //============================================================
183
184 num_groups_ = n_grps;
185 num_precursors_ = n_precs;
186 scattering_order_ = 0;
187 for (const auto& xs : xsecs)
188 scattering_order_ = std::max(scattering_order_,
189 xs->ScatteringOrder());
190
191 //mandatory cross sections
192 sigma_t_.assign(n_grps, 0.0);
193 sigma_a_.assign(n_grps, 0.0);
194
195 //init transfer matrices only if at least one exists
197 if (std::any_of(xsecs.begin(), xsecs.end(),
198 [](const XSPtr& x)
199 { return not x->TransferMatrices().empty(); }))
200 transfer_matrices_.assign(scattering_order_ + 1,
201 chi_math::SparseMatrix(num_groups_, num_groups_));
202
203 //init fission data
204 if (is_fissionable_)
205 {
206 sigma_f_.assign(n_grps, 0.0);
207 nu_sigma_f_.assign(n_grps, 0.0);
208 production_matrix_.assign(
209 num_groups_, std::vector<double>(num_groups_, 0.0));
210
211 //init prompt/delayed fission data
212 if (n_precs > 0)
213 {
214 nu_prompt_sigma_f_.assign(n_grps, 0.0);
215 nu_delayed_sigma_f_.assign(n_grps, 0.0);
216 precursors_.resize(n_precs);
217 }
218 }
219
220 //============================================================
221 // Combine the data
222 //============================================================
223
224 unsigned int precursor_count = 0;
225 for (size_t x = 0; x < xsecs.size(); ++x)
226 {
227 //atom density
228 double N_i = combinations[x].second;
229
230 //fraction of fissile density
231 double ff_i = 0.0;
232 if (xsecs[x]->IsFissionable())
233 ff_i = N_i / Nf_total;
234
235 //============================================================
236 // Combine cross sections
237 //============================================================
238
239 const auto& sig_t = xsecs[x]->SigmaTotal();
240 const auto& sig_a = xsecs[x]->SigmaAbsorption();
241 const auto& sig_f = xsecs[x]->SigmaFission();
242 const auto& nu_p_sig_f = xsecs[x]->NuPromptSigmaF();
243 const auto& nu_d_sig_f = xsecs[x]->NuDelayedSigmaF();
244 const auto& F = xsecs[x]->ProductionMatrix();
245
246 // Here, raw cross sections are scaled by densities and spectra by
247 // fractional densities. The latter is done to preserve a unit spectra.
248 for (unsigned int g = 0; g < n_grps; ++g)
249 {
250 sigma_t_[g] += sig_t[g] * N_i;
251 sigma_a_[g] += sig_a[g] * N_i;
252
253 if (xsecs[x]->IsFissionable())
254 {
255 sigma_f_[g] += sig_f[g] * N_i;
256 nu_sigma_f_[g] += sig_f[g] * N_i;
257 for (unsigned int gp = 0; gp < num_groups_; ++gp)
258 production_matrix_[g][gp] += F[g][gp] * N_i;
259
260 if (n_precs > 0)
261 {
262 nu_prompt_sigma_f_[g] += nu_p_sig_f[g] * N_i;
263 nu_delayed_sigma_f_[g] += nu_d_sig_f[g] * N_i;
264 }
265 }
266 }//for g
267
268 //============================================================
269 // Combine precursor data
270 //============================================================
271
272 // Here, all precursors across all materials are stored. The decay
273 // constants and delayed spectrum are what they are, however, some
274 // special treatment must be given to the yields. Because the yield
275 // tells us what fraction of delayed neutrons are produced from a
276 // given family, the sum over all families must yield unity. To
277 // achieve this end, we must scale all precursor yields based on
278 // the fraction of the total density of materials with precursors
279 // they make up.
280
281 if (xsecs[x]->NumPrecursors() > 0)
282 {
283 const auto& precursors = xsecs[x]->Precursors();
284 for (unsigned int j = 0; j < xsecs[x]->NumPrecursors(); ++j)
285 {
286 unsigned int count = precursor_count + j;
287 const auto& precursor = precursors[j];
288 precursors_[count].decay_constant = precursor.decay_constant;
289 precursors_[count].fractional_yield = precursor.fractional_yield * ff_i;
290 precursors_[count].emission_spectrum = precursor.emission_spectrum;
291 }//for j
292
293 precursor_count += xsecs[x]->NumPrecursors();
294 }
295
296 //============================================================
297 // Set inverse velocity data
298 //============================================================
299
300 if (x == 0 && !xsecs[x]->InverseVelocity().empty())
301 inv_velocity_ = xsecs[x]->InverseVelocity();
302 else if (xsecs[x]->InverseVelocity() != inv_velocity_)
303 throw std::logic_error(
304 "Invalid cross sections encountered.\n"
305 "All cross sections being combined must share a group "
306 "structure. This implies that the inverse speeds for "
307 "each of the cross sections must be equivalent.");
308
309 //============================================================
310 // Combine transfer matrices
311 //============================================================
312
313 // This step is somewhat tricky. The cross sections aren't guaranteed
314 // to have the same sparsity patterns and therefore simply adding them
315 // together has to take the sparse matrix's protection mechanisms into
316 // account.
317
318 if (not xsecs[x]->TransferMatrices().empty())
319 {
320 for (unsigned int m = 0; m < xsecs[x]->ScatteringOrder() + 1; ++m)
321 {
322 auto& Sm = transfer_matrices_[m];
323 const auto& Sm_other = xsecs[x]->TransferMatrix(m);
324 for (unsigned int g = 0; g < num_groups_; ++g)
325 {
326 const auto& cols = Sm_other.rowI_indices_[g];
327 const auto& vals = Sm_other.rowI_values_[g];
328 for (size_t t = 0; t < cols.size(); ++t)
329 Sm.InsertAdd(g, t, vals[t] * N_i);
330 }
331 }
332 }
333 }//for cross sections
334
335 ComputeDiffusionParameters();
336}
static std::vector< chi_physics::MultiGroupXSPtr > multigroup_xs_stack
Definition: chi_runtime.h:91
static std::shared_ptr< T > & GetStackItemPtr(std::vector< std::shared_ptr< T > > &stack, const size_t handle, const std::string &calling_function_name="Unknown")
Definition: chi_runtime.h:258
std::vector< double > diffusion_coeff_
Transport corrected diffusion coeff.
unsigned int scattering_order_
Legendre scattering order.
std::vector< double > sigma_f_
Fission cross section.
std::vector< double > sigma_removal_
Removal cross section.
std::vector< std::vector< double > > production_matrix_
std::vector< double > nu_prompt_sigma_f_
unsigned int num_groups_
Total number of groups.
unsigned int num_precursors_
Number of precursors.
std::vector< double > sigma_t_
Total cross section.
std::vector< std::vector< AnglePairs > > scat_angles_gprime_g_
std::vector< chi_math::SparseMatrix > transfer_matrices_
std::vector< double > inv_velocity_
std::vector< double > sigma_s_gtog_
Within-group scattering xs.
std::vector< std::vector< double > > cdf_gprime_g_
void MakeCombined(std::vector< std::pair< int, double > > &combinations)
std::vector< Precursor > precursors_
void MakeSimple0(unsigned int num_groups, double sigma_t)
std::vector< double > nu_sigma_f_
std::vector< double > nu_delayed_sigma_f_
void MakeSimple1(unsigned int num_groups, double sigma_t, double c)
std::vector< double > sigma_a_
Absorption cross section.
std::shared_ptr< MultiGroupXS > MultiGroupXSPtr
Definition: chi_runtime.h:37
std::shared_ptr< chi_physics::MultiGroupXS > XSPtr
Definition: lbs_structs.h:23