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 to evaluate values at the cell center. Default is "
130 "central_difference");
132 "gravity", gravity_direction,
"Direction of gravity. Default is counter_flow");
134 "implicit",
false,
"Boolean to define the use of explicit or implicit solution.");
136 "staggered_pressure",
138 "Boolean to define the use of staggered or collocated pressure.",
139 "Pressure is a face value and the pressure drop is a cell value, so the collocated "
140 "formulation is always used. This parameter is ignored.");
142 "segregated",
true,
"Boolean to define whether to use a segregated solution.");
144 "verbose_subchannel",
false,
"Boolean to print out information related to subchannel solve.");
145 params.
addRequiredParam<
bool>(
"compute_density",
"Flag that enables the calculation of density");
147 "Flag that enables the calculation of viscosity");
150 "Flag that informs whether we solve the Enthalpy/Temperature equations or not");
153 "The postprocessor (or scalar) that provides the absolute outlet pressure [Pa]. The solved "
154 "pressure variable P is relative to this value.");
155 params.
addRequiredParam<UserObjectName>(
"fp",
"Fluid properties user object name");
157 "Closure computing the friction factor");
160 "Closure computing the turbulent mixing, wire-induced "
161 "mixing and sweep flow mixing parameter where applicable");
163 "pin_HTC_closure",
"Closure computing HTC on fuel pin (required if pin mesh exists).");
164 params.
addParam<UserObjectName>(
"duct_HTC_closure",
165 "Closure computing HTC on duct (required if duct mesh exists).");
167 "full_output",
false,
"Flag that enables the output of the maximum number of variables.");
169 "Thermal diffusion coefficient used in turbulent crossflow.",
170 "Use closure system instead.");
174 "Boolean to define the use of a constant beta or beta correlation (Kim and Chung, 2001)",
175 "Use closure system instead.");
178 "P_tol P_maxit T_tol T_maxit T_relaxation enthalpy_subcycles "
179 "mass_flow_equation_relaxation pressure_equation_relaxation crossflow_equation_relaxation "
180 "mass_flow_relaxation pressure_relaxation crossflow_relaxation rtol atol dtol maxit",
181 "Solver tolerances and iterations");
183 params.
addParamNamesToGroup(
"fp friction_closure mixing_closure pin_HTC_closure duct_HTC_closure",
195 _friction_args(0, 1.0, 0.0, 0.0),
197 1.0, 1.0,
std::numeric_limits<unsigned
int>::max(), 0, 0),
198 _P_out(getPostprocessorValue(
"P_out")),
201 _n_blocks(getParam<unsigned
int>(
"n_blocks")),
202 _Wij(declareRestartableData<
libMesh::DenseMatrix<Real>>(
"Wij")),
203 _Wij_old(declareRestartableData<
libMesh::DenseMatrix<Real>>(
"Wij_old")),
205 _kij(_subchannel_mesh.getKij()),
207 _compute_density(getParam<bool>(
"compute_density")),
208 _compute_viscosity(getParam<bool>(
"compute_viscosity")),
209 _compute_power(getParam<bool>(
"compute_power")),
210 _pin_mesh_exist(_subchannel_mesh.pinMeshExist()),
211 _duct_mesh_exist(_subchannel_mesh.ductMeshExist()),
214 _P_tol(getParam<Real>(
"P_tol")),
215 _P_maxit(getParam<
int>(
"P_maxit")),
216 _T_tol(getParam<Real>(
"T_tol")),
217 _T_maxit(getParam<
int>(
"T_maxit")),
218 _T_relaxation(getParam<Real>(
"T_relaxation")),
219 _enthalpy_subcycles(getParam<unsigned
int>(
"enthalpy_subcycles")),
220 _mass_flow_equation_relaxation(getParam<Real>(
"mass_flow_equation_relaxation")),
221 _pressure_equation_relaxation(getParam<Real>(
"pressure_equation_relaxation")),
222 _crossflow_equation_relaxation(getParam<Real>(
"crossflow_equation_relaxation")),
223 _mass_flow_relaxation(getParam<Real>(
"mass_flow_relaxation")),
224 _pressure_relaxation(getParam<Real>(
"pressure_relaxation")),
225 _crossflow_relaxation(getParam<Real>(
"crossflow_relaxation")),
226 _rtol(getParam<PetscReal>(
"rtol")),
227 _atol(getParam<PetscReal>(
"atol")),
228 _dtol(getParam<PetscReal>(
"dtol")),
229 _maxit(getParam<PetscInt>(
"maxit")),
230 _interpolation_scheme(getParam<
MooseEnum>(
"interpolation_scheme")),
231 _gravity_direction(getParam<
MooseEnum>(
"gravity")),
232 _dir_grav(computeGravityDir(_gravity_direction)),
233 _implicit_bool(getParam<bool>(
"implicit")),
234 _segregated_bool(getParam<bool>(
"segregated")),
235 _verbose_subchannel(getParam<bool>(
"verbose_subchannel")),
236 _friction_closure(nullptr),
237 _mixing_closure(nullptr),
238 _pin_HTC_closure(nullptr),
239 _duct_HTC_closure(nullptr),
241 _duct_heat_flux_soln(nullptr),
242 _Tduct_soln(nullptr),
247 "You are using a deprecated parameter. Please use the mixing_closure system.");
249 paramError(
"pin_HTC_closure",
"required when a pin mesh exists.");
251 paramError(
"duct_HTC_closure",
"required when a duct mesh exists.");
253 paramError(
"segregated",
"A non-segregated solve requires 'implicit = true'.");
255 for (
const auto * relaxation_param : {
"mass_flow_equation_relaxation",
256 "pressure_equation_relaxation",
257 "crossflow_equation_relaxation",
258 "mass_flow_relaxation",
259 "pressure_relaxation",
260 "crossflow_relaxation"})
265 "' parameter is only used by the implicit non-segregated solve. Set "
266 "'implicit = true' and 'segregated = false' to use it.");
364 ": When implicit number of blocks can't be equal to number of cells. This will "
365 "cause problems with the subchannel interpolation scheme.");
377 if (getParam<bool>(
"full_output"))
407 _fp = &getUserObject<SinglePhaseFluidProperties>(getParam<UserObjectName>(
"fp"));
409 &getUserObject<SCMFrictionClosureBase>(getParam<UserObjectName>(
"friction_closure"));
411 &getUserObject<SCMMixingClosureBase>(getParam<UserObjectName>(
"mixing_closure"));
418 &getUserObject<SCMHTCClosureBase>(getParam<UserObjectName>(
"pin_HTC_closure"));
421 &getUserObject<SCMHTCClosureBase>(getParam<UserObjectName>(
"duct_HTC_closure"));
429 Real viscosity_in = 0.0;
430 Real volumetric_flow_in = 0.0;
431 Real mass_flow_in = 0.0;
435 const Real mdot_in = (*_mdot_soln)(node_in);
436 const Real rho_in = (*_rho_soln)(node_in);
437 viscosity_in += mdot_in * (*_mu_soln)(node_in);
438 volumetric_flow_in += mdot_in / rho_in;
439 mass_flow_in += mdot_in;
443 const Real inlet_mu = viscosity_in / mass_flow_in;
444 _bulk_Re = mass_flow_in * bulk_Dh / (inlet_mu * flow_area);
445 _bulk_V = volumetric_flow_in / flow_area;
451 if (MooseUtils::absoluteFuzzyEqual(
_bulk_Re, 0.0))
452 mooseError(
"The computed bulk Reynolds number is zero.");
454 if (MooseUtils::absoluteFuzzyEqual(
_bulk_V, 0.0))
455 mooseError(
"The computed bulk velocity is zero.");
468 for (
unsigned int iz = 0; iz <
_n_cells + 1; iz++)
469 for (
unsigned int i_pin = 0; i_pin <
_n_pins; i_pin++)
472 const Real Dpin = (*_Dpin_soln)(node);
473 if (std::abs(Dpin) <=
tol)
476 ". You must initialize Dpin to a non-zero value.");
477 if (std::abs(Dpin - pin_diameter) >
tol)
496 PetscErrorCode ierr =
cleanUp();
508 LibmeshPetscCall(VecDestroy(&
_Wij_vec));
509 LibmeshPetscCall(VecDestroy(&
_prod));
510 LibmeshPetscCall(VecDestroy(&
_prodp));
555 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
581 const auto Pe = Peclet;
582 if (std::abs(Pe) < 1e-6)
583 return 0.5 + Pe / 12.0;
584 const auto e = std::exp(-std::abs(Pe));
585 const auto alpha_pos = 1.0 - 1.0 / std::abs(Pe) + e / (1.0 - e);
586 return Pe > 0 ? alpha_pos : 1.0 - alpha_pos;
590 ": Interpolation scheme should be a string: upwind, downwind, central_difference, "
597 PetscScalar botValue,
601 return alpha * botValue + (1.0 - alpha) * topValue;
607 const unsigned int last_node = (iblock + 1) *
_block_size;
608 const unsigned int first_node = iblock *
_block_size + 1;
611 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
613 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
615 int i =
_n_gaps * (iz - first_node) + i_gap;
616 solution_seed(i) =
_Wij(i_gap, iz);
627 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
629 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
631 _Wij(i_gap, iz) = root(i);
640 const unsigned int last_node = (iblock + 1) *
_block_size;
641 const unsigned int first_node = iblock *
_block_size + 1;
645 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
647 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
652 unsigned int counter = 0;
667 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
669 unsigned int iz_ind = iz - first_node;
670 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
673 unsigned int counter = 0;
677 PetscInt col = i_gap +
_n_gaps * iz_ind;
679 LibmeshPetscCall(MatSetValues(
_mc_sumWij_mat, 1, &row, 1, &col, &value, INSERT_VALUES));
684 LibmeshPetscCall(MatAssemblyBegin(
_mc_sumWij_mat, MAT_FINAL_ASSEMBLY));
685 LibmeshPetscCall(MatAssemblyEnd(
_mc_sumWij_mat, MAT_FINAL_ASSEMBLY));
691 LibmeshPetscCall(VecDuplicate(
_Wij_vec, &loc_Wij));
695 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
697 LibmeshPetscCall(VecDestroy(&loc_prod));
698 LibmeshPetscCall(VecDestroy(&loc_Wij));
706 const unsigned int last_node = (iblock + 1) *
_block_size;
707 const unsigned int first_node = iblock *
_block_size + 1;
710 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
713 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
717 auto volume = dz * (*_S_flow_soln)(node_in);
718 auto time_term =
_TR * ((*_rho_soln)(node_out)-
_rho_soln->old(node_out)) * volume /
_dt;
720 auto mdot_out = (*_mdot_soln)(node_in) - (*
_SumWij_soln)(node_out)-time_term;
725 " : Calculation of negative mass flow mdot_out = : ",
729 " - Implicit solves are required for recirculating flow.");
737 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
740 auto iz_ind = iz - first_node;
741 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
745 auto volume = dz * (*_S_flow_soln)(node_in);
748 auto time_term =
_TR * ((*_rho_soln)(node_out)-
_rho_soln->old(node_out)) * volume /
_dt;
750 PetscScalar value_vec = -1.0 * time_term;
765 Real
rho, drho_dp_T, drho_dT;
768 Real h, dh_dp_T, dh_dT;
770 const Real drho_dp_h = drho_dp_T - drho_dT * dh_dp_T / dh_dT;
771 const PetscScalar pressure_coefficient = volume /
_dt * drho_dp_h;
772 const PetscInt pressure_col = i_ch +
_n_channels * (iz_ind + 1);
778 &pressure_coefficient,
780 const PetscScalar linearization_rhs = pressure_coefficient * (*_P_soln)(node_out);
786 if (iz == first_node)
788 PetscScalar value_vec = (*_mdot_soln)(node_in);
797 PetscScalar value = -1.0;
805 PetscScalar value = 1.0;
812 PetscScalar value_vec_2 = -1.0 * (*_SumWij_soln)(node_out);
830 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksploc));
832 LibmeshPetscCall(KSPGetPC(ksploc, &pc));
833 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
835 LibmeshPetscCall(KSPSetFromOptions(ksploc));
837 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
840 LibmeshPetscCall(KSPDestroy(&ksploc));
841 LibmeshPetscCall(VecDestroy(&sol));
849 const unsigned int last_node = (iblock + 1) *
_block_size;
850 const unsigned int first_node = iblock *
_block_size + 1;
853 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
857 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
861 auto rho_in = (*_rho_soln)(node_in);
862 auto rho_out = (*_rho_soln)(node_out);
863 auto mu_in = (*_mu_soln)(node_in);
864 auto S = (*_S_flow_soln)(node_in);
865 auto w_perim = (*_w_perim_soln)(node_in);
866 auto time_term =
_TR * ((*_mdot_soln)(node_out)-
_mdot_soln->old(node_out)) * dz /
_dt -
870 Utility::pow<2>((*
_mdot_soln)(node_out)) * (1.0 / S / rho_out - 1.0 / S / rho_in);
871 auto mass_term2 = -2.0 * (*_mdot_soln)(node_out) * (*
_SumWij_soln)(node_out) / S / rho_in;
872 auto crossflow_term = 0.0;
873 auto turbulent_term = 0.0;
874 unsigned int counter = 0;
878 unsigned int ii_ch = chans.first;
879 unsigned int jj_ch = chans.second;
884 auto rho_i = (*_rho_soln)(node_in_i);
885 auto rho_j = (*_rho_soln)(node_in_j);
886 auto Si = (*_S_flow_soln)(node_in_i);
887 auto Sj = (*_S_flow_soln)(node_in_j);
890 if (
_Wij(i_gap, iz) > 0.0)
891 u_star = (*
_mdot_soln)(node_out_i) / Si / rho_i;
893 u_star = (*_mdot_soln)(node_out_j) / Sj / rho_j;
898 turbulent_term +=
_WijPrime(i_gap, iz) * (2 * (*_mdot_soln)(node_out) / rho_in / S -
903 turbulent_term *=
_CT;
907 ki = k_grid[i_ch][iz - 1];
909 ki = k_grid[i_ch][iz];
912 PetscScalar Pe = 0.5;
916 const auto w_perim_mid =
918 const auto mdot_mid =
921 const auto Dh_mid = 4.0 * S_mid / w_perim_mid;
923 i_ch, std::abs(mdot_mid) / S_mid * Dh_mid / mu_mid, S_mid, w_perim_mid);
925 Pe = 1.0 / ((ff_mid * dz / Dh_mid + ki) * 0.5) * mdot_mid / std::abs(mdot_mid);
934 const auto Dh_c = 4.0 * S_c / w_perim_c;
935 auto Re = std::abs(mdot_c) / S_c * Dh_c / mu_c;
941 (ff * dz / Dh_c + ki) * 0.5 * mdot_c * std::abs(mdot_c) / (S_c * rho_c);
943 auto DP = (1 / S) * (time_term + mass_term1 + mass_term2 + crossflow_term + turbulent_term +
944 friction_term + gravity_term);
964 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
968 auto iz_ind = iz - first_node;
969 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
976 PetscScalar Pe = 0.5;
980 auto S_in = (*_S_flow_soln)(node_in);
981 auto S_out = (*_S_flow_soln)(node_out);
983 auto w_perim_in = (*_w_perim_soln)(node_in);
984 auto w_perim_out = (*_w_perim_soln)(node_out);
988 auto mu_in = (*_mu_soln)(node_in);
989 auto mu_out = (*_mu_soln)(node_out);
991 auto Dh_c = 4.0 * S_interp / w_perim_interp;
993 auto Re = ((std::abs(mdot_loc) / S_interp) * Dh_c / mu_interp);
1001 ki = k_grid[i_ch][iz - 1];
1003 ki = k_grid[i_ch][iz];
1004 Pe = 1.0 / ((ff * dz / Dh_c + ki) * 0.5) * mdot_loc / std::abs(mdot_loc);
1009 auto rho_in = (*_rho_soln)(node_in);
1010 auto rho_out = (*_rho_soln)(node_out);
1014 auto mu_in = (*_mu_soln)(node_in);
1015 auto mu_out = (*_mu_soln)(node_out);
1019 auto S_in = (*_S_flow_soln)(node_in);
1020 auto S_out = (*_S_flow_soln)(node_out);
1024 auto w_perim_in = (*_w_perim_soln)(node_in);
1025 auto w_perim_out = (*_w_perim_soln)(node_out);
1029 auto Dh_c = 4.0 * S_interp / w_perim_interp;
1036 PetscScalar value_tt =
_TR * dz /
_dt;
1037 LibmeshPetscCall(MatSetValues(
1041 PetscInt row_vec_tt = i_ch +
_n_channels * iz_ind;
1047 if (iz == first_node)
1049 PetscScalar value_vec_at = Utility::pow<2>((*
_mdot_soln)(node_in)) / (S_in * rho_in);
1050 PetscInt row_vec_at = i_ch +
_n_channels * iz_ind;
1051 LibmeshPetscCall(VecSetValues(
1057 PetscInt col_at = i_ch +
_n_channels * (iz_ind - 1);
1058 PetscScalar value_at = -1.0 * (*_mdot_soln)(node_in) / (S_in * rho_in);
1059 LibmeshPetscCall(MatSetValues(
1066 PetscScalar value_at = (*_mdot_soln)(node_out) / (S_out * rho_out);
1067 LibmeshPetscCall(MatSetValues(
1071 unsigned int counter = 0;
1072 unsigned int cross_index = iz;
1076 unsigned int ii_ch = chans.first;
1077 unsigned int jj_ch = chans.second;
1092 if (
_Wij(i_gap, cross_index) > 0.0)
1094 if (iz == first_node)
1096 u_star = (*_mdot_soln)(node_in_i) / S_i / rho_i;
1097 PetscScalar value_vec_ct = -1.0 * alpha *
1099 _Wij(i_gap, cross_index) * u_star;
1100 PetscInt row_vec_ct = i_ch +
_n_channels * iz_ind;
1101 LibmeshPetscCall(VecSetValues(
1107 _Wij(i_gap, cross_index) / S_i / rho_i;
1109 PetscInt col_ct = ii_ch +
_n_channels * (iz_ind - 1);
1110 LibmeshPetscCall(MatSetValues(
1113 PetscScalar value_ct = (1.0 - alpha) *
1115 _Wij(i_gap, cross_index) / S_i / rho_i;
1118 LibmeshPetscCall(MatSetValues(
1121 else if (
_Wij(i_gap, cross_index) < 0.0)
1123 if (iz == first_node)
1125 u_star = (*_mdot_soln)(node_in_j) / S_j / rho_j;
1126 PetscScalar value_vec_ct = -1.0 * alpha *
1128 _Wij(i_gap, cross_index) * u_star;
1129 PetscInt row_vec_ct = i_ch +
_n_channels * iz_ind;
1130 LibmeshPetscCall(VecSetValues(
1136 _Wij(i_gap, cross_index) / S_j / rho_j;
1138 PetscInt col_ct = jj_ch +
_n_channels * (iz_ind - 1);
1139 LibmeshPetscCall(MatSetValues(
1142 PetscScalar value_ct = (1.0 - alpha) *
1144 _Wij(i_gap, cross_index) / S_j / rho_j;
1147 LibmeshPetscCall(MatSetValues(
1151 if (iz == first_node)
1153 PetscScalar value_vec_ct = -2.0 * alpha * (*_mdot_soln)(node_in)*
_CT *
1154 _WijPrime(i_gap, cross_index) / (rho_interp * S_interp);
1155 value_vec_ct += alpha * (*_mdot_soln)(node_in_j)*
_CT *
_WijPrime(i_gap, cross_index) /
1157 value_vec_ct += alpha * (*_mdot_soln)(node_in_i)*
_CT *
_WijPrime(i_gap, cross_index) /
1159 PetscInt row_vec_ct = i_ch +
_n_channels * iz_ind;
1165 PetscScalar value_center_ct =
1166 2.0 * alpha *
_CT *
_WijPrime(i_gap, cross_index) / (rho_interp * S_interp);
1168 PetscInt col_ct = i_ch +
_n_channels * (iz_ind - 1);
1169 LibmeshPetscCall(MatSetValues(
1172 PetscScalar value_left_ct =
1173 -1.0 * alpha *
_CT *
_WijPrime(i_gap, cross_index) / (rho_j * S_j);
1176 LibmeshPetscCall(MatSetValues(
1179 PetscScalar value_right_ct =
1180 -1.0 * alpha *
_CT *
_WijPrime(i_gap, cross_index) / (rho_i * S_i);
1183 LibmeshPetscCall(MatSetValues(
1187 PetscScalar value_center_ct =
1188 2.0 * (1.0 - alpha) *
_CT *
_WijPrime(i_gap, cross_index) / (rho_interp * S_interp);
1191 LibmeshPetscCall(MatSetValues(
1194 PetscScalar value_left_ct =
1195 -1.0 * (1.0 - alpha) *
_CT *
_WijPrime(i_gap, cross_index) / (rho_j * S_j);
1198 LibmeshPetscCall(MatSetValues(
1201 PetscScalar value_right_ct =
1202 -1.0 * (1.0 - alpha) *
_CT *
_WijPrime(i_gap, cross_index) / (rho_i * S_i);
1205 LibmeshPetscCall(MatSetValues(
1211 PetscScalar mdot_interp =
1213 auto Re = ((std::abs(mdot_interp) / S_interp) * Dh_c / mu_interp);
1221 ki = k_grid[i_ch][iz - 1];
1223 ki = k_grid[i_ch][iz];
1224 auto coef = (ff * dz / Dh_c + ki) * 0.5 * std::abs(mdot_interp) / (S_interp * rho_interp);
1225 if (iz == first_node)
1227 PetscScalar value_vec = -1.0 * alpha * coef * (*_mdot_soln)(node_in);
1236 PetscScalar value = alpha * coef;
1244 PetscScalar value = (1.0 - alpha) * coef;
1249 PetscScalar value_vec =
_dir_grav * -1.0 *
_g_grav * rho_interp * dz * S_interp;
1251 LibmeshPetscCall(VecSetValues(
_amc_gravity_rhs, 1, &row_vec, &value_vec, ADD_VALUES));
1268#if !PETSC_VERSION_LESS_THAN(3, 15, 0)
1310 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
1317 LibmeshPetscCall(VecGetArray(ls, &xx));
1318 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1320 auto iz_ind = iz - first_node;
1321 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1328 auto S_in = (*_S_flow_soln)(node_in);
1329 auto S_out = (*_S_flow_soln)(node_out);
1335 auto DP = (1 / S_interp) * xx[iz_ind *
_n_channels + i_ch];
1349 LibmeshPetscCall(VecDestroy(&ls));
1357 const unsigned int last_node = (iblock + 1) *
_block_size;
1358 const unsigned int first_node = iblock *
_block_size + 1;
1361 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1364 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1376 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1378 auto iz_ind = iz - first_node;
1380 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1386 auto S_in = (*_S_flow_soln)(node_in);
1387 auto S_out = (*_S_flow_soln)(node_out);
1393 PetscScalar value = -1.0 * S_interp;
1401 if (iz == last_node)
1403 PetscScalar value = -1.0 * (*_P_soln)(node_out)*S_interp;
1411 PetscScalar value = 1.0 * S_interp;
1422 auto dp_out =
_DP(i_ch, iz);
1423 PetscScalar value_v = -1.0 * dp_out * S_interp;
1438 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksploc));
1440 LibmeshPetscCall(KSPGetPC(ksploc, &pc));
1441 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
1443 LibmeshPetscCall(KSPSetFromOptions(ksploc));
1446 LibmeshPetscCall(VecGetArray(sol, &xx));
1448 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1450 auto iz_ind = iz - first_node;
1451 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1454 PetscScalar value = xx[iz_ind *
_n_channels + i_ch];
1459 LibmeshPetscCall(KSPDestroy(&ksploc));
1460 LibmeshPetscCall(VecDestroy(&sol));
1468 const unsigned int last_node = (iblock + 1) *
_block_size;
1469 const unsigned int first_node = iblock *
_block_size + 1;
1470 std::vector<Real> residual;
1472 Real residual_norm_sq = 0.0;
1473 Real temperature_norm_sq = 0.0;
1474 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1476 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1479 const Real
T = (*_T_soln)(node);
1481 residual.push_back(T_from_ph -
T);
1482 residual_norm_sq += Utility::pow<2>(residual.back());
1483 temperature_norm_sq += Utility::pow<2>(
T);
1489 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1490 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1497 return std::sqrt(residual_norm_sq) / (std::sqrt(temperature_norm_sq) + 1e-14);
1503 const unsigned int last_node = (iblock + 1) *
_block_size;
1504 const unsigned int first_node = iblock *
_block_size + 1;
1507 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1513 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1515 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1526 const unsigned int last_node = (iblock + 1) *
_block_size;
1527 const unsigned int first_node = iblock *
_block_size + 1;
1530 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1536 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1538 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1549 const unsigned int last_node = (iblock + 1) *
_block_size;
1550 const unsigned int first_node = iblock *
_block_size + 1;
1555 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1558 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1561 unsigned int i_ch = chans.first;
1562 unsigned int j_ch = chans.second;
1567 auto rho_i = (*_rho_soln)(node_in_i);
1568 auto rho_j = (*_rho_soln)(node_in_j);
1569 auto Si = (*_S_flow_soln)(node_in_i);
1570 auto Sj = (*_S_flow_soln)(node_in_j);
1574 auto friction_term =
_kij *
_Wij(i_gap, iz) * std::abs(
_Wij(i_gap, iz));
1575 auto DPij = (*_P_soln)(node_in_i) - (*
_P_soln)(node_in_j);
1577 auto rho_star = 0.0;
1578 if (
_Wij(i_gap, iz) > 0.0)
1580 else if (
_Wij(i_gap, iz) < 0.0)
1583 rho_star = (rho_i + rho_j) / 2.0;
1584 auto mass_term_out =
1588 (*_mdot_soln)(node_in_i) / Si / rho_i + (*
_mdot_soln)(node_in_j) / Sj / rho_j;
1589 auto term_out = Sij * rho_star * (Lij / dz) * mass_term_out *
_Wij(i_gap, iz);
1590 auto term_in = Sij * rho_star * (Lij / dz) * mass_term_in *
_Wij(i_gap, iz - 1);
1591 auto inertia_term = term_out - term_in;
1592 auto pressure_term = 2 * Utility::pow<2>(Sij) * DPij * rho_star;
1597 time_term + friction_term + inertia_term - pressure_term;
1615 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1618 auto iz_ind = iz - first_node;
1619 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1622 unsigned int i_ch = chans.first;
1623 unsigned int j_ch = chans.second;
1630 auto rho_i_in = (*_rho_soln)(node_in_i);
1631 auto rho_i_out = (*_rho_soln)(node_out_i);
1633 auto rho_j_in = (*_rho_soln)(node_in_j);
1634 auto rho_j_out = (*_rho_soln)(node_out_j);
1638 auto S_i_in = (*_S_flow_soln)(node_in_i);
1639 auto S_i_out = (*_S_flow_soln)(node_out_i);
1640 auto S_j_in = (*_S_flow_soln)(node_in_j);
1641 auto S_j_out = (*_S_flow_soln)(node_out_j);
1648 auto rho_star = 0.0;
1649 if (
_Wij(i_gap, iz) > 0.0)
1650 rho_star = rho_i_interp;
1651 else if (
_Wij(i_gap, iz) < 0.0)
1652 rho_star = rho_j_interp;
1654 rho_star = (rho_i_interp + rho_j_interp) / 2.0;
1657 PetscScalar time_factor =
_TR * Lij * Sij * rho_star /
_dt;
1658 PetscInt row_td = i_gap +
_n_gaps * iz_ind;
1659 PetscInt col_td = i_gap +
_n_gaps * iz_ind;
1660 PetscScalar value_td = time_factor;
1661 LibmeshPetscCall(MatSetValues(
1663 PetscScalar value_td_rhs = time_factor *
_Wij_old(i_gap, iz);
1668 PetscScalar Pe = 0.5;
1670 auto mass_term_out = (*_mdot_soln)(node_out_i) / S_i_out / rho_i_out +
1671 (*
_mdot_soln)(node_out_j) / S_j_out / rho_j_out;
1672 auto mass_term_in = (*_mdot_soln)(node_in_i) / S_i_in / rho_i_in +
1673 (*
_mdot_soln)(node_in_j) / S_j_in / rho_j_in;
1674 auto term_out = Sij * rho_star * (Lij / dz) * mass_term_out / 2.0;
1675 auto term_in = Sij * rho_star * (Lij / dz) * mass_term_in / 2.0;
1676 if (iz == first_node)
1678 PetscInt row_ad = i_gap +
_n_gaps * iz_ind;
1679 PetscScalar value_ad = term_in * alpha *
_Wij(i_gap, iz - 1);
1683 PetscInt col_ad = i_gap +
_n_gaps * iz_ind;
1684 value_ad = -1.0 * term_in * (1.0 - alpha) + term_out * alpha;
1685 LibmeshPetscCall(MatSetValues(
1688 col_ad = i_gap +
_n_gaps * (iz_ind + 1);
1689 value_ad = term_out * (1.0 - alpha);
1690 LibmeshPetscCall(MatSetValues(
1693 else if (iz == last_node)
1695 PetscInt row_ad = i_gap +
_n_gaps * iz_ind;
1696 PetscInt col_ad = i_gap +
_n_gaps * (iz_ind - 1);
1697 PetscScalar value_ad = -1.0 * term_in * alpha;
1698 LibmeshPetscCall(MatSetValues(
1701 col_ad = i_gap +
_n_gaps * iz_ind;
1702 value_ad = -1.0 * term_in * (1.0 - alpha) + term_out * alpha;
1703 LibmeshPetscCall(MatSetValues(
1706 value_ad = -1.0 * term_out * (1.0 - alpha) *
_Wij(i_gap, iz);
1712 PetscInt row_ad = i_gap +
_n_gaps * iz_ind;
1713 PetscInt col_ad = i_gap +
_n_gaps * (iz_ind - 1);
1714 PetscScalar value_ad = -1.0 * term_in * alpha;
1715 LibmeshPetscCall(MatSetValues(
1718 col_ad = i_gap +
_n_gaps * iz_ind;
1719 value_ad = -1.0 * term_in * (1.0 - alpha) + term_out * alpha;
1720 LibmeshPetscCall(MatSetValues(
1723 col_ad = i_gap +
_n_gaps * (iz_ind + 1);
1724 value_ad = term_out * (1.0 - alpha);
1725 LibmeshPetscCall(MatSetValues(
1729 PetscInt row_ff = i_gap +
_n_gaps * iz_ind;
1730 PetscInt col_ff = i_gap +
_n_gaps * iz_ind;
1731 PetscScalar value_ff =
_kij * std::abs(
_Wij(i_gap, iz)) / 2.0;
1732 LibmeshPetscCall(MatSetValues(
1738 PetscScalar pressure_factor = Utility::pow<2>(Sij) * rho_star;
1739 PetscInt row_pf = i_gap +
_n_gaps * iz_ind;
1741 PetscScalar value_pf = -1.0 * alpha * pressure_factor;
1745 value_pf = alpha * pressure_factor;
1749 if (iz == last_node)
1751 PetscInt row_pf = i_gap +
_n_gaps * iz_ind;
1752 PetscScalar value_pf = (1.0 - alpha) * pressure_factor * (*
_P_soln)(node_out_i);
1755 value_pf = -1.0 * (1.0 - alpha) * pressure_factor * (*
_P_soln)(node_out_j);
1761 row_pf = i_gap +
_n_gaps * iz_ind;
1763 value_pf = -1.0 * (1.0 - alpha) * pressure_factor;
1767 value_pf = (1.0 - alpha) * pressure_factor;
1787#if !PETSC_VERSION_LESS_THAN(3, 15, 0)
1824 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
1832 LibmeshPetscCall(VecAXPY(sol_holder_W, 1.0, sol_holder_P));
1834 LibmeshPetscCall(VecGetArray(sol_holder_W, &xx));
1835 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1837 auto iz_ind = iz - first_node;
1838 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1843 LibmeshPetscCall(VecDestroy(&sol_holder_P));
1844 LibmeshPetscCall(VecDestroy(&sol_holder_W));
1852 const unsigned int last_node = (iblock + 1) *
_block_size;
1853 const unsigned int first_node = iblock *
_block_size + 1;
1855 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1858 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1861 unsigned int i_ch = chans.first;
1862 unsigned int j_ch = chans.second;
1867 auto Si_in = (*_S_flow_soln)(node_in_i);
1868 auto Sj_in = (*_S_flow_soln)(node_in_j);
1869 auto Si_out = (*_S_flow_soln)(node_out_i);
1870 auto Sj_out = (*_S_flow_soln)(node_out_j);
1872 auto Sij = dz * gap;
1878 0.5 * (((*_mdot_soln)(node_in_i) + (*
_mdot_soln)(node_in_j)) / (Si_in + Sj_in) +
1884 _WijPrime(i_gap, iz) = beta * avg_massflux * Sij;
1888 auto iz_ind = iz - first_node;
1889 PetscScalar base_value = beta * 0.5 * Sij;
1892 if (iz == first_node)
1894 PetscScalar value_tl = -1.0 * base_value / (Si_in + Sj_in) *
1896 PetscInt row = i_gap +
_n_gaps * iz_ind;
1902 PetscScalar value_tl = base_value / (Si_in + Sj_in);
1903 PetscInt row = i_gap +
_n_gaps * iz_ind;
1905 PetscInt col_ich = i_ch +
_n_channels * (iz_ind - 1);
1906 LibmeshPetscCall(MatSetValues(
1909 PetscInt col_jch = j_ch +
_n_channels * (iz_ind - 1);
1910 LibmeshPetscCall(MatSetValues(
1915 PetscScalar value_bl = base_value / (Si_out + Sj_out);
1916 PetscInt row = i_gap +
_n_gaps * iz_ind;
1919 LibmeshPetscCall(MatSetValues(
1923 LibmeshPetscCall(MatSetValues(
1938 LibmeshPetscCall(VecDuplicate(
_Wij_vec, &loc_Wij));
1939 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
1945 LibmeshPetscCall(VecDestroy(&loc_prod));
1946 LibmeshPetscCall(VecDestroy(&loc_Wij));
1954 if (!std::isfinite(beta) || beta < 0.0)
1956 ": Mixing closure returned invalid beta = ",
1962 ". Beta must be finite and non-negative.");
1971 if (!std::isfinite(beta) || beta < 0.0)
1973 ": Mixing closure returned invalid sweep-flow coefficient = ",
1979 ". sweep-flow coefficient must be finite and non-negative.");
1987 const unsigned int last_node = (iblock + 1) *
_block_size;
1988 const unsigned int first_node = iblock *
_block_size + 1;
1992 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1994 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1996 _Wij(i_gap, iz) = solution(i);
2017 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
2023 return Wij_residual_vector;
2038 LibmeshPetscCall(SNESCreate(PETSC_COMM_SELF, &snes));
2039 LibmeshPetscCall(VecCreate(PETSC_COMM_SELF, &
x));
2041 LibmeshPetscCall(VecSetFromOptions(
x));
2042 LibmeshPetscCall(VecDuplicate(
x, &r));
2044#if PETSC_VERSION_LESS_THAN(3, 13, 0)
2045 LibmeshPetscCall(PetscOptionsSetValue(PETSC_NULL,
"-snes_mf", PETSC_NULL));
2047 LibmeshPetscCall(SNESSetUseMatrixFree(snes, PETSC_FALSE, PETSC_TRUE));
2050 ctx.iblock = iblock;
2052 LibmeshPetscCall(SNESSetFunction(snes, r,
formFunction, &ctx));
2053 LibmeshPetscCall(SNESGetKSP(snes, &ksp));
2054 LibmeshPetscCall(KSPGetPC(ksp, &pc));
2055 LibmeshPetscCall(PCSetType(pc, PCNONE));
2057 LibmeshPetscCall(SNESSetFromOptions(snes));
2058 LibmeshPetscCall(VecGetArray(
x, &xx));
2061 xx[i] = solution(i);
2063 LibmeshPetscCall(VecRestoreArray(
x, &xx));
2065 LibmeshPetscCall(SNESSolve(snes, NULL,
x));
2069 SNESConvergedReason reason;
2070 LibmeshPetscCall(SNESGetConvergedReason(snes, &reason));
2073 PetscInt iterations;
2074 PetscReal residual_norm;
2075 LibmeshPetscCall(SNESGetIterationNumber(snes, &iterations));
2076 LibmeshPetscCall(SNESGetFunctionNorm(snes, &residual_norm));
2077 mooseWarning(
"Crossflow nonlinear solve did not converge: ",
2078 SNESConvergedReasons[reason],
2080 static_cast<int>(reason),
2083 " iterations; residual norm = ",
2085 ". The crossflow of this iteration is not updated.");
2087 LibmeshPetscCall(VecGetArray(
x, &xx));
2091 LibmeshPetscCall(VecRestoreArray(
x, &xx));
2092 LibmeshPetscCall(VecDestroy(&
x));
2093 LibmeshPetscCall(VecDestroy(&r));
2094 LibmeshPetscCall(SNESDestroy(&snes));
2095 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
2100 Mat
A, Vec rhs,
unsigned int first_node,
unsigned int last_node,
const char * ksp_prefix)
2106 LibmeshPetscCall(VecDuplicate(rhs, &
x));
2111 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksp));
2112 LibmeshPetscCall(KSPSetOperators(ksp,
A,
A));
2113 LibmeshPetscCall(KSPGetPC(ksp, &pc));
2114 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
2116 if (ksp_prefix && *ksp_prefix)
2117 LibmeshPetscCall(KSPSetOptionsPrefix(ksp, ksp_prefix));
2118 LibmeshPetscCall(KSPSetFromOptions(ksp));
2121 LibmeshPetscCall(KSPSolve(ksp, rhs,
x));
2122 KSPConvergedReason reason;
2123 LibmeshPetscCall(KSPGetConvergedReason(ksp, &reason));
2126 PetscInt iterations;
2127 PetscReal residual_norm;
2128 LibmeshPetscCall(KSPGetIterationNumber(ksp, &iterations));
2129 LibmeshPetscCall(KSPGetResidualNorm(ksp, &residual_norm));
2131 ": enthalpy linear solve failed: ",
2132 KSPConvergedReasons[reason],
2134 static_cast<int>(reason),
2137 " iterations; residual norm = ",
2143 PetscScalar * xx =
nullptr;
2144 LibmeshPetscCall(VecGetArray(
x, &xx));
2145 for (
unsigned int iz = first_node; iz <= last_node; ++iz)
2147 const unsigned int iz_ind = iz - first_node;
2148 for (
unsigned int i_ch = 0; i_ch <
_n_channels; ++i_ch)
2151 const PetscScalar h_out = xx[iz_ind *
_n_channels + i_ch];
2154 name(),
" : Calculation of negative Enthalpy h_out = ", h_out,
" Axial Level = ", iz);
2155 _h_soln->set(node_out, h_out);
2158 LibmeshPetscCall(VecRestoreArray(
x, &xx));
2161 LibmeshPetscCall(KSPDestroy(&ksp));
2162 LibmeshPetscCall(VecDestroy(&
x));
2164 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
2170 mooseAssert(iz > 0,
"Trapezoidal rule requires starting at index 1 at least");
2181 auto heat_rate_in = (*_duct_heat_flux_soln)(node_in_duct);
2182 auto heat_rate_out = (*_duct_heat_flux_soln)(node_out_duct);
2184 return 0.5 * (heat_rate_in + heat_rate_out) * dz * width;
2202 auto V = [&](
const std::string & s)
2208 auto DupMatAssembled = [&](Mat src, Mat * dst)
2212 LibmeshPetscCall(MatDuplicate(src, MAT_COPY_VALUES, dst));
2213 LibmeshPetscCall(MatAssemblyBegin(*dst, MAT_FINAL_ASSEMBLY));
2214 LibmeshPetscCall(MatAssemblyEnd(*dst, MAT_FINAL_ASSEMBLY));
2220 auto DupVecCopy = [&](Vec src, Vec * dst)
2222 LibmeshPetscCall(VecDuplicate(src, dst));
2223 LibmeshPetscCall(VecCopy(src, *dst));
2226 const PetscInt Q = 3;
2229 auto Idx = [&](PetscInt r, PetscInt
c) {
return Q * r +
c; };
2232 std::vector<Mat> mat_array(Q * Q, NULL);
2233 std::vector<Vec> vec_array(Q, NULL);
2236 auto AssembleEquation = [&](PetscInt
f,
2244 DupMatAssembled(
A0, &mat_array[Idx(
f, 0)]);
2245 DupMatAssembled(
A1, &mat_array[Idx(
f, 1)]);
2246 DupMatAssembled(
A2, &mat_array[Idx(
f, 2)]);
2247 DupVecCopy(rhs, &vec_array[
f]);
2249 LibmeshPetscCall(VecAXPY(vec_array[
f], 1.0, rhs_add));
2250 V(std::string(label) +
" system assembled");
2269 auto relaxEquation =
2270 [&](Mat diagonal_block, Vec rhs, Vec work,
const Real relaxation,
auto && populate)
2272 if (relaxation == 1.0)
2275 Vec diagonal =
nullptr;
2276 LibmeshPetscCall(VecDuplicate(rhs, &diagonal));
2279 LibmeshPetscCall(MatGetDiagonal(diagonal_block, diagonal));
2280 LibmeshPetscCall(VecScale(diagonal, 1.0 / relaxation));
2281 LibmeshPetscCall(MatDiagonalSet(diagonal_block, diagonal, INSERT_VALUES));
2284 LibmeshPetscCall(populate(work));
2287 LibmeshPetscCall(VecScale(diagonal, 1.0 - relaxation));
2288 LibmeshPetscCall(VecPointwiseMult(work, work, diagonal));
2289 LibmeshPetscCall(VecAXPY(rhs, 1.0, work));
2291 LibmeshPetscCall(VecDestroy(&diagonal));
2295 const unsigned int first_node = iblock *
_block_size + 1;
2296 const unsigned int last_node = (iblock + 1) *
_block_size;
2306 V(
"Starting nested system.");
2339 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
2350 LibmeshPetscCall(VecSet(unity_vec, 1.0));
2355 LibmeshPetscCall(VecSet(unity_vec_Wij, 1.0));
2358 Vec _Wij_old_loc_vec;
2363 LibmeshPetscCall(MatMult(mat_array[Q ],
_prod, mdot_estimate));
2366 LibmeshPetscCall(MatGetDiagonal(mat_array[Q + 1], pmat_diag));
2367 LibmeshPetscCall(VecAXPY(pmat_diag, 1e-10, unity_vec));
2368 LibmeshPetscCall(VecPointwiseDivide(p_estimate, mdot_estimate, pmat_diag));
2371 LibmeshPetscCall(MatMult(mat_array[2 * Q + 1], p_estimate, sol_holder_P));
2377 for (
unsigned int iz = first_node; iz <= last_node; ++iz)
2379 const auto iz_ind = iz - first_node;
2380 for (
unsigned int i_ch = 0; i_ch <
_n_channels; ++i_ch)
2382 PetscScalar sumWij = 0.0;
2383 unsigned int counter = 0;
2386 PetscInt row_vec = i_gap +
_n_gaps * iz_ind;
2387 PetscScalar loc_Wij_value;
2388 LibmeshPetscCall(VecGetValues(sol_holder_P, 1, &row_vec, &loc_Wij_value));
2393 LibmeshPetscCall(VecSetValues(sumWij_loc, 1, &row_vec, &sumWij, INSERT_VALUES));
2396 LibmeshPetscCall(VecAssemblyBegin(sumWij_loc));
2397 LibmeshPetscCall(VecAssemblyEnd(sumWij_loc));
2400 PetscScalar min_mdot, sum_mdot, avg_mdot;
2402 LibmeshPetscCall(VecAbs(
_prod));
2403 LibmeshPetscCall(VecMin(
_prod, NULL, &min_mdot));
2404 LibmeshPetscCall(VecSum(
_prod, &sum_mdot));
2405 LibmeshPetscCall(VecGetSize(
_prod, &n));
2406 avg_mdot = sum_mdot /
static_cast<PetscScalar
>(n);
2408 V(
"Average estimated mdot: " + std::to_string(avg_mdot));
2409 V(
"Minimum estimated mdot: " + std::to_string(min_mdot));
2411 LibmeshPetscCall(VecAbs(sumWij_loc));
2412 LibmeshPetscCall(VecMax(sumWij_loc, NULL, &
_max_sumWij));
2414 V(
"Maximum estimated Wij: " + std::to_string(
_max_sumWij));
2417 _Wij_loc_vec,
_Wij, first_node, last_node,
_n_gaps));
2418 LibmeshPetscCall(VecAbs(_Wij_loc_vec));
2421 LibmeshPetscCall(VecAbs(_Wij_old_loc_vec));
2422 LibmeshPetscCall(VecAXPY(_Wij_loc_vec, -1.0, _Wij_old_loc_vec));
2424 PetscScalar relax_factor;
2425 LibmeshPetscCall(VecAbs(_Wij_loc_vec));
2426#if !PETSC_VERSION_LESS_THAN(3, 16, 0)
2427 LibmeshPetscCall(VecMean(_Wij_loc_vec, &relax_factor));
2429 VecSum(_Wij_loc_vec, &relax_factor);
2433 V(
"Relax base value: " + std::to_string(relax_factor));
2436 const PetscScalar resistance_relaxation = 0.9;
2438 V(
"New cross resistance: " + std::to_string(
_added_K));
2441 V(
"Relaxed cross resistance: " + std::to_string(
_added_K));
2444 if (_added_K < 10 && _added_K >= 1.0)
2446 if (_added_K < 1.0 && _added_K >= 0.1)
2448 if (_added_K < 0.1 && _added_K >= 0.01)
2450 if (_added_K < 1e-2 && _added_K >= 1e-3)
2452 V(
"Actual added cross resistance: " + std::to_string(
_added_K));
2453 LibmeshPetscCall(VecScale(unity_vec_Wij,
_added_K));
2456 LibmeshPetscCall(MatDiagonalSet(mat_array[2 * Q + 2], unity_vec_Wij, ADD_VALUES));
2459 LibmeshPetscCall(VecDestroy(&mdot_estimate));
2460 LibmeshPetscCall(VecDestroy(&pmat_diag));
2461 LibmeshPetscCall(VecDestroy(&unity_vec));
2462 LibmeshPetscCall(VecDestroy(&p_estimate));
2463 LibmeshPetscCall(VecDestroy(&sol_holder_P));
2464 LibmeshPetscCall(VecDestroy(&unity_vec_Wij));
2465 LibmeshPetscCall(VecDestroy(&sumWij_loc));
2466 LibmeshPetscCall(VecDestroy(&_Wij_loc_vec));
2467 LibmeshPetscCall(VecDestroy(&_Wij_old_loc_vec));
2474 relaxEquation(mat_array[Idx(0, 0)],
2480 return populateVectorFromHandle<SolutionHandle>(
2485 relaxEquation(mat_array[Idx(1, 1)],
2493 return populateVectorFromHandle<SolutionHandle>(
2498 relaxEquation(mat_array[Idx(2, 2)],
2504 return populateVectorFromDense<libMesh::DenseMatrix<Real>>(
2508 V(
"Linear solver relaxed");
2514 LibmeshPetscCall(MatCreateNest(PETSC_COMM_SELF, Q, NULL, Q, NULL, mat_array.data(), &A_nest));
2515 LibmeshPetscCall(VecCreateNest(PETSC_COMM_SELF, Q, NULL, vec_array.data(), &b_nest));
2516 V(
"Nested system created");
2520 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksp));
2521 LibmeshPetscCall(KSPSetOptionsPrefix(ksp,
"scm_coupled_"));
2522 LibmeshPetscCall(KSPSetType(ksp, KSPFGMRES));
2523 LibmeshPetscCall(KSPSetOperators(ksp, A_nest, A_nest));
2524 LibmeshPetscCall(KSPGetPC(ksp, &pc));
2525 LibmeshPetscCall(PCSetType(pc, PCFIELDSPLIT));
2529 std::vector<IS> rows(Q);
2530 LibmeshPetscCall(MatNestGetISs(A_nest, rows.data(), NULL));
2531 for (PetscInt j = 0; j < Q; ++j)
2534 LibmeshPetscCall(ISDuplicate(rows[j], &part));
2535 LibmeshPetscCall(PCFieldSplitSetIS(pc, NULL, part));
2536 LibmeshPetscCall(ISDestroy(&part));
2538 LibmeshPetscCall(KSPSetFromOptions(ksp));
2539 V(
"Linear solver assembled");
2542 LibmeshPetscCall(VecDuplicate(b_nest, &x_nest));
2543 LibmeshPetscCall(VecSet(x_nest, 0.0));
2544 LibmeshPetscCall(KSPSolve(ksp, b_nest, x_nest));
2545 KSPConvergedReason reason;
2546 LibmeshPetscCall(KSPGetConvergedReason(ksp, &reason));
2549 PetscInt iterations;
2550 PetscReal residual_norm;
2551 LibmeshPetscCall(KSPGetIterationNumber(ksp, &iterations));
2552 LibmeshPetscCall(KSPGetResidualNorm(ksp, &residual_norm));
2554 ": coupled mass/momentum linear solve failed: ",
2555 KSPConvergedReasons[reason],
2557 static_cast<int>(reason),
2560 " iterations; residual norm = ",
2566 LibmeshPetscCall(VecDestroy(&b_nest));
2567 LibmeshPetscCall(MatDestroy(&A_nest));
2568 LibmeshPetscCall(KSPDestroy(&ksp));
2569 for (PetscInt i = 0; i < Q * Q; i++)
2570 LibmeshPetscCall(MatDestroy(&mat_array[i]));
2571 for (PetscInt i = 0; i < Q; i++)
2572 LibmeshPetscCall(VecDestroy(&vec_array[i]));
2573 V(
"Solver elements destroyed");
2576 Vec sol_mdot, sol_p, sol_Wij;
2577 V(
"Vectors to hold solution created");
2580 LibmeshPetscCall(VecNestGetSubVecs(x_nest, &num_vecs, &loc_vecs));
2582 LibmeshPetscCall(VecCopy(loc_vecs[0], sol_mdot));
2584 LibmeshPetscCall(VecCopy(loc_vecs[1], sol_p));
2586 LibmeshPetscCall(VecCopy(loc_vecs[2], sol_Wij));
2587 V(
"Solution from coupled solver copied to solution vectors");
2590 auto relaxSolution = [&](Vec solution, Vec old_solution,
const Real relaxation)
2592 LibmeshPetscCall(VecScale(solution, relaxation));
2593 LibmeshPetscCall(VecAXPY(solution, 1.0 - relaxation, old_solution));
2595 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
2597 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
2602 Vec pressure_residual;
2603 LibmeshPetscCall(VecDuplicate(sol_p, &pressure_residual));
2604 LibmeshPetscCall(VecCopy(sol_p, pressure_residual));
2605 LibmeshPetscCall(VecAXPY(pressure_residual, -1.0,
_prodp));
2607 const PetscScalar * residual_array;
2608 const PetscScalar * old_pressure_array;
2609 PetscInt pressure_size;
2610 LibmeshPetscCall(VecGetSize(pressure_residual, &pressure_size));
2611 LibmeshPetscCall(VecGetArrayRead(pressure_residual, &residual_array));
2612 LibmeshPetscCall(VecGetArrayRead(
_prodp, &old_pressure_array));
2613 Real residual_norm_sq = 0.0;
2614 Real pressure_norm_sq = 0.0;
2615 for (PetscInt i = 0; i < pressure_size; ++i)
2617 residual_norm_sq += Utility::pow<2>(residual_array[i]);
2618 pressure_norm_sq += Utility::pow<2>(old_pressure_array[i] +
_P_out);
2620 LibmeshPetscCall(VecRestoreArrayRead(pressure_residual, &residual_array));
2621 LibmeshPetscCall(VecRestoreArrayRead(
_prodp, &old_pressure_array));
2622 LibmeshPetscCall(VecDestroy(&pressure_residual));
2625 std::sqrt(residual_norm_sq) / (std::sqrt(pressure_norm_sq) + 1e-14));
2634 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
2639 PetscScalar * sol_p_array;
2640 LibmeshPetscCall(VecGetArray(sol_p, &sol_p_array));
2641 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
2643 const auto iz_ind = iz - first_node;
2644 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
2647 PetscScalar value = sol_p_array[iz_ind *
_n_channels + i_ch];
2651 LibmeshPetscCall(VecRestoreArray(sol_p, &sol_p_array));
2659 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
2662 LibmeshPetscCall(VecAbs(
_prod));
2667 V(
"Solutions assigned to MOOSE variables.");
2670 LibmeshPetscCall(VecDestroy(&x_nest));
2671 LibmeshPetscCall(VecDestroy(&sol_mdot));
2672 LibmeshPetscCall(VecDestroy(&sol_p));
2673 LibmeshPetscCall(VecDestroy(&sol_Wij));
2674 V(
"Solutions destroyed.");
2676 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
2682 _console <<
"Executing subchannel solver\n";
2693 for (
const auto * ti :
transient->getTimeIntegrators())
2695 mooseWarning(
"The subchannel solver always uses implicit (backward) Euler time "
2696 "integration; the requested '",
2698 "' time integrator is ignored.");
2705 auto V = [&](
const std::string & s)
2711 const unsigned int first_node,
2712 const unsigned int last_node)
2714 std::vector<Real>
values;
2716 for (
unsigned int iz = first_node; iz <= last_node; ++iz)
2717 for (
unsigned int i_ch = 0; i_ch <
_n_channels; ++i_ch)
2722 const std::vector<Real> & old_values,
2723 const unsigned int first_node,
2724 const unsigned int last_node,
2725 const Real reference_offset)
2727 Real difference_norm_sq = 0.0;
2728 Real reference_norm_sq = 0.0;
2730 for (
unsigned int iz = first_node; iz <= last_node; ++iz)
2731 for (
unsigned int i_ch = 0; i_ch <
_n_channels; ++i_ch)
2734 difference_norm_sq += Utility::pow<2>(value - old_values[i]);
2735 reference_norm_sq += Utility::pow<2>(old_values[i] + reference_offset);
2738 return std::sqrt(difference_norm_sq) / (std::sqrt(reference_norm_sq) + 1e-14);
2740 V(
"Solution initialized");
2742 unsigned int P_it = 0;
2743 unsigned int P_it_max;
2744 bool temperature_converged =
true;
2757 while ((P_error >
_P_tol && P_it < P_it_max))
2760 temperature_converged =
true;
2762 _console <<
"Solving Outer Iteration : " << P_it << std::endl;
2764 for (
unsigned int iblock = 0; iblock <
_n_blocks; iblock++)
2768 Real T_block_error = 1.0;
2770 _console <<
"Solving Block: " << iblock <<
" From first level: " << first_level
2771 <<
" to last level: " << last_level << std::endl;
2783 V(
"Done with main solve.");
2791 if (T_block_error <= _T_tol || T_it >=
_T_maxit)
2794 V(
"Enthalpy subcycle: " + std::to_string(enthalpy_subcycle + 1));
2796 const auto T_old = saveValues(*
_T_soln, first_level, last_level);
2801 T_block_error = 0.0;
2809 V(
"Done with thermal solve.");
2812 V(
"Start updating thermophysical properties.");
2817 V(
"Done updating thermophysical properties.");
2822 _aux->solution().close();
2826 relativeChange(*
_T_soln, T_old, first_level, last_level, 0.0);
2827 _console <<
"T_block_error: " << T_block_error << std::endl;
2833 const bool block_converged = T_block_error <=
_T_tol;
2834 temperature_converged &= block_converged;
2835 if (!block_converged)
2837 _console <<
"Reached maximum number of temperature iterations for block: " << iblock
2844 _console <<
"P_error :" << P_error << std::endl;
2845 V(
"Iteration: " + std::to_string(P_it));
2846 V(
"Maximum iterations: " + std::to_string(P_it_max));
2850 const bool pressure_converged = P_error <=
_P_tol;
2851 if (!pressure_converged)
2853 _console <<
"Reached maximum number of axial pressure iterations" << std::endl;
2855 _converged = pressure_converged && temperature_converged;
2858 _console <<
"Finished executing subchannel solver\n";
2861 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
2871 for (
unsigned int iz = 0; iz <
_n_cells + 1; ++iz)
2873 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
2876 auto mu = (*_mu_soln)(node);
2877 auto S = (*_S_flow_soln)(node);
2878 auto w_perim = (*_w_perim_soln)(node);
2879 auto Dh_i = 4.0 * S / w_perim;
2883 auto Pr = (*_mu_soln)(node)*cp / k;
2903 _console <<
"Commencing calculation of Pin surface temperature \n";
2904 for (
unsigned int i_pin = 0; i_pin <
_n_pins; i_pin++)
2906 for (
unsigned int iz = 0; iz <
_n_cells + 1; ++iz)
2914 auto mu = (*_mu_soln)(node);
2915 auto S = (*_S_flow_soln)(node);
2916 auto w_perim = (*_w_perim_soln)(node);
2917 auto Dh_i = 4.0 * S / w_perim;
2921 auto Pr = (*_mu_soln)(node)*cp / k;
2930 (*_q_prime_soln)(pin_node) / ((*
_Dpin_soln)(pin_node)*M_PI * hw) + (*_T_soln)(node);
2935 mooseError(
"Pin was not found for pin index: " + std::to_string(i_pin));
2943 _console <<
"Commencing calculation of duct surface temperature " << std::endl;
2945 for (Node * dn : duct_nodes)
2948 auto mu = (*_mu_soln)(node_chan);
2949 auto S = (*_S_flow_soln)(node_chan);
2950 auto w_perim = (*_w_perim_soln)(node_chan);
2951 auto Dh_i = 4.0 * S / w_perim;
2952 auto Re = ((std::abs((*
_mdot_soln)(node_chan)) / S) * Dh_i /
mu);
2955 auto Pr = (*_mu_soln)(node_chan)*cp / k;
2972 auto T_chan = (*_duct_heat_flux_soln)(dn) / hw + (*
_T_soln)(node_chan);
2976 _aux->solution().close();
2984 Real power_in = 0.0;
2985 Real power_out = 0.0;
2986 Real mass_flow_in = 0.0;
2987 Real mass_flow_out = 0.0;
2988 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
2992 const Real mdot_in = (*_mdot_soln)(node_in);
2993 power_in += mdot_in * (*_h_soln)(node_in);
2994 power_out += (*_mdot_soln)(node_out) * (*
_h_soln)(node_out);
2995 mass_flow_in += mdot_in;
2996 mass_flow_out += (*_mdot_soln)(node_out);
2998 auto h_bulk_out = power_out / mass_flow_out;
2999 auto T_bulk_out =
_fp->T_from_p_h(
_P_out, h_bulk_out);
3004 _console <<
" ======================================= " << std::endl;
3005 _console <<
" ======== Subchannel Print Outs ======== " << std::endl;
3006 _console <<
" ======================================= " << std::endl;
3009 _console <<
"Assembly hydraulic diameter :" << bulk_Dh <<
" m" << std::endl;
3011 _console <<
"Bulk coolant temperature at outlet :" << T_bulk_out <<
" K" << std::endl;
3012 _console <<
"Power added to coolant is : " << power_out - power_in <<
" Watt" << std::endl;
3013 _console <<
"Mass flow rate in is : " << mass_flow_in <<
" kg/sec" << std::endl;
3014 _console <<
"Mass balance is : " << mass_flow_out - mass_flow_in <<
" kg/sec" << std::endl;
3015 _console <<
"User defined outlet pressure is : " <<
_P_out <<
" Pa" << std::endl;
3016 _console <<
" ======================================= " << std::endl;
3019 if (MooseUtils::absoluteFuzzyLessEqual((power_out - power_in), -1.0))
3021 "Energy conservation equation might not be solved correctly, Power added to coolant: " +
3022 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.
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...