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()),
209 _P_tol(getParam<Real>(
"P_tol")),
210 _P_maxit(getParam<
int>(
"P_maxit")),
211 _T_tol(getParam<Real>(
"T_tol")),
212 _T_maxit(getParam<
int>(
"T_maxit")),
213 _T_relaxation(getParam<Real>(
"T_relaxation")),
214 _enthalpy_subcycles(getParam<unsigned
int>(
"enthalpy_subcycles")),
215 _mass_flow_equation_relaxation(getParam<Real>(
"mass_flow_equation_relaxation")),
216 _pressure_equation_relaxation(getParam<Real>(
"pressure_equation_relaxation")),
217 _crossflow_equation_relaxation(getParam<Real>(
"crossflow_equation_relaxation")),
218 _mass_flow_relaxation(getParam<Real>(
"mass_flow_relaxation")),
219 _pressure_relaxation(getParam<Real>(
"pressure_relaxation")),
220 _crossflow_relaxation(getParam<Real>(
"crossflow_relaxation")),
221 _rtol(getParam<PetscReal>(
"rtol")),
222 _atol(getParam<PetscReal>(
"atol")),
223 _dtol(getParam<PetscReal>(
"dtol")),
224 _maxit(getParam<PetscInt>(
"maxit")),
225 _interpolation_scheme(getParam<
MooseEnum>(
"interpolation_scheme")),
226 _gravity_direction(getParam<
MooseEnum>(
"gravity")),
227 _dir_grav(computeGravityDir(_gravity_direction)),
228 _implicit_bool(getParam<bool>(
"implicit")),
229 _staggered_pressure_bool(getParam<bool>(
"staggered_pressure")),
230 _segregated_bool(getParam<bool>(
"segregated")),
231 _verbose_subchannel(getParam<bool>(
"verbose_subchannel")),
232 _friction_closure(nullptr),
233 _mixing_closure(nullptr),
234 _pin_HTC_closure(nullptr),
235 _duct_HTC_closure(nullptr),
237 _duct_heat_flux_soln(nullptr),
238 _Tduct_soln(nullptr),
243 "You are using a deprecated parameter. Please use the mixing_closure system.");
245 paramError(
"pin_HTC_closure",
"required when a pin mesh exists.");
247 paramError(
"duct_HTC_closure",
"required when a duct mesh exists.");
249 paramError(
"segregated",
"A non-segregated solve requires 'implicit = true'.");
251 for (
const auto * relaxation_param : {
"mass_flow_equation_relaxation",
252 "pressure_equation_relaxation",
253 "crossflow_equation_relaxation",
254 "mass_flow_relaxation",
255 "pressure_relaxation",
256 "crossflow_relaxation"})
261 "' parameter is only used by the implicit non-segregated solve. Set "
262 "'implicit = true' and 'segregated = false' to use it.");
360 ": When implicit number of blocks can't be equal to number of cells. This will "
361 "cause problems with the subchannel interpolation scheme.");
370 _fp = &getUserObject<SinglePhaseFluidProperties>(getParam<UserObjectName>(
"fp"));
372 &getUserObject<SCMFrictionClosureBase>(getParam<UserObjectName>(
"friction_closure"));
374 &getUserObject<SCMMixingClosureBase>(getParam<UserObjectName>(
"mixing_closure"));
383 if (getParam<bool>(
"full_output"))
397 &getUserObject<SCMHTCClosureBase>(getParam<UserObjectName>(
"pin_HTC_closure"));
412 &getUserObject<SCMHTCClosureBase>(getParam<UserObjectName>(
"duct_HTC_closure"));
424 for (
unsigned int iz = 0; iz <
_n_cells + 1; iz++)
425 for (
unsigned int i_pin = 0; i_pin <
_n_pins; i_pin++)
428 const Real Dpin = (*_Dpin_soln)(node);
429 if (std::abs(Dpin) <=
tol)
432 ". You must initialize Dpin to a non-zero value.");
433 if (std::abs(Dpin - pin_diameter) >
tol)
452 PetscErrorCode ierr =
cleanUp();
464 LibmeshPetscCall(VecDestroy(&
_Wij_vec));
465 LibmeshPetscCall(VecDestroy(&
_prod));
466 LibmeshPetscCall(VecDestroy(&
_prodp));
511 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
532 return ((Peclet - 1.0) * std::exp(Peclet) + 1) / (Peclet * (std::exp(Peclet) - 1.) + 1e-10);
535 ": Interpolation scheme should be a string: upwind, downwind, central_difference, "
542 PetscScalar botValue,
546 return alpha * botValue + (1.0 - alpha) * topValue;
552 const unsigned int last_node = (iblock + 1) *
_block_size;
553 const unsigned int first_node = iblock *
_block_size + 1;
556 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
558 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
560 int i =
_n_gaps * (iz - first_node) + i_gap;
561 solution_seed(i) =
_Wij(i_gap, iz);
572 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
574 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
576 _Wij(i_gap, iz) = root(i);
585 const unsigned int last_node = (iblock + 1) *
_block_size;
586 const unsigned int first_node = iblock *
_block_size + 1;
590 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
592 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
597 unsigned int counter = 0;
612 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
614 unsigned int iz_ind = iz - first_node;
615 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
618 unsigned int counter = 0;
622 PetscInt col = i_gap +
_n_gaps * iz_ind;
624 LibmeshPetscCall(MatSetValues(
_mc_sumWij_mat, 1, &row, 1, &col, &value, INSERT_VALUES));
629 LibmeshPetscCall(MatAssemblyBegin(
_mc_sumWij_mat, MAT_FINAL_ASSEMBLY));
630 LibmeshPetscCall(MatAssemblyEnd(
_mc_sumWij_mat, MAT_FINAL_ASSEMBLY));
636 LibmeshPetscCall(VecDuplicate(
_Wij_vec, &loc_Wij));
640 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
642 LibmeshPetscCall(VecDestroy(&loc_prod));
643 LibmeshPetscCall(VecDestroy(&loc_Wij));
651 const unsigned int last_node = (iblock + 1) *
_block_size;
652 const unsigned int first_node = iblock *
_block_size + 1;
655 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
658 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
662 auto volume = dz * (*_S_flow_soln)(node_in);
663 auto time_term =
_TR * ((*_rho_soln)(node_out)-
_rho_soln->old(node_out)) * volume /
_dt;
665 auto mdot_out = (*_mdot_soln)(node_in) - (*
_SumWij_soln)(node_out)-time_term;
670 " : Calculation of negative mass flow mdot_out = : ",
674 " - Implicit solves are required for recirculating flow.");
682 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
685 auto iz_ind = iz - first_node;
686 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
690 auto volume = dz * (*_S_flow_soln)(node_in);
693 auto time_term =
_TR * ((*_rho_soln)(node_out)-
_rho_soln->old(node_out)) * volume /
_dt;
695 PetscScalar value_vec = -1.0 * time_term;
710 Real
rho, drho_dp_T, drho_dT;
713 Real h, dh_dp_T, dh_dT;
715 const Real drho_dp_h = drho_dp_T - drho_dT * dh_dp_T / dh_dT;
716 const PetscScalar pressure_coefficient = volume /
_dt * drho_dp_h;
717 const PetscInt pressure_col = i_ch +
_n_channels * (iz_ind + 1);
723 &pressure_coefficient,
725 const PetscScalar linearization_rhs = pressure_coefficient * (*_P_soln)(node_out);
731 if (iz == first_node)
733 PetscScalar value_vec = (*_mdot_soln)(node_in);
742 PetscScalar value = -1.0;
750 PetscScalar value = 1.0;
757 PetscScalar value_vec_2 = -1.0 * (*_SumWij_soln)(node_out);
775 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksploc));
777 LibmeshPetscCall(KSPGetPC(ksploc, &pc));
778 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
780 LibmeshPetscCall(KSPSetFromOptions(ksploc));
782 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
785 LibmeshPetscCall(KSPDestroy(&ksploc));
786 LibmeshPetscCall(VecDestroy(&sol));
794 const unsigned int last_node = (iblock + 1) *
_block_size;
795 const unsigned int first_node = iblock *
_block_size + 1;
798 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
802 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
806 auto rho_in = (*_rho_soln)(node_in);
807 auto rho_out = (*_rho_soln)(node_out);
808 auto mu_in = (*_mu_soln)(node_in);
809 auto S = (*_S_flow_soln)(node_in);
810 auto w_perim = (*_w_perim_soln)(node_in);
812 auto Dh_i = 4.0 * S / w_perim;
813 auto time_term =
_TR * ((*_mdot_soln)(node_out)-
_mdot_soln->old(node_out)) * dz /
_dt -
817 Utility::pow<2>((*
_mdot_soln)(node_out)) * (1.0 / S / rho_out - 1.0 / S / rho_in);
818 auto mass_term2 = -2.0 * (*_mdot_soln)(node_out) * (*
_SumWij_soln)(node_out) / S / rho_in;
819 auto crossflow_term = 0.0;
820 auto turbulent_term = 0.0;
821 unsigned int counter = 0;
825 unsigned int ii_ch = chans.first;
826 unsigned int jj_ch = chans.second;
831 auto rho_i = (*_rho_soln)(node_in_i);
832 auto rho_j = (*_rho_soln)(node_in_j);
833 auto Si = (*_S_flow_soln)(node_in_i);
834 auto Sj = (*_S_flow_soln)(node_in_j);
837 if (
_Wij(i_gap, iz) > 0.0)
838 u_star = (*
_mdot_soln)(node_out_i) / Si / rho_i;
840 u_star = (*_mdot_soln)(node_out_j) / Sj / rho_j;
845 turbulent_term +=
_WijPrime(i_gap, iz) * (2 * (*_mdot_soln)(node_out) / rho_in / S -
850 turbulent_term *=
_CT;
851 auto Re = (((*_mdot_soln)(node_in) / S) * Dh_i / mu_in);
859 ki = k_grid[i_ch][iz - 1];
861 ki = k_grid[i_ch][iz];
862 auto friction_term = (ff * dz / Dh_i + ki) * 0.5 *
864 (S * (*_rho_soln)(node_out));
866 auto DP = (1 / S) * (time_term + mass_term1 + mass_term2 + crossflow_term + turbulent_term +
867 friction_term + gravity_term);
887 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
891 auto iz_ind = iz - first_node;
892 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
899 PetscScalar Pe = 0.5;
903 auto S_in = (*_S_flow_soln)(node_in);
904 auto S_out = (*_S_flow_soln)(node_out);
906 auto w_perim_in = (*_w_perim_soln)(node_in);
907 auto w_perim_out = (*_w_perim_soln)(node_out);
911 auto mu_in = (*_mu_soln)(node_in);
912 auto mu_out = (*_mu_soln)(node_out);
914 auto Dh_i = 4.0 * S_interp / w_perim_interp;
916 auto Re = ((mdot_loc / S_interp) * Dh_i / mu_interp);
924 ki = k_grid[i_ch][iz - 1];
926 ki = k_grid[i_ch][iz];
927 Pe = 1.0 / ((ff * dz / Dh_i + ki) * 0.5) * mdot_loc / std::abs(mdot_loc);
932 auto rho_in = (*_rho_soln)(node_in);
933 auto rho_out = (*_rho_soln)(node_out);
937 auto mu_in = (*_mu_soln)(node_in);
938 auto mu_out = (*_mu_soln)(node_out);
942 auto S_in = (*_S_flow_soln)(node_in);
943 auto S_out = (*_S_flow_soln)(node_out);
947 auto w_perim_in = (*_w_perim_soln)(node_in);
948 auto w_perim_out = (*_w_perim_soln)(node_out);
952 auto Dh_i = 4.0 * S_interp / w_perim_interp;
959 PetscScalar value_tt =
_TR * dz /
_dt;
960 LibmeshPetscCall(MatSetValues(
969 if (iz == first_node)
971 PetscScalar value_vec_at = Utility::pow<2>((*
_mdot_soln)(node_in)) / (S_in * rho_in);
973 LibmeshPetscCall(VecSetValues(
979 PetscInt col_at = i_ch +
_n_channels * (iz_ind - 1);
980 PetscScalar value_at = -1.0 * std::abs((*
_mdot_soln)(node_in)) / (S_in * rho_in);
981 LibmeshPetscCall(MatSetValues(
988 PetscScalar value_at = std::abs((*
_mdot_soln)(node_out)) / (S_out * rho_out);
989 LibmeshPetscCall(MatSetValues(
993 unsigned int counter = 0;
994 unsigned int cross_index = iz;
998 unsigned int ii_ch = chans.first;
999 unsigned int jj_ch = chans.second;
1014 if (
_Wij(i_gap, cross_index) > 0.0)
1016 if (iz == first_node)
1018 u_star = (*_mdot_soln)(node_in_i) / S_i / rho_i;
1019 PetscScalar value_vec_ct = -1.0 * alpha *
1021 _Wij(i_gap, cross_index) * u_star;
1022 PetscInt row_vec_ct = i_ch +
_n_channels * iz_ind;
1023 LibmeshPetscCall(VecSetValues(
1029 _Wij(i_gap, cross_index) / S_i / rho_i;
1031 PetscInt col_ct = ii_ch +
_n_channels * (iz_ind - 1);
1032 LibmeshPetscCall(MatSetValues(
1035 PetscScalar value_ct = (1.0 - alpha) *
1037 _Wij(i_gap, cross_index) / S_i / rho_i;
1040 LibmeshPetscCall(MatSetValues(
1043 else if (
_Wij(i_gap, cross_index) < 0.0)
1045 if (iz == first_node)
1047 u_star = (*_mdot_soln)(node_in_j) / S_j / rho_j;
1048 PetscScalar value_vec_ct = -1.0 * alpha *
1050 _Wij(i_gap, cross_index) * u_star;
1051 PetscInt row_vec_ct = i_ch +
_n_channels * iz_ind;
1052 LibmeshPetscCall(VecSetValues(
1058 _Wij(i_gap, cross_index) / S_j / rho_j;
1060 PetscInt col_ct = jj_ch +
_n_channels * (iz_ind - 1);
1061 LibmeshPetscCall(MatSetValues(
1064 PetscScalar value_ct = (1.0 - alpha) *
1066 _Wij(i_gap, cross_index) / S_j / rho_j;
1069 LibmeshPetscCall(MatSetValues(
1073 if (iz == first_node)
1075 PetscScalar value_vec_ct = -2.0 * alpha * (*_mdot_soln)(node_in)*
_CT *
1076 _WijPrime(i_gap, cross_index) / (rho_interp * S_interp);
1077 value_vec_ct += alpha * (*_mdot_soln)(node_in_j)*
_CT *
_WijPrime(i_gap, cross_index) /
1079 value_vec_ct += alpha * (*_mdot_soln)(node_in_i)*
_CT *
_WijPrime(i_gap, cross_index) /
1081 PetscInt row_vec_ct = i_ch +
_n_channels * iz_ind;
1087 PetscScalar value_center_ct =
1088 2.0 * alpha *
_CT *
_WijPrime(i_gap, cross_index) / (rho_interp * S_interp);
1090 PetscInt col_ct = i_ch +
_n_channels * (iz_ind - 1);
1091 LibmeshPetscCall(MatSetValues(
1094 PetscScalar value_left_ct =
1095 -1.0 * alpha *
_CT *
_WijPrime(i_gap, cross_index) / (rho_j * S_j);
1098 LibmeshPetscCall(MatSetValues(
1101 PetscScalar value_right_ct =
1102 -1.0 * alpha *
_CT *
_WijPrime(i_gap, cross_index) / (rho_i * S_i);
1105 LibmeshPetscCall(MatSetValues(
1109 PetscScalar value_center_ct =
1110 2.0 * (1.0 - alpha) *
_CT *
_WijPrime(i_gap, cross_index) / (rho_interp * S_interp);
1113 LibmeshPetscCall(MatSetValues(
1116 PetscScalar value_left_ct =
1117 -1.0 * (1.0 - alpha) *
_CT *
_WijPrime(i_gap, cross_index) / (rho_j * S_j);
1120 LibmeshPetscCall(MatSetValues(
1123 PetscScalar value_right_ct =
1124 -1.0 * (1.0 - alpha) *
_CT *
_WijPrime(i_gap, cross_index) / (rho_i * S_i);
1127 LibmeshPetscCall(MatSetValues(
1133 PetscScalar mdot_interp =
1135 auto Re = ((mdot_interp / S_interp) * Dh_i / mu_interp);
1143 ki = k_grid[i_ch][iz - 1];
1145 ki = k_grid[i_ch][iz];
1146 auto coef = (ff * dz / Dh_i + ki) * 0.5 * std::abs((*
_mdot_soln)(node_out)) /
1147 (S_interp * rho_interp);
1148 if (iz == first_node)
1150 PetscScalar value_vec = -1.0 * alpha * coef * (*_mdot_soln)(node_in);
1159 PetscScalar value = alpha * coef;
1167 PetscScalar value = (1.0 - alpha) * coef;
1172 PetscScalar value_vec =
_dir_grav * -1.0 *
_g_grav * rho_interp * dz * S_interp;
1174 LibmeshPetscCall(VecSetValues(
_amc_gravity_rhs, 1, &row_vec, &value_vec, ADD_VALUES));
1191#if !PETSC_VERSION_LESS_THAN(3, 15, 0)
1233 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
1240 LibmeshPetscCall(VecGetArray(ls, &xx));
1241 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1243 auto iz_ind = iz - first_node;
1244 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1251 auto S_in = (*_S_flow_soln)(node_in);
1252 auto S_out = (*_S_flow_soln)(node_out);
1258 auto DP = (1 / S_interp) * xx[iz_ind *
_n_channels + i_ch];
1272 LibmeshPetscCall(VecDestroy(&ls));
1280 const unsigned int last_node = (iblock + 1) *
_block_size;
1281 const unsigned int first_node = iblock *
_block_size + 1;
1286 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1289 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1300 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1303 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1311 PetscScalar Pe = 0.5;
1313 if (iz == last_node)
1320 (*
_P_soln)(node_out) + (1.0 - alpha) *
_DP(i_ch, iz) +
1321 alpha *
_DP(i_ch, iz - 1));
1332 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1334 auto iz_ind = iz - first_node;
1336 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1342 auto S_in = (*_S_flow_soln)(node_in);
1343 auto S_out = (*_S_flow_soln)(node_out);
1349 PetscScalar value = -1.0 * S_interp;
1353 if (iz == last_node)
1355 PetscScalar value = -1.0 * (*_P_soln)(node_out)*S_interp;
1363 PetscScalar value = 1.0 * S_interp;
1370 auto dp_out =
_DP(i_ch, iz);
1371 PetscScalar value_v = -1.0 * dp_out * S_interp;
1387 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksploc));
1389 LibmeshPetscCall(KSPGetPC(ksploc, &pc));
1390 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
1392 LibmeshPetscCall(KSPSetFromOptions(ksploc));
1395 LibmeshPetscCall(VecGetArray(sol, &xx));
1397 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1399 auto iz_ind = iz - first_node;
1400 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1403 PetscScalar value = xx[iz_ind *
_n_channels + i_ch];
1408 LibmeshPetscCall(KSPDestroy(&ksploc));
1409 LibmeshPetscCall(VecDestroy(&sol));
1415 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1417 auto iz_ind = iz - first_node;
1419 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1425 auto S_in = (*_S_flow_soln)(node_in);
1426 auto S_out = (*_S_flow_soln)(node_out);
1432 PetscScalar value = -1.0 * S_interp;
1436 if (iz == last_node)
1438 PetscScalar value = -1.0 * (*_P_soln)(node_out)*S_interp;
1442 auto dp_out =
_DP(i_ch, iz);
1443 PetscScalar value_v = -1.0 * dp_out / 2.0 * S_interp;
1452 PetscScalar value = 1.0 * S_interp;
1458 auto dp_in =
_DP(i_ch, iz - 1);
1459 auto dp_out =
_DP(i_ch, iz);
1461 PetscScalar value_v = -1.0 * dp_interp * S_interp;
1473 _console <<
"Block: " << iblock <<
" - Axial momentum pressure force matrix assembled"
1482 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksploc));
1484 LibmeshPetscCall(KSPGetPC(ksploc, &pc));
1485 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
1487 LibmeshPetscCall(KSPSetFromOptions(ksploc));
1490 LibmeshPetscCall(VecGetArray(sol, &xx));
1492 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1494 auto iz_ind = iz - first_node;
1495 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1498 PetscScalar value = xx[iz_ind *
_n_channels + i_ch];
1503 LibmeshPetscCall(KSPDestroy(&ksploc));
1504 LibmeshPetscCall(VecDestroy(&sol));
1513 const unsigned int last_node = (iblock + 1) *
_block_size;
1514 const unsigned int first_node = iblock *
_block_size + 1;
1515 std::vector<Real> residual;
1517 Real residual_norm_sq = 0.0;
1518 Real temperature_norm_sq = 0.0;
1519 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1521 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1524 const Real
T = (*_T_soln)(node);
1526 residual.push_back(T_from_ph -
T);
1527 residual_norm_sq += Utility::pow<2>(residual.back());
1528 temperature_norm_sq += Utility::pow<2>(
T);
1534 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1535 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1542 return std::sqrt(residual_norm_sq) / (std::sqrt(temperature_norm_sq) + 1e-14);
1548 const unsigned int last_node = (iblock + 1) *
_block_size;
1549 const unsigned int first_node = iblock *
_block_size + 1;
1552 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1558 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1560 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1571 const unsigned int last_node = (iblock + 1) *
_block_size;
1572 const unsigned int first_node = iblock *
_block_size + 1;
1575 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1581 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1583 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1594 const unsigned int last_node = (iblock + 1) *
_block_size;
1595 const unsigned int first_node = iblock *
_block_size + 1;
1600 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1603 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1606 unsigned int i_ch = chans.first;
1607 unsigned int j_ch = chans.second;
1612 auto rho_i = (*_rho_soln)(node_in_i);
1613 auto rho_j = (*_rho_soln)(node_in_j);
1614 auto Si = (*_S_flow_soln)(node_in_i);
1615 auto Sj = (*_S_flow_soln)(node_in_j);
1619 auto friction_term =
_kij *
_Wij(i_gap, iz) * std::abs(
_Wij(i_gap, iz));
1620 auto DPij = (*_P_soln)(node_in_i) - (*
_P_soln)(node_in_j);
1622 auto rho_star = 0.0;
1623 if (
_Wij(i_gap, iz) > 0.0)
1625 else if (
_Wij(i_gap, iz) < 0.0)
1628 rho_star = (rho_i + rho_j) / 2.0;
1629 auto mass_term_out =
1633 (*_mdot_soln)(node_in_i) / Si / rho_i + (*
_mdot_soln)(node_in_j) / Sj / rho_j;
1634 auto term_out = Sij * rho_star * (Lij / dz) * mass_term_out *
_Wij(i_gap, iz);
1635 auto term_in = Sij * rho_star * (Lij / dz) * mass_term_in *
_Wij(i_gap, iz - 1);
1636 auto inertia_term = term_out - term_in;
1637 auto pressure_term = 2 * Utility::pow<2>(Sij) * DPij * rho_star;
1642 time_term + friction_term + inertia_term - pressure_term;
1660 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1663 auto iz_ind = iz - first_node;
1664 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1667 unsigned int i_ch = chans.first;
1668 unsigned int j_ch = chans.second;
1675 auto rho_i_in = (*_rho_soln)(node_in_i);
1676 auto rho_i_out = (*_rho_soln)(node_out_i);
1678 auto rho_j_in = (*_rho_soln)(node_in_j);
1679 auto rho_j_out = (*_rho_soln)(node_out_j);
1683 auto S_i_in = (*_S_flow_soln)(node_in_i);
1684 auto S_i_out = (*_S_flow_soln)(node_out_i);
1685 auto S_j_in = (*_S_flow_soln)(node_in_j);
1686 auto S_j_out = (*_S_flow_soln)(node_out_j);
1693 auto rho_star = 0.0;
1694 if (
_Wij(i_gap, iz) > 0.0)
1695 rho_star = rho_i_interp;
1696 else if (
_Wij(i_gap, iz) < 0.0)
1697 rho_star = rho_j_interp;
1699 rho_star = (rho_i_interp + rho_j_interp) / 2.0;
1702 PetscScalar time_factor =
_TR * Lij * Sij * rho_star /
_dt;
1703 PetscInt row_td = i_gap +
_n_gaps * iz_ind;
1704 PetscInt col_td = i_gap +
_n_gaps * iz_ind;
1705 PetscScalar value_td = time_factor;
1706 LibmeshPetscCall(MatSetValues(
1708 PetscScalar value_td_rhs = time_factor *
_Wij_old(i_gap, iz);
1713 PetscScalar Pe = 0.5;
1715 auto mass_term_out = (*_mdot_soln)(node_out_i) / S_i_out / rho_i_out +
1716 (*
_mdot_soln)(node_out_j) / S_j_out / rho_j_out;
1717 auto mass_term_in = (*_mdot_soln)(node_in_i) / S_i_in / rho_i_in +
1718 (*
_mdot_soln)(node_in_j) / S_j_in / rho_j_in;
1719 auto term_out = Sij * rho_star * (Lij / dz) * mass_term_out / 2.0;
1720 auto term_in = Sij * rho_star * (Lij / dz) * mass_term_in / 2.0;
1721 if (iz == first_node)
1723 PetscInt row_ad = i_gap +
_n_gaps * iz_ind;
1724 PetscScalar value_ad = term_in * alpha *
_Wij(i_gap, iz - 1);
1728 PetscInt col_ad = i_gap +
_n_gaps * iz_ind;
1729 value_ad = -1.0 * term_in * (1.0 - alpha) + term_out * alpha;
1730 LibmeshPetscCall(MatSetValues(
1733 col_ad = i_gap +
_n_gaps * (iz_ind + 1);
1734 value_ad = term_out * (1.0 - alpha);
1735 LibmeshPetscCall(MatSetValues(
1738 else if (iz == last_node)
1740 PetscInt row_ad = i_gap +
_n_gaps * iz_ind;
1741 PetscInt col_ad = i_gap +
_n_gaps * (iz_ind - 1);
1742 PetscScalar value_ad = -1.0 * term_in * alpha;
1743 LibmeshPetscCall(MatSetValues(
1746 col_ad = i_gap +
_n_gaps * iz_ind;
1747 value_ad = -1.0 * term_in * (1.0 - alpha) + term_out * alpha;
1748 LibmeshPetscCall(MatSetValues(
1751 value_ad = -1.0 * term_out * (1.0 - alpha) *
_Wij(i_gap, iz);
1757 PetscInt row_ad = i_gap +
_n_gaps * iz_ind;
1758 PetscInt col_ad = i_gap +
_n_gaps * (iz_ind - 1);
1759 PetscScalar value_ad = -1.0 * term_in * alpha;
1760 LibmeshPetscCall(MatSetValues(
1763 col_ad = i_gap +
_n_gaps * iz_ind;
1764 value_ad = -1.0 * term_in * (1.0 - alpha) + term_out * alpha;
1765 LibmeshPetscCall(MatSetValues(
1768 col_ad = i_gap +
_n_gaps * (iz_ind + 1);
1769 value_ad = term_out * (1.0 - alpha);
1770 LibmeshPetscCall(MatSetValues(
1774 PetscInt row_ff = i_gap +
_n_gaps * iz_ind;
1775 PetscInt col_ff = i_gap +
_n_gaps * iz_ind;
1776 PetscScalar value_ff =
_kij * std::abs(
_Wij(i_gap, iz)) / 2.0;
1777 LibmeshPetscCall(MatSetValues(
1785 PetscScalar pressure_factor = Utility::pow<2>(Sij) * rho_star;
1786 PetscInt row_pf = i_gap +
_n_gaps * iz_ind;
1788 PetscScalar value_pf = -1.0 * alpha * pressure_factor;
1792 value_pf = alpha * pressure_factor;
1796 if (iz == last_node)
1798 PetscInt row_pf = i_gap +
_n_gaps * iz_ind;
1799 PetscScalar value_pf = (1.0 - alpha) * pressure_factor * (*
_P_soln)(node_out_i);
1802 value_pf = -1.0 * (1.0 - alpha) * pressure_factor * (*
_P_soln)(node_out_j);
1808 row_pf = i_gap +
_n_gaps * iz_ind;
1810 value_pf = -1.0 * (1.0 - alpha) * pressure_factor;
1811 LibmeshPetscCall(MatSetValues(
1814 value_pf = (1.0 - alpha) * pressure_factor;
1815 LibmeshPetscCall(MatSetValues(
1821 PetscScalar pressure_factor = Utility::pow<2>(Sij) * rho_star;
1822 PetscInt row_pf = i_gap +
_n_gaps * iz_ind;
1824 PetscScalar value_pf = -1.0 * pressure_factor;
1828 value_pf = pressure_factor;
1848#if !PETSC_VERSION_LESS_THAN(3, 15, 0)
1885 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
1893 LibmeshPetscCall(VecAXPY(sol_holder_W, 1.0, sol_holder_P));
1895 LibmeshPetscCall(VecGetArray(sol_holder_W, &xx));
1896 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1898 auto iz_ind = iz - first_node;
1899 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1904 LibmeshPetscCall(VecDestroy(&sol_holder_P));
1905 LibmeshPetscCall(VecDestroy(&sol_holder_W));
1913 const unsigned int last_node = (iblock + 1) *
_block_size;
1914 const unsigned int first_node = iblock *
_block_size + 1;
1915 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1918 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1921 unsigned int i_ch = chans.first;
1922 unsigned int j_ch = chans.second;
1927 auto Si_in = (*_S_flow_soln)(node_in_i);
1928 auto Sj_in = (*_S_flow_soln)(node_in_j);
1929 auto Si_out = (*_S_flow_soln)(node_out_i);
1930 auto Sj_out = (*_S_flow_soln)(node_out_j);
1932 auto Sij = dz * gap;
1934 0.5 * (((*_mdot_soln)(node_in_i) + (*
_mdot_soln)(node_in_j)) / (Si_in + Sj_in) +
1940 _WijPrime(i_gap, iz) = beta * avg_massflux * Sij;
1944 auto iz_ind = iz - first_node;
1945 PetscScalar base_value = beta * 0.5 * Sij;
1948 if (iz == first_node)
1950 PetscScalar value_tl = -1.0 * base_value / (Si_in + Sj_in) *
1952 PetscInt row = i_gap +
_n_gaps * iz_ind;
1958 PetscScalar value_tl = base_value / (Si_in + Sj_in);
1959 PetscInt row = i_gap +
_n_gaps * iz_ind;
1961 PetscInt col_ich = i_ch +
_n_channels * (iz_ind - 1);
1962 LibmeshPetscCall(MatSetValues(
1965 PetscInt col_jch = j_ch +
_n_channels * (iz_ind - 1);
1966 LibmeshPetscCall(MatSetValues(
1971 PetscScalar value_bl = base_value / (Si_out + Sj_out);
1972 PetscInt row = i_gap +
_n_gaps * iz_ind;
1975 LibmeshPetscCall(MatSetValues(
1979 LibmeshPetscCall(MatSetValues(
1994 LibmeshPetscCall(VecDuplicate(
_Wij_vec, &loc_Wij));
1995 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
2001 LibmeshPetscCall(VecDestroy(&loc_prod));
2002 LibmeshPetscCall(VecDestroy(&loc_Wij));
2010 if (!std::isfinite(beta) || beta < 0.0)
2012 ": Mixing closure returned invalid beta = ",
2018 ". Beta must be finite and non-negative.");
2027 if (!std::isfinite(beta) || beta < 0.0)
2029 ": Mixing closure returned invalid sweep-flow coefficient = ",
2035 ". sweep-flow coefficient must be finite and non-negative.");
2043 const unsigned int last_node = (iblock + 1) *
_block_size;
2044 const unsigned int first_node = iblock *
_block_size + 1;
2048 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
2050 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
2052 _Wij(i_gap, iz) = solution(i);
2073 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
2079 return Wij_residual_vector;
2094 LibmeshPetscCall(SNESCreate(PETSC_COMM_SELF, &snes));
2095 LibmeshPetscCall(VecCreate(PETSC_COMM_SELF, &
x));
2097 LibmeshPetscCall(VecSetFromOptions(
x));
2098 LibmeshPetscCall(VecDuplicate(
x, &r));
2100#if PETSC_VERSION_LESS_THAN(3, 13, 0)
2101 LibmeshPetscCall(PetscOptionsSetValue(PETSC_NULL,
"-snes_mf", PETSC_NULL));
2103 LibmeshPetscCall(SNESSetUseMatrixFree(snes, PETSC_FALSE, PETSC_TRUE));
2106 ctx.iblock = iblock;
2108 LibmeshPetscCall(SNESSetFunction(snes, r,
formFunction, &ctx));
2109 LibmeshPetscCall(SNESGetKSP(snes, &ksp));
2110 LibmeshPetscCall(KSPGetPC(ksp, &pc));
2111 LibmeshPetscCall(PCSetType(pc, PCNONE));
2113 LibmeshPetscCall(SNESSetFromOptions(snes));
2114 LibmeshPetscCall(VecGetArray(
x, &xx));
2117 xx[i] = solution(i);
2119 LibmeshPetscCall(VecRestoreArray(
x, &xx));
2121 LibmeshPetscCall(SNESSolve(snes, NULL,
x));
2122 LibmeshPetscCall(VecGetArray(
x, &xx));
2126 LibmeshPetscCall(VecRestoreArray(
x, &xx));
2127 LibmeshPetscCall(VecDestroy(&
x));
2128 LibmeshPetscCall(VecDestroy(&r));
2129 LibmeshPetscCall(SNESDestroy(&snes));
2130 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
2135 Mat
A, Vec rhs,
unsigned int first_node,
unsigned int last_node,
const char * ksp_prefix)
2141 LibmeshPetscCall(VecDuplicate(rhs, &
x));
2146 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksp));
2147 LibmeshPetscCall(KSPSetOperators(ksp,
A,
A));
2148 LibmeshPetscCall(KSPGetPC(ksp, &pc));
2149 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
2151 if (ksp_prefix && *ksp_prefix)
2152 LibmeshPetscCall(KSPSetOptionsPrefix(ksp, ksp_prefix));
2153 LibmeshPetscCall(KSPSetFromOptions(ksp));
2156 LibmeshPetscCall(KSPSolve(ksp, rhs,
x));
2157 KSPConvergedReason reason;
2158 LibmeshPetscCall(KSPGetConvergedReason(ksp, &reason));
2161 PetscInt iterations;
2162 PetscReal residual_norm;
2163 LibmeshPetscCall(KSPGetIterationNumber(ksp, &iterations));
2164 LibmeshPetscCall(KSPGetResidualNorm(ksp, &residual_norm));
2166 ": enthalpy linear solve failed: ",
2167 KSPConvergedReasons[reason],
2169 static_cast<int>(reason),
2172 " iterations; residual norm = ",
2178 PetscScalar * xx =
nullptr;
2179 LibmeshPetscCall(VecGetArray(
x, &xx));
2180 for (
unsigned int iz = first_node; iz <= last_node; ++iz)
2182 const unsigned int iz_ind = iz - first_node;
2183 for (
unsigned int i_ch = 0; i_ch <
_n_channels; ++i_ch)
2186 const PetscScalar h_out = xx[iz_ind *
_n_channels + i_ch];
2189 name(),
" : Calculation of negative Enthalpy h_out = ", h_out,
" Axial Level = ", iz);
2190 _h_soln->set(node_out, h_out);
2193 LibmeshPetscCall(VecRestoreArray(
x, &xx));
2196 LibmeshPetscCall(KSPDestroy(&ksp));
2197 LibmeshPetscCall(VecDestroy(&
x));
2199 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
2205 mooseAssert(iz > 0,
"Trapezoidal rule requires starting at index 1 at least");
2216 auto heat_rate_in = (*_duct_heat_flux_soln)(node_in_duct);
2217 auto heat_rate_out = (*_duct_heat_flux_soln)(node_out_duct);
2219 return 0.5 * (heat_rate_in + heat_rate_out) * dz * width;
2237 auto V = [&](
const std::string & s)
2243 auto DupMatAssembled = [&](Mat src, Mat * dst)
2247 LibmeshPetscCall(MatDuplicate(src, MAT_COPY_VALUES, dst));
2248 LibmeshPetscCall(MatAssemblyBegin(*dst, MAT_FINAL_ASSEMBLY));
2249 LibmeshPetscCall(MatAssemblyEnd(*dst, MAT_FINAL_ASSEMBLY));
2255 auto DupVecCopy = [&](Vec src, Vec * dst)
2257 LibmeshPetscCall(VecDuplicate(src, dst));
2258 LibmeshPetscCall(VecCopy(src, *dst));
2261 const PetscInt Q = 3;
2264 auto Idx = [&](PetscInt r, PetscInt
c) {
return Q * r +
c; };
2267 std::vector<Mat> mat_array(Q * Q, NULL);
2268 std::vector<Vec> vec_array(Q, NULL);
2271 auto AssembleEquation = [&](PetscInt
f,
2279 DupMatAssembled(
A0, &mat_array[Idx(
f, 0)]);
2280 DupMatAssembled(
A1, &mat_array[Idx(
f, 1)]);
2281 DupMatAssembled(
A2, &mat_array[Idx(
f, 2)]);
2282 DupVecCopy(rhs, &vec_array[
f]);
2284 LibmeshPetscCall(VecAXPY(vec_array[
f], 1.0, rhs_add));
2285 V(std::string(label) +
" system assembled");
2304 auto relaxEquation =
2305 [&](Mat diagonal_block, Vec rhs, Vec work,
const Real relaxation,
auto && populate)
2307 if (relaxation == 1.0)
2310 Vec diagonal =
nullptr;
2311 LibmeshPetscCall(VecDuplicate(rhs, &diagonal));
2314 LibmeshPetscCall(MatGetDiagonal(diagonal_block, diagonal));
2315 LibmeshPetscCall(VecScale(diagonal, 1.0 / relaxation));
2316 LibmeshPetscCall(MatDiagonalSet(diagonal_block, diagonal, INSERT_VALUES));
2319 LibmeshPetscCall(populate(work));
2322 LibmeshPetscCall(VecScale(diagonal, 1.0 - relaxation));
2323 LibmeshPetscCall(VecPointwiseMult(work, work, diagonal));
2324 LibmeshPetscCall(VecAXPY(rhs, 1.0, work));
2326 LibmeshPetscCall(VecDestroy(&diagonal));
2330 const unsigned int first_node = iblock *
_block_size + 1;
2331 const unsigned int last_node = (iblock + 1) *
_block_size;
2341 V(
"Starting nested system.");
2374 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
2385 LibmeshPetscCall(VecSet(unity_vec, 1.0));
2390 LibmeshPetscCall(VecSet(unity_vec_Wij, 1.0));
2393 Vec _Wij_old_loc_vec;
2398 LibmeshPetscCall(MatMult(mat_array[Q ],
_prod, mdot_estimate));
2401 LibmeshPetscCall(MatGetDiagonal(mat_array[Q + 1], pmat_diag));
2402 LibmeshPetscCall(VecAXPY(pmat_diag, 1e-10, unity_vec));
2403 LibmeshPetscCall(VecPointwiseDivide(p_estimate, mdot_estimate, pmat_diag));
2406 LibmeshPetscCall(MatMult(mat_array[2 * Q + 1], p_estimate, sol_holder_P));
2412 for (
unsigned int iz = first_node; iz <= last_node; ++iz)
2414 const auto iz_ind = iz - first_node;
2415 for (
unsigned int i_ch = 0; i_ch <
_n_channels; ++i_ch)
2417 PetscScalar sumWij = 0.0;
2418 unsigned int counter = 0;
2422 unsigned int i_ch_loc = chans.first;
2423 PetscInt row_vec = i_ch_loc +
_n_channels * iz_ind;
2424 PetscScalar loc_Wij_value;
2425 LibmeshPetscCall(VecGetValues(sol_holder_P, 1, &row_vec, &loc_Wij_value));
2430 LibmeshPetscCall(VecSetValues(sumWij_loc, 1, &row_vec, &sumWij, INSERT_VALUES));
2433 LibmeshPetscCall(VecAssemblyBegin(sumWij_loc));
2434 LibmeshPetscCall(VecAssemblyEnd(sumWij_loc));
2437 PetscScalar min_mdot;
2438 LibmeshPetscCall(VecAbs(
_prod));
2439 LibmeshPetscCall(VecMin(
_prod, NULL, &min_mdot));
2440 V(
"Minimum estimated mdot: " + std::to_string(min_mdot));
2442 LibmeshPetscCall(VecAbs(sumWij_loc));
2443 LibmeshPetscCall(VecMax(sumWij_loc, NULL, &
_max_sumWij));
2445 V(
"Maximum estimated Wij: " + std::to_string(
_max_sumWij));
2448 _Wij_loc_vec,
_Wij, first_node, last_node,
_n_gaps));
2449 LibmeshPetscCall(VecAbs(_Wij_loc_vec));
2452 LibmeshPetscCall(VecAbs(_Wij_old_loc_vec));
2453 LibmeshPetscCall(VecAXPY(_Wij_loc_vec, -1.0, _Wij_old_loc_vec));
2455 PetscScalar relax_factor;
2456 LibmeshPetscCall(VecAbs(_Wij_loc_vec));
2457#if !PETSC_VERSION_LESS_THAN(3, 16, 0)
2458 LibmeshPetscCall(VecMean(_Wij_loc_vec, &relax_factor));
2460 VecSum(_Wij_loc_vec, &relax_factor);
2464 V(
"Relax base value: " + std::to_string(relax_factor));
2467 const PetscScalar resistance_relaxation = 0.9;
2469 V(
"New cross resistance: " + std::to_string(
_added_K));
2472 V(
"Relaxed cross resistance: " + std::to_string(
_added_K));
2475 if (_added_K < 10 && _added_K >= 1.0)
2477 if (_added_K < 1.0 && _added_K >= 0.1)
2479 if (_added_K < 0.1 && _added_K >= 0.01)
2481 if (_added_K < 1e-2 && _added_K >= 1e-3)
2483 V(
"Actual added cross resistance: " + std::to_string(
_added_K));
2484 LibmeshPetscCall(VecScale(unity_vec_Wij,
_added_K));
2487 LibmeshPetscCall(MatDiagonalSet(mat_array[2 * Q + 2], unity_vec_Wij, ADD_VALUES));
2490 LibmeshPetscCall(VecDestroy(&mdot_estimate));
2491 LibmeshPetscCall(VecDestroy(&pmat_diag));
2492 LibmeshPetscCall(VecDestroy(&unity_vec));
2493 LibmeshPetscCall(VecDestroy(&p_estimate));
2494 LibmeshPetscCall(VecDestroy(&sol_holder_P));
2495 LibmeshPetscCall(VecDestroy(&unity_vec_Wij));
2496 LibmeshPetscCall(VecDestroy(&sumWij_loc));
2497 LibmeshPetscCall(VecDestroy(&_Wij_loc_vec));
2498 LibmeshPetscCall(VecDestroy(&_Wij_old_loc_vec));
2505 relaxEquation(mat_array[Idx(0, 0)],
2511 return populateVectorFromHandle<SolutionHandle>(
2516 relaxEquation(mat_array[Idx(1, 1)],
2524 return populateVectorFromHandle<SolutionHandle>(
2529 relaxEquation(mat_array[Idx(2, 2)],
2535 return populateVectorFromDense<libMesh::DenseMatrix<Real>>(
2539 V(
"Linear solver relaxed");
2545 LibmeshPetscCall(MatCreateNest(PETSC_COMM_SELF, Q, NULL, Q, NULL, mat_array.data(), &A_nest));
2546 LibmeshPetscCall(VecCreateNest(PETSC_COMM_SELF, Q, NULL, vec_array.data(), &b_nest));
2547 V(
"Nested system created");
2551 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksp));
2552 LibmeshPetscCall(KSPSetOptionsPrefix(ksp,
"scm_coupled_"));
2553 LibmeshPetscCall(KSPSetType(ksp, KSPFGMRES));
2554 LibmeshPetscCall(KSPSetOperators(ksp, A_nest, A_nest));
2555 LibmeshPetscCall(KSPGetPC(ksp, &pc));
2556 LibmeshPetscCall(PCSetType(pc, PCFIELDSPLIT));
2560 std::vector<IS> rows(Q);
2561 LibmeshPetscCall(MatNestGetISs(A_nest, rows.data(), NULL));
2562 for (PetscInt j = 0; j < Q; ++j)
2565 LibmeshPetscCall(ISDuplicate(rows[j], &part));
2566 LibmeshPetscCall(PCFieldSplitSetIS(pc, NULL, part));
2567 LibmeshPetscCall(ISDestroy(&part));
2569 LibmeshPetscCall(KSPSetFromOptions(ksp));
2570 V(
"Linear solver assembled");
2573 LibmeshPetscCall(VecDuplicate(b_nest, &x_nest));
2574 LibmeshPetscCall(VecSet(x_nest, 0.0));
2575 LibmeshPetscCall(KSPSolve(ksp, b_nest, x_nest));
2576 KSPConvergedReason reason;
2577 LibmeshPetscCall(KSPGetConvergedReason(ksp, &reason));
2580 PetscInt iterations;
2581 PetscReal residual_norm;
2582 LibmeshPetscCall(KSPGetIterationNumber(ksp, &iterations));
2583 LibmeshPetscCall(KSPGetResidualNorm(ksp, &residual_norm));
2585 ": coupled mass/momentum linear solve failed: ",
2586 KSPConvergedReasons[reason],
2588 static_cast<int>(reason),
2591 " iterations; residual norm = ",
2597 LibmeshPetscCall(VecDestroy(&b_nest));
2598 LibmeshPetscCall(MatDestroy(&A_nest));
2599 LibmeshPetscCall(KSPDestroy(&ksp));
2600 for (PetscInt i = 0; i < Q * Q; i++)
2601 LibmeshPetscCall(MatDestroy(&mat_array[i]));
2602 for (PetscInt i = 0; i < Q; i++)
2603 LibmeshPetscCall(VecDestroy(&vec_array[i]));
2604 V(
"Solver elements destroyed");
2607 Vec sol_mdot, sol_p, sol_Wij;
2608 V(
"Vectors to hold solution created");
2611 LibmeshPetscCall(VecNestGetSubVecs(x_nest, &num_vecs, &loc_vecs));
2613 LibmeshPetscCall(VecCopy(loc_vecs[0], sol_mdot));
2615 LibmeshPetscCall(VecCopy(loc_vecs[1], sol_p));
2617 LibmeshPetscCall(VecCopy(loc_vecs[2], sol_Wij));
2618 V(
"Solution from coupled solver copied to solution vectors");
2621 auto relaxSolution = [&](Vec solution, Vec old_solution,
const Real relaxation)
2623 LibmeshPetscCall(VecScale(solution, relaxation));
2624 LibmeshPetscCall(VecAXPY(solution, 1.0 - relaxation, old_solution));
2626 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
2628 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
2633 Vec pressure_residual;
2634 LibmeshPetscCall(VecDuplicate(sol_p, &pressure_residual));
2635 LibmeshPetscCall(VecCopy(sol_p, pressure_residual));
2636 LibmeshPetscCall(VecAXPY(pressure_residual, -1.0,
_prodp));
2638 const PetscScalar * residual_array;
2639 const PetscScalar * old_pressure_array;
2640 PetscInt pressure_size;
2641 LibmeshPetscCall(VecGetSize(pressure_residual, &pressure_size));
2642 LibmeshPetscCall(VecGetArrayRead(pressure_residual, &residual_array));
2643 LibmeshPetscCall(VecGetArrayRead(
_prodp, &old_pressure_array));
2644 Real residual_norm_sq = 0.0;
2645 Real pressure_norm_sq = 0.0;
2646 for (PetscInt i = 0; i < pressure_size; ++i)
2648 residual_norm_sq += Utility::pow<2>(residual_array[i]);
2649 pressure_norm_sq += Utility::pow<2>(old_pressure_array[i] +
_P_out);
2651 LibmeshPetscCall(VecRestoreArrayRead(pressure_residual, &residual_array));
2652 LibmeshPetscCall(VecRestoreArrayRead(
_prodp, &old_pressure_array));
2653 LibmeshPetscCall(VecDestroy(&pressure_residual));
2656 std::sqrt(residual_norm_sq) / (std::sqrt(pressure_norm_sq) + 1e-14));
2665 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
2670 PetscScalar * sol_p_array;
2671 LibmeshPetscCall(VecGetArray(sol_p, &sol_p_array));
2672 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
2674 const auto iz_ind = iz - first_node;
2675 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
2678 PetscScalar value = sol_p_array[iz_ind *
_n_channels + i_ch];
2682 LibmeshPetscCall(VecRestoreArray(sol_p, &sol_p_array));
2690 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
2693 LibmeshPetscCall(VecAbs(
_prod));
2698 V(
"Solutions assigned to MOOSE variables.");
2701 LibmeshPetscCall(VecDestroy(&x_nest));
2702 LibmeshPetscCall(VecDestroy(&sol_mdot));
2703 LibmeshPetscCall(VecDestroy(&sol_p));
2704 LibmeshPetscCall(VecDestroy(&sol_Wij));
2705 V(
"Solutions destroyed.");
2707 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
2713 _console <<
"Executing subchannel solver\n";
2724 for (
const auto * ti :
transient->getTimeIntegrators())
2726 mooseWarning(
"The subchannel solver always uses implicit (backward) Euler time "
2727 "integration; the requested '",
2729 "' time integrator is ignored.");
2735 auto V = [&](
const std::string & s)
2741 const unsigned int first_node,
2742 const unsigned int last_node)
2744 std::vector<Real>
values;
2746 for (
unsigned int iz = first_node; iz <= last_node; ++iz)
2747 for (
unsigned int i_ch = 0; i_ch <
_n_channels; ++i_ch)
2752 const std::vector<Real> & old_values,
2753 const unsigned int first_node,
2754 const unsigned int last_node,
2755 const Real reference_offset)
2757 Real difference_norm_sq = 0.0;
2758 Real reference_norm_sq = 0.0;
2760 for (
unsigned int iz = first_node; iz <= last_node; ++iz)
2761 for (
unsigned int i_ch = 0; i_ch <
_n_channels; ++i_ch)
2764 difference_norm_sq += Utility::pow<2>(value - old_values[i]);
2765 reference_norm_sq += Utility::pow<2>(old_values[i] + reference_offset);
2768 return std::sqrt(difference_norm_sq) / (std::sqrt(reference_norm_sq) + 1e-14);
2770 V(
"Solution initialized");
2772 unsigned int P_it = 0;
2773 unsigned int P_it_max;
2774 bool temperature_converged =
true;
2787 while ((P_error >
_P_tol && P_it < P_it_max))
2790 temperature_converged =
true;
2792 _console <<
"Solving Outer Iteration : " << P_it << std::endl;
2794 for (
unsigned int iblock = 0; iblock <
_n_blocks; iblock++)
2798 Real T_block_error = 1.0;
2800 _console <<
"Solving Block: " << iblock <<
" From first level: " << first_level
2801 <<
" to last level: " << last_level << std::endl;
2813 V(
"Done with main solve.");
2821 if (T_block_error <= _T_tol || T_it >=
_T_maxit)
2824 V(
"Enthalpy subcycle: " + std::to_string(enthalpy_subcycle + 1));
2826 const auto T_old = saveValues(*
_T_soln, first_level, last_level);
2831 T_block_error = 0.0;
2839 V(
"Done with thermal solve.");
2842 V(
"Start updating thermophysical properties.");
2847 V(
"Done updating thermophysical properties.");
2852 _aux->solution().close();
2856 relativeChange(*
_T_soln, T_old, first_level, last_level, 0.0);
2857 _console <<
"T_block_error: " << T_block_error << std::endl;
2863 const bool block_converged = T_block_error <=
_T_tol;
2864 temperature_converged &= block_converged;
2865 if (!block_converged)
2867 _console <<
"Reached maximum number of temperature iterations for block: " << iblock
2874 _console <<
"P_error :" << P_error << std::endl;
2875 V(
"Iteration: " + std::to_string(P_it));
2876 V(
"Maximum iterations: " + std::to_string(P_it_max));
2880 const bool pressure_converged = P_error <=
_P_tol;
2881 if (!pressure_converged)
2883 _console <<
"Reached maximum number of axial pressure iterations" << std::endl;
2885 _converged = pressure_converged && temperature_converged;
2888 _console <<
"Finished executing subchannel solver\n";
2891 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
2901 for (
unsigned int iz = 0; iz <
_n_cells + 1; ++iz)
2903 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
2906 auto mu = (*_mu_soln)(node);
2907 auto S = (*_S_flow_soln)(node);
2908 auto w_perim = (*_w_perim_soln)(node);
2909 auto Dh_i = 4.0 * S / w_perim;
2910 auto Re = (((*_mdot_soln)(node) / S) * Dh_i /
mu);
2913 auto Pr = (*_mu_soln)(node)*cp / k;
2933 _console <<
"Commencing calculation of Pin surface temperature \n";
2934 for (
unsigned int i_pin = 0; i_pin <
_n_pins; i_pin++)
2936 for (
unsigned int iz = 0; iz <
_n_cells + 1; ++iz)
2944 auto mu = (*_mu_soln)(node);
2945 auto S = (*_S_flow_soln)(node);
2946 auto w_perim = (*_w_perim_soln)(node);
2947 auto Dh_i = 4.0 * S / w_perim;
2948 auto Re = (((*_mdot_soln)(node) / S) * Dh_i /
mu);
2951 auto Pr = (*_mu_soln)(node)*cp / k;
2960 (*_q_prime_soln)(pin_node) / ((*
_Dpin_soln)(pin_node)*M_PI * hw) + (*_T_soln)(node);
2965 mooseError(
"Pin was not found for pin index: " + std::to_string(i_pin));
2973 _console <<
"Commencing calculation of duct surface temperature " << std::endl;
2975 for (Node * dn : duct_nodes)
2978 auto mu = (*_mu_soln)(node_chan);
2979 auto S = (*_S_flow_soln)(node_chan);
2980 auto w_perim = (*_w_perim_soln)(node_chan);
2981 auto Dh_i = 4.0 * S / w_perim;
2982 auto Re = (((*_mdot_soln)(node_chan) / S) * Dh_i /
mu);
2985 auto Pr = (*_mu_soln)(node_chan)*cp / k;
3002 auto T_chan = (*_duct_heat_flux_soln)(dn) / hw + (*
_T_soln)(node_chan);
3006 _aux->solution().close();
3011 Real power_in = 0.0;
3012 Real power_out = 0.0;
3013 Real viscosity_in = 0.0;
3014 Real mass_flow_in = 0.0;
3015 Real mass_flow_out = 0.0;
3016 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
3020 const Real mdot_in = (*_mdot_soln)(node_in);
3021 power_in += mdot_in * (*_h_soln)(node_in);
3022 power_out += (*_mdot_soln)(node_out) * (*
_h_soln)(node_out);
3023 viscosity_in += mdot_in * (*_mu_soln)(node_in);
3024 mass_flow_in += mdot_in;
3025 mass_flow_out += (*_mdot_soln)(node_out);
3027 auto h_bulk_out = power_out / mass_flow_out;
3028 auto T_bulk_out =
_fp->T_from_p_h(
_P_out, h_bulk_out);
3031 Real inlet_mu = viscosity_in / mass_flow_in;
3035 _console <<
" ======================================= " << std::endl;
3036 _console <<
" ======== Subchannel Print Outs ======== " << std::endl;
3037 _console <<
" ======================================= " << std::endl;
3040 _console <<
"Assembly hydraulic diameter :" << bulk_Dh <<
" m" << std::endl;
3041 _console <<
"Assembly Re number :" << bulk_Re <<
" [-]" << std::endl;
3042 _console <<
"Bulk coolant temperature at outlet :" << T_bulk_out <<
" K" << std::endl;
3043 _console <<
"Power added to coolant is : " << power_out - power_in <<
" Watt" << std::endl;
3044 _console <<
"Mass flow rate in is : " << mass_flow_in <<
" kg/sec" << std::endl;
3045 _console <<
"Mass balance is : " << mass_flow_out - mass_flow_in <<
" kg/sec" << std::endl;
3046 _console <<
"User defined outlet pressure is : " <<
_P_out <<
" Pa" << std::endl;
3047 _console <<
" ======================================= " << std::endl;
3050 if (MooseUtils::absoluteFuzzyLessEqual((power_out - power_in), -1.0))
3052 "Energy conservation equation might not be solved correctly, Power added to coolant: " +
3053 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
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.
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...