12#include "libmesh/petsc_vector.h"
13#include "libmesh/dense_matrix.h"
14#include "libmesh/dense_vector.h"
35 const PetscScalar * xx;
40 Ctx * cc =
static_cast<Ctx *
>(ctx);
41 LibmeshPetscCallQ(VecGetSize(
x, &size));
44 LibmeshPetscCallQ(VecGetArrayRead(
x, &xx));
45 for (PetscInt i = 0; i < size; i++)
46 solution_seed(i) = xx[i];
48 LibmeshPetscCallQ(VecRestoreArrayRead(
x, &xx));
53 LibmeshPetscCallQ(VecGetArray(
f, &ff));
54 for (
int i = 0; i < size; i++)
55 ff[i] = Wij_residual_vector(i);
57 LibmeshPetscCallQ(VecRestoreArray(
f, &ff));
58 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
65 MooseEnum schemes(
"upwind downwind central_difference exponential",
"central_difference");
66 MooseEnum gravity_direction(
"counter_flow co_flow none",
"counter_flow");
72 params.
addParam<
unsigned int>(
"n_blocks", 1,
"The number of blocks in the axial direction");
73 params.
addParam<Real>(
"P_tol", 1e-6,
"Pressure tolerance");
78 "Maximum number of pressure iterations; zero selects the solver's automatic limit");
79 params.
addParam<Real>(
"T_tol", 1e-6,
"Temperature tolerance");
80 params.
addParam<
int>(
"T_maxit", 100,
"Maximum number of iterations for inner temperature loop");
84 "T_relaxation > 0 & T_relaxation <= 1",
85 "Relaxation factor for temperature updates in the inner thermal-hydraulic iteration");
89 "enthalpy_subcycles > 0",
90 "Number of enthalpy, temperature, and property updates performed per flow solve");
92 "mass_flow_equation_relaxation",
94 "mass_flow_equation_relaxation > 0 & mass_flow_equation_relaxation <= 1",
95 "Equation relaxation factor for mass flow rate in the implicit non-segregated solve");
97 "pressure_equation_relaxation",
99 "pressure_equation_relaxation > 0 & pressure_equation_relaxation <= 1",
100 "Equation relaxation factor for pressure in the implicit non-segregated solve");
102 "crossflow_equation_relaxation",
104 "crossflow_equation_relaxation > 0 & crossflow_equation_relaxation <= 1",
105 "Equation relaxation factor for crossflow in the implicit non-segregated solve");
107 "mass_flow_relaxation",
109 "mass_flow_relaxation > 0 & mass_flow_relaxation <= 1",
110 "Post-solve relaxation factor for mass flow rate updates in the implicit non-segregated "
113 "pressure_relaxation",
115 "pressure_relaxation > 0 & pressure_relaxation <= 1",
116 "Post-solve relaxation factor for pressure updates in the implicit non-segregated solve");
118 "crossflow_relaxation",
120 "crossflow_relaxation > 0 & crossflow_relaxation <= 1",
121 "Post-solve relaxation factor for crossflow updates in the implicit non-segregated solve");
122 params.
addParam<PetscReal>(
"rtol", 1e-6,
"Relative tolerance for ksp solver");
123 params.
addParam<PetscReal>(
"atol", 1e-6,
"Absolute tolerance for ksp solver");
124 params.
addParam<PetscReal>(
"dtol", 1e5,
"Divergence tolerance or ksp solver");
125 params.
addParam<PetscInt>(
"maxit", 1e4,
"Maximum number of iterations for ksp solver");
127 "interpolation_scheme",
129 "Interpolation scheme used for the method. Default is central_difference");
131 "gravity", gravity_direction,
"Direction of gravity. Default is counter_flow");
133 "implicit",
false,
"Boolean to define the use of explicit or implicit solution.");
134 params.
addParam<
bool>(
"staggered_pressure",
136 "Boolean to define the use of staggered or collocated pressure.");
138 "segregated",
true,
"Boolean to define whether to use a segregated solution.");
140 "verbose_subchannel",
false,
"Boolean to print out information related to subchannel solve.");
141 params.
addRequiredParam<
bool>(
"compute_density",
"Flag that enables the calculation of density");
143 "Flag that enables the calculation of viscosity");
146 "Flag that informs whether we solve the Enthalpy/Temperature equations or not");
149 "The postprocessor (or scalar) that provides the absolute outlet pressure [Pa]. The solved "
150 "pressure variable P is relative to this value.");
151 params.
addRequiredParam<UserObjectName>(
"fp",
"Fluid properties user object name");
153 "Closure computing the friction factor");
156 "Closure computing the turbulent mixing, wire-induced "
157 "mixing and sweep flow mixing parameter where applicable");
159 "pin_HTC_closure",
"Closure computing HTC on fuel pin (required if pin mesh exists).");
160 params.
addParam<UserObjectName>(
"duct_HTC_closure",
161 "Closure computing HTC on duct (required if duct mesh exists).");
163 "full_output",
false,
"Flag that enables the output of the maximum number of variables.");
165 "Thermal diffusion coefficient used in turbulent crossflow.",
166 "Use closure system instead.");
170 "Boolean to define the use of a constant beta or beta correlation (Kim and Chung, 2001)",
171 "Use closure system instead.");
174 "P_tol P_maxit T_tol T_maxit T_relaxation enthalpy_subcycles "
175 "mass_flow_equation_relaxation pressure_equation_relaxation crossflow_equation_relaxation "
176 "mass_flow_relaxation pressure_relaxation crossflow_relaxation rtol atol dtol maxit",
177 "Solver tolerances and iterations");
180 params.
addParamNamesToGroup(
"fp friction_closure mixing_closure pin_HTC_closure duct_HTC_closure",
192 _friction_args(0, 1.0, 0.0, 0.0),
194 1.0, 1.0,
std::numeric_limits<unsigned
int>::max(), 0, 0),
195 _P_out(getPostprocessorValue(
"P_out")),
198 _n_blocks(getParam<unsigned
int>(
"n_blocks")),
199 _Wij(declareRestartableData<
libMesh::DenseMatrix<Real>>(
"Wij")),
200 _Wij_old(declareRestartableData<
libMesh::DenseMatrix<Real>>(
"Wij_old")),
202 _kij(_subchannel_mesh.getKij()),
204 _compute_density(getParam<bool>(
"compute_density")),
205 _compute_viscosity(getParam<bool>(
"compute_viscosity")),
206 _compute_power(getParam<bool>(
"compute_power")),
207 _pin_mesh_exist(_subchannel_mesh.pinMeshExist()),
208 _duct_mesh_exist(_subchannel_mesh.ductMeshExist()),
211 _P_tol(getParam<Real>(
"P_tol")),
212 _P_maxit(getParam<
int>(
"P_maxit")),
213 _T_tol(getParam<Real>(
"T_tol")),
214 _T_maxit(getParam<
int>(
"T_maxit")),
215 _T_relaxation(getParam<Real>(
"T_relaxation")),
216 _enthalpy_subcycles(getParam<unsigned
int>(
"enthalpy_subcycles")),
217 _mass_flow_equation_relaxation(getParam<Real>(
"mass_flow_equation_relaxation")),
218 _pressure_equation_relaxation(getParam<Real>(
"pressure_equation_relaxation")),
219 _crossflow_equation_relaxation(getParam<Real>(
"crossflow_equation_relaxation")),
220 _mass_flow_relaxation(getParam<Real>(
"mass_flow_relaxation")),
221 _pressure_relaxation(getParam<Real>(
"pressure_relaxation")),
222 _crossflow_relaxation(getParam<Real>(
"crossflow_relaxation")),
223 _rtol(getParam<PetscReal>(
"rtol")),
224 _atol(getParam<PetscReal>(
"atol")),
225 _dtol(getParam<PetscReal>(
"dtol")),
226 _maxit(getParam<PetscInt>(
"maxit")),
227 _interpolation_scheme(getParam<
MooseEnum>(
"interpolation_scheme")),
228 _gravity_direction(getParam<
MooseEnum>(
"gravity")),
229 _dir_grav(computeGravityDir(_gravity_direction)),
230 _implicit_bool(getParam<bool>(
"implicit")),
231 _staggered_pressure_bool(getParam<bool>(
"staggered_pressure")),
232 _segregated_bool(getParam<bool>(
"segregated")),
233 _verbose_subchannel(getParam<bool>(
"verbose_subchannel")),
234 _friction_closure(nullptr),
235 _mixing_closure(nullptr),
236 _pin_HTC_closure(nullptr),
237 _duct_HTC_closure(nullptr),
239 _duct_heat_flux_soln(nullptr),
240 _Tduct_soln(nullptr),
245 "You are using a deprecated parameter. Please use the mixing_closure system.");
247 paramError(
"pin_HTC_closure",
"required when a pin mesh exists.");
249 paramError(
"duct_HTC_closure",
"required when a duct mesh exists.");
251 paramError(
"segregated",
"A non-segregated solve requires 'implicit = true'.");
253 for (
const auto * relaxation_param : {
"mass_flow_equation_relaxation",
254 "pressure_equation_relaxation",
255 "crossflow_equation_relaxation",
256 "mass_flow_relaxation",
257 "pressure_relaxation",
258 "crossflow_relaxation"})
263 "' parameter is only used by the implicit non-segregated solve. Set "
264 "'implicit = true' and 'segregated = false' to use it.");
362 ": When implicit number of blocks can't be equal to number of cells. This will "
363 "cause problems with the subchannel interpolation scheme.");
375 if (getParam<bool>(
"full_output"))
405 _fp = &getUserObject<SinglePhaseFluidProperties>(getParam<UserObjectName>(
"fp"));
407 &getUserObject<SCMFrictionClosureBase>(getParam<UserObjectName>(
"friction_closure"));
409 &getUserObject<SCMMixingClosureBase>(getParam<UserObjectName>(
"mixing_closure"));
416 &getUserObject<SCMHTCClosureBase>(getParam<UserObjectName>(
"pin_HTC_closure"));
419 &getUserObject<SCMHTCClosureBase>(getParam<UserObjectName>(
"duct_HTC_closure"));
427 Real viscosity_in = 0.0;
428 Real volumetric_flow_in = 0.0;
429 Real mass_flow_in = 0.0;
433 const Real mdot_in = (*_mdot_soln)(node_in);
434 const Real rho_in = (*_rho_soln)(node_in);
435 viscosity_in += mdot_in * (*_mu_soln)(node_in);
436 volumetric_flow_in += mdot_in / rho_in;
437 mass_flow_in += mdot_in;
441 const Real inlet_mu = viscosity_in / mass_flow_in;
442 _bulk_Re = mass_flow_in * bulk_Dh / (inlet_mu * flow_area);
443 _bulk_V = volumetric_flow_in / flow_area;
449 if (MooseUtils::absoluteFuzzyEqual(
_bulk_Re, 0.0))
450 mooseError(
"The computed bulk Reynolds number is zero.");
452 if (MooseUtils::absoluteFuzzyEqual(
_bulk_V, 0.0))
453 mooseError(
"The computed bulk velocity is zero.");
466 for (
unsigned int iz = 0; iz <
_n_cells + 1; iz++)
467 for (
unsigned int i_pin = 0; i_pin <
_n_pins; i_pin++)
470 const Real Dpin = (*_Dpin_soln)(node);
471 if (std::abs(Dpin) <=
tol)
474 ". You must initialize Dpin to a non-zero value.");
475 if (std::abs(Dpin - pin_diameter) >
tol)
494 PetscErrorCode ierr =
cleanUp();
506 LibmeshPetscCall(VecDestroy(&
_Wij_vec));
507 LibmeshPetscCall(VecDestroy(&
_prod));
508 LibmeshPetscCall(VecDestroy(&
_prodp));
553 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
574 return ((Peclet - 1.0) * std::exp(Peclet) + 1) / (Peclet * (std::exp(Peclet) - 1.) + 1e-10);
577 ": Interpolation scheme should be a string: upwind, downwind, central_difference, "
584 PetscScalar botValue,
588 return alpha * botValue + (1.0 - alpha) * topValue;
594 const unsigned int last_node = (iblock + 1) *
_block_size;
595 const unsigned int first_node = iblock *
_block_size + 1;
598 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
600 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
602 int i =
_n_gaps * (iz - first_node) + i_gap;
603 solution_seed(i) =
_Wij(i_gap, iz);
614 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
616 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
618 _Wij(i_gap, iz) = root(i);
627 const unsigned int last_node = (iblock + 1) *
_block_size;
628 const unsigned int first_node = iblock *
_block_size + 1;
632 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
634 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
639 unsigned int counter = 0;
654 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
656 unsigned int iz_ind = iz - first_node;
657 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
660 unsigned int counter = 0;
664 PetscInt col = i_gap +
_n_gaps * iz_ind;
666 LibmeshPetscCall(MatSetValues(
_mc_sumWij_mat, 1, &row, 1, &col, &value, INSERT_VALUES));
671 LibmeshPetscCall(MatAssemblyBegin(
_mc_sumWij_mat, MAT_FINAL_ASSEMBLY));
672 LibmeshPetscCall(MatAssemblyEnd(
_mc_sumWij_mat, MAT_FINAL_ASSEMBLY));
678 LibmeshPetscCall(VecDuplicate(
_Wij_vec, &loc_Wij));
682 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
684 LibmeshPetscCall(VecDestroy(&loc_prod));
685 LibmeshPetscCall(VecDestroy(&loc_Wij));
693 const unsigned int last_node = (iblock + 1) *
_block_size;
694 const unsigned int first_node = iblock *
_block_size + 1;
697 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
700 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
704 auto volume = dz * (*_S_flow_soln)(node_in);
705 auto time_term =
_TR * ((*_rho_soln)(node_out)-
_rho_soln->old(node_out)) * volume /
_dt;
707 auto mdot_out = (*_mdot_soln)(node_in) - (*
_SumWij_soln)(node_out)-time_term;
712 " : Calculation of negative mass flow mdot_out = : ",
716 " - Implicit solves are required for recirculating flow.");
724 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
727 auto iz_ind = iz - first_node;
728 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
732 auto volume = dz * (*_S_flow_soln)(node_in);
735 auto time_term =
_TR * ((*_rho_soln)(node_out)-
_rho_soln->old(node_out)) * volume /
_dt;
737 PetscScalar value_vec = -1.0 * time_term;
752 Real
rho, drho_dp_T, drho_dT;
755 Real h, dh_dp_T, dh_dT;
757 const Real drho_dp_h = drho_dp_T - drho_dT * dh_dp_T / dh_dT;
758 const PetscScalar pressure_coefficient = volume /
_dt * drho_dp_h;
759 const PetscInt pressure_col = i_ch +
_n_channels * (iz_ind + 1);
765 &pressure_coefficient,
767 const PetscScalar linearization_rhs = pressure_coefficient * (*_P_soln)(node_out);
773 if (iz == first_node)
775 PetscScalar value_vec = (*_mdot_soln)(node_in);
784 PetscScalar value = -1.0;
792 PetscScalar value = 1.0;
799 PetscScalar value_vec_2 = -1.0 * (*_SumWij_soln)(node_out);
817 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksploc));
819 LibmeshPetscCall(KSPGetPC(ksploc, &pc));
820 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
822 LibmeshPetscCall(KSPSetFromOptions(ksploc));
824 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
827 LibmeshPetscCall(KSPDestroy(&ksploc));
828 LibmeshPetscCall(VecDestroy(&sol));
836 const unsigned int last_node = (iblock + 1) *
_block_size;
837 const unsigned int first_node = iblock *
_block_size + 1;
840 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
844 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
848 auto rho_in = (*_rho_soln)(node_in);
849 auto rho_out = (*_rho_soln)(node_out);
850 auto mu_in = (*_mu_soln)(node_in);
851 auto S = (*_S_flow_soln)(node_in);
852 auto w_perim = (*_w_perim_soln)(node_in);
854 auto Dh_i = 4.0 * S / w_perim;
855 auto time_term =
_TR * ((*_mdot_soln)(node_out)-
_mdot_soln->old(node_out)) * dz /
_dt -
859 Utility::pow<2>((*
_mdot_soln)(node_out)) * (1.0 / S / rho_out - 1.0 / S / rho_in);
860 auto mass_term2 = -2.0 * (*_mdot_soln)(node_out) * (*
_SumWij_soln)(node_out) / S / rho_in;
861 auto crossflow_term = 0.0;
862 auto turbulent_term = 0.0;
863 unsigned int counter = 0;
867 unsigned int ii_ch = chans.first;
868 unsigned int jj_ch = chans.second;
873 auto rho_i = (*_rho_soln)(node_in_i);
874 auto rho_j = (*_rho_soln)(node_in_j);
875 auto Si = (*_S_flow_soln)(node_in_i);
876 auto Sj = (*_S_flow_soln)(node_in_j);
879 if (
_Wij(i_gap, iz) > 0.0)
880 u_star = (*
_mdot_soln)(node_out_i) / Si / rho_i;
882 u_star = (*_mdot_soln)(node_out_j) / Sj / rho_j;
887 turbulent_term +=
_WijPrime(i_gap, iz) * (2 * (*_mdot_soln)(node_out) / rho_in / S -
892 turbulent_term *=
_CT;
893 auto Re = (((*_mdot_soln)(node_in) / S) * Dh_i / mu_in);
901 ki = k_grid[i_ch][iz - 1];
903 ki = k_grid[i_ch][iz];
904 auto friction_term = (ff * dz / Dh_i + ki) * 0.5 *
906 (S * (*_rho_soln)(node_out));
908 auto DP = (1 / S) * (time_term + mass_term1 + mass_term2 + crossflow_term + turbulent_term +
909 friction_term + gravity_term);
929 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
933 auto iz_ind = iz - first_node;
934 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
941 PetscScalar Pe = 0.5;
945 auto S_in = (*_S_flow_soln)(node_in);
946 auto S_out = (*_S_flow_soln)(node_out);
948 auto w_perim_in = (*_w_perim_soln)(node_in);
949 auto w_perim_out = (*_w_perim_soln)(node_out);
953 auto mu_in = (*_mu_soln)(node_in);
954 auto mu_out = (*_mu_soln)(node_out);
956 auto Dh_i = 4.0 * S_interp / w_perim_interp;
958 auto Re = ((mdot_loc / S_interp) * Dh_i / mu_interp);
966 ki = k_grid[i_ch][iz - 1];
968 ki = k_grid[i_ch][iz];
969 Pe = 1.0 / ((ff * dz / Dh_i + ki) * 0.5) * mdot_loc / std::abs(mdot_loc);
974 auto rho_in = (*_rho_soln)(node_in);
975 auto rho_out = (*_rho_soln)(node_out);
979 auto mu_in = (*_mu_soln)(node_in);
980 auto mu_out = (*_mu_soln)(node_out);
984 auto S_in = (*_S_flow_soln)(node_in);
985 auto S_out = (*_S_flow_soln)(node_out);
989 auto w_perim_in = (*_w_perim_soln)(node_in);
990 auto w_perim_out = (*_w_perim_soln)(node_out);
994 auto Dh_i = 4.0 * S_interp / w_perim_interp;
1001 PetscScalar value_tt =
_TR * dz /
_dt;
1002 LibmeshPetscCall(MatSetValues(
1006 PetscInt row_vec_tt = i_ch +
_n_channels * iz_ind;
1011 if (iz == first_node)
1013 PetscScalar value_vec_at = Utility::pow<2>((*
_mdot_soln)(node_in)) / (S_in * rho_in);
1014 PetscInt row_vec_at = i_ch +
_n_channels * iz_ind;
1015 LibmeshPetscCall(VecSetValues(
1021 PetscInt col_at = i_ch +
_n_channels * (iz_ind - 1);
1022 PetscScalar value_at = -1.0 * std::abs((*
_mdot_soln)(node_in)) / (S_in * rho_in);
1023 LibmeshPetscCall(MatSetValues(
1030 PetscScalar value_at = std::abs((*
_mdot_soln)(node_out)) / (S_out * rho_out);
1031 LibmeshPetscCall(MatSetValues(
1035 unsigned int counter = 0;
1036 unsigned int cross_index = iz;
1040 unsigned int ii_ch = chans.first;
1041 unsigned int jj_ch = chans.second;
1056 if (
_Wij(i_gap, cross_index) > 0.0)
1058 if (iz == first_node)
1060 u_star = (*_mdot_soln)(node_in_i) / S_i / rho_i;
1061 PetscScalar value_vec_ct = -1.0 * alpha *
1063 _Wij(i_gap, cross_index) * u_star;
1064 PetscInt row_vec_ct = i_ch +
_n_channels * iz_ind;
1065 LibmeshPetscCall(VecSetValues(
1071 _Wij(i_gap, cross_index) / S_i / rho_i;
1073 PetscInt col_ct = ii_ch +
_n_channels * (iz_ind - 1);
1074 LibmeshPetscCall(MatSetValues(
1077 PetscScalar value_ct = (1.0 - alpha) *
1079 _Wij(i_gap, cross_index) / S_i / rho_i;
1082 LibmeshPetscCall(MatSetValues(
1085 else if (
_Wij(i_gap, cross_index) < 0.0)
1087 if (iz == first_node)
1089 u_star = (*_mdot_soln)(node_in_j) / S_j / rho_j;
1090 PetscScalar value_vec_ct = -1.0 * alpha *
1092 _Wij(i_gap, cross_index) * u_star;
1093 PetscInt row_vec_ct = i_ch +
_n_channels * iz_ind;
1094 LibmeshPetscCall(VecSetValues(
1100 _Wij(i_gap, cross_index) / S_j / rho_j;
1102 PetscInt col_ct = jj_ch +
_n_channels * (iz_ind - 1);
1103 LibmeshPetscCall(MatSetValues(
1106 PetscScalar value_ct = (1.0 - alpha) *
1108 _Wij(i_gap, cross_index) / S_j / rho_j;
1111 LibmeshPetscCall(MatSetValues(
1115 if (iz == first_node)
1117 PetscScalar value_vec_ct = -2.0 * alpha * (*_mdot_soln)(node_in)*
_CT *
1118 _WijPrime(i_gap, cross_index) / (rho_interp * S_interp);
1119 value_vec_ct += alpha * (*_mdot_soln)(node_in_j)*
_CT *
_WijPrime(i_gap, cross_index) /
1121 value_vec_ct += alpha * (*_mdot_soln)(node_in_i)*
_CT *
_WijPrime(i_gap, cross_index) /
1123 PetscInt row_vec_ct = i_ch +
_n_channels * iz_ind;
1129 PetscScalar value_center_ct =
1130 2.0 * alpha *
_CT *
_WijPrime(i_gap, cross_index) / (rho_interp * S_interp);
1132 PetscInt col_ct = i_ch +
_n_channels * (iz_ind - 1);
1133 LibmeshPetscCall(MatSetValues(
1136 PetscScalar value_left_ct =
1137 -1.0 * alpha *
_CT *
_WijPrime(i_gap, cross_index) / (rho_j * S_j);
1140 LibmeshPetscCall(MatSetValues(
1143 PetscScalar value_right_ct =
1144 -1.0 * alpha *
_CT *
_WijPrime(i_gap, cross_index) / (rho_i * S_i);
1147 LibmeshPetscCall(MatSetValues(
1151 PetscScalar value_center_ct =
1152 2.0 * (1.0 - alpha) *
_CT *
_WijPrime(i_gap, cross_index) / (rho_interp * S_interp);
1155 LibmeshPetscCall(MatSetValues(
1158 PetscScalar value_left_ct =
1159 -1.0 * (1.0 - alpha) *
_CT *
_WijPrime(i_gap, cross_index) / (rho_j * S_j);
1162 LibmeshPetscCall(MatSetValues(
1165 PetscScalar value_right_ct =
1166 -1.0 * (1.0 - alpha) *
_CT *
_WijPrime(i_gap, cross_index) / (rho_i * S_i);
1169 LibmeshPetscCall(MatSetValues(
1175 PetscScalar mdot_interp =
1177 auto Re = ((mdot_interp / S_interp) * Dh_i / mu_interp);
1185 ki = k_grid[i_ch][iz - 1];
1187 ki = k_grid[i_ch][iz];
1188 auto coef = (ff * dz / Dh_i + ki) * 0.5 * std::abs((*
_mdot_soln)(node_out)) /
1189 (S_interp * rho_interp);
1190 if (iz == first_node)
1192 PetscScalar value_vec = -1.0 * alpha * coef * (*_mdot_soln)(node_in);
1201 PetscScalar value = alpha * coef;
1209 PetscScalar value = (1.0 - alpha) * coef;
1214 PetscScalar value_vec =
_dir_grav * -1.0 *
_g_grav * rho_interp * dz * S_interp;
1216 LibmeshPetscCall(VecSetValues(
_amc_gravity_rhs, 1, &row_vec, &value_vec, ADD_VALUES));
1233#if !PETSC_VERSION_LESS_THAN(3, 15, 0)
1275 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
1282 LibmeshPetscCall(VecGetArray(ls, &xx));
1283 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1285 auto iz_ind = iz - first_node;
1286 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1293 auto S_in = (*_S_flow_soln)(node_in);
1294 auto S_out = (*_S_flow_soln)(node_out);
1300 auto DP = (1 / S_interp) * xx[iz_ind *
_n_channels + i_ch];
1314 LibmeshPetscCall(VecDestroy(&ls));
1322 const unsigned int last_node = (iblock + 1) *
_block_size;
1323 const unsigned int first_node = iblock *
_block_size + 1;
1328 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1331 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1342 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1345 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1353 PetscScalar Pe = 0.5;
1355 if (iz == last_node)
1362 (*
_P_soln)(node_out) + (1.0 - alpha) *
_DP(i_ch, iz) +
1363 alpha *
_DP(i_ch, iz - 1));
1374 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1376 auto iz_ind = iz - first_node;
1378 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1384 auto S_in = (*_S_flow_soln)(node_in);
1385 auto S_out = (*_S_flow_soln)(node_out);
1391 PetscScalar value = -1.0 * S_interp;
1395 if (iz == last_node)
1397 PetscScalar value = -1.0 * (*_P_soln)(node_out)*S_interp;
1405 PetscScalar value = 1.0 * S_interp;
1412 auto dp_out =
_DP(i_ch, iz);
1413 PetscScalar value_v = -1.0 * dp_out * S_interp;
1429 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksploc));
1431 LibmeshPetscCall(KSPGetPC(ksploc, &pc));
1432 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
1434 LibmeshPetscCall(KSPSetFromOptions(ksploc));
1437 LibmeshPetscCall(VecGetArray(sol, &xx));
1439 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1441 auto iz_ind = iz - first_node;
1442 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1445 PetscScalar value = xx[iz_ind *
_n_channels + i_ch];
1450 LibmeshPetscCall(KSPDestroy(&ksploc));
1451 LibmeshPetscCall(VecDestroy(&sol));
1457 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1459 auto iz_ind = iz - first_node;
1461 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1467 auto S_in = (*_S_flow_soln)(node_in);
1468 auto S_out = (*_S_flow_soln)(node_out);
1474 PetscScalar value = -1.0 * S_interp;
1478 if (iz == last_node)
1480 PetscScalar value = -1.0 * (*_P_soln)(node_out)*S_interp;
1484 auto dp_out =
_DP(i_ch, iz);
1485 PetscScalar value_v = -1.0 * dp_out / 2.0 * S_interp;
1494 PetscScalar value = 1.0 * S_interp;
1500 auto dp_in =
_DP(i_ch, iz - 1);
1501 auto dp_out =
_DP(i_ch, iz);
1503 PetscScalar value_v = -1.0 * dp_interp * S_interp;
1515 _console <<
"Block: " << iblock <<
" - Axial momentum pressure force matrix assembled"
1524 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksploc));
1526 LibmeshPetscCall(KSPGetPC(ksploc, &pc));
1527 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
1529 LibmeshPetscCall(KSPSetFromOptions(ksploc));
1532 LibmeshPetscCall(VecGetArray(sol, &xx));
1534 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1536 auto iz_ind = iz - first_node;
1537 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1540 PetscScalar value = xx[iz_ind *
_n_channels + i_ch];
1545 LibmeshPetscCall(KSPDestroy(&ksploc));
1546 LibmeshPetscCall(VecDestroy(&sol));
1555 const unsigned int last_node = (iblock + 1) *
_block_size;
1556 const unsigned int first_node = iblock *
_block_size + 1;
1557 std::vector<Real> residual;
1559 Real residual_norm_sq = 0.0;
1560 Real temperature_norm_sq = 0.0;
1561 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1563 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1566 const Real
T = (*_T_soln)(node);
1568 residual.push_back(T_from_ph -
T);
1569 residual_norm_sq += Utility::pow<2>(residual.back());
1570 temperature_norm_sq += Utility::pow<2>(
T);
1576 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1577 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1584 return std::sqrt(residual_norm_sq) / (std::sqrt(temperature_norm_sq) + 1e-14);
1590 const unsigned int last_node = (iblock + 1) *
_block_size;
1591 const unsigned int first_node = iblock *
_block_size + 1;
1594 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1600 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1602 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1613 const unsigned int last_node = (iblock + 1) *
_block_size;
1614 const unsigned int first_node = iblock *
_block_size + 1;
1617 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1623 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1625 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1636 const unsigned int last_node = (iblock + 1) *
_block_size;
1637 const unsigned int first_node = iblock *
_block_size + 1;
1642 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1645 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1648 unsigned int i_ch = chans.first;
1649 unsigned int j_ch = chans.second;
1654 auto rho_i = (*_rho_soln)(node_in_i);
1655 auto rho_j = (*_rho_soln)(node_in_j);
1656 auto Si = (*_S_flow_soln)(node_in_i);
1657 auto Sj = (*_S_flow_soln)(node_in_j);
1661 auto friction_term =
_kij *
_Wij(i_gap, iz) * std::abs(
_Wij(i_gap, iz));
1662 auto DPij = (*_P_soln)(node_in_i) - (*
_P_soln)(node_in_j);
1664 auto rho_star = 0.0;
1665 if (
_Wij(i_gap, iz) > 0.0)
1667 else if (
_Wij(i_gap, iz) < 0.0)
1670 rho_star = (rho_i + rho_j) / 2.0;
1671 auto mass_term_out =
1675 (*_mdot_soln)(node_in_i) / Si / rho_i + (*
_mdot_soln)(node_in_j) / Sj / rho_j;
1676 auto term_out = Sij * rho_star * (Lij / dz) * mass_term_out *
_Wij(i_gap, iz);
1677 auto term_in = Sij * rho_star * (Lij / dz) * mass_term_in *
_Wij(i_gap, iz - 1);
1678 auto inertia_term = term_out - term_in;
1679 auto pressure_term = 2 * Utility::pow<2>(Sij) * DPij * rho_star;
1684 time_term + friction_term + inertia_term - pressure_term;
1702 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1705 auto iz_ind = iz - first_node;
1706 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1709 unsigned int i_ch = chans.first;
1710 unsigned int j_ch = chans.second;
1717 auto rho_i_in = (*_rho_soln)(node_in_i);
1718 auto rho_i_out = (*_rho_soln)(node_out_i);
1720 auto rho_j_in = (*_rho_soln)(node_in_j);
1721 auto rho_j_out = (*_rho_soln)(node_out_j);
1725 auto S_i_in = (*_S_flow_soln)(node_in_i);
1726 auto S_i_out = (*_S_flow_soln)(node_out_i);
1727 auto S_j_in = (*_S_flow_soln)(node_in_j);
1728 auto S_j_out = (*_S_flow_soln)(node_out_j);
1735 auto rho_star = 0.0;
1736 if (
_Wij(i_gap, iz) > 0.0)
1737 rho_star = rho_i_interp;
1738 else if (
_Wij(i_gap, iz) < 0.0)
1739 rho_star = rho_j_interp;
1741 rho_star = (rho_i_interp + rho_j_interp) / 2.0;
1744 PetscScalar time_factor =
_TR * Lij * Sij * rho_star /
_dt;
1745 PetscInt row_td = i_gap +
_n_gaps * iz_ind;
1746 PetscInt col_td = i_gap +
_n_gaps * iz_ind;
1747 PetscScalar value_td = time_factor;
1748 LibmeshPetscCall(MatSetValues(
1750 PetscScalar value_td_rhs = time_factor *
_Wij_old(i_gap, iz);
1755 PetscScalar Pe = 0.5;
1757 auto mass_term_out = (*_mdot_soln)(node_out_i) / S_i_out / rho_i_out +
1758 (*
_mdot_soln)(node_out_j) / S_j_out / rho_j_out;
1759 auto mass_term_in = (*_mdot_soln)(node_in_i) / S_i_in / rho_i_in +
1760 (*
_mdot_soln)(node_in_j) / S_j_in / rho_j_in;
1761 auto term_out = Sij * rho_star * (Lij / dz) * mass_term_out / 2.0;
1762 auto term_in = Sij * rho_star * (Lij / dz) * mass_term_in / 2.0;
1763 if (iz == first_node)
1765 PetscInt row_ad = i_gap +
_n_gaps * iz_ind;
1766 PetscScalar value_ad = term_in * alpha *
_Wij(i_gap, iz - 1);
1770 PetscInt col_ad = i_gap +
_n_gaps * iz_ind;
1771 value_ad = -1.0 * term_in * (1.0 - alpha) + term_out * alpha;
1772 LibmeshPetscCall(MatSetValues(
1775 col_ad = i_gap +
_n_gaps * (iz_ind + 1);
1776 value_ad = term_out * (1.0 - alpha);
1777 LibmeshPetscCall(MatSetValues(
1780 else if (iz == last_node)
1782 PetscInt row_ad = i_gap +
_n_gaps * iz_ind;
1783 PetscInt col_ad = i_gap +
_n_gaps * (iz_ind - 1);
1784 PetscScalar value_ad = -1.0 * term_in * alpha;
1785 LibmeshPetscCall(MatSetValues(
1788 col_ad = i_gap +
_n_gaps * iz_ind;
1789 value_ad = -1.0 * term_in * (1.0 - alpha) + term_out * alpha;
1790 LibmeshPetscCall(MatSetValues(
1793 value_ad = -1.0 * term_out * (1.0 - alpha) *
_Wij(i_gap, iz);
1799 PetscInt row_ad = i_gap +
_n_gaps * iz_ind;
1800 PetscInt col_ad = i_gap +
_n_gaps * (iz_ind - 1);
1801 PetscScalar value_ad = -1.0 * term_in * alpha;
1802 LibmeshPetscCall(MatSetValues(
1805 col_ad = i_gap +
_n_gaps * iz_ind;
1806 value_ad = -1.0 * term_in * (1.0 - alpha) + term_out * alpha;
1807 LibmeshPetscCall(MatSetValues(
1810 col_ad = i_gap +
_n_gaps * (iz_ind + 1);
1811 value_ad = term_out * (1.0 - alpha);
1812 LibmeshPetscCall(MatSetValues(
1816 PetscInt row_ff = i_gap +
_n_gaps * iz_ind;
1817 PetscInt col_ff = i_gap +
_n_gaps * iz_ind;
1818 PetscScalar value_ff =
_kij * std::abs(
_Wij(i_gap, iz)) / 2.0;
1819 LibmeshPetscCall(MatSetValues(
1827 PetscScalar pressure_factor = Utility::pow<2>(Sij) * rho_star;
1828 PetscInt row_pf = i_gap +
_n_gaps * iz_ind;
1830 PetscScalar value_pf = -1.0 * alpha * pressure_factor;
1834 value_pf = alpha * pressure_factor;
1838 if (iz == last_node)
1840 PetscInt row_pf = i_gap +
_n_gaps * iz_ind;
1841 PetscScalar value_pf = (1.0 - alpha) * pressure_factor * (*
_P_soln)(node_out_i);
1844 value_pf = -1.0 * (1.0 - alpha) * pressure_factor * (*
_P_soln)(node_out_j);
1850 row_pf = i_gap +
_n_gaps * iz_ind;
1852 value_pf = -1.0 * (1.0 - alpha) * pressure_factor;
1853 LibmeshPetscCall(MatSetValues(
1856 value_pf = (1.0 - alpha) * pressure_factor;
1857 LibmeshPetscCall(MatSetValues(
1863 PetscScalar pressure_factor = Utility::pow<2>(Sij) * rho_star;
1864 PetscInt row_pf = i_gap +
_n_gaps * iz_ind;
1866 PetscScalar value_pf = -1.0 * pressure_factor;
1870 value_pf = pressure_factor;
1890#if !PETSC_VERSION_LESS_THAN(3, 15, 0)
1927 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
1935 LibmeshPetscCall(VecAXPY(sol_holder_W, 1.0, sol_holder_P));
1937 LibmeshPetscCall(VecGetArray(sol_holder_W, &xx));
1938 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1940 auto iz_ind = iz - first_node;
1941 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1946 LibmeshPetscCall(VecDestroy(&sol_holder_P));
1947 LibmeshPetscCall(VecDestroy(&sol_holder_W));
1955 const unsigned int last_node = (iblock + 1) *
_block_size;
1956 const unsigned int first_node = iblock *
_block_size + 1;
1958 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1961 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1964 unsigned int i_ch = chans.first;
1965 unsigned int j_ch = chans.second;
1970 auto Si_in = (*_S_flow_soln)(node_in_i);
1971 auto Sj_in = (*_S_flow_soln)(node_in_j);
1972 auto Si_out = (*_S_flow_soln)(node_out_i);
1973 auto Sj_out = (*_S_flow_soln)(node_out_j);
1975 auto Sij = dz * gap;
1981 0.5 * (((*_mdot_soln)(node_in_i) + (*
_mdot_soln)(node_in_j)) / (Si_in + Sj_in) +
1987 _WijPrime(i_gap, iz) = beta * avg_massflux * Sij;
1991 auto iz_ind = iz - first_node;
1992 PetscScalar base_value = beta * 0.5 * Sij;
1995 if (iz == first_node)
1997 PetscScalar value_tl = -1.0 * base_value / (Si_in + Sj_in) *
1999 PetscInt row = i_gap +
_n_gaps * iz_ind;
2005 PetscScalar value_tl = base_value / (Si_in + Sj_in);
2006 PetscInt row = i_gap +
_n_gaps * iz_ind;
2008 PetscInt col_ich = i_ch +
_n_channels * (iz_ind - 1);
2009 LibmeshPetscCall(MatSetValues(
2012 PetscInt col_jch = j_ch +
_n_channels * (iz_ind - 1);
2013 LibmeshPetscCall(MatSetValues(
2018 PetscScalar value_bl = base_value / (Si_out + Sj_out);
2019 PetscInt row = i_gap +
_n_gaps * iz_ind;
2022 LibmeshPetscCall(MatSetValues(
2026 LibmeshPetscCall(MatSetValues(
2041 LibmeshPetscCall(VecDuplicate(
_Wij_vec, &loc_Wij));
2042 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
2048 LibmeshPetscCall(VecDestroy(&loc_prod));
2049 LibmeshPetscCall(VecDestroy(&loc_Wij));
2057 if (!std::isfinite(beta) || beta < 0.0)
2059 ": Mixing closure returned invalid beta = ",
2065 ". Beta must be finite and non-negative.");
2074 if (!std::isfinite(beta) || beta < 0.0)
2076 ": Mixing closure returned invalid sweep-flow coefficient = ",
2082 ". sweep-flow coefficient must be finite and non-negative.");
2090 const unsigned int last_node = (iblock + 1) *
_block_size;
2091 const unsigned int first_node = iblock *
_block_size + 1;
2095 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
2097 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
2099 _Wij(i_gap, iz) = solution(i);
2120 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
2126 return Wij_residual_vector;
2141 LibmeshPetscCall(SNESCreate(PETSC_COMM_SELF, &snes));
2142 LibmeshPetscCall(VecCreate(PETSC_COMM_SELF, &
x));
2144 LibmeshPetscCall(VecSetFromOptions(
x));
2145 LibmeshPetscCall(VecDuplicate(
x, &r));
2147#if PETSC_VERSION_LESS_THAN(3, 13, 0)
2148 LibmeshPetscCall(PetscOptionsSetValue(PETSC_NULL,
"-snes_mf", PETSC_NULL));
2150 LibmeshPetscCall(SNESSetUseMatrixFree(snes, PETSC_FALSE, PETSC_TRUE));
2153 ctx.iblock = iblock;
2155 LibmeshPetscCall(SNESSetFunction(snes, r,
formFunction, &ctx));
2156 LibmeshPetscCall(SNESGetKSP(snes, &ksp));
2157 LibmeshPetscCall(KSPGetPC(ksp, &pc));
2158 LibmeshPetscCall(PCSetType(pc, PCNONE));
2160 LibmeshPetscCall(SNESSetFromOptions(snes));
2161 LibmeshPetscCall(VecGetArray(
x, &xx));
2164 xx[i] = solution(i);
2166 LibmeshPetscCall(VecRestoreArray(
x, &xx));
2168 LibmeshPetscCall(SNESSolve(snes, NULL,
x));
2169 LibmeshPetscCall(VecGetArray(
x, &xx));
2173 LibmeshPetscCall(VecRestoreArray(
x, &xx));
2174 LibmeshPetscCall(VecDestroy(&
x));
2175 LibmeshPetscCall(VecDestroy(&r));
2176 LibmeshPetscCall(SNESDestroy(&snes));
2177 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
2182 Mat
A, Vec rhs,
unsigned int first_node,
unsigned int last_node,
const char * ksp_prefix)
2188 LibmeshPetscCall(VecDuplicate(rhs, &
x));
2193 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksp));
2194 LibmeshPetscCall(KSPSetOperators(ksp,
A,
A));
2195 LibmeshPetscCall(KSPGetPC(ksp, &pc));
2196 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
2198 if (ksp_prefix && *ksp_prefix)
2199 LibmeshPetscCall(KSPSetOptionsPrefix(ksp, ksp_prefix));
2200 LibmeshPetscCall(KSPSetFromOptions(ksp));
2203 LibmeshPetscCall(KSPSolve(ksp, rhs,
x));
2204 KSPConvergedReason reason;
2205 LibmeshPetscCall(KSPGetConvergedReason(ksp, &reason));
2208 PetscInt iterations;
2209 PetscReal residual_norm;
2210 LibmeshPetscCall(KSPGetIterationNumber(ksp, &iterations));
2211 LibmeshPetscCall(KSPGetResidualNorm(ksp, &residual_norm));
2213 ": enthalpy linear solve failed: ",
2214 KSPConvergedReasons[reason],
2216 static_cast<int>(reason),
2219 " iterations; residual norm = ",
2225 PetscScalar * xx =
nullptr;
2226 LibmeshPetscCall(VecGetArray(
x, &xx));
2227 for (
unsigned int iz = first_node; iz <= last_node; ++iz)
2229 const unsigned int iz_ind = iz - first_node;
2230 for (
unsigned int i_ch = 0; i_ch <
_n_channels; ++i_ch)
2233 const PetscScalar h_out = xx[iz_ind *
_n_channels + i_ch];
2236 name(),
" : Calculation of negative Enthalpy h_out = ", h_out,
" Axial Level = ", iz);
2237 _h_soln->set(node_out, h_out);
2240 LibmeshPetscCall(VecRestoreArray(
x, &xx));
2243 LibmeshPetscCall(KSPDestroy(&ksp));
2244 LibmeshPetscCall(VecDestroy(&
x));
2246 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
2252 mooseAssert(iz > 0,
"Trapezoidal rule requires starting at index 1 at least");
2263 auto heat_rate_in = (*_duct_heat_flux_soln)(node_in_duct);
2264 auto heat_rate_out = (*_duct_heat_flux_soln)(node_out_duct);
2266 return 0.5 * (heat_rate_in + heat_rate_out) * dz * width;
2284 auto V = [&](
const std::string & s)
2290 auto DupMatAssembled = [&](Mat src, Mat * dst)
2294 LibmeshPetscCall(MatDuplicate(src, MAT_COPY_VALUES, dst));
2295 LibmeshPetscCall(MatAssemblyBegin(*dst, MAT_FINAL_ASSEMBLY));
2296 LibmeshPetscCall(MatAssemblyEnd(*dst, MAT_FINAL_ASSEMBLY));
2302 auto DupVecCopy = [&](Vec src, Vec * dst)
2304 LibmeshPetscCall(VecDuplicate(src, dst));
2305 LibmeshPetscCall(VecCopy(src, *dst));
2308 const PetscInt Q = 3;
2311 auto Idx = [&](PetscInt r, PetscInt
c) {
return Q * r +
c; };
2314 std::vector<Mat> mat_array(Q * Q, NULL);
2315 std::vector<Vec> vec_array(Q, NULL);
2318 auto AssembleEquation = [&](PetscInt
f,
2326 DupMatAssembled(
A0, &mat_array[Idx(
f, 0)]);
2327 DupMatAssembled(
A1, &mat_array[Idx(
f, 1)]);
2328 DupMatAssembled(
A2, &mat_array[Idx(
f, 2)]);
2329 DupVecCopy(rhs, &vec_array[
f]);
2331 LibmeshPetscCall(VecAXPY(vec_array[
f], 1.0, rhs_add));
2332 V(std::string(label) +
" system assembled");
2351 auto relaxEquation =
2352 [&](Mat diagonal_block, Vec rhs, Vec work,
const Real relaxation,
auto && populate)
2354 if (relaxation == 1.0)
2357 Vec diagonal =
nullptr;
2358 LibmeshPetscCall(VecDuplicate(rhs, &diagonal));
2361 LibmeshPetscCall(MatGetDiagonal(diagonal_block, diagonal));
2362 LibmeshPetscCall(VecScale(diagonal, 1.0 / relaxation));
2363 LibmeshPetscCall(MatDiagonalSet(diagonal_block, diagonal, INSERT_VALUES));
2366 LibmeshPetscCall(populate(work));
2369 LibmeshPetscCall(VecScale(diagonal, 1.0 - relaxation));
2370 LibmeshPetscCall(VecPointwiseMult(work, work, diagonal));
2371 LibmeshPetscCall(VecAXPY(rhs, 1.0, work));
2373 LibmeshPetscCall(VecDestroy(&diagonal));
2377 const unsigned int first_node = iblock *
_block_size + 1;
2378 const unsigned int last_node = (iblock + 1) *
_block_size;
2388 V(
"Starting nested system.");
2421 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
2432 LibmeshPetscCall(VecSet(unity_vec, 1.0));
2437 LibmeshPetscCall(VecSet(unity_vec_Wij, 1.0));
2440 Vec _Wij_old_loc_vec;
2445 LibmeshPetscCall(MatMult(mat_array[Q ],
_prod, mdot_estimate));
2448 LibmeshPetscCall(MatGetDiagonal(mat_array[Q + 1], pmat_diag));
2449 LibmeshPetscCall(VecAXPY(pmat_diag, 1e-10, unity_vec));
2450 LibmeshPetscCall(VecPointwiseDivide(p_estimate, mdot_estimate, pmat_diag));
2453 LibmeshPetscCall(MatMult(mat_array[2 * Q + 1], p_estimate, sol_holder_P));
2459 for (
unsigned int iz = first_node; iz <= last_node; ++iz)
2461 const auto iz_ind = iz - first_node;
2462 for (
unsigned int i_ch = 0; i_ch <
_n_channels; ++i_ch)
2464 PetscScalar sumWij = 0.0;
2465 unsigned int counter = 0;
2468 PetscInt row_vec = i_gap +
_n_gaps * iz_ind;
2469 PetscScalar loc_Wij_value;
2470 LibmeshPetscCall(VecGetValues(sol_holder_P, 1, &row_vec, &loc_Wij_value));
2475 LibmeshPetscCall(VecSetValues(sumWij_loc, 1, &row_vec, &sumWij, INSERT_VALUES));
2478 LibmeshPetscCall(VecAssemblyBegin(sumWij_loc));
2479 LibmeshPetscCall(VecAssemblyEnd(sumWij_loc));
2482 PetscScalar min_mdot, sum_mdot, avg_mdot;
2484 LibmeshPetscCall(VecAbs(
_prod));
2485 LibmeshPetscCall(VecMin(
_prod, NULL, &min_mdot));
2486 LibmeshPetscCall(VecSum(
_prod, &sum_mdot));
2487 LibmeshPetscCall(VecGetSize(
_prod, &n));
2488 avg_mdot = sum_mdot /
static_cast<PetscScalar
>(n);
2490 V(
"Average estimated mdot: " + std::to_string(avg_mdot));
2491 V(
"Minimum estimated mdot: " + std::to_string(min_mdot));
2493 LibmeshPetscCall(VecAbs(sumWij_loc));
2494 LibmeshPetscCall(VecMax(sumWij_loc, NULL, &
_max_sumWij));
2496 V(
"Maximum estimated Wij: " + std::to_string(
_max_sumWij));
2499 _Wij_loc_vec,
_Wij, first_node, last_node,
_n_gaps));
2500 LibmeshPetscCall(VecAbs(_Wij_loc_vec));
2503 LibmeshPetscCall(VecAbs(_Wij_old_loc_vec));
2504 LibmeshPetscCall(VecAXPY(_Wij_loc_vec, -1.0, _Wij_old_loc_vec));
2506 PetscScalar relax_factor;
2507 LibmeshPetscCall(VecAbs(_Wij_loc_vec));
2508#if !PETSC_VERSION_LESS_THAN(3, 16, 0)
2509 LibmeshPetscCall(VecMean(_Wij_loc_vec, &relax_factor));
2511 VecSum(_Wij_loc_vec, &relax_factor);
2515 V(
"Relax base value: " + std::to_string(relax_factor));
2518 const PetscScalar resistance_relaxation = 0.9;
2520 V(
"New cross resistance: " + std::to_string(
_added_K));
2523 V(
"Relaxed cross resistance: " + std::to_string(
_added_K));
2526 if (_added_K < 10 && _added_K >= 1.0)
2528 if (_added_K < 1.0 && _added_K >= 0.1)
2530 if (_added_K < 0.1 && _added_K >= 0.01)
2532 if (_added_K < 1e-2 && _added_K >= 1e-3)
2534 V(
"Actual added cross resistance: " + std::to_string(
_added_K));
2535 LibmeshPetscCall(VecScale(unity_vec_Wij,
_added_K));
2538 LibmeshPetscCall(MatDiagonalSet(mat_array[2 * Q + 2], unity_vec_Wij, ADD_VALUES));
2541 LibmeshPetscCall(VecDestroy(&mdot_estimate));
2542 LibmeshPetscCall(VecDestroy(&pmat_diag));
2543 LibmeshPetscCall(VecDestroy(&unity_vec));
2544 LibmeshPetscCall(VecDestroy(&p_estimate));
2545 LibmeshPetscCall(VecDestroy(&sol_holder_P));
2546 LibmeshPetscCall(VecDestroy(&unity_vec_Wij));
2547 LibmeshPetscCall(VecDestroy(&sumWij_loc));
2548 LibmeshPetscCall(VecDestroy(&_Wij_loc_vec));
2549 LibmeshPetscCall(VecDestroy(&_Wij_old_loc_vec));
2556 relaxEquation(mat_array[Idx(0, 0)],
2562 return populateVectorFromHandle<SolutionHandle>(
2567 relaxEquation(mat_array[Idx(1, 1)],
2575 return populateVectorFromHandle<SolutionHandle>(
2580 relaxEquation(mat_array[Idx(2, 2)],
2586 return populateVectorFromDense<libMesh::DenseMatrix<Real>>(
2590 V(
"Linear solver relaxed");
2596 LibmeshPetscCall(MatCreateNest(PETSC_COMM_SELF, Q, NULL, Q, NULL, mat_array.data(), &A_nest));
2597 LibmeshPetscCall(VecCreateNest(PETSC_COMM_SELF, Q, NULL, vec_array.data(), &b_nest));
2598 V(
"Nested system created");
2602 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksp));
2603 LibmeshPetscCall(KSPSetOptionsPrefix(ksp,
"scm_coupled_"));
2604 LibmeshPetscCall(KSPSetType(ksp, KSPFGMRES));
2605 LibmeshPetscCall(KSPSetOperators(ksp, A_nest, A_nest));
2606 LibmeshPetscCall(KSPGetPC(ksp, &pc));
2607 LibmeshPetscCall(PCSetType(pc, PCFIELDSPLIT));
2611 std::vector<IS> rows(Q);
2612 LibmeshPetscCall(MatNestGetISs(A_nest, rows.data(), NULL));
2613 for (PetscInt j = 0; j < Q; ++j)
2616 LibmeshPetscCall(ISDuplicate(rows[j], &part));
2617 LibmeshPetscCall(PCFieldSplitSetIS(pc, NULL, part));
2618 LibmeshPetscCall(ISDestroy(&part));
2620 LibmeshPetscCall(KSPSetFromOptions(ksp));
2621 V(
"Linear solver assembled");
2624 LibmeshPetscCall(VecDuplicate(b_nest, &x_nest));
2625 LibmeshPetscCall(VecSet(x_nest, 0.0));
2626 LibmeshPetscCall(KSPSolve(ksp, b_nest, x_nest));
2627 KSPConvergedReason reason;
2628 LibmeshPetscCall(KSPGetConvergedReason(ksp, &reason));
2631 PetscInt iterations;
2632 PetscReal residual_norm;
2633 LibmeshPetscCall(KSPGetIterationNumber(ksp, &iterations));
2634 LibmeshPetscCall(KSPGetResidualNorm(ksp, &residual_norm));
2636 ": coupled mass/momentum linear solve failed: ",
2637 KSPConvergedReasons[reason],
2639 static_cast<int>(reason),
2642 " iterations; residual norm = ",
2648 LibmeshPetscCall(VecDestroy(&b_nest));
2649 LibmeshPetscCall(MatDestroy(&A_nest));
2650 LibmeshPetscCall(KSPDestroy(&ksp));
2651 for (PetscInt i = 0; i < Q * Q; i++)
2652 LibmeshPetscCall(MatDestroy(&mat_array[i]));
2653 for (PetscInt i = 0; i < Q; i++)
2654 LibmeshPetscCall(VecDestroy(&vec_array[i]));
2655 V(
"Solver elements destroyed");
2658 Vec sol_mdot, sol_p, sol_Wij;
2659 V(
"Vectors to hold solution created");
2662 LibmeshPetscCall(VecNestGetSubVecs(x_nest, &num_vecs, &loc_vecs));
2664 LibmeshPetscCall(VecCopy(loc_vecs[0], sol_mdot));
2666 LibmeshPetscCall(VecCopy(loc_vecs[1], sol_p));
2668 LibmeshPetscCall(VecCopy(loc_vecs[2], sol_Wij));
2669 V(
"Solution from coupled solver copied to solution vectors");
2672 auto relaxSolution = [&](Vec solution, Vec old_solution,
const Real relaxation)
2674 LibmeshPetscCall(VecScale(solution, relaxation));
2675 LibmeshPetscCall(VecAXPY(solution, 1.0 - relaxation, old_solution));
2677 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
2679 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
2684 Vec pressure_residual;
2685 LibmeshPetscCall(VecDuplicate(sol_p, &pressure_residual));
2686 LibmeshPetscCall(VecCopy(sol_p, pressure_residual));
2687 LibmeshPetscCall(VecAXPY(pressure_residual, -1.0,
_prodp));
2689 const PetscScalar * residual_array;
2690 const PetscScalar * old_pressure_array;
2691 PetscInt pressure_size;
2692 LibmeshPetscCall(VecGetSize(pressure_residual, &pressure_size));
2693 LibmeshPetscCall(VecGetArrayRead(pressure_residual, &residual_array));
2694 LibmeshPetscCall(VecGetArrayRead(
_prodp, &old_pressure_array));
2695 Real residual_norm_sq = 0.0;
2696 Real pressure_norm_sq = 0.0;
2697 for (PetscInt i = 0; i < pressure_size; ++i)
2699 residual_norm_sq += Utility::pow<2>(residual_array[i]);
2700 pressure_norm_sq += Utility::pow<2>(old_pressure_array[i] +
_P_out);
2702 LibmeshPetscCall(VecRestoreArrayRead(pressure_residual, &residual_array));
2703 LibmeshPetscCall(VecRestoreArrayRead(
_prodp, &old_pressure_array));
2704 LibmeshPetscCall(VecDestroy(&pressure_residual));
2707 std::sqrt(residual_norm_sq) / (std::sqrt(pressure_norm_sq) + 1e-14));
2716 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
2721 PetscScalar * sol_p_array;
2722 LibmeshPetscCall(VecGetArray(sol_p, &sol_p_array));
2723 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
2725 const auto iz_ind = iz - first_node;
2726 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
2729 PetscScalar value = sol_p_array[iz_ind *
_n_channels + i_ch];
2733 LibmeshPetscCall(VecRestoreArray(sol_p, &sol_p_array));
2741 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
2744 LibmeshPetscCall(VecAbs(
_prod));
2749 V(
"Solutions assigned to MOOSE variables.");
2752 LibmeshPetscCall(VecDestroy(&x_nest));
2753 LibmeshPetscCall(VecDestroy(&sol_mdot));
2754 LibmeshPetscCall(VecDestroy(&sol_p));
2755 LibmeshPetscCall(VecDestroy(&sol_Wij));
2756 V(
"Solutions destroyed.");
2758 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
2764 _console <<
"Executing subchannel solver\n";
2775 for (
const auto * ti :
transient->getTimeIntegrators())
2777 mooseWarning(
"The subchannel solver always uses implicit (backward) Euler time "
2778 "integration; the requested '",
2780 "' time integrator is ignored.");
2787 auto V = [&](
const std::string & s)
2793 const unsigned int first_node,
2794 const unsigned int last_node)
2796 std::vector<Real>
values;
2798 for (
unsigned int iz = first_node; iz <= last_node; ++iz)
2799 for (
unsigned int i_ch = 0; i_ch <
_n_channels; ++i_ch)
2804 const std::vector<Real> & old_values,
2805 const unsigned int first_node,
2806 const unsigned int last_node,
2807 const Real reference_offset)
2809 Real difference_norm_sq = 0.0;
2810 Real reference_norm_sq = 0.0;
2812 for (
unsigned int iz = first_node; iz <= last_node; ++iz)
2813 for (
unsigned int i_ch = 0; i_ch <
_n_channels; ++i_ch)
2816 difference_norm_sq += Utility::pow<2>(value - old_values[i]);
2817 reference_norm_sq += Utility::pow<2>(old_values[i] + reference_offset);
2820 return std::sqrt(difference_norm_sq) / (std::sqrt(reference_norm_sq) + 1e-14);
2822 V(
"Solution initialized");
2824 unsigned int P_it = 0;
2825 unsigned int P_it_max;
2826 bool temperature_converged =
true;
2839 while ((P_error >
_P_tol && P_it < P_it_max))
2842 temperature_converged =
true;
2844 _console <<
"Solving Outer Iteration : " << P_it << std::endl;
2846 for (
unsigned int iblock = 0; iblock <
_n_blocks; iblock++)
2850 Real T_block_error = 1.0;
2852 _console <<
"Solving Block: " << iblock <<
" From first level: " << first_level
2853 <<
" to last level: " << last_level << std::endl;
2865 V(
"Done with main solve.");
2873 if (T_block_error <= _T_tol || T_it >=
_T_maxit)
2876 V(
"Enthalpy subcycle: " + std::to_string(enthalpy_subcycle + 1));
2878 const auto T_old = saveValues(*
_T_soln, first_level, last_level);
2883 T_block_error = 0.0;
2891 V(
"Done with thermal solve.");
2894 V(
"Start updating thermophysical properties.");
2899 V(
"Done updating thermophysical properties.");
2904 _aux->solution().close();
2908 relativeChange(*
_T_soln, T_old, first_level, last_level, 0.0);
2909 _console <<
"T_block_error: " << T_block_error << std::endl;
2915 const bool block_converged = T_block_error <=
_T_tol;
2916 temperature_converged &= block_converged;
2917 if (!block_converged)
2919 _console <<
"Reached maximum number of temperature iterations for block: " << iblock
2926 _console <<
"P_error :" << P_error << std::endl;
2927 V(
"Iteration: " + std::to_string(P_it));
2928 V(
"Maximum iterations: " + std::to_string(P_it_max));
2932 const bool pressure_converged = P_error <=
_P_tol;
2933 if (!pressure_converged)
2935 _console <<
"Reached maximum number of axial pressure iterations" << std::endl;
2937 _converged = pressure_converged && temperature_converged;
2940 _console <<
"Finished executing subchannel solver\n";
2943 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
2953 for (
unsigned int iz = 0; iz <
_n_cells + 1; ++iz)
2955 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
2958 auto mu = (*_mu_soln)(node);
2959 auto S = (*_S_flow_soln)(node);
2960 auto w_perim = (*_w_perim_soln)(node);
2961 auto Dh_i = 4.0 * S / w_perim;
2962 auto Re = (((*_mdot_soln)(node) / S) * Dh_i /
mu);
2965 auto Pr = (*_mu_soln)(node)*cp / k;
2985 _console <<
"Commencing calculation of Pin surface temperature \n";
2986 for (
unsigned int i_pin = 0; i_pin <
_n_pins; i_pin++)
2988 for (
unsigned int iz = 0; iz <
_n_cells + 1; ++iz)
2996 auto mu = (*_mu_soln)(node);
2997 auto S = (*_S_flow_soln)(node);
2998 auto w_perim = (*_w_perim_soln)(node);
2999 auto Dh_i = 4.0 * S / w_perim;
3000 auto Re = (((*_mdot_soln)(node) / S) * Dh_i /
mu);
3003 auto Pr = (*_mu_soln)(node)*cp / k;
3012 (*_q_prime_soln)(pin_node) / ((*
_Dpin_soln)(pin_node)*M_PI * hw) + (*_T_soln)(node);
3017 mooseError(
"Pin was not found for pin index: " + std::to_string(i_pin));
3025 _console <<
"Commencing calculation of duct surface temperature " << std::endl;
3027 for (Node * dn : duct_nodes)
3030 auto mu = (*_mu_soln)(node_chan);
3031 auto S = (*_S_flow_soln)(node_chan);
3032 auto w_perim = (*_w_perim_soln)(node_chan);
3033 auto Dh_i = 4.0 * S / w_perim;
3034 auto Re = (((*_mdot_soln)(node_chan) / S) * Dh_i /
mu);
3037 auto Pr = (*_mu_soln)(node_chan)*cp / k;
3054 auto T_chan = (*_duct_heat_flux_soln)(dn) / hw + (*
_T_soln)(node_chan);
3058 _aux->solution().close();
3066 Real power_in = 0.0;
3067 Real power_out = 0.0;
3068 Real mass_flow_in = 0.0;
3069 Real mass_flow_out = 0.0;
3070 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
3074 const Real mdot_in = (*_mdot_soln)(node_in);
3075 power_in += mdot_in * (*_h_soln)(node_in);
3076 power_out += (*_mdot_soln)(node_out) * (*
_h_soln)(node_out);
3077 mass_flow_in += mdot_in;
3078 mass_flow_out += (*_mdot_soln)(node_out);
3080 auto h_bulk_out = power_out / mass_flow_out;
3081 auto T_bulk_out =
_fp->T_from_p_h(
_P_out, h_bulk_out);
3086 _console <<
" ======================================= " << std::endl;
3087 _console <<
" ======== Subchannel Print Outs ======== " << std::endl;
3088 _console <<
" ======================================= " << std::endl;
3091 _console <<
"Assembly hydraulic diameter :" << bulk_Dh <<
" m" << std::endl;
3093 _console <<
"Bulk coolant temperature at outlet :" << T_bulk_out <<
" K" << std::endl;
3094 _console <<
"Power added to coolant is : " << power_out - power_in <<
" Watt" << std::endl;
3095 _console <<
"Mass flow rate in is : " << mass_flow_in <<
" kg/sec" << std::endl;
3096 _console <<
"Mass balance is : " << mass_flow_out - mass_flow_in <<
" kg/sec" << std::endl;
3097 _console <<
"User defined outlet pressure is : " <<
_P_out <<
" Pa" << std::endl;
3098 _console <<
" ======================================= " << std::endl;
3101 if (MooseUtils::absoluteFuzzyLessEqual((power_out - power_in), -1.0))
3103 "Energy conservation equation might not be solved correctly, Power added to coolant: " +
3104 std::to_string(power_out - power_in) +
" Watt ");
Real f(Real x)
Test function for Brents method.
const std::vector< double > x
std::array< Real, 2 > values
PetscErrorCode formFunction(SNES, Vec x, Vec f, void *ctx)
void ErrorVector unsigned int
const ConsoleStream _console
static InputParameters validParams()
std::shared_ptr< AuxiliarySystem > _aux
virtual Real & dt() const
virtual const MooseVariableFieldBase & getVariable(const THREAD_ID tid, const std::string &var_name, Moose::VarKindType expected_var_type=Moose::VarKindType::VAR_ANY, Moose::VarFieldType expected_var_field_type=Moose::VarFieldType::VAR_FIELD_ANY) const override
virtual void transient(bool trans)
virtual bool isTransient() const override
void initialSetup() override
bool isRestarting() const
Executioner * getExecutioner() const
bool isRecovering() const
const std::string & name() const
void paramError(const std::string ¶m, Args... args) const
void mooseError(Args &&... args) const
void mooseWarning(Args &&... args) const
bool isParamValid(const std::string &name) const
static InputParameters validParams()
virtual Real computeFrictionFactor(const FrictionStruct &friction_info) const =0
Computes the friction factor for the local conditions.
Real computeHTC(const FrictionStruct &friction_info, const NusseltStruct &nusselt_info, const Real conduction_k) const
Computes the convective heat transfer coefficient for the local conditions.
virtual void computeBulkMixingParameters() const
Precomputes the mixing coefficients that depend only on the bulk flow.
virtual Real computeSweepFlowMixingParameter(const unsigned int i_gap, const unsigned int iz) const
Computes the wire-wrap sweep-flow coefficient for peripheral gaps.
virtual void computeBlockMixingParameters(const unsigned int, const unsigned int) const
Precomputes the mixing coefficients that depend on the flow solution of the axial levels first_node t...
virtual Real getCT() const
Return the Turbulent modeling parameter.
virtual Real computeMixingParameter(const unsigned int i_gap, const unsigned int iz) const =0
Computes the turbulent mixing coefficient for the local conditions around gap(i_gap) and axial level(...
Provide a simple RAII interface for linear lagrange solution variables.
Base class for the 1-phase steady-state/transient subchannel solver.
libMesh::DenseMatrix< Real > _DP
void computeP(int iblock)
Computes Pressure per channel for block iblock.
Mat _hc_sys_h_mat
System matrices.
const Real & _mass_flow_equation_relaxation
Equation relaxation factor for mass flow rate in the coupled implicit solve.
PetscScalar _correction_factor
Vec _mc_axial_convection_rhs
const Real & _pressure_equation_relaxation
Equation relaxation factor for pressure in the coupled implicit solve.
PetscErrorCode createPetscVector(Vec &v, PetscInt n)
Petsc Functions.
virtual void syncSolutions(Direction direction) override
const bool _segregated_bool
Segregated solve.
PetscScalar computeInterpolatedValue(PetscScalar topValue, PetscScalar botValue, PetscScalar Peclet=0.0)
const SCMMixingClosureBase * _mixing_closure
Turbulent Mixing closure object.
Real computeSweepFlowMixingParameter(unsigned int i_gap, unsigned int iz) const
Computes and validates the sweep-flow mixing parameter.
virtual ~SubChannel1PhaseProblem()
const SCMHTCClosureBase * _pin_HTC_closure
HTC closure objects.
const SCMHTCClosureBase * _duct_HTC_closure
SubChannel1PhaseProblem(const InputParameters ¶ms)
Mat _cmc_friction_force_mat
Cross momentum conservation - friction force.
std::unique_ptr< SolutionHandle > _w_perim_soln
PetscErrorCode petscSnesSolver(int iblock, const libMesh::DenseVector< Real > &solution, libMesh::DenseVector< Real > &root)
Computes solution of nonlinear equation using snes and provided a residual in a formFunction.
const PetscReal & _dtol
The divergence tolerance for the ksp linear solver.
PetscErrorCode createPetscMatrix(Mat &M, PetscInt n, PetscInt m)
virtual void initializeSolution()=0
Function to initialize the solution & geometry fields.
std::unique_ptr< SolutionHandle > _displacement_soln
Mat _hc_time_derivative_mat
Enthalpy Enthalpy conservation - time derivative.
Mat _cmc_time_derivative_mat
Cross momentum Cross momentum conservation - time derivative.
const SCMFrictionClosureBase * _friction_closure
Friction closure object.
Mat _amc_turbulent_cross_flows_mat
Axial momentum Axial momentum conservation - compute turbulent cross fluxes.
static InputParameters validParams()
PetscErrorCode solveAndPopulateEnthalpy(Mat A, Vec rhs, unsigned int first_node, unsigned int last_node, const char *ksp_prefix)
Solve a linear system (A * x = rhs) with a simple PCJACOBI KSP and populate the enthalpy solution int...
const SinglePhaseFluidProperties * _fp
Non-owning pointer to fluid properties user object.
Mat _amc_sys_mdot_mat
Axial momentum system matrix.
Mat _cmc_sys_Wij_mat
Lateral momentum system matrix.
libMesh::DenseMatrix< Real > _WijPrime
Vec _hc_cross_derivative_rhs
void computeRho(int iblock)
Computes Density per channel for block iblock.
virtual Real getSubChannelPeripheralDuctWidth(unsigned int i_ch) const =0
Function that computes the width of the duct cell that the peripheral subchannel i_ch sees.
PetscScalar _max_sumWij_new
std::unique_ptr< SolutionHandle > _DP_soln
const MooseEnum _interpolation_scheme
The interpolation method used in constructing the systems.
const bool _staggered_pressure_bool
Flag to define the usage of staggered or collocated pressure.
std::unique_ptr< SolutionHandle > _rho_soln
Mat _mc_sumWij_mat
Matrices and vectors to be used in implicit assembly Mass conservation Mass conservation - sum of cro...
std::unique_ptr< SolutionHandle > _duct_heat_flux_soln
struct SubChannel1PhaseProblem::FrictionStruct _friction_args
void computeDP(int iblock)
Computes Pressure Drop per channel for block iblock.
const Real & _T_tol
Convergence tolerance for the temperature loop in internal solve.
const bool _duct_mesh_exist
Flag that informs if there is a duct mesh or not.
std::unique_ptr< SolutionHandle > _S_flow_soln
void computeWijResidual(int iblock)
Computes Residual Matrix based on the lateral momentum conservation equation for block iblock.
const bool _compute_power
Flag that informs if we need to solve the Enthalpy/Temperature equations or not.
const PostprocessorValue & _P_out
Outlet pressure postprocessor value.
virtual void initialSetup() override
std::unique_ptr< SolutionHandle > _Dpin_soln
Mat _cmc_pressure_force_mat
Cross momentum conservation - pressure force.
std::unique_ptr< SolutionHandle > _P_soln
Real _bulk_Re
Assembly bulk Reynolds number.
Vec _hc_advective_derivative_rhs
Vec _amc_pressure_force_rhs
unsigned int _n_blocks
number of axial blocks
void detectDeformation()
Detects whether pin diameter or duct displacement fields require geometry recalculation.
Mat _amc_time_derivative_mat
Axial momentum conservation - time derivative.
libMesh::DenseMatrix< Real > & _Wij
std::unique_ptr< SolutionHandle > _Tduct_soln
bool _deformation
Flag that activates the effect of deformation (pin/duct) based on the auxvalues for displacement,...
libMesh::DenseMatrix< Real > _Wij_residual_matrix
friend PetscErrorCode formFunction(SNES snes, Vec x, Vec f, void *ctx)
This is the residual Vector function in a form compatible with the SNES PETC solvers.
std::unique_ptr< SolutionHandle > _h_soln
std::unique_ptr< SolutionHandle > _T_soln
virtual void computeh(int iblock)=0
Computes Enthalpy per channel for block iblock.
std::unique_ptr< SolutionHandle > _mu_soln
Real _TR
Flag that activates or deactivates the transient parts of the equations we solve by multiplication.
Vec _hc_time_derivative_rhs
virtual void externalSolve() override
PetscScalar computeInterpolationCoefficients(PetscScalar Peclet=0.0)
Functions that computes the interpolation scheme given the Peclet number.
Mat _cmc_advective_derivative_mat
Cross momentum conservation - advective (Eulerian) derivative.
bool _time_integrator_checked
Whether the time integrator has been checked for consistency with the implementation.
Vec _hc_added_heat_rhs
Enthalpy conservation - source and sink.
const Real & _P_tol
Convergence tolerance for the pressure loop in external solve.
Mat _amc_friction_force_mat
Axial momentum conservation - friction force.
Real _CT
Turbulent modeling parameter used in axial momentum equation.
PetscErrorCode populateDenseFromVector(const Vec &x, T &solution, const unsigned int first_axial_level, const unsigned int last_axial_level, const unsigned int cross_dimension)
Real _pressure_fixed_point_error
Maximum pressure fixed-point update before solution relaxation over the blocks.
Mat _mc_density_pressure_mat
Mass conservation - pressure derivative of transient density.
const bool _compute_viscosity
Flag that activates or deactivates the calculation of viscosity.
Mat _hc_advective_derivative_mat
Enthalpy conservation - advective (Eulerian) derivative;.
const PetscInt & _maxit
The maximum number of iterations to use for the ksp linear solver.
Vec _cmc_time_derivative_rhs
Vec _cmc_advective_derivative_rhs
PetscErrorCode implicitPetscSolve(int iblock)
Computes implicit solve using PetSc.
const bool _compute_density
Flag that activates or deactivates the calculation of density.
libMesh::DenseVector< Real > residualFunction(int iblock, libMesh::DenseVector< Real > solution)
Computes Residual Vector based on the lateral momentum conservation equation for block iblock & updat...
bool _converged
Variable that informs whether we exited external solve with a converged solution or not.
void computeSumWij(int iblock)
Computes net diversion crossflow per channel for block iblock.
const int & _T_maxit
Maximum iterations for the inner temperature loop.
const Real & _T_relaxation
Relaxation factor for temperature updates in the inner thermal-hydraulic iteration.
const Real & _crossflow_relaxation
Relaxation factor for crossflow updates in the coupled implicit solve.
std::unique_ptr< SolutionHandle > _Tpin_soln
const bool _pin_mesh_exist
Flag that informs if there is a pin mesh or not.
Vec _amc_time_derivative_rhs
Mat _amc_pressure_force_mat
Axial momentum conservation - pressure force.
void computeMdot(int iblock)
Computes mass flow per channel for block iblock.
Real _bulk_V
Assembly bulk velocity.
std::unique_ptr< SolutionHandle > _SumWij_soln
const bool _implicit_bool
Flag to define the usage of a implicit or explicit solution.
const int & _P_maxit
Maximum number of pressure iterations; zero selects the solver's existing automatic limit.
std::vector< Real > _z_grid
axial location of nodes
virtual bool solverSystemConverged(const unsigned int) override
Vec _cmc_pressure_force_rhs
const Real & _mass_flow_relaxation
Relaxation factor for mass flow rate updates in the coupled implicit solve.
Vec _amc_cross_derivative_rhs
Mat _amc_cross_derivative_mat
Axial momentum conservation - cross flux derivative.
void computeWijFromSolve(int iblock)
Computes diversion crossflow per gap for block iblock.
const unsigned int & _enthalpy_subcycles
Number of enthalpy, temperature, and property updates performed per flow solve.
void computeMu(int iblock)
Computes Viscosity per channel for block iblock.
Vec _amc_friction_force_rhs
Vec _amc_turbulent_cross_flows_rhs
PetscErrorCode populateVectorFromDense(Vec &x, const T &solution, const unsigned int first_axial_level, const unsigned int last_axial_level, const unsigned int cross_dimension)
libMesh::DenseMatrix< Real > & _Wij_old
SubChannelMesh & _subchannel_mesh
struct SubChannel1PhaseProblem::NusseltStruct _nusselt_args
std::unique_ptr< SolutionHandle > _mdot_soln
Solutions handles and link to TH tables properties.
std::unique_ptr< SolutionHandle > _q_prime_soln
virtual Real computeAddedHeatDuct(unsigned int i_ch, unsigned int iz) const
Non-pure: implemented in the base (or override in a child if needed)
const PetscReal & _rtol
The relative convergence tolerance, (relative decrease) for the ksp linear solver.
const Real & _crossflow_equation_relaxation
Equation relaxation factor for crossflow in the coupled implicit solve.
Vec _amc_gravity_rhs
Axial momentum conservation - buoyancy force No implicit matrix.
Mat _mc_axial_convection_mat
Mass conservation - axial convection.
PetscScalar _added_K
Added resistances for monolithic convergence.
Vec _amc_advective_derivative_rhs
Mat _amc_advective_derivative_mat
Axial momentum conservation - advective (Eulerian) derivative.
void computeBulkReynoldsNumber()
Computes the assembly bulk Reynolds number from inlet flow conditions.
Real computeT(int iblock)
Computes and relaxes Temperature per channel for block iblock.
void computeWijPrime(int iblock)
Computes turbulent crossflow per gap for block iblock.
Real computeMixingParameter(unsigned int i_gap, unsigned int iz) const
Computes and validates the turbulent mixing parameter.
std::unique_ptr< SolutionHandle > _ff_soln
Vec _cmc_friction_force_rhs
const bool _verbose_subchannel
Boolean to printout information related to subchannel solve.
Mat _hc_cross_derivative_mat
Enthalpy conservation - cross flux derivative.
const PetscReal & _atol
The absolute convergence tolerance for the ksp linear solver.
const Real & _pressure_relaxation
Relaxation factor for pressure updates in the coupled implicit solve.
std::unique_ptr< SolutionHandle > _HTC_soln
static const std::string ENTHALPY
static const std::string DISPLACEMENT
static const std::string PRESSURE_DROP
static const std::string WETTED_PERIMETER
static const std::string PRESSURE
static const std::string DUCT_TEMPERATURE
static const std::string FRICTION_FACTOR
static const std::string MASS_FLOW_RATE
static const std::string SURFACE_AREA
static const std::string VISCOSITY
static const std::string DENSITY
static const std::string PIN_DIAMETER
static const std::string HEAT_TRANSFER_COEFFICIENT
static const std::string LINEAR_HEAT_RATE
static const std::string DUCT_HEAT_FLUX
static const std::string SUM_CROSSFLOW
static const std::string PIN_TEMPERATURE
static const std::string TEMPERATURE
Base class for subchannel meshes.
virtual unsigned int getNumOfChannels() const =0
Return the number of channels per layer.
virtual const std::vector< unsigned int > & getChannelPins(unsigned int i_chan) const =0
Return a vector of pin indices for a given channel index.
virtual unsigned int channelIndex(const Point &point) const =0
Real getAssemblyFlowArea() const
Return undeformed bundle inlet flow area.
Real getAssemblyHydraulicDiameter() const
Return undeformed bundle-average hydraulic diameter.
virtual const std::vector< Real > & getZGrid() const
Get axial location of layers.
Node * getChannelNodeFromDuct(Node *duct_node) const
Function that gets the channel node from the duct node.
virtual Real getGapWidth(unsigned int axial_index, unsigned int gap_index) const =0
Return gap width for a given gap index.
virtual const Real & getPitch() const
Return the undeformed pitch between 2 subchannels.
virtual const std::pair< unsigned int, unsigned int > & getGapChannels(unsigned int i_gap) const =0
Return a pair of subchannel indices for a given gap index.
const std::vector< Node * > & getDuctNodes() const
Function that returns the vector with the duct nodes.
Node * getDuctNodeFromChannel(Node *channel_node) const
Function that gets the duct node from the channel node.
virtual unsigned int getNumOfPins() const =0
Return the number of pins.
virtual EChannelType getSubchannelType(unsigned int index) const =0
Return the type of the subchannel for given subchannel index.
virtual const Real & getCrossflowSign(unsigned int i_chan, unsigned int i_local) const =0
Return a sign for the crossflow given a subchannel index and local neighbor index.
virtual const std::vector< std::vector< Real > > & getKGrid() const
Get axial cell location and value of loss coefficient.
virtual unsigned int getZIndex(const Point &point) const
Get axial index of point.
virtual Node * getChannelNode(unsigned int i_chan, unsigned int iz) const =0
Get the subchannel mesh node for a given channel index and elevation index.
virtual unsigned int getNumOfGapsPerLayer() const =0
Return the number of gaps per layer.
virtual const std::vector< unsigned int > & getChannelGaps(unsigned int i_chan) const =0
Return a vector of gap indices for a given channel index.
virtual unsigned int getNumOfAxialCells() const
Return the number of axial cells.
virtual const Real & getPinDiameter() const
Return undeformed Pin diameter.
virtual Node * getPinNode(unsigned int i_pin, unsigned int iz) const =0
Get the pin mesh node for a given pin index and elevation index.
virtual const std::vector< unsigned int > & getPinChannels(unsigned int i_pin) const =0
Return a vector of channel indices for a given Pin index.
void max(const T &r, T &o, Request &req) const
void broadcast(T &data, const unsigned int root_id=0, const bool identical_sizes=false) const
void resize(const unsigned int new_m, const unsigned int new_n)
virtual void zero() override final
const Parallel::Communicator & _communicator
processor_id_type processor_id() const
const Parallel::Communicator & comm() const
The following methods are specializations for using the Parallel::packed_range_* routines for a vecto...
static constexpr Real TOLERANCE
SubChannel1PhaseProblem * schp
structure with the needed information to compute the friction factor at a specific subchannel cell
structure with the needed information to compute the Nusselt number at a specific subchannel cell and...