1<br>
2
3<i>This program was contributed by Yaqi Wang and Wolfgang
4Bangerth. Results from this program are used and discussed in the publication
5"Three-dimensional h-adaptivity for the multigroup neutron diffusion
6equations" by Yaqi Wang, Wolfgang Bangerth and Jean Ragusa. The paper's full
7bibliographic details are as follows:
8@code
9@Article{WBR09,
10  author  = {Yaqi Wang and Wolfgang Bangerth and Jean Ragusa},
11  title   = {Three-dimensional h-adaptivity for the multigroup
12             neutron diffusion equations},
13  journal = {Progr. Nucl. Energy},
14  year    = 2009,
15  volume  = 51,
16  pages   = {543--555}
17}
18@endcode
19The paper is available <a target="_top"
20href="https://www.semanticscholar.org/paper/Three-dimensional-h-adaptivity-for-the-multigroup-Wang-Bangerth/900592e8e891d9b888d59a69ec58bf2bbda56b4b">here</a>.
21</i>
22
23<br>
24
25
26<a name="Intro"></a> <h1>Introduction</h1>
27In this example, we intend to solve the multigroup diffusion approximation of
28the neutron transport equation. Essentially, the way to view this is as follows: In a
29nuclear reactor, neutrons are speeding around at different energies, get
30absorbed or scattered, or start a new fission
31event. If viewed at long enough length scales, the movement of neutrons can be
32considered a diffusion process.
33
34A mathematical description of this would group neutrons into energy bins, and
35consider the balance equations for the neutron fluxes in each of these
36bins, or energy groups. The scattering, absorption, and fission events would
37then be operators within the diffusion equation describing the neutron
38fluxes. Assume we have energy groups $g=1,\ldots,G$, where by convention we
39assume that the neutrons with the highest energy are in group 1 and those with
40the lowest energy in group $G$. Then the neutron flux of each group satisfies the
41following equations:
42@f{eqnarray*}
43\frac 1{v_g}\frac{\partial \phi_g(x,t)}{\partial t}
44&=&
45\nabla \cdot(D_g(x) \nabla \phi_g(x,t))
46-
47\Sigma_{r,g}(x)\phi_g(x,t)
48\\
49&& \qquad
50+
51\chi_g\sum_{g'=1}^G\nu\Sigma_{f,g'}(x)\phi_{g'}(x,t)
52+
53\sum_{g'\ne g}\Sigma_{s,g'\to g}(x)\phi_{g'}(x,t)
54+
55s_{\mathrm{ext},g}(x,t)
56@f}
57augmented by appropriate boundary conditions. Here, $v_g$ is the velocity of
58neutrons within group $g$. In other words, the change in
59time in flux of neutrons in group $g$ is governed by the following
60processes:
61<ul>
62<li> Diffusion $\nabla \cdot(D_g(x) \nabla \phi_g(x,t))$. Here, $D_g$ is the
63  (spatially variable) diffusion coefficient.
64<li> Absorption $\Sigma_{r,g}(x)\phi_g(x,t)$ (note the
65  negative sign). The coefficient $\Sigma_{r,g}$ is called the <i>removal
66  cross section</i>.
67<li> Nuclear fission $\chi_g\sum_{g'=1}^G\nu\Sigma_{f,g'}(x)\phi_{g'}(x,t)$.
68  The production of neutrons of energy $g$ is
69  proportional to the flux of neutrons of energy $g'$ times the
70  probability $\Sigma_{f,g'}$ that neutrons of energy $g'$ cause a fission
71  event times the number $\nu$ of neutrons produced in each fission event
72  times the probability that a neutron produced in this event has energy
73  $g$. $\nu\Sigma_{f,g'}$ is called the <i>fission cross section</i> and
74  $\chi_g$ the <i>fission spectrum</i>. We will denote the term
75  $\chi_g\nu\Sigma_{f,g'}$ as the <i>fission distribution cross
76    section</i> in the program.
77<li> Scattering $\sum_{g'\ne g}\Sigma_{s,g'\to g}(x)\phi_{g'}(x,t)$
78  of neutrons of energy $g'$ producing neutrons
79  of energy $g$. $\Sigma_{s,g'\to g}$ is called the <i>scattering cross
80    section</i>. The case of elastic, in-group scattering $g'=g$ exists, too, but
81  we subsume this into the removal cross section. The case $g'<g$ is called
82  down-scattering, since a neutron loses energy in such an event. On the
83  other hand, $g'>g$ corresponds to up-scattering: a neutron gains energy in
84  a scattering event from the thermal motion of the atoms surrounding it;
85  up-scattering is therefore only an important process for neutrons with
86  kinetic energies that are already on the same order as the thermal kinetic
87  energy (i.e. in the sub $eV$ range).
88<li> An extraneous source $s_{\mathrm{ext},g}$.
89</ul>
90
91For realistic simulations in reactor analysis, one may want to split the
92continuous spectrum of neutron energies into many energy groups, often up to 100.
93However, if neutron energy spectra are known well enough for some type of
94reactor (for example Pressurized Water Reactors, PWR), it is possible to obtain
95satisfactory results with only 2 energy groups.
96
97In the program shown in this tutorial program, we provide the structure to
98compute with as many energy groups as desired. However, to keep computing
99times moderate and in order to avoid tabulating hundreds of coefficients, we
100only provide the coefficients for above equations for a two-group simulation,
101i.e. $g=1,2$. We do, however, consider a realistic situation by assuming that
102the coefficients are not constant, but rather depend on the materials that are
103assembled into reactor fuel assemblies in rather complicated ways (see
104below).
105
106
107<h3>The eigenvalue problem</h3>
108
109If we consider all energy groups at once, we may write above equations in the
110following operator form:
111@f{eqnarray*}
112\frac 1v \frac{\partial \phi}{\partial t}
113=
114-L\phi
115+
116F\phi
117+
118X\phi
119+
120s_{\mathrm{ext}},
121@f}
122where $L,F,X$ are sinking, fission, and scattering operators,
123respectively. $L$ here includes both the diffusion and removal terms. Note
124that $L$ is symmetric, whereas $F$ and $X$ are not.
125
126It is well known that this equation admits a stable solution if all
127eigenvalues of the operator $-L+F+X$ are negative. This can be readily seen by
128multiplying the equation by $\phi$ and integrating over the domain, leading to
129@f{eqnarray*}
130  \frac 1{2v} \frac{\partial}{\partial t}  \|\phi\|^2 = ((-L+F+X)\phi,\phi).
131@f}
132Stability means that the solution does not grow, i.e. we want the left hand
133side to be less than zero, which is the case if the eigenvalues of the
134operator on the right are all negative. For obvious reasons, it is
135not very desirable if a nuclear reactor produces neutron fluxes that grow
136exponentially, so eigenvalue analyses are the bread-and-butter of nuclear
137engineers. The main point of the program is therefore to consider the
138eigenvalue problem
139@f{eqnarray*}
140  (L-F-X) \phi = \lambda \phi,
141@f}
142where we want to make sure that all eigenvalues are positive. Note that $L$,
143being the diffusion operator plus the absorption (removal), is positive
144definite; the condition that all eigenvalues are positive therefore means that
145we want to make sure that fission and inter-group scattering are weak enough
146to not shift the spectrum into the negative.
147
148In nuclear engineering, one typically looks at a slightly different
149formulation of the eigenvalue problem. To this end, we do not just multiply
150with $\phi$ and integrate, but rather multiply with $\phi(L-X)^{-1}$. We then
151get the following evolution equation:
152@f{eqnarray*}
153  \frac 1{2v} \frac{\partial}{\partial t}  \|\phi\|^2_{(L-X)^{-1}} = ((L-X)^{-1}(-L+F+X)\phi,\phi).
154@f}
155Stability is then guaranteed if the eigenvalues of the following problem are
156all negative:
157@f{eqnarray*}
158  (L-X)^{-1}(-L+F+X)\phi = \lambda_F \phi,
159@f}
160which is equivalent to the eigenvalue problem
161@f{eqnarray*}
162  (L-X)\phi = \frac 1{\lambda_F+1} F \phi.
163@f}
164The typical formulation in nuclear engineering is to write this as
165@f{eqnarray*}
166  (L-X) \phi = \frac 1{k_{\mathrm{eff}}} F \phi,
167@f}
168where $k_{\mathrm{eff}}=\frac 1{\lambda^F+1}$.
169Intuitively, $k_{\mathrm{eff}}$ is something like the multiplication
170factor for neutrons per typical time scale and should be less than or equal to
171one for stable operation of a reactor: if it is less than one, the chain reaction will
172die down, whereas nuclear bombs for example have a $k$-eigenvalue larger than
173one. A stable reactor should have $k_{\mathrm{eff}}=1$.
174
175For those who wonder how this can be achieved in practice without
176inadvertently getting slightly larger than one and triggering a nuclear bomb:
177first, fission processes happen on different time scales. While most neutrons
178are released very quickly after a fission event, a small number of neutrons
179are only released by daughter nuclei after several further decays, up to 10-60
180seconds after the fission was initiated. If one is therefore slightly beyond
181$k_{\mathrm{eff}}=1$, one therefore has many seconds to react until all the
182neutrons created in fission re-enter the fission cycle. Nevertheless, control
183rods in nuclear reactors absorbing neutrons -- and therefore reducing
184$k_{\mathrm{eff}}$ -- are designed in such a way that they are all the way in
185the reactor in at most 2 seconds.
186
187One therefore has on the order of 10-60 seconds to regulate the nuclear reaction
188if $k_{\mathrm{eff}}$ should be larger than one for some time, as indicated by
189a growing neutron flux. Regulation can be achieved by continuously monitoring
190the neutron flux, and if necessary increase or reduce neutron flux by moving
191neutron-absorbing control rods a few millimeters into or out of the
192reactor. On a longer scale, the water cooling the reactor contains boron, a
193good neutron absorber. Every few hours, boron concentrations are adjusted by
194adding boron or diluting the coolant.
195
196Finally, some of the absorption and scattering reactions have some
197stability built in; for example, higher neutron fluxes result in locally
198higher temperatures, which lowers the density of water and therefore reduces
199the number of scatterers that are necessary to moderate neutrons from high to
200low energies before they can start fission events themselves.
201
202In this tutorial program, we solve above $k$-eigenvalue problem for two energy
203groups, and we are looking for the largest multiplication factor
204$k_{\mathrm{eff}}$, which is proportional to the inverse of the minimum
205eigenvalue plus one. To solve the eigenvalue problem, we generally
206use a modified version of the <i>inverse power method</i>. The algorithm looks
207like this:
208
209<ol>
210<li> Initialize $\phi_g$ and $k_{\mathrm{eff}}$ with $\phi_g^{(0)}$
211  and $k_{\mathrm{eff}}^{(0)}$ and let $n=1$.
212
213<li> Define the so-called <i>fission source</i> by
214  @f{eqnarray*}
215    s_f^{(n-1)}(x)
216    =
217    \frac{1}{k_{\mathrm{eff}}^{(n-1)}}
218    \sum_{g'=1}^G\nu\Sigma_{f,g'}(x)\phi_{g'}^{(n-1)}(x).
219  @f}
220
221<li> Solve for all group fluxes $\phi_g,g=1,\ldots,G$ using
222  @f{eqnarray*}
223    -\nabla \cdot D_g\nabla \phi_g^{(n)}
224    +
225    \Sigma_{r,g}\phi_g^{(n)}
226    =
227    \chi_g s_f^{(n-1)}
228    +
229    \sum_{g'< g} \Sigma_{s,g'\to g} \phi_{g'}^{(n)}
230    +
231    \sum_{g'> g}\Sigma_{s,g'\to g}\phi_{g'}^{(n-1)}.
232  @f}
233
234<li> Update
235  @f{eqnarray*}
236    k_{\mathrm{eff}}^{(n)}
237    =
238    \sum_{g'=1}^G
239    \int_{\Omega}\nu\Sigma_{f,g'}(x)
240    \phi_{g'}^{(n)}(x)dx.
241  @f}
242
243<li> Compare $k_{\mathrm{eff}}^{(n)}$ with $k_{\mathrm{eff}}^{(n-1)}$.
244  If the change greater than a prescribed tolerance then set $n=n+1$ repeat
245  the iteration starting at step 2, otherwise end the iteration.
246</ol>
247
248Note that in this scheme, we do not solve group fluxes exactly in each power
249iteration, but rather consider previously compute $\phi_{g'}^{(n)}$ only for
250down-scattering events $g'<g$. Up-scattering is only treated by using old
251iterators $\phi_{g'}^{(n-1)}$, in essence assuming that the scattering
252operator is triangular. This is physically motivated since up-scattering does
253not play a too important role in neutron scattering. In addition, practices
254shows that the inverse power iteration is stable even using this
255simplification.
256
257Note also that one can use lots of extrapolation techniques to accelerate the
258power iteration laid out above. However, none of these are implemented in this
259example.
260
261
262<h3>Meshes and mesh refinement</h3>
263
264One may wonder whether it is appropriate to solve for the solutions of the
265individual energy group equations on the same meshes. The question boils down
266to this: will $\phi_g$ and $\phi_{g'}$ have similar smoothness properties? If
267this is the case, then it is appropriate to use the same mesh for the two; a
268typical application could be chemical combustion, where typically the
269concentrations of all or most chemical species change rapidly within the flame
270front. As it turns out, and as will be apparent by looking at the
271graphs shown in the results section of this tutorial program, this isn't the
272case here, however: since the diffusion coefficient is different for different
273energy groups, fast neutrons (in bins with a small group number $g$) have a very
274smooth flux function, whereas slow neutrons (in bins with a large group
275number) are much more affected by the local material properties and have a
276correspondingly rough solution if the coefficient are rough as in the case we
277compute here. Consequently, we will want to use different meshes to compute
278each energy group.
279
280This has two implications that we will have to consider: First, we need to
281find a way to refine the meshes individually. Second, assembling the source
282terms for the inverse power iteration, where we have to integrate solution
283$\phi_{g'}^{(n)}$ defined on mesh $g'$ against the shape functions defined on
284mesh $g$, becomes a much more complicated task.
285
286
287<h4>Mesh refinement</h4>
288
289We use the usual paradigm: solve on a given mesh, then evaluate an error
290indicator for each cell of each mesh we have. Because it is so convenient, we
291again use the a posteriori error estimator by Kelly, Gago, Zienkiewicz
292and Babuska which approximates the error per cell by integrating the jump of
293the gradient of the solution along the faces of each cell. Using this, we
294obtain indicators
295@f{eqnarray*}
296\eta_{g,K}, \qquad g=1,2,\ldots,G,\qquad K\in{\cal T}_g,
297@f}
298where ${\cal T}_g$ is the triangulation used in the solution of
299$\phi_g$. The question is what to do with this. For one, it is clear that
300refining only those cells with the highest error indicators might lead to bad
301results. To understand this, it is important to realize that $\eta_{g,K}$
302scales with the second derivative of $\phi_g$. In other words, if we have two
303energy groups $g=1,2$ whose solutions are equally smooth but where one is
304larger by a factor of 10,000, for example, then only the cells of that mesh
305will be refined, whereas the mesh for the solution of small magnitude will
306remain coarse. This is probably not what one wants, since we can consider both
307components of the solution equally important.
308
309In essence, we would therefore have to scale $\eta_{g,K}$ by an importance
310factor $z_g$ that says how important it is to resolve $\phi_g$ to any given
311accuracy. Such important factors can be computed using duality techniques
312(see, for example, the step-14 tutorial program, and the
313reference to the book by Bangerth and Rannacher cited there). We won't go
314there, however, and simply assume that all energy groups are equally
315important, and will therefore normalize the error indicators $\eta_{g,K}$ for
316group $g$ by the maximum of the solution $\phi_g$. We then refine the cells
317whose errors satisfy
318@f{eqnarray*}
319  \frac{\eta_{g,K}}{\|\phi_g\|_\infty}
320  >
321  \alpha_1
322  \displaystyle{\max_{\begin{matrix}1\le g\le G \\ K\in {\cal T}_g\end{matrix}}
323    \frac{\eta_{g,K}}{\|\phi_g\|_\infty}}
324@f}
325and coarsen the cells where
326@f{eqnarray*}
327  \frac{\eta_{g,K}}{\|\phi_g\|_\infty}
328  <
329  \alpha_2
330  \displaystyle{\max_{\begin{matrix}1\le g\le G \\ K\in {\cal T}_g\end{matrix}}
331    \frac{\eta_{g,K}}{\|\phi_g\|_\infty}}.
332@f}
333We chose $\alpha_1=0.3$ and $\alpha_2=0.01$ in the code. Note that this will,
334of course, lead to different meshes for the different energy groups.
335
336The strategy above essentially means the following: If for energy group $g$
337there are many cells $K\in {\cal T}_g$ on which the error is large, for
338example because the solution is globally very rough, then many cells will be
339above the threshold. On the other hand, if there are a few cells with large
340and many with small errors, for example because the solution is overall rather
341smooth except at a few places, then only the few cells with large errors will
342be refined. Consequently, the strategy allows for meshes that track the global
343smoothness properties of the corresponding solutions rather well.
344
345
346<h4>Assembling terms on different meshes</h4>
347
348As pointed out above, the multigroup refinement strategy results in
349different meshes for the different solutions $\phi_g$. So what's the problem?
350In essence it goes like this: in step 3 of the eigenvalue iteration, we have
351form the weak form for the equation to compute $\phi_g^{(n)}$ as usual by
352multiplication with test functions $\varphi_g^i$ defined on the mesh for
353energy group $g$; in the process, we have to
354compute the right hand side vector that contains terms of the following form:
355@f{eqnarray*}
356  F_i = \int_\Omega f(x) \varphi_g^i(x) \phi_{g'}(x) \ dx,
357@f}
358where $f(x)$ is one of the coefficient functions $\Sigma_{s,g'\to g}$ or
359$\nu\chi_g\Sigma_{f,g'}$ used in the right hand side
360of eigenvalue equation. The difficulty now is that $\phi_{g'}$ is defined on
361the mesh for energy group $g'$, i.e. it can be expanded as
362$\phi_{g'}(x)=\sum_j\phi_{g'}^j \varphi_{g'}^j(x)$, with basis functions
363$\varphi_{g'}^j(x)$ defined on mesh $g'$. The contribution to the right hand
364side can therefore be written as
365@f{eqnarray*}
366  F_i = \sum_j \left\{\int_\Omega f(x) \varphi_g^i(x) \varphi_{g'}^j(x)
367  \ dx \right\} \phi_{g'}^j ,
368@f}
369On the other hand, the test functions $\varphi_g^i(x)$ are defined on mesh
370$g$. This means that we can't just split the integral $\Omega$ into integrals
371over the cells of either mesh $g$ or $g'$, since the respectively other basis
372functions may not be defined on these cells.
373
374The solution to this problem lies in the fact that both the meshes for $g$ and
375$g'$ are derived by adaptive refinement from a common coarse mesh. We can
376therefore always find a set of cells, which we denote by ${\cal T}_g \cap
377{\cal T}_{g'}$, that satisfy the following conditions:
378<ul>
379<li> the union of the cells covers the entire domain, and
380<li> a cell $K \in {\cal T}_g \cap {\cal T}_{g'}$ is active on at least
381  one of the two meshes.
382</ul>
383A way to construct this set is to take each cell of coarse mesh and do the
384following steps: (i) if the cell is active on either ${\cal T}_g$ or
385${\cal T}_{g'}$, then add this cell to the set; (ii) otherwise, i.e. if
386this cell has children on both meshes, then do step (i) for each of the
387children of this cell. In fact, deal.II has a function
388GridTools::get_finest_common_cells that computes exactly this set
389of cells that are active on at least one of two meshes.
390
391With this, we can write above integral as follows:
392@f{eqnarray*}
393  F_i
394  =
395  \sum_{K \in {\cal T}_g \cap {\cal T}_{g'}}
396  \sum_j \left\{\int_K f(x) \varphi_g^i(x) \varphi_{g'}^j(x)
397  \ dx \right\} \phi_{g'}^j.
398@f}
399 In the code, we
400compute the right hand side in the function
401<code>NeutronDiffusionProblem::assemble_rhs</code>, where (among other things) we
402loop over the set of common most refined cells, calling the function
403<code>NeutronDiffusionProblem::assemble_common_cell</code> on each pair of
404these cells.
405
406By construction, there are now three cases to be considered:
407<ol>
408<li> The cell $K$ is active on both meshes, i.e. both the basis
409  functions $\varphi_g^i$ as well as $\varphi_{g'}^j$ are defined on $K$.
410<li> The cell $K$ is active on mesh $g$, but not $g'$, i.e. the
411  $\varphi_g^i$  are defined on $K$, whereas the $\varphi_{g'}^j$ are defined
412  on children of $K$.
413<li> The cell $K$ is active on mesh $g'$, but not $g$, with opposite
414  conclusions than in (ii).
415</ol>
416
417To compute the right hand side above, we then need to have different code for
418these three cases, as follows:
419<ol>
420<li> If the cell $K$ is active on both meshes, then we can directly
421  evaluate the integral. In fact, we don't even have to bother with the basis
422  functions $\varphi_{g'}$, since all we need is the values of $\phi_{g'}$ at
423  the quadrature points. We can do this using the
424  FEValues::get_function_values function. This is done directly in
425  the <code>NeutronDiffusionProblem::assemble_common_cell</code> function.
426
427<li> If the cell $K$ is active on mesh $g$, but not $g'$, then the
428  basis functions $\varphi_{g'}^j$ are only defined either on the children
429  $K_c,0\le c<2^{\texttt{dim}}$, or on children of these children if cell $K$
430  is refined more than once on mesh $g'$.
431
432  Let us assume for a second that $K$ is only once more refined on mesh $g'$
433  than on mesh $g$. Using the fact that we use embedded finite element spaces
434  where each basis function on one mesh can be written as a linear combination
435  of basis functions on the next refined mesh, we can expand the restriction
436  of $\phi_g^i$ to child cell $K_c$ into the basis functions defined on that
437  child cell (i.e. on cells on which the basis functions $\varphi_{g'}^l$ are
438  defined):
439  @f{eqnarray*}
440    \phi_g^i|_{K_c} = B_c^{il} \varphi_{g'}^l|_{K_c}.
441  @f}
442  Here, and in the following, summation over indices appearing twice is
443  implied. The matrix $B_c$ is the matrix that interpolated data from a cell
444  to its $c$-th child.
445
446  Then we can write the contribution of cell $K$ to the right hand side
447  component $F_i$ as
448  @f{eqnarray*}
449    F_i|_K
450    &=&
451    \left\{ \int_K f(x) \varphi_g^i(x) \varphi_{g'}^j(x)
452    \ dx \right\} \phi_{g'}^j
453    \\
454    &=&
455    \left\{
456    \sum_{0\le c<2^{\texttt{dim}}}
457    B_c^{il} \int_{K_c} f(x) \varphi_{g'}^l(x) \varphi_{g'}^j(x)
458    \ dx \right\} \phi_{g'}^j.
459  @f}
460  In matrix notation, this can be written as
461  @f{eqnarray*}
462    F_i|_K
463    =
464    \sum_{0\le c<2^{\texttt{dim}}}
465    F_i|_{K_c},
466    \qquad
467    \qquad
468    F_i|_{K_c} = B_c^{il} M_{K_c}^{lj}  \phi_{g'}^j
469    = (B_c M_{K_c})^{ij} \phi_{g'}^j,
470  @f}
471  where $M_{K_c}^{lj}=\int_{K_c} f(x) \varphi_{g'}^l(x) \varphi_{g'}^j(x)$ is
472  the weighted mass matrix on child $c$ of cell $K$.
473
474  The next question is what happens if a child $K_c$ of $K$ is not
475  active. Then, we have to apply the process recursively, i.e. we have to
476  interpolate the basis functions $\varphi_g^i$ onto child $K_c$ of $K$, then
477  onto child $K_{cc'}$ of that cell, onto child $K_{cc'c''}$ of that one, etc,
478  until we find an active cell. We then have to sum up all the contributions
479  from all the children, grandchildren, etc, of cell $K$, with contributions
480  of the form
481  @f{eqnarray*}
482    F_i|_{K_{cc'}} = (B_cB_{c'} M_{K_{cc'}})^{ij}  \phi_{g'}^j,
483  @f}
484  or
485  @f{eqnarray*}
486    F_i|_{K_{cc'c''}} = (B_c B_{c'} B_{c''}M_{K_{cc'c''}})^{ij}
487    \phi_{g'}^j,
488  @f}
489  etc. We do this process recursively, i.e. if we sit on cell $K$ and see that
490  it has children on grid $g'$, then we call a function
491  <code>assemble_case_2</code> with an identity matrix; the function will
492  multiply it's argument from the left with the prolongation matrix; if the
493  cell has further children, it will call itself with this new matrix,
494  otherwise it will perform the integration.
495
496<li> The last case is where $K$ is active on mesh $g'$ but not mesh
497  $g$. In that case, we have to express basis function $\varphi_{g'}^j$ in
498  terms of the basis functions defined on the children of cell $K$, rather
499  than $\varphi_g^i$ as before. This of course works in exactly the same
500  way. If the children of $K$ are active on mesh $g$, then
501  leading to the expression
502  @f{eqnarray*}
503    F_i|_K
504    &=&
505    \left\{ \int_K f(x) \varphi_g^i(x) \varphi_{g'}^j(x)
506    \ dx \right\} \phi_{g'}^j
507    \\
508    &=&
509    \left\{
510    \sum_{0\le c<2^{\texttt{dim}}}
511    \int_{K_c} f(x) \varphi_g^i(x) B_c^{jl} \varphi_{g}^l(x)
512    \ dx \right\} \phi_{g'}^j.
513  @f}
514  In matrix notation, this expression now reads as
515  @f{eqnarray*}
516    F_i|_K
517    =
518    \sum_{0\le c<2^{\texttt{dim}}}
519    F_i|_{K_c},
520    \qquad
521    \qquad
522    F_i|_{K_c} = M_{K_c}^{il} B_c^{jl}  \phi_{g'}^j
523    =
524    (M_{K_c} B_c^T)^{ij} \phi_{g'}^j,
525  @f}
526  and correspondingly for cases where cell $K$ is refined more than once on
527  mesh $g$:
528  @f{eqnarray*}
529    F_i|_{K_{cc'}} = (M_{K_{cc'}} B_{c'}^T B_c^T)^{ij}  \phi_{g'}^j,
530  @f}
531  or
532  @f{eqnarray*}
533    F_i|_{K_{cc'c''}} = (M_{K_{cc'c''}} B_{c''}^T B_{c'}^T B_c^T)^{ij}
534    \phi_{g'}^j,
535  @f}
536  etc. In other words, the process works in exactly the same way as before,
537  except that we have to take the transpose of the prolongation matrices and
538  need to multiply it to the mass matrix from the other side.
539</ol>
540
541
542The expressions for cases (ii) and (iii) can be understood as repeatedly
543interpolating either the left or right basis functions in the scalar product
544$(f \varphi_g^i, \varphi_{g'}^j)_K$ onto child cells, and then finally
545forming the inner product (the mass matrix) on the final cell. To make the
546symmetry in these cases more obvious, we can write them like this: for case
547(ii), we have
548@f{eqnarray*}
549  F_i|_{K_{cc'\cdots c^{(k)}}}
550  = [B_c B_{c'} \cdots B_{c^{(k)}} M_{K_{cc'\cdots c^{(k)}}}]^{ij}
551    \phi_{g'}^j,
552@f}
553whereas for case (iii) we get
554@f{eqnarray*}
555  F_i|_{K_{cc'\cdots c^{(k)}}}
556  = [(B_c B_{c'} \cdots B_{c^{(k)}} M_{K_{cc'\cdots c^{(k)}}})^T]^{ij}
557    \phi_{g'}^j,
558@f}
559
560
561
562<h3>Description of the test case</h3>
563
564A nuclear reactor core is composed of different types of assemblies. An
565assembly is essentially the smallest unit that can be moved in and out of a
566reactor, and is usually rectangular or square. However, assemblies are not
567fixed units, as they are assembled from a complex lattice of different fuel
568rods, control rods, and instrumentation elements that are held in place
569relative to each other by spacers that are permanently attached to the rods.
570To make things more complicated, there are different kinds of assemblies that
571are used at the same time in a reactor, where assemblies differ in the type
572and arrangement of rods they are made up of.
573
574Obviously, the arrangement of assemblies as well as the arrangement of rods
575inside them affect the distribution of neutron fluxes in the reactor (a fact
576that will be obvious by looking at the solution shown below in the results
577sections of this program). Fuel rods, for example, differ from each other in
578the enrichment of U-235 or Pu-239. Control rods, on the other hand, have zero
579fission, but nonzero scattering and absorption cross sections.
580
581This whole arrangement would make the description or spatially dependent
582material parameters very complicated. It will not become much simpler, but we
583will make one approximation: we merge the volume inhabited by each cylindrical
584rod and the surrounding water into volumes of quadratic cross section into
585so-called `pin cells' for which homogenized material data are obtained with
586nuclear database and knowledge of neutron spectrum. The homogenization makes
587all material data piecewise constant on the solution domain for a reactor with
588fresh fuel. Spatially dependent material parameters are then looked up for the
589quadratic assembly in which a point is located, and then for the quadratic pin
590cell within this assembly.
591
592In this tutorial program, we simulate a quarter of a reactor consisting of $4
593\times 4$ assemblies. We use symmetry (Neumann) boundary conditions to reduce
594the problem to one quarter of the domain, and consequently only simulate a
595$2\times 2$ set of assemblies. Two of them will be UO${}_2$ fuel, the other
596two of them MOX fuel. Each of these assemblies consists of $17\times 17$ rods
597of different compositions. In total, we therefore create a $34\times 34$
598lattice of rods. To make things simpler later on, we reflect this fact by
599creating a coarse mesh of $34\times 34$ cells (even though the domain is a
600square, for which we would usually use a single cell). In deal.II, each cell
601has a <code>material_id</code> which one may use to associated each cell with a
602particular number identifying the material from which this cell's volume is
603made of; we will use this material ID to identify which of the 8 different
604kinds of rods that are used in this testcase make up a particular cell. Note
605that upon mesh refinement, the children of a cell inherit the material ID,
606making it simple to track the material even after mesh refinement.
607
608The arrangement of the rods will be clearly visible in the images shown in
609the results section. The cross sections for materials and for both energy
610groups are taken from a OECD/NEA benchmark problem. The detailed configuration
611and material data is given in the code.
612
613
614<h3>What the program does (and how it does that)</h3>
615
616As a coarse overview of what exactly the program does, here is the basic
617layout: starting on a coarse mesh that is the same for each energy group, we
618compute inverse eigenvalue iterations to compute the $k$-eigenvalue on a given
619set of meshes. We stop these iterations when the change in the eigenvalue
620drops below a certain tolerance, and then write out the meshes and solutions
621for each energy group for inspection by a graphics program. Because the meshes
622for the solutions are different, we have to generate a separate output file
623for each energy group, rather than being able to add all energy group
624solutions into the same file.
625
626After this, we evaluate the error indicators as explained in one of the sections
627above for each of the meshes, and refine and coarsen the cells of each mesh
628independently. Since the eigenvalue iterations are fairly expensive, we don't
629want to start all over on the new mesh; rather, we use the SolutionTransfer
630class to interpolate the solution on the previous mesh to the next one upon
631mesh refinement. A simple experiment will convince you that this is a lot
632cheaper than if we omitted this step. After doing so, we resume our eigenvalue
633iterations on the next set of meshes.
634
635The program is controlled by a parameter file, using the ParameterHandler
636class. We will show a
637parameter file in the results section of this tutorial. For the moment suffice
638it to say that it controls the polynomial degree of the finite elements used,
639the number of energy groups (even though all that is presently implemented are
640the coefficients for a 2-group problem), the tolerance where to stop the
641inverse eigenvalue iteration, and the number of refinement cycles we will do.
642