Skip to content

Commit ee1c546

Browse files
authored
Merge pull request #31785 from kyriv1980/delete_full_monlithic
Delete full monolithic solver & re-organize problems using lambdas
2 parents ac88058 + ce6ccf5 commit ee1c546

File tree

32 files changed

+430
-1287
lines changed

32 files changed

+430
-1287
lines changed

modules/combined/test/tests/subchannel_thm_coupling/subchannel.i

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@ heated_length = 1.0
105105
implicit = true
106106
segregated = false
107107
staggered_pressure = false
108-
monolithic_thermal = false
109108
verbose_multiapps = true
110109
verbose_subchannel = false
111110
interpolation_scheme = 'upwind'

modules/subchannel/doc/content/modules/subchannel/general/subchannel_theory.md

Lines changed: 93 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ h_{ij}' = \sum_{j} w_{ij}'\Delta h_{ij} = \sum_{j} w'_{ij}\big[ h_i - h_j \big]
118118
w_{ij}' = \beta S_{ij} \bar{G}, ~\frac{dw_{ij}'}{dz} = \frac{w_{ij}'}{\Delta Z}=\beta g_{ij} \bar{G}.
119119
\end{equation}
120120

121-
where $\beta$ is the turbulent mixing parameter or thermal transfer coefficient and $\bar{G}$ is the average mass flux of the adjacent subchannels. The $\beta$ term is the tuning parameter for the mixing model. Physically, it is a non-dimensional coefficient that represents the ratio of the lateral mass flux due to mixing to the axial mass flux. It is used to model the effect of the unresolved scales of motion that are produced through the averaging process. In single-phase flow no net mass exchange occurs, both momentum and energy are exchanged between subchannels, and their rates of exchange are characterized in terms of hypothetical turbulent interchange flow rates ($w_{ij}^{'H},w_{ij}^{'M}$) [!cite](TODREAS), for enthalpy and momentum respectively. The approximation that the rate of turbulent exchange for energy and momentum are equal is adopted: $w'_{ij} = w_{ij}^{'H} = w_{ij}^{'M}$.
121+
where $\beta$ is the turbulent mixing parameter or thermal transfer coefficient and $\bar{G}$ is the average mass flux of the adjacent subchannels. The $\beta$ term is the tuning parameter for the mixing model. Physically, it is a non-dimensional coefficient that represents the ratio of the lateral mass flux due to mixing to the axial mass flux. It is used to model the effect of the unresolved scales of motion that are produced through the averaging process. In single-phase flow no net mass exchange occurs, both momentum and energy are exchanged between subchannels, and their rates of exchange are characterized in terms of hypothetical turbulent interchange flow rates ($w_{ij}^{'H},w_{ij}^{'M}$) [!cite](TODREAS), for enthalpy and momentum respectively. The approximation that the rate of turbulent exchange for energy and momentum are related as follows is adopted: $w'_{ij} = w_{ij}^{'H} = w_{ij}^{'M} / C_T$.
122122

123123
Additional turbulent mixing parameters are implemented as follows:
124124

@@ -136,7 +136,6 @@ After calibrating the turbulent diffusion coefficient $\beta$ we turned our atte
136136

137137
For quadrilateral assemblies: $C_{T} = 2.6$, $\beta = 0.006$ [!cite](kyriakopoulos2022development).
138138

139-
140139
## Discretization
141140

142141
The collocated discretization of the variables is presented in [fig:dis] . $i,j$ are the subchannel indexes. $ij$ is the name of the gap between subchannels $i,j$. $k$ is the index in the axial direction.
@@ -269,11 +268,11 @@ This is the default algorithm, where the unknown flow variables are calculated i
269268

270269
#### Implicit segregated
271270

272-
In this case, the governing equations are recast in matrix form and the flow variables are calculated by solving the corresponding system. This means that variables are retrieved concurrently for the whole block. Otherwise, the solution algorithm is the same as in the default method.
271+
In this case, the governing mass, axial momentum and crossflow momentum, equations are recast in matrix form and the flow variables are calculated by solving the corresponding system. This means that variables are retrieved concurrently for the whole block. Otherwise, the solution algorithm is the same as in the default explicit method.
273272

274273
#### Implicit
275274

276-
In this case, the conservation equations are recast in matrix form and combined into a single system. The user can decide whether or not they will include the enthalpy calculation in the matrix formulation. The flow variables are calculated by solving that big system to retrieve all the unknows at the same time instead of one by one, and on all the nodes of the block: $\vec{\dot{m}}, \vec{P}, \vec{w_{ij}}, \vec{h}$. The solution algorithm is the same as in the default method, but the solver used in this version is a fixed point iteration instead of a Newton method. The system looks like this:
275+
In this case, the governing mass, axial momentum and crossflow momentum conservation equations are recast in matrix form and combined into a single system. The system of all the subchannel equations looks like this:
277276

278277
\begin{equation}
279278
\begin{bmatrix}
@@ -297,5 +296,93 @@ In this case, the conservation equations are recast in matrix form and combined
297296
\end{bmatrix}
298297
\end{equation}
299298

300-
As soon as the big matrix is constructed, the solver will calculate cross-flow resistances to achieve realizable solutions. This is done by an initial calculation of the axial mass flows, crossflows, and the sum of crossflows.
301-
The defined relaxation factor is the average crossflow divided by the maximum and added to 0.5. The added cross-flow resistance is a blending of a current value and the previous one using the relaxation factor calculated above. The current value is the maximum of the sum of cross-flows per subchannel over the minimum axial mass-flow rate. The added cross-flow resistance is added to the diagonal of $M_{ww}$ matrix.
299+
Since the enthalpy governing equations are uncoupled from the other equations in this otherwise monolithic system (enthalpy is coupled to the flow equations via the fluid properties update), it makes sense to lag the enthalpy solution and solve for it separately. The flow variables are calculated by solving that big system (without the enthalpy) to retrieve all the unknowns at the same time instead of one by one, and on all the nodes of the block: $\vec{\dot{m}}, \vec{P}, \vec{w_{ij}}$. The solution algorithm is the same as in the default method and the solver used is PETSc KSPSolve.
300+
301+
As soon as the big matrix is constructed, the solver will calculate cross-flow resistances to maintain realizability. A distinctive feature of this method is the introduction of a *weak relaxation* logic that stabilizes and accelerates convergence of the coupled $mass flow: (\dot{\mathbf{m}})$, $pressure: (\mathbf{P})$, and $crossflow:(\mathbf{w}_{ij})$ fields in a $Q{=}3$ block-nested linear system with matrix blocks $M_{ij}$ and right-hand-side blocks $\mathbf{b}_i$ that represent the individual governing equations. Note that the solution is influenced by the stabilization method and its coefficients.
302+
303+
#### 1. Fast scale estimates
304+
305+
From the axial- and cross-momentum rows, the code forms quick, diagonally preconditioned estimates:
306+
\begin{equation}
307+
\begin{aligned}
308+
\hat{\mathbf m} &= M_{pm}\,\mathbf m, \\
309+
\hat{\mathbf p} &= \frac{\hat{\mathbf m}}{\operatorname{diag}(M_{pp}) + \varepsilon_p\mathbf 1},\\
310+
\hat{\mathbf W} &= \frac{M_{wp}\,\hat{\mathbf p} - \mathbf b_w}{\operatorname{diag}(M_{ww}) + \varepsilon_W\mathbf 1},
311+
\end{aligned}
312+
\end{equation}
313+
with small safeguards $\varepsilon_p,\varepsilon_W\sim 10^{-10}$ to avoid division by zero. Using $\hat{\mathbf W}$, the per-channel crossflow sum $\sum_{j} w_{ij}$ is assembled into a vector $\mathrm{sumw_{ij}}_{\mathrm{loc}}$.
314+
315+
#### 2. Crossflow relaxation parameter
316+
317+
Two guarded scalars are computed:
318+
319+
\begin{equation}
320+
\begin{aligned}
321+
m_{\min} &= \max\big(\min |\mathbf m|,\; 10^{-10}\big),\\
322+
S_{\max} &= \max\Big(\max |\mathrm{sumw_{ijloc}}|,\; 10^{-10}\Big)
323+
\end{aligned}
324+
\end{equation}
325+
326+
Additionally, a mean inter-iteration change for crossflow is formed
327+
\begin{equation}
328+
r_{\mathrm{base}} = \operatorname{mean}\big(\big|\mathbf W^{(k)}| - |\mathbf W^{(k-1)}\big|\big),
329+
\end{equation}
330+
leading to a relaxation factor
331+
\begin{equation}
332+
r = \frac{r_{\mathrm{base}}}{\max(S_{\max}, \varepsilon)} + 0.5,\qquad \varepsilon\sim10^{-10}.
333+
\end{equation}
334+
The +0.5 offset biases toward mild under-relaxation.
335+
336+
#### 3. Crossflow resistance inflation
337+
338+
A cross-coupling resistance is estimated and smoothed:
339+
\begin{equation}
340+
\begin{aligned}
341+
\tilde K &= \frac{S_{\max}}{m_{\min}}, &
342+
K^\star &= 0.9\,\tilde K + 0.1\,K_{\text{old}}, &
343+
K &= r\,K^\star.
344+
\end{aligned}
345+
\end{equation}
346+
After smoothing, the provisional crossflow resistance $K$ is mapped through a piecewise lower-bound function that enforces minimum safe damping levels in specific ranges.
347+
348+
\begin{equation}
349+
K \rightarrow
350+
\begin{cases}
351+
K , & K >= 10, \\
352+
1.0, & 1 \leq K < 10, \\
353+
0.5, & 0.1 \leq K < 1, \\
354+
\frac{1}{3}, & 0.01 \leq K < 0.1, \\
355+
0.1, & 0.001 \leq K < 0.01, \\
356+
K, & K < 10^{-3}.
357+
\end{cases}
358+
\end{equation}
359+
360+
This mapping acts as a {snap-up} rule for the crossflow resistance $K$ over the range $[10^{-3}, 10]$:
361+
it raises $K$ out of weak-damping intervals but leaves very small and very large
362+
values unchanged. The purpose is to maintain numerical stability and adequate
363+
diagonal dominance in the cross-momentum equations without introducing full quantization or "bucketing".
364+
365+
Finally, $K$ is added to the diagonal of the cross-momentum block,
366+
\begin{equation}
367+
M_{ww} \;\leftarrow\; M_{ww} + K\,I,
368+
\end{equation}
369+
thereby increasing diagonal dominance and improving conditioning for the crossflow equations. Note that this treatment does influence the cross-flow distribution solution.
370+
371+
#### 4. Per-equation under-relaxation
372+
373+
Classical linear under-relaxation is applied automatically and separately to each equation $f\in\{\mathbf m,\mathbf p,\mathbf W\}$ using factors
374+
\begin{equation}
375+
\alpha_m=1.0,\qquad \alpha_p=1.0,\qquad \alpha_W=0.1.
376+
\end{equation}
377+
For each equation, with the corresponding diagonal $D_f=\operatorname{diag}(M_{ff})$, the system is modified as
378+
\begin{equation}
379+
\begin{aligned}
380+
M_{ff} &\leftarrow \frac{1}{\alpha_f} M_{ff}, \\
381+
\mathbf b_f &\leftarrow \mathbf b_f + (1-\alpha_f)\,D_f\,\mathbf x^{\text{old}}_f.
382+
\end{aligned}
383+
\end{equation}
384+
This standard construction ensures that solving the modified linear system yields the *under-relaxed* update for equation $f$. In practice, only $\mathbf W$ is strongly damped, while $\mathbf m$ and $\mathbf p$ can be solved without additional damping. This relaxation happens inside the temperature loop.
385+
386+
#### 5. Net effect
387+
388+
The combination of (i) safeguarded scale estimation, (ii) adaptive, time smoothed, and piecewise snapped added crossflow resistance, and (iii) selective under-relaxation produces a more diagonally dominant and robust nested solve that tolerates rapid changes in crossflow while preserving good convergence properties for mass flow and pressure.

modules/subchannel/examples/MultiApp/fuel_assembly.i

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,6 @@ duct_inside = '${fparse duct_outside - 2 * duct_thickness}'
145145
implicit = false
146146
segregated = true
147147
staggered_pressure = false
148-
monolithic_thermal = false
149148

150149
# Tolerances
151150
P_tol = 1.0e-4

modules/subchannel/examples/duct/test.i

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ P_out = 2.0e5 # Pa
9292
implicit = true
9393
segregated = false
9494
staggered_pressure = false
95-
monolithic_thermal = false
9695
verbose_multiapps = true
9796
verbose_subchannel = false
9897
[]

modules/subchannel/include/problems/SubChannel1PhaseProblem.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,22 @@ class SubChannel1PhaseProblem : public ExternalProblem, public PostprocessorInte
138138
}
139139
}
140140

141+
/**
142+
* Solve a linear system (A * x = rhs) with a simple PCJACOBI KSP and populate the
143+
* enthalpy solution into _h_soln for nodes [first_node, last_node].
144+
*
145+
* Uses member tolerances (_rtol, _atol, _dtol, _maxit), mesh (_subchannel_mesh),
146+
* channel count (_n_channels), and error/solution handles (mooseError, _h_soln).
147+
*
148+
* @param A PETSc matrix (operators)
149+
* @param rhs PETSc vector (right-hand side)
150+
* @param first_node inclusive start axial node index
151+
* @param last_node inclusive end axial node index
152+
* @param ksp_prefix options prefix for KSP (e.g. "h_sys_"), may be nullptr
153+
*/
154+
PetscErrorCode solveAndPopulateEnthalpy(
155+
Mat A, Vec rhs, unsigned int first_node, unsigned int last_node, const char * ksp_prefix);
156+
141157
PetscErrorCode cleanUp();
142158
SubChannelMesh & _subchannel_mesh;
143159
/// number of axial blocks
@@ -201,8 +217,6 @@ class SubChannel1PhaseProblem : public ExternalProblem, public PostprocessorInte
201217
const bool _staggered_pressure_bool;
202218
/// Segregated solve
203219
const bool _segregated_bool;
204-
/// Thermal monolithic bool
205-
const bool _monolithic_thermal_bool;
206220
/// Boolean to printout information related to subchannel solve
207221
const bool _verbose_subchannel;
208222
/// Flag that activates the effect of deformation (pin/duct) based on the auxvalues for displacement, Dpin

modules/subchannel/src/problems/QuadSubChannel1PhaseProblem.C

Lines changed: 3 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -806,43 +806,8 @@ QuadSubChannel1PhaseProblem::computeh(int iblock)
806806
LibmeshPetscCall(VecAXPY(_hc_sys_h_rhs, 1.0, _hc_cross_derivative_rhs));
807807
LibmeshPetscCall(VecAXPY(_hc_sys_h_rhs, 1.0, _hc_added_heat_rhs));
808808

809-
if (_segregated_bool || (!_monolithic_thermal_bool))
810-
{
811-
// Assembly the matrix system
812-
KSP ksploc;
813-
PC pc;
814-
Vec sol;
815-
LibmeshPetscCall(VecDuplicate(_hc_sys_h_rhs, &sol));
816-
LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksploc));
817-
LibmeshPetscCall(KSPSetOperators(ksploc, _hc_sys_h_mat, _hc_sys_h_mat));
818-
LibmeshPetscCall(KSPGetPC(ksploc, &pc));
819-
LibmeshPetscCall(PCSetType(pc, PCJACOBI));
820-
LibmeshPetscCall(KSPSetTolerances(ksploc, _rtol, _atol, _dtol, _maxit));
821-
LibmeshPetscCall(KSPSetOptionsPrefix(ksploc, "h_sys_"));
822-
LibmeshPetscCall(KSPSetFromOptions(ksploc));
823-
LibmeshPetscCall(KSPSolve(ksploc, _hc_sys_h_rhs, sol));
824-
PetscScalar * xx;
825-
LibmeshPetscCall(VecGetArray(sol, &xx));
826-
for (unsigned int iz = first_node; iz < last_node + 1; iz++)
827-
{
828-
auto iz_ind = iz - first_node;
829-
for (unsigned int i_ch = 0; i_ch < _n_channels; i_ch++)
830-
{
831-
auto * node_out = _subchannel_mesh.getChannelNode(i_ch, iz);
832-
auto h_out = xx[iz_ind * _n_channels + i_ch];
833-
if (h_out < 0)
834-
{
835-
mooseError(name(),
836-
" : Calculation of negative Enthalpy h_out = : ",
837-
h_out,
838-
" Axial Level= : ",
839-
iz);
840-
}
841-
_h_soln->set(node_out, h_out);
842-
}
843-
}
844-
LibmeshPetscCall(KSPDestroy(&ksploc));
845-
LibmeshPetscCall(VecDestroy(&sol));
846-
}
809+
// Use system to solve for and populate enthalpy
810+
LibmeshPetscCall(this->solveAndPopulateEnthalpy(
811+
_hc_sys_h_mat, _hc_sys_h_rhs, first_node, last_node, "h_sys_"));
847812
}
848813
}

0 commit comments

Comments
 (0)