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.
addRequiredParam<
unsigned int>(
"n_blocks",
"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()),
210 _P_tol(getParam<Real>(
"P_tol")),
211 _P_maxit(getParam<
int>(
"P_maxit")),
212 _T_tol(getParam<Real>(
"T_tol")),
213 _T_maxit(getParam<
int>(
"T_maxit")),
214 _T_relaxation(getParam<Real>(
"T_relaxation")),
215 _enthalpy_subcycles(getParam<unsigned
int>(
"enthalpy_subcycles")),
216 _mass_flow_equation_relaxation(getParam<Real>(
"mass_flow_equation_relaxation")),
217 _pressure_equation_relaxation(getParam<Real>(
"pressure_equation_relaxation")),
218 _crossflow_equation_relaxation(getParam<Real>(
"crossflow_equation_relaxation")),
219 _mass_flow_relaxation(getParam<Real>(
"mass_flow_relaxation")),
220 _pressure_relaxation(getParam<Real>(
"pressure_relaxation")),
221 _crossflow_relaxation(getParam<Real>(
"crossflow_relaxation")),
222 _rtol(getParam<PetscReal>(
"rtol")),
223 _atol(getParam<PetscReal>(
"atol")),
224 _dtol(getParam<PetscReal>(
"dtol")),
225 _maxit(getParam<PetscInt>(
"maxit")),
226 _interpolation_scheme(getParam<
MooseEnum>(
"interpolation_scheme")),
227 _gravity_direction(getParam<
MooseEnum>(
"gravity")),
228 _dir_grav(computeGravityDir(_gravity_direction)),
229 _implicit_bool(getParam<bool>(
"implicit")),
230 _staggered_pressure_bool(getParam<bool>(
"staggered_pressure")),
231 _segregated_bool(getParam<bool>(
"segregated")),
232 _verbose_subchannel(getParam<bool>(
"verbose_subchannel")),
233 _friction_closure(nullptr),
234 _mixing_closure(nullptr),
235 _pin_HTC_closure(nullptr),
236 _duct_HTC_closure(nullptr),
238 _duct_heat_flux_soln(nullptr),
239 _Tduct_soln(nullptr),
244 "You are using a deprecated parameter. Please use the mixing_closure system.");
246 paramError(
"pin_HTC_closure",
"required when a pin mesh exists.");
248 paramError(
"duct_HTC_closure",
"required when a duct mesh exists.");
250 paramError(
"segregated",
"A non-segregated solve requires 'implicit = true'.");
252 for (
const auto * relaxation_param : {
"mass_flow_equation_relaxation",
253 "pressure_equation_relaxation",
254 "crossflow_equation_relaxation",
255 "mass_flow_relaxation",
256 "pressure_relaxation",
257 "crossflow_relaxation"})
262 "' parameter is only used by the implicit non-segregated solve. Set "
263 "'implicit = true' and 'segregated = false' to use it.");
361 ": When implicit number of blocks can't be equal to number of cells. This will "
362 "cause problems with the subchannel interpolation scheme.");
371 _fp = &getUserObject<SinglePhaseFluidProperties>(getParam<UserObjectName>(
"fp"));
373 &getUserObject<SCMFrictionClosureBase>(getParam<UserObjectName>(
"friction_closure"));
375 &getUserObject<SCMMixingClosureBase>(getParam<UserObjectName>(
"mixing_closure"));
384 if (getParam<bool>(
"full_output"))
398 &getUserObject<SCMHTCClosureBase>(getParam<UserObjectName>(
"pin_HTC_closure"));
413 &getUserObject<SCMHTCClosureBase>(getParam<UserObjectName>(
"duct_HTC_closure"));
423 Real viscosity_in = 0.0;
424 Real mass_flow_in = 0.0;
428 const Real mdot_in = (*_mdot_soln)(node_in);
429 viscosity_in += mdot_in * (*_mu_soln)(node_in);
430 mass_flow_in += mdot_in;
434 const Real inlet_mu = viscosity_in / mass_flow_in;
446 for (
unsigned int iz = 0; iz <
_n_cells + 1; iz++)
447 for (
unsigned int i_pin = 0; i_pin <
_n_pins; i_pin++)
450 const Real Dpin = (*_Dpin_soln)(node);
451 if (std::abs(Dpin) <=
tol)
454 ". You must initialize Dpin to a non-zero value.");
455 if (std::abs(Dpin - pin_diameter) >
tol)
474 PetscErrorCode ierr =
cleanUp();
486 LibmeshPetscCall(VecDestroy(&
_Wij_vec));
487 LibmeshPetscCall(VecDestroy(&
_prod));
488 LibmeshPetscCall(VecDestroy(&
_prodp));
533 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
554 return ((Peclet - 1.0) * std::exp(Peclet) + 1) / (Peclet * (std::exp(Peclet) - 1.) + 1e-10);
557 ": Interpolation scheme should be a string: upwind, downwind, central_difference, "
564 PetscScalar botValue,
568 return alpha * botValue + (1.0 - alpha) * topValue;
574 const unsigned int last_node = (iblock + 1) *
_block_size;
575 const unsigned int first_node = iblock *
_block_size + 1;
578 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
580 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
582 int i =
_n_gaps * (iz - first_node) + i_gap;
583 solution_seed(i) =
_Wij(i_gap, iz);
594 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
596 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
598 _Wij(i_gap, iz) = root(i);
607 const unsigned int last_node = (iblock + 1) *
_block_size;
608 const unsigned int first_node = iblock *
_block_size + 1;
612 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
614 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
619 unsigned int counter = 0;
634 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
636 unsigned int iz_ind = iz - first_node;
637 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
640 unsigned int counter = 0;
644 PetscInt col = i_gap +
_n_gaps * iz_ind;
646 LibmeshPetscCall(MatSetValues(
_mc_sumWij_mat, 1, &row, 1, &col, &value, INSERT_VALUES));
651 LibmeshPetscCall(MatAssemblyBegin(
_mc_sumWij_mat, MAT_FINAL_ASSEMBLY));
652 LibmeshPetscCall(MatAssemblyEnd(
_mc_sumWij_mat, MAT_FINAL_ASSEMBLY));
658 LibmeshPetscCall(VecDuplicate(
_Wij_vec, &loc_Wij));
662 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
664 LibmeshPetscCall(VecDestroy(&loc_prod));
665 LibmeshPetscCall(VecDestroy(&loc_Wij));
673 const unsigned int last_node = (iblock + 1) *
_block_size;
674 const unsigned int first_node = iblock *
_block_size + 1;
677 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
680 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
684 auto volume = dz * (*_S_flow_soln)(node_in);
685 auto time_term =
_TR * ((*_rho_soln)(node_out)-
_rho_soln->old(node_out)) * volume /
_dt;
687 auto mdot_out = (*_mdot_soln)(node_in) - (*
_SumWij_soln)(node_out)-time_term;
692 " : Calculation of negative mass flow mdot_out = : ",
696 " - Implicit solves are required for recirculating flow.");
704 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
707 auto iz_ind = iz - first_node;
708 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
712 auto volume = dz * (*_S_flow_soln)(node_in);
715 auto time_term =
_TR * ((*_rho_soln)(node_out)-
_rho_soln->old(node_out)) * volume /
_dt;
717 PetscScalar value_vec = -1.0 * time_term;
732 Real
rho, drho_dp_T, drho_dT;
735 Real h, dh_dp_T, dh_dT;
737 const Real drho_dp_h = drho_dp_T - drho_dT * dh_dp_T / dh_dT;
738 const PetscScalar pressure_coefficient = volume /
_dt * drho_dp_h;
739 const PetscInt pressure_col = i_ch +
_n_channels * (iz_ind + 1);
745 &pressure_coefficient,
747 const PetscScalar linearization_rhs = pressure_coefficient * (*_P_soln)(node_out);
753 if (iz == first_node)
755 PetscScalar value_vec = (*_mdot_soln)(node_in);
764 PetscScalar value = -1.0;
772 PetscScalar value = 1.0;
779 PetscScalar value_vec_2 = -1.0 * (*_SumWij_soln)(node_out);
797 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksploc));
799 LibmeshPetscCall(KSPGetPC(ksploc, &pc));
800 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
802 LibmeshPetscCall(KSPSetFromOptions(ksploc));
804 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
807 LibmeshPetscCall(KSPDestroy(&ksploc));
808 LibmeshPetscCall(VecDestroy(&sol));
816 const unsigned int last_node = (iblock + 1) *
_block_size;
817 const unsigned int first_node = iblock *
_block_size + 1;
820 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
824 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
828 auto rho_in = (*_rho_soln)(node_in);
829 auto rho_out = (*_rho_soln)(node_out);
830 auto mu_in = (*_mu_soln)(node_in);
831 auto S = (*_S_flow_soln)(node_in);
832 auto w_perim = (*_w_perim_soln)(node_in);
834 auto Dh_i = 4.0 * S / w_perim;
835 auto time_term =
_TR * ((*_mdot_soln)(node_out)-
_mdot_soln->old(node_out)) * dz /
_dt -
839 Utility::pow<2>((*
_mdot_soln)(node_out)) * (1.0 / S / rho_out - 1.0 / S / rho_in);
840 auto mass_term2 = -2.0 * (*_mdot_soln)(node_out) * (*
_SumWij_soln)(node_out) / S / rho_in;
841 auto crossflow_term = 0.0;
842 auto turbulent_term = 0.0;
843 unsigned int counter = 0;
847 unsigned int ii_ch = chans.first;
848 unsigned int jj_ch = chans.second;
853 auto rho_i = (*_rho_soln)(node_in_i);
854 auto rho_j = (*_rho_soln)(node_in_j);
855 auto Si = (*_S_flow_soln)(node_in_i);
856 auto Sj = (*_S_flow_soln)(node_in_j);
859 if (
_Wij(i_gap, iz) > 0.0)
860 u_star = (*
_mdot_soln)(node_out_i) / Si / rho_i;
862 u_star = (*_mdot_soln)(node_out_j) / Sj / rho_j;
867 turbulent_term +=
_WijPrime(i_gap, iz) * (2 * (*_mdot_soln)(node_out) / rho_in / S -
872 turbulent_term *=
_CT;
873 auto Re = (((*_mdot_soln)(node_in) / S) * Dh_i / mu_in);
881 ki = k_grid[i_ch][iz - 1];
883 ki = k_grid[i_ch][iz];
884 auto friction_term = (ff * dz / Dh_i + ki) * 0.5 *
886 (S * (*_rho_soln)(node_out));
888 auto DP = (1 / S) * (time_term + mass_term1 + mass_term2 + crossflow_term + turbulent_term +
889 friction_term + gravity_term);
909 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
913 auto iz_ind = iz - first_node;
914 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
921 PetscScalar Pe = 0.5;
925 auto S_in = (*_S_flow_soln)(node_in);
926 auto S_out = (*_S_flow_soln)(node_out);
928 auto w_perim_in = (*_w_perim_soln)(node_in);
929 auto w_perim_out = (*_w_perim_soln)(node_out);
933 auto mu_in = (*_mu_soln)(node_in);
934 auto mu_out = (*_mu_soln)(node_out);
936 auto Dh_i = 4.0 * S_interp / w_perim_interp;
938 auto Re = ((mdot_loc / S_interp) * Dh_i / mu_interp);
946 ki = k_grid[i_ch][iz - 1];
948 ki = k_grid[i_ch][iz];
949 Pe = 1.0 / ((ff * dz / Dh_i + ki) * 0.5) * mdot_loc / std::abs(mdot_loc);
954 auto rho_in = (*_rho_soln)(node_in);
955 auto rho_out = (*_rho_soln)(node_out);
959 auto mu_in = (*_mu_soln)(node_in);
960 auto mu_out = (*_mu_soln)(node_out);
964 auto S_in = (*_S_flow_soln)(node_in);
965 auto S_out = (*_S_flow_soln)(node_out);
969 auto w_perim_in = (*_w_perim_soln)(node_in);
970 auto w_perim_out = (*_w_perim_soln)(node_out);
974 auto Dh_i = 4.0 * S_interp / w_perim_interp;
981 PetscScalar value_tt =
_TR * dz /
_dt;
982 LibmeshPetscCall(MatSetValues(
991 if (iz == first_node)
993 PetscScalar value_vec_at = Utility::pow<2>((*
_mdot_soln)(node_in)) / (S_in * rho_in);
995 LibmeshPetscCall(VecSetValues(
1001 PetscInt col_at = i_ch +
_n_channels * (iz_ind - 1);
1002 PetscScalar value_at = -1.0 * std::abs((*
_mdot_soln)(node_in)) / (S_in * rho_in);
1003 LibmeshPetscCall(MatSetValues(
1010 PetscScalar value_at = std::abs((*
_mdot_soln)(node_out)) / (S_out * rho_out);
1011 LibmeshPetscCall(MatSetValues(
1015 unsigned int counter = 0;
1016 unsigned int cross_index = iz;
1020 unsigned int ii_ch = chans.first;
1021 unsigned int jj_ch = chans.second;
1036 if (
_Wij(i_gap, cross_index) > 0.0)
1038 if (iz == first_node)
1040 u_star = (*_mdot_soln)(node_in_i) / S_i / rho_i;
1041 PetscScalar value_vec_ct = -1.0 * alpha *
1043 _Wij(i_gap, cross_index) * u_star;
1044 PetscInt row_vec_ct = i_ch +
_n_channels * iz_ind;
1045 LibmeshPetscCall(VecSetValues(
1051 _Wij(i_gap, cross_index) / S_i / rho_i;
1053 PetscInt col_ct = ii_ch +
_n_channels * (iz_ind - 1);
1054 LibmeshPetscCall(MatSetValues(
1057 PetscScalar value_ct = (1.0 - alpha) *
1059 _Wij(i_gap, cross_index) / S_i / rho_i;
1062 LibmeshPetscCall(MatSetValues(
1065 else if (
_Wij(i_gap, cross_index) < 0.0)
1067 if (iz == first_node)
1069 u_star = (*_mdot_soln)(node_in_j) / S_j / rho_j;
1070 PetscScalar value_vec_ct = -1.0 * alpha *
1072 _Wij(i_gap, cross_index) * u_star;
1073 PetscInt row_vec_ct = i_ch +
_n_channels * iz_ind;
1074 LibmeshPetscCall(VecSetValues(
1080 _Wij(i_gap, cross_index) / S_j / rho_j;
1082 PetscInt col_ct = jj_ch +
_n_channels * (iz_ind - 1);
1083 LibmeshPetscCall(MatSetValues(
1086 PetscScalar value_ct = (1.0 - alpha) *
1088 _Wij(i_gap, cross_index) / S_j / rho_j;
1091 LibmeshPetscCall(MatSetValues(
1095 if (iz == first_node)
1097 PetscScalar value_vec_ct = -2.0 * alpha * (*_mdot_soln)(node_in)*
_CT *
1098 _WijPrime(i_gap, cross_index) / (rho_interp * S_interp);
1099 value_vec_ct += alpha * (*_mdot_soln)(node_in_j)*
_CT *
_WijPrime(i_gap, cross_index) /
1101 value_vec_ct += alpha * (*_mdot_soln)(node_in_i)*
_CT *
_WijPrime(i_gap, cross_index) /
1103 PetscInt row_vec_ct = i_ch +
_n_channels * iz_ind;
1109 PetscScalar value_center_ct =
1110 2.0 * alpha *
_CT *
_WijPrime(i_gap, cross_index) / (rho_interp * S_interp);
1112 PetscInt col_ct = i_ch +
_n_channels * (iz_ind - 1);
1113 LibmeshPetscCall(MatSetValues(
1116 PetscScalar value_left_ct =
1117 -1.0 * alpha *
_CT *
_WijPrime(i_gap, cross_index) / (rho_j * S_j);
1120 LibmeshPetscCall(MatSetValues(
1123 PetscScalar value_right_ct =
1124 -1.0 * alpha *
_CT *
_WijPrime(i_gap, cross_index) / (rho_i * S_i);
1127 LibmeshPetscCall(MatSetValues(
1131 PetscScalar value_center_ct =
1132 2.0 * (1.0 - alpha) *
_CT *
_WijPrime(i_gap, cross_index) / (rho_interp * S_interp);
1135 LibmeshPetscCall(MatSetValues(
1138 PetscScalar value_left_ct =
1139 -1.0 * (1.0 - alpha) *
_CT *
_WijPrime(i_gap, cross_index) / (rho_j * S_j);
1142 LibmeshPetscCall(MatSetValues(
1145 PetscScalar value_right_ct =
1146 -1.0 * (1.0 - alpha) *
_CT *
_WijPrime(i_gap, cross_index) / (rho_i * S_i);
1149 LibmeshPetscCall(MatSetValues(
1155 PetscScalar mdot_interp =
1157 auto Re = ((mdot_interp / S_interp) * Dh_i / mu_interp);
1165 ki = k_grid[i_ch][iz - 1];
1167 ki = k_grid[i_ch][iz];
1168 auto coef = (ff * dz / Dh_i + ki) * 0.5 * std::abs((*
_mdot_soln)(node_out)) /
1169 (S_interp * rho_interp);
1170 if (iz == first_node)
1172 PetscScalar value_vec = -1.0 * alpha * coef * (*_mdot_soln)(node_in);
1181 PetscScalar value = alpha * coef;
1189 PetscScalar value = (1.0 - alpha) * coef;
1194 PetscScalar value_vec =
_dir_grav * -1.0 *
_g_grav * rho_interp * dz * S_interp;
1196 LibmeshPetscCall(VecSetValues(
_amc_gravity_rhs, 1, &row_vec, &value_vec, ADD_VALUES));
1213#if !PETSC_VERSION_LESS_THAN(3, 15, 0)
1255 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
1262 LibmeshPetscCall(VecGetArray(ls, &xx));
1263 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1265 auto iz_ind = iz - first_node;
1266 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1273 auto S_in = (*_S_flow_soln)(node_in);
1274 auto S_out = (*_S_flow_soln)(node_out);
1280 auto DP = (1 / S_interp) * xx[iz_ind *
_n_channels + i_ch];
1294 LibmeshPetscCall(VecDestroy(&ls));
1302 const unsigned int last_node = (iblock + 1) *
_block_size;
1303 const unsigned int first_node = iblock *
_block_size + 1;
1308 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1311 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1322 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1325 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1333 PetscScalar Pe = 0.5;
1335 if (iz == last_node)
1342 (*
_P_soln)(node_out) + (1.0 - alpha) *
_DP(i_ch, iz) +
1343 alpha *
_DP(i_ch, iz - 1));
1354 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1356 auto iz_ind = iz - first_node;
1358 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1364 auto S_in = (*_S_flow_soln)(node_in);
1365 auto S_out = (*_S_flow_soln)(node_out);
1371 PetscScalar value = -1.0 * S_interp;
1375 if (iz == last_node)
1377 PetscScalar value = -1.0 * (*_P_soln)(node_out)*S_interp;
1385 PetscScalar value = 1.0 * S_interp;
1392 auto dp_out =
_DP(i_ch, iz);
1393 PetscScalar value_v = -1.0 * dp_out * S_interp;
1409 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksploc));
1411 LibmeshPetscCall(KSPGetPC(ksploc, &pc));
1412 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
1414 LibmeshPetscCall(KSPSetFromOptions(ksploc));
1417 LibmeshPetscCall(VecGetArray(sol, &xx));
1419 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1421 auto iz_ind = iz - first_node;
1422 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1425 PetscScalar value = xx[iz_ind *
_n_channels + i_ch];
1430 LibmeshPetscCall(KSPDestroy(&ksploc));
1431 LibmeshPetscCall(VecDestroy(&sol));
1437 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1439 auto iz_ind = iz - first_node;
1441 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1447 auto S_in = (*_S_flow_soln)(node_in);
1448 auto S_out = (*_S_flow_soln)(node_out);
1454 PetscScalar value = -1.0 * S_interp;
1458 if (iz == last_node)
1460 PetscScalar value = -1.0 * (*_P_soln)(node_out)*S_interp;
1464 auto dp_out =
_DP(i_ch, iz);
1465 PetscScalar value_v = -1.0 * dp_out / 2.0 * S_interp;
1474 PetscScalar value = 1.0 * S_interp;
1480 auto dp_in =
_DP(i_ch, iz - 1);
1481 auto dp_out =
_DP(i_ch, iz);
1483 PetscScalar value_v = -1.0 * dp_interp * S_interp;
1495 _console <<
"Block: " << iblock <<
" - Axial momentum pressure force matrix assembled"
1504 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksploc));
1506 LibmeshPetscCall(KSPGetPC(ksploc, &pc));
1507 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
1509 LibmeshPetscCall(KSPSetFromOptions(ksploc));
1512 LibmeshPetscCall(VecGetArray(sol, &xx));
1514 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1516 auto iz_ind = iz - first_node;
1517 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1520 PetscScalar value = xx[iz_ind *
_n_channels + i_ch];
1525 LibmeshPetscCall(KSPDestroy(&ksploc));
1526 LibmeshPetscCall(VecDestroy(&sol));
1535 const unsigned int last_node = (iblock + 1) *
_block_size;
1536 const unsigned int first_node = iblock *
_block_size + 1;
1537 std::vector<Real> residual;
1539 Real residual_norm_sq = 0.0;
1540 Real temperature_norm_sq = 0.0;
1541 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1543 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1546 const Real
T = (*_T_soln)(node);
1548 residual.push_back(T_from_ph -
T);
1549 residual_norm_sq += Utility::pow<2>(residual.back());
1550 temperature_norm_sq += Utility::pow<2>(
T);
1556 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1557 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1564 return std::sqrt(residual_norm_sq) / (std::sqrt(temperature_norm_sq) + 1e-14);
1570 const unsigned int last_node = (iblock + 1) *
_block_size;
1571 const unsigned int first_node = iblock *
_block_size + 1;
1574 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1580 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1582 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1593 const unsigned int last_node = (iblock + 1) *
_block_size;
1594 const unsigned int first_node = iblock *
_block_size + 1;
1597 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1603 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1605 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1616 const unsigned int last_node = (iblock + 1) *
_block_size;
1617 const unsigned int first_node = iblock *
_block_size + 1;
1622 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1625 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1628 unsigned int i_ch = chans.first;
1629 unsigned int j_ch = chans.second;
1634 auto rho_i = (*_rho_soln)(node_in_i);
1635 auto rho_j = (*_rho_soln)(node_in_j);
1636 auto Si = (*_S_flow_soln)(node_in_i);
1637 auto Sj = (*_S_flow_soln)(node_in_j);
1641 auto friction_term =
_kij *
_Wij(i_gap, iz) * std::abs(
_Wij(i_gap, iz));
1642 auto DPij = (*_P_soln)(node_in_i) - (*
_P_soln)(node_in_j);
1644 auto rho_star = 0.0;
1645 if (
_Wij(i_gap, iz) > 0.0)
1647 else if (
_Wij(i_gap, iz) < 0.0)
1650 rho_star = (rho_i + rho_j) / 2.0;
1651 auto mass_term_out =
1655 (*_mdot_soln)(node_in_i) / Si / rho_i + (*
_mdot_soln)(node_in_j) / Sj / rho_j;
1656 auto term_out = Sij * rho_star * (Lij / dz) * mass_term_out *
_Wij(i_gap, iz);
1657 auto term_in = Sij * rho_star * (Lij / dz) * mass_term_in *
_Wij(i_gap, iz - 1);
1658 auto inertia_term = term_out - term_in;
1659 auto pressure_term = 2 * Utility::pow<2>(Sij) * DPij * rho_star;
1664 time_term + friction_term + inertia_term - pressure_term;
1682 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1685 auto iz_ind = iz - first_node;
1686 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1689 unsigned int i_ch = chans.first;
1690 unsigned int j_ch = chans.second;
1697 auto rho_i_in = (*_rho_soln)(node_in_i);
1698 auto rho_i_out = (*_rho_soln)(node_out_i);
1700 auto rho_j_in = (*_rho_soln)(node_in_j);
1701 auto rho_j_out = (*_rho_soln)(node_out_j);
1705 auto S_i_in = (*_S_flow_soln)(node_in_i);
1706 auto S_i_out = (*_S_flow_soln)(node_out_i);
1707 auto S_j_in = (*_S_flow_soln)(node_in_j);
1708 auto S_j_out = (*_S_flow_soln)(node_out_j);
1715 auto rho_star = 0.0;
1716 if (
_Wij(i_gap, iz) > 0.0)
1717 rho_star = rho_i_interp;
1718 else if (
_Wij(i_gap, iz) < 0.0)
1719 rho_star = rho_j_interp;
1721 rho_star = (rho_i_interp + rho_j_interp) / 2.0;
1724 PetscScalar time_factor =
_TR * Lij * Sij * rho_star /
_dt;
1725 PetscInt row_td = i_gap +
_n_gaps * iz_ind;
1726 PetscInt col_td = i_gap +
_n_gaps * iz_ind;
1727 PetscScalar value_td = time_factor;
1728 LibmeshPetscCall(MatSetValues(
1730 PetscScalar value_td_rhs = time_factor *
_Wij_old(i_gap, iz);
1735 PetscScalar Pe = 0.5;
1737 auto mass_term_out = (*_mdot_soln)(node_out_i) / S_i_out / rho_i_out +
1738 (*
_mdot_soln)(node_out_j) / S_j_out / rho_j_out;
1739 auto mass_term_in = (*_mdot_soln)(node_in_i) / S_i_in / rho_i_in +
1740 (*
_mdot_soln)(node_in_j) / S_j_in / rho_j_in;
1741 auto term_out = Sij * rho_star * (Lij / dz) * mass_term_out / 2.0;
1742 auto term_in = Sij * rho_star * (Lij / dz) * mass_term_in / 2.0;
1743 if (iz == first_node)
1745 PetscInt row_ad = i_gap +
_n_gaps * iz_ind;
1746 PetscScalar value_ad = term_in * alpha *
_Wij(i_gap, iz - 1);
1750 PetscInt col_ad = i_gap +
_n_gaps * iz_ind;
1751 value_ad = -1.0 * term_in * (1.0 - alpha) + term_out * alpha;
1752 LibmeshPetscCall(MatSetValues(
1755 col_ad = i_gap +
_n_gaps * (iz_ind + 1);
1756 value_ad = term_out * (1.0 - alpha);
1757 LibmeshPetscCall(MatSetValues(
1760 else if (iz == last_node)
1762 PetscInt row_ad = i_gap +
_n_gaps * iz_ind;
1763 PetscInt col_ad = i_gap +
_n_gaps * (iz_ind - 1);
1764 PetscScalar value_ad = -1.0 * term_in * alpha;
1765 LibmeshPetscCall(MatSetValues(
1768 col_ad = i_gap +
_n_gaps * iz_ind;
1769 value_ad = -1.0 * term_in * (1.0 - alpha) + term_out * alpha;
1770 LibmeshPetscCall(MatSetValues(
1773 value_ad = -1.0 * term_out * (1.0 - alpha) *
_Wij(i_gap, iz);
1779 PetscInt row_ad = i_gap +
_n_gaps * iz_ind;
1780 PetscInt col_ad = i_gap +
_n_gaps * (iz_ind - 1);
1781 PetscScalar value_ad = -1.0 * term_in * alpha;
1782 LibmeshPetscCall(MatSetValues(
1785 col_ad = i_gap +
_n_gaps * iz_ind;
1786 value_ad = -1.0 * term_in * (1.0 - alpha) + term_out * alpha;
1787 LibmeshPetscCall(MatSetValues(
1790 col_ad = i_gap +
_n_gaps * (iz_ind + 1);
1791 value_ad = term_out * (1.0 - alpha);
1792 LibmeshPetscCall(MatSetValues(
1796 PetscInt row_ff = i_gap +
_n_gaps * iz_ind;
1797 PetscInt col_ff = i_gap +
_n_gaps * iz_ind;
1798 PetscScalar value_ff =
_kij * std::abs(
_Wij(i_gap, iz)) / 2.0;
1799 LibmeshPetscCall(MatSetValues(
1807 PetscScalar pressure_factor = Utility::pow<2>(Sij) * rho_star;
1808 PetscInt row_pf = i_gap +
_n_gaps * iz_ind;
1810 PetscScalar value_pf = -1.0 * alpha * pressure_factor;
1814 value_pf = alpha * pressure_factor;
1818 if (iz == last_node)
1820 PetscInt row_pf = i_gap +
_n_gaps * iz_ind;
1821 PetscScalar value_pf = (1.0 - alpha) * pressure_factor * (*
_P_soln)(node_out_i);
1824 value_pf = -1.0 * (1.0 - alpha) * pressure_factor * (*
_P_soln)(node_out_j);
1830 row_pf = i_gap +
_n_gaps * iz_ind;
1832 value_pf = -1.0 * (1.0 - alpha) * pressure_factor;
1833 LibmeshPetscCall(MatSetValues(
1836 value_pf = (1.0 - alpha) * pressure_factor;
1837 LibmeshPetscCall(MatSetValues(
1843 PetscScalar pressure_factor = Utility::pow<2>(Sij) * rho_star;
1844 PetscInt row_pf = i_gap +
_n_gaps * iz_ind;
1846 PetscScalar value_pf = -1.0 * pressure_factor;
1850 value_pf = pressure_factor;
1870#if !PETSC_VERSION_LESS_THAN(3, 15, 0)
1907 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
1915 LibmeshPetscCall(VecAXPY(sol_holder_W, 1.0, sol_holder_P));
1917 LibmeshPetscCall(VecGetArray(sol_holder_W, &xx));
1918 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1920 auto iz_ind = iz - first_node;
1921 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1926 LibmeshPetscCall(VecDestroy(&sol_holder_P));
1927 LibmeshPetscCall(VecDestroy(&sol_holder_W));
1935 const unsigned int last_node = (iblock + 1) *
_block_size;
1936 const unsigned int first_node = iblock *
_block_size + 1;
1937 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1940 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1943 unsigned int i_ch = chans.first;
1944 unsigned int j_ch = chans.second;
1949 auto Si_in = (*_S_flow_soln)(node_in_i);
1950 auto Sj_in = (*_S_flow_soln)(node_in_j);
1951 auto Si_out = (*_S_flow_soln)(node_out_i);
1952 auto Sj_out = (*_S_flow_soln)(node_out_j);
1954 auto Sij = dz * gap;
1956 0.5 * (((*_mdot_soln)(node_in_i) + (*
_mdot_soln)(node_in_j)) / (Si_in + Sj_in) +
1962 _WijPrime(i_gap, iz) = beta * avg_massflux * Sij;
1966 auto iz_ind = iz - first_node;
1967 PetscScalar base_value = beta * 0.5 * Sij;
1970 if (iz == first_node)
1972 PetscScalar value_tl = -1.0 * base_value / (Si_in + Sj_in) *
1974 PetscInt row = i_gap +
_n_gaps * iz_ind;
1980 PetscScalar value_tl = base_value / (Si_in + Sj_in);
1981 PetscInt row = i_gap +
_n_gaps * iz_ind;
1983 PetscInt col_ich = i_ch +
_n_channels * (iz_ind - 1);
1984 LibmeshPetscCall(MatSetValues(
1987 PetscInt col_jch = j_ch +
_n_channels * (iz_ind - 1);
1988 LibmeshPetscCall(MatSetValues(
1993 PetscScalar value_bl = base_value / (Si_out + Sj_out);
1994 PetscInt row = i_gap +
_n_gaps * iz_ind;
1997 LibmeshPetscCall(MatSetValues(
2001 LibmeshPetscCall(MatSetValues(
2016 LibmeshPetscCall(VecDuplicate(
_Wij_vec, &loc_Wij));
2017 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
2023 LibmeshPetscCall(VecDestroy(&loc_prod));
2024 LibmeshPetscCall(VecDestroy(&loc_Wij));
2032 if (!std::isfinite(beta) || beta < 0.0)
2034 ": Mixing closure returned invalid beta = ",
2040 ". Beta must be finite and non-negative.");
2049 if (!std::isfinite(beta) || beta < 0.0)
2051 ": Mixing closure returned invalid sweep-flow coefficient = ",
2057 ". sweep-flow coefficient must be finite and non-negative.");
2065 const unsigned int last_node = (iblock + 1) *
_block_size;
2066 const unsigned int first_node = iblock *
_block_size + 1;
2070 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
2072 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
2074 _Wij(i_gap, iz) = solution(i);
2095 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
2101 return Wij_residual_vector;
2116 LibmeshPetscCall(SNESCreate(PETSC_COMM_SELF, &snes));
2117 LibmeshPetscCall(VecCreate(PETSC_COMM_SELF, &
x));
2119 LibmeshPetscCall(VecSetFromOptions(
x));
2120 LibmeshPetscCall(VecDuplicate(
x, &r));
2122#if PETSC_VERSION_LESS_THAN(3, 13, 0)
2123 LibmeshPetscCall(PetscOptionsSetValue(PETSC_NULL,
"-snes_mf", PETSC_NULL));
2125 LibmeshPetscCall(SNESSetUseMatrixFree(snes, PETSC_FALSE, PETSC_TRUE));
2128 ctx.iblock = iblock;
2130 LibmeshPetscCall(SNESSetFunction(snes, r,
formFunction, &ctx));
2131 LibmeshPetscCall(SNESGetKSP(snes, &ksp));
2132 LibmeshPetscCall(KSPGetPC(ksp, &pc));
2133 LibmeshPetscCall(PCSetType(pc, PCNONE));
2135 LibmeshPetscCall(SNESSetFromOptions(snes));
2136 LibmeshPetscCall(VecGetArray(
x, &xx));
2139 xx[i] = solution(i);
2141 LibmeshPetscCall(VecRestoreArray(
x, &xx));
2143 LibmeshPetscCall(SNESSolve(snes, NULL,
x));
2144 LibmeshPetscCall(VecGetArray(
x, &xx));
2148 LibmeshPetscCall(VecRestoreArray(
x, &xx));
2149 LibmeshPetscCall(VecDestroy(&
x));
2150 LibmeshPetscCall(VecDestroy(&r));
2151 LibmeshPetscCall(SNESDestroy(&snes));
2152 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
2157 Mat
A, Vec rhs,
unsigned int first_node,
unsigned int last_node,
const char * ksp_prefix)
2163 LibmeshPetscCall(VecDuplicate(rhs, &
x));
2168 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksp));
2169 LibmeshPetscCall(KSPSetOperators(ksp,
A,
A));
2170 LibmeshPetscCall(KSPGetPC(ksp, &pc));
2171 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
2173 if (ksp_prefix && *ksp_prefix)
2174 LibmeshPetscCall(KSPSetOptionsPrefix(ksp, ksp_prefix));
2175 LibmeshPetscCall(KSPSetFromOptions(ksp));
2178 LibmeshPetscCall(KSPSolve(ksp, rhs,
x));
2179 KSPConvergedReason reason;
2180 LibmeshPetscCall(KSPGetConvergedReason(ksp, &reason));
2183 PetscInt iterations;
2184 PetscReal residual_norm;
2185 LibmeshPetscCall(KSPGetIterationNumber(ksp, &iterations));
2186 LibmeshPetscCall(KSPGetResidualNorm(ksp, &residual_norm));
2188 ": enthalpy linear solve failed: ",
2189 KSPConvergedReasons[reason],
2191 static_cast<int>(reason),
2194 " iterations; residual norm = ",
2200 PetscScalar * xx =
nullptr;
2201 LibmeshPetscCall(VecGetArray(
x, &xx));
2202 for (
unsigned int iz = first_node; iz <= last_node; ++iz)
2204 const unsigned int iz_ind = iz - first_node;
2205 for (
unsigned int i_ch = 0; i_ch <
_n_channels; ++i_ch)
2208 const PetscScalar h_out = xx[iz_ind *
_n_channels + i_ch];
2211 name(),
" : Calculation of negative Enthalpy h_out = ", h_out,
" Axial Level = ", iz);
2212 _h_soln->set(node_out, h_out);
2215 LibmeshPetscCall(VecRestoreArray(
x, &xx));
2218 LibmeshPetscCall(KSPDestroy(&ksp));
2219 LibmeshPetscCall(VecDestroy(&
x));
2221 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
2227 mooseAssert(iz > 0,
"Trapezoidal rule requires starting at index 1 at least");
2238 auto heat_rate_in = (*_duct_heat_flux_soln)(node_in_duct);
2239 auto heat_rate_out = (*_duct_heat_flux_soln)(node_out_duct);
2241 return 0.5 * (heat_rate_in + heat_rate_out) * dz * width;
2259 auto V = [&](
const std::string & s)
2265 auto DupMatAssembled = [&](Mat src, Mat * dst)
2269 LibmeshPetscCall(MatDuplicate(src, MAT_COPY_VALUES, dst));
2270 LibmeshPetscCall(MatAssemblyBegin(*dst, MAT_FINAL_ASSEMBLY));
2271 LibmeshPetscCall(MatAssemblyEnd(*dst, MAT_FINAL_ASSEMBLY));
2277 auto DupVecCopy = [&](Vec src, Vec * dst)
2279 LibmeshPetscCall(VecDuplicate(src, dst));
2280 LibmeshPetscCall(VecCopy(src, *dst));
2283 const PetscInt Q = 3;
2286 auto Idx = [&](PetscInt r, PetscInt
c) {
return Q * r +
c; };
2289 std::vector<Mat> mat_array(Q * Q, NULL);
2290 std::vector<Vec> vec_array(Q, NULL);
2293 auto AssembleEquation = [&](PetscInt
f,
2301 DupMatAssembled(
A0, &mat_array[Idx(
f, 0)]);
2302 DupMatAssembled(
A1, &mat_array[Idx(
f, 1)]);
2303 DupMatAssembled(
A2, &mat_array[Idx(
f, 2)]);
2304 DupVecCopy(rhs, &vec_array[
f]);
2306 LibmeshPetscCall(VecAXPY(vec_array[
f], 1.0, rhs_add));
2307 V(std::string(label) +
" system assembled");
2326 auto relaxEquation =
2327 [&](Mat diagonal_block, Vec rhs, Vec work,
const Real relaxation,
auto && populate)
2329 if (relaxation == 1.0)
2332 Vec diagonal =
nullptr;
2333 LibmeshPetscCall(VecDuplicate(rhs, &diagonal));
2336 LibmeshPetscCall(MatGetDiagonal(diagonal_block, diagonal));
2337 LibmeshPetscCall(VecScale(diagonal, 1.0 / relaxation));
2338 LibmeshPetscCall(MatDiagonalSet(diagonal_block, diagonal, INSERT_VALUES));
2341 LibmeshPetscCall(populate(work));
2344 LibmeshPetscCall(VecScale(diagonal, 1.0 - relaxation));
2345 LibmeshPetscCall(VecPointwiseMult(work, work, diagonal));
2346 LibmeshPetscCall(VecAXPY(rhs, 1.0, work));
2348 LibmeshPetscCall(VecDestroy(&diagonal));
2352 const unsigned int first_node = iblock *
_block_size + 1;
2353 const unsigned int last_node = (iblock + 1) *
_block_size;
2363 V(
"Starting nested system.");
2396 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
2407 LibmeshPetscCall(VecSet(unity_vec, 1.0));
2412 LibmeshPetscCall(VecSet(unity_vec_Wij, 1.0));
2415 Vec _Wij_old_loc_vec;
2420 LibmeshPetscCall(MatMult(mat_array[Q ],
_prod, mdot_estimate));
2423 LibmeshPetscCall(MatGetDiagonal(mat_array[Q + 1], pmat_diag));
2424 LibmeshPetscCall(VecAXPY(pmat_diag, 1e-10, unity_vec));
2425 LibmeshPetscCall(VecPointwiseDivide(p_estimate, mdot_estimate, pmat_diag));
2428 LibmeshPetscCall(MatMult(mat_array[2 * Q + 1], p_estimate, sol_holder_P));
2434 for (
unsigned int iz = first_node; iz <= last_node; ++iz)
2436 const auto iz_ind = iz - first_node;
2437 for (
unsigned int i_ch = 0; i_ch <
_n_channels; ++i_ch)
2439 PetscScalar sumWij = 0.0;
2440 unsigned int counter = 0;
2443 PetscInt row_vec = i_gap +
_n_gaps * iz_ind;
2444 PetscScalar loc_Wij_value;
2445 LibmeshPetscCall(VecGetValues(sol_holder_P, 1, &row_vec, &loc_Wij_value));
2450 LibmeshPetscCall(VecSetValues(sumWij_loc, 1, &row_vec, &sumWij, INSERT_VALUES));
2453 LibmeshPetscCall(VecAssemblyBegin(sumWij_loc));
2454 LibmeshPetscCall(VecAssemblyEnd(sumWij_loc));
2457 PetscScalar min_mdot, sum_mdot, avg_mdot;
2459 LibmeshPetscCall(VecAbs(
_prod));
2460 LibmeshPetscCall(VecMin(
_prod, NULL, &min_mdot));
2461 LibmeshPetscCall(VecSum(
_prod, &sum_mdot));
2462 LibmeshPetscCall(VecGetSize(
_prod, &n));
2463 avg_mdot = sum_mdot /
static_cast<PetscScalar
>(n);
2465 V(
"Average estimated mdot: " + std::to_string(avg_mdot));
2466 V(
"Minimum estimated mdot: " + std::to_string(min_mdot));
2468 LibmeshPetscCall(VecAbs(sumWij_loc));
2469 LibmeshPetscCall(VecMax(sumWij_loc, NULL, &
_max_sumWij));
2471 V(
"Maximum estimated Wij: " + std::to_string(
_max_sumWij));
2474 _Wij_loc_vec,
_Wij, first_node, last_node,
_n_gaps));
2475 LibmeshPetscCall(VecAbs(_Wij_loc_vec));
2478 LibmeshPetscCall(VecAbs(_Wij_old_loc_vec));
2479 LibmeshPetscCall(VecAXPY(_Wij_loc_vec, -1.0, _Wij_old_loc_vec));
2481 PetscScalar relax_factor;
2482 LibmeshPetscCall(VecAbs(_Wij_loc_vec));
2483#if !PETSC_VERSION_LESS_THAN(3, 16, 0)
2484 LibmeshPetscCall(VecMean(_Wij_loc_vec, &relax_factor));
2486 VecSum(_Wij_loc_vec, &relax_factor);
2490 V(
"Relax base value: " + std::to_string(relax_factor));
2493 const PetscScalar resistance_relaxation = 0.9;
2495 V(
"New cross resistance: " + std::to_string(
_added_K));
2498 V(
"Relaxed cross resistance: " + std::to_string(
_added_K));
2501 if (_added_K < 10 && _added_K >= 1.0)
2503 if (_added_K < 1.0 && _added_K >= 0.1)
2505 if (_added_K < 0.1 && _added_K >= 0.01)
2507 if (_added_K < 1e-2 && _added_K >= 1e-3)
2509 V(
"Actual added cross resistance: " + std::to_string(
_added_K));
2510 LibmeshPetscCall(VecScale(unity_vec_Wij,
_added_K));
2513 LibmeshPetscCall(MatDiagonalSet(mat_array[2 * Q + 2], unity_vec_Wij, ADD_VALUES));
2516 LibmeshPetscCall(VecDestroy(&mdot_estimate));
2517 LibmeshPetscCall(VecDestroy(&pmat_diag));
2518 LibmeshPetscCall(VecDestroy(&unity_vec));
2519 LibmeshPetscCall(VecDestroy(&p_estimate));
2520 LibmeshPetscCall(VecDestroy(&sol_holder_P));
2521 LibmeshPetscCall(VecDestroy(&unity_vec_Wij));
2522 LibmeshPetscCall(VecDestroy(&sumWij_loc));
2523 LibmeshPetscCall(VecDestroy(&_Wij_loc_vec));
2524 LibmeshPetscCall(VecDestroy(&_Wij_old_loc_vec));
2531 relaxEquation(mat_array[Idx(0, 0)],
2537 return populateVectorFromHandle<SolutionHandle>(
2542 relaxEquation(mat_array[Idx(1, 1)],
2550 return populateVectorFromHandle<SolutionHandle>(
2555 relaxEquation(mat_array[Idx(2, 2)],
2561 return populateVectorFromDense<libMesh::DenseMatrix<Real>>(
2565 V(
"Linear solver relaxed");
2571 LibmeshPetscCall(MatCreateNest(PETSC_COMM_SELF, Q, NULL, Q, NULL, mat_array.data(), &A_nest));
2572 LibmeshPetscCall(VecCreateNest(PETSC_COMM_SELF, Q, NULL, vec_array.data(), &b_nest));
2573 V(
"Nested system created");
2577 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksp));
2578 LibmeshPetscCall(KSPSetOptionsPrefix(ksp,
"scm_coupled_"));
2579 LibmeshPetscCall(KSPSetType(ksp, KSPFGMRES));
2580 LibmeshPetscCall(KSPSetOperators(ksp, A_nest, A_nest));
2581 LibmeshPetscCall(KSPGetPC(ksp, &pc));
2582 LibmeshPetscCall(PCSetType(pc, PCFIELDSPLIT));
2586 std::vector<IS> rows(Q);
2587 LibmeshPetscCall(MatNestGetISs(A_nest, rows.data(), NULL));
2588 for (PetscInt j = 0; j < Q; ++j)
2591 LibmeshPetscCall(ISDuplicate(rows[j], &part));
2592 LibmeshPetscCall(PCFieldSplitSetIS(pc, NULL, part));
2593 LibmeshPetscCall(ISDestroy(&part));
2595 LibmeshPetscCall(KSPSetFromOptions(ksp));
2596 V(
"Linear solver assembled");
2599 LibmeshPetscCall(VecDuplicate(b_nest, &x_nest));
2600 LibmeshPetscCall(VecSet(x_nest, 0.0));
2601 LibmeshPetscCall(KSPSolve(ksp, b_nest, x_nest));
2602 KSPConvergedReason reason;
2603 LibmeshPetscCall(KSPGetConvergedReason(ksp, &reason));
2606 PetscInt iterations;
2607 PetscReal residual_norm;
2608 LibmeshPetscCall(KSPGetIterationNumber(ksp, &iterations));
2609 LibmeshPetscCall(KSPGetResidualNorm(ksp, &residual_norm));
2611 ": coupled mass/momentum linear solve failed: ",
2612 KSPConvergedReasons[reason],
2614 static_cast<int>(reason),
2617 " iterations; residual norm = ",
2623 LibmeshPetscCall(VecDestroy(&b_nest));
2624 LibmeshPetscCall(MatDestroy(&A_nest));
2625 LibmeshPetscCall(KSPDestroy(&ksp));
2626 for (PetscInt i = 0; i < Q * Q; i++)
2627 LibmeshPetscCall(MatDestroy(&mat_array[i]));
2628 for (PetscInt i = 0; i < Q; i++)
2629 LibmeshPetscCall(VecDestroy(&vec_array[i]));
2630 V(
"Solver elements destroyed");
2633 Vec sol_mdot, sol_p, sol_Wij;
2634 V(
"Vectors to hold solution created");
2637 LibmeshPetscCall(VecNestGetSubVecs(x_nest, &num_vecs, &loc_vecs));
2639 LibmeshPetscCall(VecCopy(loc_vecs[0], sol_mdot));
2641 LibmeshPetscCall(VecCopy(loc_vecs[1], sol_p));
2643 LibmeshPetscCall(VecCopy(loc_vecs[2], sol_Wij));
2644 V(
"Solution from coupled solver copied to solution vectors");
2647 auto relaxSolution = [&](Vec solution, Vec old_solution,
const Real relaxation)
2649 LibmeshPetscCall(VecScale(solution, relaxation));
2650 LibmeshPetscCall(VecAXPY(solution, 1.0 - relaxation, old_solution));
2652 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
2654 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
2659 Vec pressure_residual;
2660 LibmeshPetscCall(VecDuplicate(sol_p, &pressure_residual));
2661 LibmeshPetscCall(VecCopy(sol_p, pressure_residual));
2662 LibmeshPetscCall(VecAXPY(pressure_residual, -1.0,
_prodp));
2664 const PetscScalar * residual_array;
2665 const PetscScalar * old_pressure_array;
2666 PetscInt pressure_size;
2667 LibmeshPetscCall(VecGetSize(pressure_residual, &pressure_size));
2668 LibmeshPetscCall(VecGetArrayRead(pressure_residual, &residual_array));
2669 LibmeshPetscCall(VecGetArrayRead(
_prodp, &old_pressure_array));
2670 Real residual_norm_sq = 0.0;
2671 Real pressure_norm_sq = 0.0;
2672 for (PetscInt i = 0; i < pressure_size; ++i)
2674 residual_norm_sq += Utility::pow<2>(residual_array[i]);
2675 pressure_norm_sq += Utility::pow<2>(old_pressure_array[i] +
_P_out);
2677 LibmeshPetscCall(VecRestoreArrayRead(pressure_residual, &residual_array));
2678 LibmeshPetscCall(VecRestoreArrayRead(
_prodp, &old_pressure_array));
2679 LibmeshPetscCall(VecDestroy(&pressure_residual));
2682 std::sqrt(residual_norm_sq) / (std::sqrt(pressure_norm_sq) + 1e-14));
2691 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
2696 PetscScalar * sol_p_array;
2697 LibmeshPetscCall(VecGetArray(sol_p, &sol_p_array));
2698 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
2700 const auto iz_ind = iz - first_node;
2701 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
2704 PetscScalar value = sol_p_array[iz_ind *
_n_channels + i_ch];
2708 LibmeshPetscCall(VecRestoreArray(sol_p, &sol_p_array));
2716 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
2719 LibmeshPetscCall(VecAbs(
_prod));
2724 V(
"Solutions assigned to MOOSE variables.");
2727 LibmeshPetscCall(VecDestroy(&x_nest));
2728 LibmeshPetscCall(VecDestroy(&sol_mdot));
2729 LibmeshPetscCall(VecDestroy(&sol_p));
2730 LibmeshPetscCall(VecDestroy(&sol_Wij));
2731 V(
"Solutions destroyed.");
2733 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
2739 _console <<
"Executing subchannel solver\n";
2750 for (
const auto * ti :
transient->getTimeIntegrators())
2752 mooseWarning(
"The subchannel solver always uses implicit (backward) Euler time "
2753 "integration; the requested '",
2755 "' time integrator is ignored.");
2762 auto V = [&](
const std::string & s)
2768 const unsigned int first_node,
2769 const unsigned int last_node)
2771 std::vector<Real>
values;
2773 for (
unsigned int iz = first_node; iz <= last_node; ++iz)
2774 for (
unsigned int i_ch = 0; i_ch <
_n_channels; ++i_ch)
2779 const std::vector<Real> & old_values,
2780 const unsigned int first_node,
2781 const unsigned int last_node,
2782 const Real reference_offset)
2784 Real difference_norm_sq = 0.0;
2785 Real reference_norm_sq = 0.0;
2787 for (
unsigned int iz = first_node; iz <= last_node; ++iz)
2788 for (
unsigned int i_ch = 0; i_ch <
_n_channels; ++i_ch)
2791 difference_norm_sq += Utility::pow<2>(value - old_values[i]);
2792 reference_norm_sq += Utility::pow<2>(old_values[i] + reference_offset);
2795 return std::sqrt(difference_norm_sq) / (std::sqrt(reference_norm_sq) + 1e-14);
2797 V(
"Solution initialized");
2799 unsigned int P_it = 0;
2800 unsigned int P_it_max;
2801 bool temperature_converged =
true;
2814 while ((P_error >
_P_tol && P_it < P_it_max))
2817 temperature_converged =
true;
2819 _console <<
"Solving Outer Iteration : " << P_it << std::endl;
2821 for (
unsigned int iblock = 0; iblock <
_n_blocks; iblock++)
2825 Real T_block_error = 1.0;
2827 _console <<
"Solving Block: " << iblock <<
" From first level: " << first_level
2828 <<
" to last level: " << last_level << std::endl;
2840 V(
"Done with main solve.");
2848 if (T_block_error <= _T_tol || T_it >=
_T_maxit)
2851 V(
"Enthalpy subcycle: " + std::to_string(enthalpy_subcycle + 1));
2853 const auto T_old = saveValues(*
_T_soln, first_level, last_level);
2858 T_block_error = 0.0;
2866 V(
"Done with thermal solve.");
2869 V(
"Start updating thermophysical properties.");
2874 V(
"Done updating thermophysical properties.");
2879 _aux->solution().close();
2883 relativeChange(*
_T_soln, T_old, first_level, last_level, 0.0);
2884 _console <<
"T_block_error: " << T_block_error << std::endl;
2890 const bool block_converged = T_block_error <=
_T_tol;
2891 temperature_converged &= block_converged;
2892 if (!block_converged)
2894 _console <<
"Reached maximum number of temperature iterations for block: " << iblock
2901 _console <<
"P_error :" << P_error << std::endl;
2902 V(
"Iteration: " + std::to_string(P_it));
2903 V(
"Maximum iterations: " + std::to_string(P_it_max));
2907 const bool pressure_converged = P_error <=
_P_tol;
2908 if (!pressure_converged)
2910 _console <<
"Reached maximum number of axial pressure iterations" << std::endl;
2912 _converged = pressure_converged && temperature_converged;
2915 _console <<
"Finished executing subchannel solver\n";
2918 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
2928 for (
unsigned int iz = 0; iz <
_n_cells + 1; ++iz)
2930 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
2933 auto mu = (*_mu_soln)(node);
2934 auto S = (*_S_flow_soln)(node);
2935 auto w_perim = (*_w_perim_soln)(node);
2936 auto Dh_i = 4.0 * S / w_perim;
2937 auto Re = (((*_mdot_soln)(node) / S) * Dh_i /
mu);
2940 auto Pr = (*_mu_soln)(node)*cp / k;
2960 _console <<
"Commencing calculation of Pin surface temperature \n";
2961 for (
unsigned int i_pin = 0; i_pin <
_n_pins; i_pin++)
2963 for (
unsigned int iz = 0; iz <
_n_cells + 1; ++iz)
2971 auto mu = (*_mu_soln)(node);
2972 auto S = (*_S_flow_soln)(node);
2973 auto w_perim = (*_w_perim_soln)(node);
2974 auto Dh_i = 4.0 * S / w_perim;
2975 auto Re = (((*_mdot_soln)(node) / S) * Dh_i /
mu);
2978 auto Pr = (*_mu_soln)(node)*cp / k;
2987 (*_q_prime_soln)(pin_node) / ((*
_Dpin_soln)(pin_node)*M_PI * hw) + (*_T_soln)(node);
2992 mooseError(
"Pin was not found for pin index: " + std::to_string(i_pin));
3000 _console <<
"Commencing calculation of duct surface temperature " << std::endl;
3002 for (Node * dn : duct_nodes)
3005 auto mu = (*_mu_soln)(node_chan);
3006 auto S = (*_S_flow_soln)(node_chan);
3007 auto w_perim = (*_w_perim_soln)(node_chan);
3008 auto Dh_i = 4.0 * S / w_perim;
3009 auto Re = (((*_mdot_soln)(node_chan) / S) * Dh_i /
mu);
3012 auto Pr = (*_mu_soln)(node_chan)*cp / k;
3029 auto T_chan = (*_duct_heat_flux_soln)(dn) / hw + (*
_T_soln)(node_chan);
3033 _aux->solution().close();
3038 Real power_in = 0.0;
3039 Real power_out = 0.0;
3040 Real mass_flow_in = 0.0;
3041 Real mass_flow_out = 0.0;
3042 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
3046 const Real mdot_in = (*_mdot_soln)(node_in);
3047 power_in += mdot_in * (*_h_soln)(node_in);
3048 power_out += (*_mdot_soln)(node_out) * (*
_h_soln)(node_out);
3049 mass_flow_in += mdot_in;
3050 mass_flow_out += (*_mdot_soln)(node_out);
3052 auto h_bulk_out = power_out / mass_flow_out;
3053 auto T_bulk_out =
_fp->T_from_p_h(
_P_out, h_bulk_out);
3059 _console <<
" ======================================= " << std::endl;
3060 _console <<
" ======== Subchannel Print Outs ======== " << std::endl;
3061 _console <<
" ======================================= " << std::endl;
3064 _console <<
"Assembly hydraulic diameter :" << bulk_Dh <<
" m" << std::endl;
3066 _console <<
"Bulk coolant temperature at outlet :" << T_bulk_out <<
" K" << std::endl;
3067 _console <<
"Power added to coolant is : " << power_out - power_in <<
" Watt" << std::endl;
3068 _console <<
"Mass flow rate in is : " << mass_flow_in <<
" kg/sec" << std::endl;
3069 _console <<
"Mass balance is : " << mass_flow_out - mass_flow_in <<
" kg/sec" << std::endl;
3070 _console <<
"User defined outlet pressure is : " <<
_P_out <<
" Pa" << std::endl;
3071 _console <<
" ======================================= " << std::endl;
3074 if (MooseUtils::absoluteFuzzyLessEqual((power_out - power_in), -1.0))
3076 "Energy conservation equation might not be solved correctly, Power added to coolant: " +
3077 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 Real computeSweepFlowMixingParameter(const unsigned int i_gap, const unsigned int iz) const
Computes the wire-wrap sweep-flow coefficient for peripheral gaps.
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.
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 resize(const unsigned int new_m, const unsigned int new_n)
virtual void zero() override final
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...