12 #include "libmesh/petsc_vector.h" 13 #include "libmesh/dense_matrix.h" 14 #include "libmesh/dense_vector.h" 35 const PetscScalar * xx;
45 for (PetscInt i = 0; i < size; i++)
46 solution_seed(i) = xx[i];
54 for (
int i = 0; i < size; i++)
55 ff[i] = Wij_residual_vector(i);
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");
74 params.
addParam<
Real>(
"T_tol", 1e-6,
"Temperature tolerance");
75 params.
addParam<
int>(
"T_maxit", 100,
"Maximum number of iterations for inner temperature loop");
76 params.
addParam<PetscReal>(
"rtol", 1e-6,
"Relative tolerance for ksp solver");
77 params.
addParam<PetscReal>(
"atol", 1e-6,
"Absolute tolerance for ksp solver");
78 params.
addParam<PetscReal>(
"dtol", 1e5,
"Divergence tolerance or ksp solver");
79 params.
addParam<PetscInt>(
"maxit", 1e4,
"Maximum number of iterations for ksp solver");
81 "interpolation_scheme",
83 "Interpolation scheme used for the method. Default is central_difference");
85 "gravity", gravity_direction,
"Direction of gravity. Default is counter_flow");
87 "implicit",
false,
"Boolean to define the use of explicit or implicit solution.");
88 params.
addParam<
bool>(
"staggered_pressure",
90 "Boolean to define the use of staggered or collocated pressure.");
92 "segregated",
true,
"Boolean to define whether to use a segregated solution.");
94 "verbose_subchannel",
false,
"Boolean to print out information related to subchannel solve.");
95 params.
addRequiredParam<
bool>(
"compute_density",
"Flag that enables the calculation of density");
97 "Flag that enables the calculation of viscosity");
100 "Flag that informs whether we solve the Enthalpy/Temperature equations or not");
103 "The postprocessor (or scalar) that provides the absolute outlet pressure [Pa]. The solved " 104 "pressure variable P is relative to this value.");
105 params.
addRequiredParam<UserObjectName>(
"fp",
"Fluid properties user object name");
107 "Closure computing the friction factor");
110 "Closure computing the turbulent mixing, wire-induced " 111 "mixing and sweep flow mixing parameter where applicable");
113 "pin_HTC_closure",
"Closure computing HTC on fuel pin (required if pin mesh exists).");
114 params.
addParam<UserObjectName>(
"duct_HTC_closure",
115 "Closure computing HTC on duct (required if duct mesh exists).");
117 "full_output",
false,
"Flag that enables the output of the maximum number of variables.");
119 "Thermal diffusion coefficient used in turbulent crossflow.",
120 "Use closure system instead.");
124 "Boolean to define the use of a constant beta or beta correlation (Kim and Chung, 2001)",
125 "Use closure system instead.");
128 "Solver tolerances and iterations");
131 params.
addParamNamesToGroup(
"fp friction_closure mixing_closure pin_HTC_closure duct_HTC_closure",
143 _friction_args(0, 1.0, 0.0, 0.0),
145 1.0, 1.0,
std::numeric_limits<unsigned
int>::
max(), 0, 0),
146 _P_out(getPostprocessorValue(
"P_out")),
149 _n_blocks(getParam<unsigned
int>(
"n_blocks")),
150 _Wij(declareRestartableData<
libMesh::DenseMatrix<
Real>>(
"Wij")),
152 _kij(_subchannel_mesh.getKij()),
154 _compute_density(getParam<bool>(
"compute_density")),
155 _compute_viscosity(getParam<bool>(
"compute_viscosity")),
156 _compute_power(getParam<bool>(
"compute_power")),
157 _pin_mesh_exist(_subchannel_mesh.pinMeshExist()),
158 _duct_mesh_exist(_subchannel_mesh.ductMeshExist()),
159 _P_tol(getParam<
Real>(
"P_tol")),
160 _T_tol(getParam<
Real>(
"T_tol")),
161 _T_maxit(getParam<
int>(
"T_maxit")),
162 _rtol(getParam<PetscReal>(
"rtol")),
163 _atol(getParam<PetscReal>(
"atol")),
164 _dtol(getParam<PetscReal>(
"dtol")),
165 _maxit(getParam<PetscInt>(
"maxit")),
166 _interpolation_scheme(getParam<
MooseEnum>(
"interpolation_scheme")),
167 _gravity_direction(getParam<
MooseEnum>(
"gravity")),
168 _dir_grav(computeGravityDir(_gravity_direction)),
169 _implicit_bool(getParam<bool>(
"implicit")),
170 _staggered_pressure_bool(getParam<bool>(
"staggered_pressure")),
171 _segregated_bool(getParam<bool>(
"segregated")),
172 _verbose_subchannel(getParam<bool>(
"verbose_subchannel")),
173 _friction_closure(nullptr),
174 _mixing_closure(nullptr),
175 _pin_HTC_closure(nullptr),
176 _duct_HTC_closure(nullptr),
178 _duct_heat_flux_soln(nullptr),
179 _Tduct_soln(nullptr),
184 "You are using a deprecated parameter. Please use the mixing_closure system.");
186 paramError(
"pin_HTC_closure",
"required when a pin mesh exists.");
188 paramError(
"duct_HTC_closure",
"required when a duct mesh exists.");
283 ": When implicit number of blocks can't be equal to number of cells. This will " 284 "cause problems with the subchannel interpolation scheme.");
293 _fp = &getUserObject<SinglePhaseFluidProperties>(getParam<UserObjectName>(
"fp"));
295 &getUserObject<SCMFrictionClosureBase>(getParam<UserObjectName>(
"friction_closure"));
297 &getUserObject<SCMMixingClosureBase>(getParam<UserObjectName>(
"mixing_closure"));
306 if (getParam<bool>(
"full_output"))
320 &getUserObject<SCMHTCClosureBase>(getParam<UserObjectName>(
"pin_HTC_closure"));
335 &getUserObject<SCMHTCClosureBase>(getParam<UserObjectName>(
"duct_HTC_closure"));
347 for (
unsigned int iz = 0; iz <
_n_cells + 1; iz++)
348 for (
unsigned int i_pin = 0; i_pin <
_n_pins; i_pin++)
351 const Real Dpin = (*_Dpin_soln)(node);
352 if (std::abs(Dpin) <=
tol)
355 ". You must initialize Dpin to a non-zero value.");
356 if (std::abs(Dpin - pin_diameter) >
tol)
375 PetscErrorCode ierr =
cleanUp();
387 LibmeshPetscCall(VecDestroy(&
_Wij_vec));
388 LibmeshPetscCall(VecDestroy(&
_prod));
389 LibmeshPetscCall(VecDestroy(&
_prodp));
457 ": Interpolation scheme should be a string: upwind, downwind, central_difference, " 464 PetscScalar botValue,
468 return alpha * botValue + (1.0 -
alpha) * topValue;
474 const unsigned int last_node = (iblock + 1) *
_block_size;
475 const unsigned int first_node = iblock *
_block_size + 1;
478 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
480 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
482 int i =
_n_gaps * (iz - first_node) + i_gap;
483 solution_seed(i) =
_Wij(i_gap, iz);
494 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
496 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
507 const unsigned int last_node = (iblock + 1) *
_block_size;
508 const unsigned int first_node = iblock *
_block_size + 1;
512 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
514 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
519 unsigned int counter = 0;
533 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
535 unsigned int iz_ind = iz - first_node;
536 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
539 unsigned int counter = 0;
543 PetscInt col = i_gap +
_n_gaps * iz_ind;
550 LibmeshPetscCall(MatAssemblyBegin(
_mc_sumWij_mat, MAT_FINAL_ASSEMBLY));
551 LibmeshPetscCall(MatAssemblyEnd(
_mc_sumWij_mat, MAT_FINAL_ASSEMBLY));
557 LibmeshPetscCall(VecDuplicate(
_Wij_vec, &loc_Wij));
561 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
563 LibmeshPetscCall(VecDestroy(&loc_prod));
564 LibmeshPetscCall(VecDestroy(&loc_Wij));
572 const unsigned int last_node = (iblock + 1) *
_block_size;
573 const unsigned int first_node = iblock *
_block_size + 1;
576 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
579 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
583 auto volume = dz * (*_S_flow_soln)(node_in);
586 auto mdot_out = (*_mdot_soln)(node_in) - (*
_SumWij_soln)(node_out)-time_term;
591 " : Calculation of negative mass flow mdot_out = : ",
595 " - Implicit solves are required for recirculating flow.");
603 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
606 auto iz_ind = iz - first_node;
607 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
611 auto volume = dz * (*_S_flow_soln)(node_in);
616 PetscScalar value_vec = -1.0 * time_term;
621 if (iz == first_node)
623 PetscScalar value_vec = (*_mdot_soln)(node_in);
632 PetscScalar
value = -1.0;
640 PetscScalar
value = 1.0;
647 PetscScalar value_vec_2 = -1.0 * (*_SumWij_soln)(node_out);
663 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksploc));
665 LibmeshPetscCall(KSPGetPC(ksploc, &pc));
666 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
668 LibmeshPetscCall(KSPSetFromOptions(ksploc));
670 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
673 LibmeshPetscCall(KSPDestroy(&ksploc));
674 LibmeshPetscCall(VecDestroy(&sol));
682 const unsigned int last_node = (iblock + 1) *
_block_size;
683 const unsigned int first_node = iblock *
_block_size + 1;
686 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
690 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
694 auto rho_in = (*_rho_soln)(node_in);
695 auto rho_out = (*_rho_soln)(node_out);
696 auto mu_in = (*_mu_soln)(node_in);
697 auto S = (*_S_flow_soln)(node_in);
698 auto w_perim = (*_w_perim_soln)(node_in);
700 auto Dh_i = 4.0 *
S / w_perim;
701 auto time_term =
_TR * ((*_mdot_soln)(node_out)-
_mdot_soln->old(node_out)) * dz /
_dt -
705 Utility::pow<2>((*_mdot_soln)(node_out)) * (1.0 /
S / rho_out - 1.0 /
S / rho_in);
706 auto mass_term2 = -2.0 * (*_mdot_soln)(node_out) * (*
_SumWij_soln)(node_out) /
S / rho_in;
707 auto crossflow_term = 0.0;
708 auto turbulent_term = 0.0;
709 unsigned int counter = 0;
713 unsigned int ii_ch = chans.first;
714 unsigned int jj_ch = chans.second;
719 auto rho_i = (*_rho_soln)(node_in_i);
720 auto rho_j = (*_rho_soln)(node_in_j);
721 auto Si = (*_S_flow_soln)(node_in_i);
722 auto Sj = (*_S_flow_soln)(node_in_j);
725 if (
_Wij(i_gap, iz) > 0.0)
726 u_star = (*_mdot_soln)(node_out_i) / Si / rho_i;
728 u_star = (*_mdot_soln)(node_out_j) / Sj / rho_j;
733 turbulent_term +=
_WijPrime(i_gap, iz) * (2 * (*_mdot_soln)(node_out) / rho_in /
S -
738 turbulent_term *=
_CT;
739 auto Re = (((*_mdot_soln)(node_in) /
S) * Dh_i / mu_in);
747 ki = k_grid[i_ch][iz - 1];
749 ki = k_grid[i_ch][iz];
750 auto friction_term = (ff * dz / Dh_i + ki) * 0.5 *
752 (
S * (*_rho_soln)(node_out));
754 auto DP = (1 /
S) * (time_term + mass_term1 + mass_term2 + crossflow_term + turbulent_term +
755 friction_term + gravity_term);
775 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
779 auto iz_ind = iz - first_node;
780 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
787 PetscScalar Pe = 0.5;
791 auto S_in = (*_S_flow_soln)(node_in);
792 auto S_out = (*_S_flow_soln)(node_out);
794 auto w_perim_in = (*_w_perim_soln)(node_in);
795 auto w_perim_out = (*_w_perim_soln)(node_out);
799 auto mu_in = (*_mu_soln)(node_in);
800 auto mu_out = (*_mu_soln)(node_out);
802 auto Dh_i = 4.0 * S_interp / w_perim_interp;
804 auto Re = ((mdot_loc / S_interp) * Dh_i / mu_interp);
812 ki = k_grid[i_ch][iz - 1];
814 ki = k_grid[i_ch][iz];
815 Pe = 1.0 / ((ff * dz / Dh_i + ki) * 0.5) * mdot_loc / std::abs(mdot_loc);
820 auto rho_in = (*_rho_soln)(node_in);
821 auto rho_out = (*_rho_soln)(node_out);
825 auto mu_in = (*_mu_soln)(node_in);
826 auto mu_out = (*_mu_soln)(node_out);
830 auto S_in = (*_S_flow_soln)(node_in);
831 auto S_out = (*_S_flow_soln)(node_out);
835 auto w_perim_in = (*_w_perim_soln)(node_in);
836 auto w_perim_out = (*_w_perim_soln)(node_out);
840 auto Dh_i = 4.0 * S_interp / w_perim_interp;
843 if (iz == first_node)
845 PetscScalar value_vec_tt = -1.0 *
_TR *
alpha * (*_mdot_soln)(node_in)*dz /
_dt;
853 PetscInt col_tt = i_ch +
_n_channels * (iz_ind - 1);
855 LibmeshPetscCall(MatSetValues(
862 PetscScalar value_tt =
_TR * (1.0 -
alpha) * dz /
_dt;
863 LibmeshPetscCall(MatSetValues(
867 PetscScalar mdot_old_interp =
869 PetscScalar value_vec_tt =
_TR * mdot_old_interp * dz /
_dt;
875 if (iz == first_node)
877 PetscScalar value_vec_at = Utility::pow<2>((*_mdot_soln)(node_in)) / (S_in * rho_in);
879 LibmeshPetscCall(VecSetValues(
885 PetscInt col_at = i_ch +
_n_channels * (iz_ind - 1);
886 PetscScalar value_at = -1.0 * std::abs((*
_mdot_soln)(node_in)) / (S_in * rho_in);
887 LibmeshPetscCall(MatSetValues(
894 PetscScalar value_at = std::abs((*
_mdot_soln)(node_out)) / (S_out * rho_out);
895 LibmeshPetscCall(MatSetValues(
899 unsigned int counter = 0;
900 unsigned int cross_index = iz;
904 unsigned int ii_ch = chans.first;
905 unsigned int jj_ch = chans.second;
920 if (
_Wij(i_gap, cross_index) > 0.0)
922 if (iz == first_node)
924 u_star = (*_mdot_soln)(node_in_i) / S_i / rho_i;
925 PetscScalar value_vec_ct = -1.0 *
alpha *
927 _Wij(i_gap, cross_index) * u_star;
929 LibmeshPetscCall(VecSetValues(
935 _Wij(i_gap, cross_index) / S_i / rho_i;
937 PetscInt col_ct = ii_ch +
_n_channels * (iz_ind - 1);
938 LibmeshPetscCall(MatSetValues(
941 PetscScalar value_ct = (1.0 -
alpha) *
943 _Wij(i_gap, cross_index) / S_i / rho_i;
946 LibmeshPetscCall(MatSetValues(
949 else if (
_Wij(i_gap, cross_index) < 0.0)
951 if (iz == first_node)
953 u_star = (*_mdot_soln)(node_in_j) / S_j / rho_j;
954 PetscScalar value_vec_ct = -1.0 *
alpha *
956 _Wij(i_gap, cross_index) * u_star;
958 LibmeshPetscCall(VecSetValues(
964 _Wij(i_gap, cross_index) / S_j / rho_j;
966 PetscInt col_ct = jj_ch +
_n_channels * (iz_ind - 1);
967 LibmeshPetscCall(MatSetValues(
970 PetscScalar value_ct = (1.0 -
alpha) *
972 _Wij(i_gap, cross_index) / S_j / rho_j;
975 LibmeshPetscCall(MatSetValues(
979 if (iz == first_node)
981 PetscScalar value_vec_ct = -2.0 *
alpha * (*_mdot_soln)(node_in)*
_CT *
982 _WijPrime(i_gap, cross_index) / (rho_interp * S_interp);
983 value_vec_ct +=
alpha * (*_mdot_soln)(node_in_j)*
_CT *
_WijPrime(i_gap, cross_index) /
985 value_vec_ct +=
alpha * (*_mdot_soln)(node_in_i)*
_CT *
_WijPrime(i_gap, cross_index) /
993 PetscScalar value_center_ct =
996 PetscInt col_ct = i_ch +
_n_channels * (iz_ind - 1);
997 LibmeshPetscCall(MatSetValues(
1000 PetscScalar value_left_ct =
1004 LibmeshPetscCall(MatSetValues(
1007 PetscScalar value_right_ct =
1011 LibmeshPetscCall(MatSetValues(
1015 PetscScalar value_center_ct =
1016 2.0 * (1.0 -
alpha) *
_CT *
_WijPrime(i_gap, cross_index) / (rho_interp * S_interp);
1019 LibmeshPetscCall(MatSetValues(
1022 PetscScalar value_left_ct =
1026 LibmeshPetscCall(MatSetValues(
1029 PetscScalar value_right_ct =
1033 LibmeshPetscCall(MatSetValues(
1039 PetscScalar mdot_interp =
1041 auto Re = ((mdot_interp / S_interp) * Dh_i / mu_interp);
1049 ki = k_grid[i_ch][iz - 1];
1051 ki = k_grid[i_ch][iz];
1052 auto coef = (ff * dz / Dh_i + ki) * 0.5 * std::abs((*
_mdot_soln)(node_out)) /
1053 (S_interp * rho_interp);
1054 if (iz == first_node)
1056 PetscScalar value_vec = -1.0 *
alpha * coef * (*_mdot_soln)(node_in);
1078 PetscScalar value_vec =
_dir_grav * -1.0 *
_g_grav * rho_interp * dz * S_interp;
1080 LibmeshPetscCall(VecSetValues(
_amc_gravity_rhs, 1, &row_vec, &value_vec, ADD_VALUES));
1097 #if !PETSC_VERSION_LESS_THAN(3, 15, 0) 1139 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
1146 LibmeshPetscCall(VecGetArray(ls, &xx));
1147 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1149 auto iz_ind = iz - first_node;
1150 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1157 auto S_in = (*_S_flow_soln)(node_in);
1158 auto S_out = (*_S_flow_soln)(node_out);
1164 auto DP = (1 / S_interp) * xx[iz_ind *
_n_channels + i_ch];
1178 LibmeshPetscCall(VecDestroy(&ls));
1186 const unsigned int last_node = (iblock + 1) *
_block_size;
1187 const unsigned int first_node = iblock *
_block_size + 1;
1192 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1195 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1206 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1209 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1217 PetscScalar Pe = 0.5;
1219 if (iz == last_node)
1238 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1240 auto iz_ind = iz - first_node;
1242 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1248 auto S_in = (*_S_flow_soln)(node_in);
1249 auto S_out = (*_S_flow_soln)(node_out);
1255 PetscScalar
value = -1.0 * S_interp;
1259 if (iz == last_node)
1261 PetscScalar
value = -1.0 * (*_P_soln)(node_out)*S_interp;
1269 PetscScalar
value = 1.0 * S_interp;
1276 auto dp_out =
_DP(i_ch, iz);
1277 PetscScalar value_v = -1.0 * dp_out * S_interp;
1293 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksploc));
1295 LibmeshPetscCall(KSPGetPC(ksploc, &pc));
1296 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
1298 LibmeshPetscCall(KSPSetFromOptions(ksploc));
1301 LibmeshPetscCall(VecGetArray(sol, &xx));
1303 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1305 auto iz_ind = iz - first_node;
1306 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1314 LibmeshPetscCall(KSPDestroy(&ksploc));
1315 LibmeshPetscCall(VecDestroy(&sol));
1321 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1323 auto iz_ind = iz - first_node;
1325 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1331 auto S_in = (*_S_flow_soln)(node_in);
1332 auto S_out = (*_S_flow_soln)(node_out);
1338 PetscScalar
value = -1.0 * S_interp;
1342 if (iz == last_node)
1344 PetscScalar
value = -1.0 * (*_P_soln)(node_out)*S_interp;
1348 auto dp_out =
_DP(i_ch, iz);
1349 PetscScalar value_v = -1.0 * dp_out / 2.0 * S_interp;
1358 PetscScalar
value = 1.0 * S_interp;
1364 auto dp_in =
_DP(i_ch, iz - 1);
1365 auto dp_out =
_DP(i_ch, iz);
1367 PetscScalar value_v = -1.0 * dp_interp * S_interp;
1379 _console <<
"Block: " << iblock <<
" - Axial momentum pressure force matrix assembled" 1388 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksploc));
1390 LibmeshPetscCall(KSPGetPC(ksploc, &pc));
1391 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
1393 LibmeshPetscCall(KSPSetFromOptions(ksploc));
1396 LibmeshPetscCall(VecGetArray(sol, &xx));
1398 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1400 auto iz_ind = iz - first_node;
1401 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1409 LibmeshPetscCall(KSPDestroy(&ksploc));
1410 LibmeshPetscCall(VecDestroy(&sol));
1419 const unsigned int last_node = (iblock + 1) *
_block_size;
1420 const unsigned int first_node = iblock *
_block_size + 1;
1421 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1423 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1434 const unsigned int last_node = (iblock + 1) *
_block_size;
1435 const unsigned int first_node = iblock *
_block_size + 1;
1438 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1444 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1446 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1457 const unsigned int last_node = (iblock + 1) *
_block_size;
1458 const unsigned int first_node = iblock *
_block_size + 1;
1461 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1467 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1469 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1480 const unsigned int last_node = (iblock + 1) *
_block_size;
1481 const unsigned int first_node = iblock *
_block_size + 1;
1486 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1489 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1492 unsigned int i_ch = chans.first;
1493 unsigned int j_ch = chans.second;
1498 auto rho_i = (*_rho_soln)(node_in_i);
1499 auto rho_j = (*_rho_soln)(node_in_j);
1500 auto Si = (*_S_flow_soln)(node_in_i);
1501 auto Sj = (*_S_flow_soln)(node_in_j);
1505 auto friction_term =
_kij *
_Wij(i_gap, iz) * std::abs(
_Wij(i_gap, iz));
1506 auto DPij = (*_P_soln)(node_in_i) - (*
_P_soln)(node_in_j);
1508 auto rho_star = 0.0;
1509 if (
_Wij(i_gap, iz) > 0.0)
1511 else if (
_Wij(i_gap, iz) < 0.0)
1514 rho_star = (rho_i + rho_j) / 2.0;
1515 auto mass_term_out =
1519 (*_mdot_soln)(node_in_i) / Si / rho_i + (*
_mdot_soln)(node_in_j) / Sj / rho_j;
1520 auto term_out = Sij * rho_star * (Lij / dz) * mass_term_out *
_Wij(i_gap, iz);
1521 auto term_in = Sij * rho_star * (Lij / dz) * mass_term_in *
_Wij(i_gap, iz - 1);
1522 auto inertia_term = term_out - term_in;
1523 auto pressure_term = 2 * Utility::pow<2>(Sij) * DPij * rho_star;
1528 time_term + friction_term + inertia_term - pressure_term;
1546 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1549 auto iz_ind = iz - first_node;
1550 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1553 unsigned int i_ch = chans.first;
1554 unsigned int j_ch = chans.second;
1561 auto rho_i_in = (*_rho_soln)(node_in_i);
1562 auto rho_i_out = (*_rho_soln)(node_out_i);
1564 auto rho_j_in = (*_rho_soln)(node_in_j);
1565 auto rho_j_out = (*_rho_soln)(node_out_j);
1569 auto S_i_in = (*_S_flow_soln)(node_in_i);
1570 auto S_i_out = (*_S_flow_soln)(node_out_i);
1571 auto S_j_in = (*_S_flow_soln)(node_in_j);
1572 auto S_j_out = (*_S_flow_soln)(node_out_j);
1579 auto rho_star = 0.0;
1580 if (
_Wij(i_gap, iz) > 0.0)
1581 rho_star = rho_i_interp;
1582 else if (
_Wij(i_gap, iz) < 0.0)
1583 rho_star = rho_j_interp;
1585 rho_star = (rho_i_interp + rho_j_interp) / 2.0;
1588 PetscScalar time_factor =
_TR * Lij * Sij * rho_star /
_dt;
1589 PetscInt row_td = i_gap +
_n_gaps * iz_ind;
1590 PetscInt col_td = i_gap +
_n_gaps * iz_ind;
1591 PetscScalar value_td = time_factor;
1592 LibmeshPetscCall(MatSetValues(
1594 PetscScalar value_td_rhs = time_factor *
_Wij_old(i_gap, iz);
1599 PetscScalar Pe = 0.5;
1601 auto mass_term_out = (*_mdot_soln)(node_out_i) / S_i_out / rho_i_out +
1602 (*
_mdot_soln)(node_out_j) / S_j_out / rho_j_out;
1603 auto mass_term_in = (*_mdot_soln)(node_in_i) / S_i_in / rho_i_in +
1604 (*
_mdot_soln)(node_in_j) / S_j_in / rho_j_in;
1605 auto term_out = Sij * rho_star * (Lij / dz) * mass_term_out / 2.0;
1606 auto term_in = Sij * rho_star * (Lij / dz) * mass_term_in / 2.0;
1607 if (iz == first_node)
1609 PetscInt row_ad = i_gap +
_n_gaps * iz_ind;
1610 PetscScalar value_ad = term_in *
alpha *
_Wij(i_gap, iz - 1);
1614 PetscInt col_ad = i_gap +
_n_gaps * iz_ind;
1615 value_ad = -1.0 * term_in * (1.0 -
alpha) + term_out *
alpha;
1616 LibmeshPetscCall(MatSetValues(
1619 col_ad = i_gap +
_n_gaps * (iz_ind + 1);
1620 value_ad = term_out * (1.0 -
alpha);
1621 LibmeshPetscCall(MatSetValues(
1624 else if (iz == last_node)
1626 PetscInt row_ad = i_gap +
_n_gaps * iz_ind;
1627 PetscInt col_ad = i_gap +
_n_gaps * (iz_ind - 1);
1628 PetscScalar value_ad = -1.0 * term_in *
alpha;
1629 LibmeshPetscCall(MatSetValues(
1632 col_ad = i_gap +
_n_gaps * iz_ind;
1633 value_ad = -1.0 * term_in * (1.0 -
alpha) + term_out *
alpha;
1634 LibmeshPetscCall(MatSetValues(
1637 value_ad = -1.0 * term_out * (1.0 -
alpha) *
_Wij(i_gap, iz);
1643 PetscInt row_ad = i_gap +
_n_gaps * iz_ind;
1644 PetscInt col_ad = i_gap +
_n_gaps * (iz_ind - 1);
1645 PetscScalar value_ad = -1.0 * term_in *
alpha;
1646 LibmeshPetscCall(MatSetValues(
1649 col_ad = i_gap +
_n_gaps * iz_ind;
1650 value_ad = -1.0 * term_in * (1.0 -
alpha) + term_out *
alpha;
1651 LibmeshPetscCall(MatSetValues(
1654 col_ad = i_gap +
_n_gaps * (iz_ind + 1);
1655 value_ad = term_out * (1.0 -
alpha);
1656 LibmeshPetscCall(MatSetValues(
1660 PetscInt row_ff = i_gap +
_n_gaps * iz_ind;
1661 PetscInt col_ff = i_gap +
_n_gaps * iz_ind;
1662 PetscScalar value_ff =
_kij * std::abs(
_Wij(i_gap, iz)) / 2.0;
1663 LibmeshPetscCall(MatSetValues(
1671 PetscScalar pressure_factor = Utility::pow<2>(Sij) * rho_star;
1672 PetscInt row_pf = i_gap +
_n_gaps * iz_ind;
1674 PetscScalar value_pf = -1.0 *
alpha * pressure_factor;
1678 value_pf =
alpha * pressure_factor;
1682 if (iz == last_node)
1684 PetscInt row_pf = i_gap +
_n_gaps * iz_ind;
1685 PetscScalar value_pf = (1.0 -
alpha) * pressure_factor * (*
_P_soln)(node_out_i);
1688 value_pf = -1.0 * (1.0 -
alpha) * pressure_factor * (*
_P_soln)(node_out_j);
1694 row_pf = i_gap +
_n_gaps * iz_ind;
1696 value_pf = -1.0 * (1.0 -
alpha) * pressure_factor;
1697 LibmeshPetscCall(MatSetValues(
1700 value_pf = (1.0 -
alpha) * pressure_factor;
1701 LibmeshPetscCall(MatSetValues(
1707 PetscScalar pressure_factor = Utility::pow<2>(Sij) * rho_star;
1708 PetscInt row_pf = i_gap +
_n_gaps * iz_ind;
1710 PetscScalar value_pf = -1.0 * pressure_factor;
1714 value_pf = pressure_factor;
1734 #if !PETSC_VERSION_LESS_THAN(3, 15, 0) 1771 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
1779 LibmeshPetscCall(VecAXPY(sol_holder_W, 1.0, sol_holder_P));
1781 LibmeshPetscCall(VecGetArray(sol_holder_W, &xx));
1782 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1784 auto iz_ind = iz - first_node;
1785 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1790 LibmeshPetscCall(VecDestroy(&sol_holder_P));
1791 LibmeshPetscCall(VecDestroy(&sol_holder_W));
1799 const unsigned int last_node = (iblock + 1) *
_block_size;
1800 const unsigned int first_node = iblock *
_block_size + 1;
1801 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1804 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1807 unsigned int i_ch = chans.first;
1808 unsigned int j_ch = chans.second;
1813 auto Si_in = (*_S_flow_soln)(node_in_i);
1814 auto Sj_in = (*_S_flow_soln)(node_in_j);
1815 auto Si_out = (*_S_flow_soln)(node_out_i);
1816 auto Sj_out = (*_S_flow_soln)(node_out_j);
1818 auto Sij = dz * gap;
1820 0.5 * (((*_mdot_soln)(node_in_i) + (*
_mdot_soln)(node_in_j)) / (Si_in + Sj_in) +
1826 _WijPrime(i_gap, iz) = beta * avg_massflux * Sij;
1830 auto iz_ind = iz - first_node;
1831 PetscScalar base_value = beta * 0.5 * Sij;
1834 if (iz == first_node)
1836 PetscScalar value_tl = -1.0 * base_value / (Si_in + Sj_in) *
1838 PetscInt row = i_gap +
_n_gaps * iz_ind;
1844 PetscScalar value_tl = base_value / (Si_in + Sj_in);
1845 PetscInt row = i_gap +
_n_gaps * iz_ind;
1847 PetscInt col_ich = i_ch +
_n_channels * (iz_ind - 1);
1848 LibmeshPetscCall(MatSetValues(
1851 PetscInt col_jch = j_ch +
_n_channels * (iz_ind - 1);
1852 LibmeshPetscCall(MatSetValues(
1857 PetscScalar value_bl = base_value / (Si_out + Sj_out);
1858 PetscInt row = i_gap +
_n_gaps * iz_ind;
1861 LibmeshPetscCall(MatSetValues(
1865 LibmeshPetscCall(MatSetValues(
1880 LibmeshPetscCall(VecDuplicate(
_Wij_vec, &loc_Wij));
1881 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
1887 LibmeshPetscCall(VecDestroy(&loc_prod));
1888 LibmeshPetscCall(VecDestroy(&loc_Wij));
1896 if (!std::isfinite(beta) || beta < 0.0)
1898 ": Mixing closure returned invalid beta = ",
1904 ". Beta must be finite and non-negative.");
1913 if (!std::isfinite(beta) || beta < 0.0)
1915 ": Mixing closure returned invalid sweep-flow coefficient = ",
1921 ". sweep-flow coefficient must be finite and non-negative.");
1929 const unsigned int last_node = (iblock + 1) *
_block_size;
1930 const unsigned int first_node = iblock *
_block_size + 1;
1934 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1936 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1938 _Wij(i_gap, iz) = solution(i);
1959 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1965 return Wij_residual_vector;
1980 LibmeshPetscCall(SNESCreate(PETSC_COMM_SELF, &snes));
1981 LibmeshPetscCall(VecCreate(PETSC_COMM_SELF, &
x));
1983 LibmeshPetscCall(VecSetFromOptions(
x));
1984 LibmeshPetscCall(VecDuplicate(
x, &r));
1986 #if PETSC_VERSION_LESS_THAN(3, 13, 0) 1987 LibmeshPetscCall(PetscOptionsSetValue(PETSC_NULL,
"-snes_mf", PETSC_NULL));
1989 LibmeshPetscCall(SNESSetUseMatrixFree(snes, PETSC_FALSE, PETSC_TRUE));
1992 ctx.iblock = iblock;
1995 LibmeshPetscCall(SNESGetKSP(snes, &ksp));
1996 LibmeshPetscCall(KSPGetPC(ksp, &pc));
1997 LibmeshPetscCall(PCSetType(pc, PCNONE));
1999 LibmeshPetscCall(SNESSetFromOptions(snes));
2000 LibmeshPetscCall(VecGetArray(
x, &xx));
2003 xx[i] = solution(i);
2005 LibmeshPetscCall(VecRestoreArray(
x, &xx));
2007 LibmeshPetscCall(SNESSolve(snes, NULL,
x));
2008 LibmeshPetscCall(VecGetArray(
x, &xx));
2012 LibmeshPetscCall(VecRestoreArray(
x, &xx));
2013 LibmeshPetscCall(VecDestroy(&
x));
2014 LibmeshPetscCall(VecDestroy(&r));
2015 LibmeshPetscCall(SNESDestroy(&snes));
2021 Mat
A, Vec rhs,
unsigned int first_node,
unsigned int last_node,
const char * ksp_prefix)
2027 LibmeshPetscCall(VecDuplicate(rhs, &
x));
2032 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksp));
2033 LibmeshPetscCall(KSPSetOperators(ksp,
A,
A));
2034 LibmeshPetscCall(KSPGetPC(ksp, &pc));
2035 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
2037 if (ksp_prefix && *ksp_prefix)
2038 LibmeshPetscCall(KSPSetOptionsPrefix(ksp, ksp_prefix));
2039 LibmeshPetscCall(KSPSetFromOptions(ksp));
2042 LibmeshPetscCall(KSPSolve(ksp, rhs,
x));
2045 PetscScalar * xx =
nullptr;
2046 LibmeshPetscCall(VecGetArray(
x, &xx));
2047 for (
unsigned int iz = first_node; iz <= last_node; ++iz)
2049 const unsigned int iz_ind = iz - first_node;
2050 for (
unsigned int i_ch = 0; i_ch <
_n_channels; ++i_ch)
2053 const PetscScalar h_out = xx[iz_ind *
_n_channels + i_ch];
2056 name(),
" : Calculation of negative Enthalpy h_out = ", h_out,
" Axial Level = ", iz);
2057 _h_soln->set(node_out, h_out);
2060 LibmeshPetscCall(VecRestoreArray(
x, &xx));
2063 LibmeshPetscCall(KSPDestroy(&ksp));
2064 LibmeshPetscCall(VecDestroy(&
x));
2072 mooseAssert(iz > 0,
"Trapezoidal rule requires starting at index 1 at least");
2083 auto heat_rate_in = (*_duct_heat_flux_soln)(node_in_duct);
2084 auto heat_rate_out = (*_duct_heat_flux_soln)(node_out_duct);
2086 return 0.5 * (heat_rate_in + heat_rate_out) * dz * width;
2104 auto V = [&](
const std::string & s)
2110 auto DupMatAssembled = [&](Mat src, Mat * dst)
2114 LibmeshPetscCall(MatDuplicate(src, MAT_COPY_VALUES, dst));
2115 LibmeshPetscCall(MatAssemblyBegin(*dst, MAT_FINAL_ASSEMBLY));
2116 LibmeshPetscCall(MatAssemblyEnd(*dst, MAT_FINAL_ASSEMBLY));
2122 auto DupVecCopy = [&](Vec src, Vec * dst)
2124 LibmeshPetscCall(VecDuplicate(src, dst));
2125 LibmeshPetscCall(VecCopy(src, *dst));
2128 const PetscInt Q = 3;
2131 auto Idx = [&](PetscInt r, PetscInt
c) {
return Q * r +
c; };
2134 std::vector<Mat> mat_array(Q * Q, NULL);
2135 std::vector<Vec> vec_array(Q, NULL);
2138 auto AssembleEquation = [&](PetscInt
f,
2146 DupMatAssembled(
A0, &mat_array[Idx(
f, 0)]);
2147 DupMatAssembled(
A1, &mat_array[Idx(
f, 1)]);
2148 DupMatAssembled(
A2, &mat_array[Idx(
f, 2)]);
2149 DupVecCopy(rhs, &vec_array[
f]);
2151 LibmeshPetscCall(VecAXPY(vec_array[
f], 1.0, rhs_add));
2152 V(std::string(label) +
" system assembled");
2170 auto RelaxEquation =
2171 [&](Mat A_ff, Vec rhs_f, Vec like_vec, Vec work, PetscScalar
alpha,
auto && populate)
2174 LibmeshPetscCall(VecDuplicate(like_vec, &
d));
2177 LibmeshPetscCall(MatGetDiagonal(A_ff,
d));
2178 LibmeshPetscCall(VecScale(
d, 1.0 /
alpha));
2179 LibmeshPetscCall(MatDiagonalSet(A_ff,
d, INSERT_VALUES));
2182 LibmeshPetscCall(populate(work));
2185 LibmeshPetscCall(VecScale(
d, (1.0 -
alpha)));
2186 LibmeshPetscCall(VecPointwiseMult(work, work,
d));
2187 LibmeshPetscCall(VecAXPY(rhs_f, 1.0, work));
2189 LibmeshPetscCall(VecDestroy(&
d));
2193 const unsigned int first_node = iblock *
_block_size + 1;
2194 const unsigned int last_node = (iblock + 1) *
_block_size;
2204 V(
"Starting nested system.");
2237 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
2248 LibmeshPetscCall(VecSet(unity_vec, 1.0));
2253 LibmeshPetscCall(VecSet(unity_vec_Wij, 1.0));
2256 Vec _Wij_old_loc_vec;
2261 LibmeshPetscCall(MatMult(mat_array[Q ],
_prod, mdot_estimate));
2264 LibmeshPetscCall(MatGetDiagonal(mat_array[Q + 1], pmat_diag));
2265 LibmeshPetscCall(VecAXPY(pmat_diag, 1e-10, unity_vec));
2266 LibmeshPetscCall(VecPointwiseDivide(p_estimate, mdot_estimate, pmat_diag));
2269 LibmeshPetscCall(MatMult(mat_array[2 * Q + 1], p_estimate, sol_holder_P));
2275 for (
unsigned int iz = first_node; iz <= last_node; ++iz)
2277 const auto iz_ind = iz - first_node;
2278 for (
unsigned int i_ch = 0; i_ch <
_n_channels; ++i_ch)
2280 PetscScalar sumWij = 0.0;
2281 unsigned int counter = 0;
2285 unsigned int i_ch_loc = chans.first;
2286 PetscInt row_vec = i_ch_loc +
_n_channels * iz_ind;
2287 PetscScalar loc_Wij_value;
2288 LibmeshPetscCall(VecGetValues(sol_holder_P, 1, &row_vec, &loc_Wij_value));
2293 LibmeshPetscCall(VecSetValues(sumWij_loc, 1, &row_vec, &sumWij, INSERT_VALUES));
2296 LibmeshPetscCall(VecAssemblyBegin(sumWij_loc));
2297 LibmeshPetscCall(VecAssemblyEnd(sumWij_loc));
2300 PetscScalar min_mdot;
2301 LibmeshPetscCall(VecAbs(
_prod));
2302 LibmeshPetscCall(VecMin(
_prod, NULL, &min_mdot));
2303 V(
"Minimum estimated mdot: " + std::to_string(min_mdot));
2305 LibmeshPetscCall(VecAbs(sumWij_loc));
2306 LibmeshPetscCall(VecMax(sumWij_loc, NULL, &
_max_sumWij));
2308 V(
"Maximum estimated Wij: " + std::to_string(
_max_sumWij));
2311 _Wij_loc_vec,
_Wij, first_node, last_node,
_n_gaps));
2312 LibmeshPetscCall(VecAbs(_Wij_loc_vec));
2315 LibmeshPetscCall(VecAbs(_Wij_old_loc_vec));
2316 LibmeshPetscCall(VecAXPY(_Wij_loc_vec, -1.0, _Wij_old_loc_vec));
2318 PetscScalar relax_factor;
2319 LibmeshPetscCall(VecAbs(_Wij_loc_vec));
2320 #if !PETSC_VERSION_LESS_THAN(3, 16, 0) 2321 LibmeshPetscCall(VecMean(_Wij_loc_vec, &relax_factor));
2323 VecSum(_Wij_loc_vec, &relax_factor);
2327 V(
"Relax base value: " + std::to_string(relax_factor));
2330 const PetscScalar resistance_relaxation = 0.9;
2332 V(
"New cross resistance: " + std::to_string(
_added_K));
2335 V(
"Relaxed cross resistance: " + std::to_string(
_added_K));
2338 if (_added_K < 10 && _added_K >= 1.0)
2340 if (_added_K < 1.0 && _added_K >= 0.1)
2342 if (_added_K < 0.1 && _added_K >= 0.01)
2344 if (_added_K < 1e-2 && _added_K >= 1e-3)
2346 V(
"Actual added cross resistance: " + std::to_string(
_added_K));
2347 LibmeshPetscCall(VecScale(unity_vec_Wij,
_added_K));
2350 LibmeshPetscCall(MatDiagonalSet(mat_array[2 * Q + 2], unity_vec_Wij, ADD_VALUES));
2353 LibmeshPetscCall(VecDestroy(&mdot_estimate));
2354 LibmeshPetscCall(VecDestroy(&pmat_diag));
2355 LibmeshPetscCall(VecDestroy(&unity_vec));
2356 LibmeshPetscCall(VecDestroy(&p_estimate));
2357 LibmeshPetscCall(VecDestroy(&sol_holder_P));
2358 LibmeshPetscCall(VecDestroy(&unity_vec_Wij));
2359 LibmeshPetscCall(VecDestroy(&sumWij_loc));
2360 LibmeshPetscCall(VecDestroy(&_Wij_loc_vec));
2361 LibmeshPetscCall(VecDestroy(&_Wij_old_loc_vec));
2364 const PetscScalar relaxation_factor_mdot = 1.0;
2365 const PetscScalar relaxation_factor_P = 1.0;
2366 const PetscScalar relaxation_factor_Wij = 0.1;
2368 V(
"Relax mdot: " + std::to_string(relaxation_factor_mdot));
2369 V(
"Relax P: " + std::to_string(relaxation_factor_P));
2370 V(
"Relax Wij: " + std::to_string(relaxation_factor_Wij));
2373 RelaxEquation(mat_array[Idx(0, 0)],
2377 relaxation_factor_mdot,
2380 return populateVectorFromHandle<SolutionHandle>(
2386 RelaxEquation(mat_array[Idx(1, 1)],
2390 relaxation_factor_P,
2393 return populateVectorFromHandle<SolutionHandle>(
2399 RelaxEquation(mat_array[Idx(2, 2)],
2403 relaxation_factor_Wij,
2406 return populateVectorFromDense<libMesh::DenseMatrix<Real>>(
2411 V(
"Linear solver relaxed");
2417 LibmeshPetscCall(MatCreateNest(PETSC_COMM_SELF, Q, NULL, Q, NULL, mat_array.data(), &A_nest));
2418 LibmeshPetscCall(VecCreateNest(PETSC_COMM_SELF, Q, NULL, vec_array.data(), &b_nest));
2419 V(
"Nested system created");
2423 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksp));
2424 LibmeshPetscCall(KSPSetType(ksp, KSPFGMRES));
2425 LibmeshPetscCall(KSPSetOperators(ksp, A_nest, A_nest));
2426 LibmeshPetscCall(KSPGetPC(ksp, &pc));
2427 LibmeshPetscCall(PCSetType(pc, PCFIELDSPLIT));
2431 std::vector<IS> rows(Q);
2432 LibmeshPetscCall(MatNestGetISs(A_nest, rows.data(), NULL));
2433 for (PetscInt
j = 0;
j < Q; ++
j)
2436 LibmeshPetscCall(ISDuplicate(rows[
j], &part));
2437 LibmeshPetscCall(PCFieldSplitSetIS(pc, NULL, part));
2438 LibmeshPetscCall(ISDestroy(&part));
2440 V(
"Linear solver assembled");
2443 LibmeshPetscCall(VecDuplicate(b_nest, &x_nest));
2444 LibmeshPetscCall(VecSet(x_nest, 0.0));
2445 LibmeshPetscCall(KSPSolve(ksp, b_nest, x_nest));
2448 LibmeshPetscCall(VecDestroy(&b_nest));
2449 LibmeshPetscCall(MatDestroy(&A_nest));
2450 LibmeshPetscCall(KSPDestroy(&ksp));
2451 for (PetscInt i = 0; i < Q * Q; i++)
2452 LibmeshPetscCall(MatDestroy(&mat_array[i]));
2453 for (PetscInt i = 0; i < Q; i++)
2454 LibmeshPetscCall(VecDestroy(&vec_array[i]));
2455 V(
"Solver elements destroyed");
2458 Vec sol_mdot, sol_p, sol_Wij;
2459 V(
"Vectors to hold solution created");
2462 LibmeshPetscCall(VecNestGetSubVecs(x_nest, &num_vecs, &loc_vecs));
2464 LibmeshPetscCall(VecCopy(loc_vecs[0], sol_mdot));
2466 LibmeshPetscCall(VecCopy(loc_vecs[1], sol_p));
2468 LibmeshPetscCall(VecCopy(loc_vecs[2], sol_Wij));
2469 V(
"Solution from coupled solver copied to solution vectors");
2472 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
2477 PetscScalar * sol_p_array;
2478 LibmeshPetscCall(VecGetArray(sol_p, &sol_p_array));
2479 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
2481 const auto iz_ind = iz - first_node;
2482 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
2489 LibmeshPetscCall(VecRestoreArray(sol_p, &sol_p_array));
2497 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
2500 LibmeshPetscCall(VecAbs(
_prod));
2505 V(
"Solutions assigned to MOOSE variables.");
2508 LibmeshPetscCall(VecDestroy(&x_nest));
2509 LibmeshPetscCall(VecDestroy(&sol_mdot));
2510 LibmeshPetscCall(VecDestroy(&sol_p));
2511 LibmeshPetscCall(VecDestroy(&sol_Wij));
2512 V(
"Solutions destroyed.");
2520 _console <<
"Executing subchannel solver\n";
2531 for (
const auto * ti :
transient->getTimeIntegrators())
2532 if (!dynamic_cast<const ImplicitEuler *>(ti))
2533 mooseWarning(
"The subchannel solver always uses implicit (backward) Euler time " 2534 "integration; the requested '",
2536 "' time integrator is ignored.");
2542 auto V = [&](
const std::string & s)
2547 V(
"Solution initialized");
2549 unsigned int P_it = 0;
2550 unsigned int P_it_max;
2560 while ((P_error >
_P_tol && P_it < P_it_max))
2565 _console <<
"Reached maximum number of axial pressure iterations" << std::endl;
2568 _console <<
"Solving Outer Iteration : " << P_it << std::endl;
2569 auto P_L2norm_old_axial =
_P_soln->L2norm();
2570 for (
unsigned int iblock = 0; iblock <
_n_blocks; iblock++)
2574 Real T_block_error = 1.0;
2576 _console <<
"Solving Block: " << iblock <<
" From first level: " << first_level
2577 <<
" to last level: " << last_level << std::endl;
2583 _console <<
"Reached maximum number of temperature iterations for block: " << iblock
2587 auto T_L2norm_old_block =
_T_soln->L2norm();
2605 V(
"Done with main solve.");
2611 V(
"Done with thermal solve.");
2614 V(
"Start updating thermophysical properties.");
2619 V(
"Done updating thermophysical properties.");
2624 _aux->solution().close();
2626 auto T_L2norm_new =
_T_soln->L2norm();
2628 std::abs((T_L2norm_new - T_L2norm_old_block) / (T_L2norm_old_block + 1E-14));
2629 _console <<
"T_block_error: " << T_block_error << std::endl;
2635 auto P_L2norm_new_axial =
_P_soln->L2norm();
2637 std::abs((P_L2norm_new_axial - P_L2norm_old_axial) / (P_L2norm_old_axial +
_P_out + 1E-14));
2638 _console <<
"P_error :" << P_error << std::endl;
2639 V(
"Iteration: " + std::to_string(P_it));
2640 V(
"Maximum iterations: " + std::to_string(P_it_max));
2644 _console <<
"Finished executing subchannel solver\n";
2647 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
2657 for (
unsigned int iz = 0; iz <
_n_cells + 1; ++iz)
2659 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
2662 auto mu = (*_mu_soln)(node);
2663 auto S = (*_S_flow_soln)(node);
2664 auto w_perim = (*_w_perim_soln)(node);
2665 auto Dh_i = 4.0 *
S / w_perim;
2666 auto Re = (((*_mdot_soln)(node) /
S) * Dh_i /
mu);
2669 auto Pr = (*_mu_soln)(node)*
cp /
k;
2689 _console <<
"Commencing calculation of Pin surface temperature \n";
2690 for (
unsigned int i_pin = 0; i_pin <
_n_pins; i_pin++)
2692 for (
unsigned int iz = 0; iz <
_n_cells + 1; ++iz)
2700 auto mu = (*_mu_soln)(node);
2701 auto S = (*_S_flow_soln)(node);
2702 auto w_perim = (*_w_perim_soln)(node);
2703 auto Dh_i = 4.0 *
S / w_perim;
2704 auto Re = (((*_mdot_soln)(node) /
S) * Dh_i /
mu);
2707 auto Pr = (*_mu_soln)(node)*
cp /
k;
2716 (*_q_prime_soln)(pin_node) / ((*
_Dpin_soln)(pin_node)*M_PI * hw) + (*_T_soln)(node);
2721 mooseError(
"Pin was not found for pin index: " + std::to_string(i_pin));
2729 _console <<
"Commencing calculation of duct surface temperature " << std::endl;
2731 for (Node * dn : duct_nodes)
2734 auto mu = (*_mu_soln)(node_chan);
2735 auto S = (*_S_flow_soln)(node_chan);
2736 auto w_perim = (*_w_perim_soln)(node_chan);
2737 auto Dh_i = 4.0 *
S / w_perim;
2738 auto Re = (((*_mdot_soln)(node_chan) /
S) * Dh_i /
mu);
2741 auto Pr = (*_mu_soln)(node_chan)*
cp /
k;
2758 auto T_chan = (*_duct_heat_flux_soln)(dn) / hw + (*
_T_soln)(node_chan);
2762 _aux->solution().close();
2767 Real power_in = 0.0;
2768 Real power_out = 0.0;
2769 Real viscosity_in = 0.0;
2770 Real mass_flow_in = 0.0;
2771 Real mass_flow_out = 0.0;
2772 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
2776 const Real mdot_in = (*_mdot_soln)(node_in);
2777 power_in += mdot_in * (*_h_soln)(node_in);
2778 power_out += (*_mdot_soln)(node_out) * (*
_h_soln)(node_out);
2779 viscosity_in += mdot_in * (*_mu_soln)(node_in);
2780 mass_flow_in += mdot_in;
2781 mass_flow_out += (*_mdot_soln)(node_out);
2783 auto h_bulk_out = power_out / mass_flow_out;
2784 auto T_bulk_out =
_fp->T_from_p_h(
_P_out, h_bulk_out);
2787 Real inlet_mu = viscosity_in / mass_flow_in;
2791 _console <<
" ======================================= " << std::endl;
2792 _console <<
" ======== Subchannel Print Outs ======== " << std::endl;
2793 _console <<
" ======================================= " << std::endl;
2796 _console <<
"Assembly hydraulic diameter :" << bulk_Dh <<
" m" << std::endl;
2797 _console <<
"Assembly Re number :" << bulk_Re <<
" [-]" << std::endl;
2798 _console <<
"Bulk coolant temperature at outlet :" << T_bulk_out <<
" K" << std::endl;
2799 _console <<
"Power added to coolant is : " << power_out - power_in <<
" Watt" << std::endl;
2800 _console <<
"Mass flow rate in is : " << mass_flow_in <<
" kg/sec" << std::endl;
2801 _console <<
"Mass balance is : " << mass_flow_out - mass_flow_in <<
" kg/sec" << std::endl;
2802 _console <<
"User defined outlet pressure is : " <<
_P_out <<
" Pa" << std::endl;
2803 _console <<
" ======================================= " << std::endl;
2806 if (MooseUtils::absoluteFuzzyLessEqual((power_out - power_in), -1.0))
2808 "Energy conservation equation might not be solved correctly, Power added to coolant: " +
2809 std::to_string(power_out - power_in) +
" Watt ");
Vec _amc_friction_force_rhs
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...
Mat _amc_sys_mdot_mat
Axial momentum system matrix.
static const std::string PRESSURE_DROP
static const std::string FRICTION_FACTOR
static const std::string MASS_FLOW_RATE
const bool _pin_mesh_exist
Flag that informs if there is a pin mesh or not.
void computeRho(int iblock)
Computes Density per channel for block iblock.
Vec _amc_gravity_rhs
Axial momentum conservation - buoyancy force No implicit matrix.
virtual unsigned int getNumOfGapsPerLayer() const =0
Return the number of gaps per layer.
std::unique_ptr< SolutionHandle > _Tduct_soln
std::unique_ptr< SolutionHandle > _duct_heat_flux_soln
static const std::string DENSITY
void computeSumWij(int iblock)
Computes net diversion crossflow per channel for block iblock.
unsigned int _n_blocks
number of axial blocks
const bool _compute_power
Flag that informs if we need to solve the Enthalpy/Temperature equations or not.
virtual const Real & getPinDiameter() const
Return undeformed Pin diameter.
static InputParameters validParams()
std::unique_ptr< SolutionHandle > _T_soln
std::unique_ptr< SolutionHandle > _h_soln
const PetscReal & _dtol
The divergence tolerance for the ksp linear solver.
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 paramError(const std::string ¶m, Args... args) const
T & getMesh(MooseMesh &mesh)
function to cast mesh
PetscScalar _max_sumWij_new
Mat _cmc_friction_force_mat
Cross momentum conservation - friction force.
void computeP(int iblock)
Computes Pressure per channel for block iblock.
Node * getDuctNodeFromChannel(Node *channel_node) const
Function that gets the duct node from the channel node.
Real _TR
Flag that activates or deactivates the transient parts of the equations we solve by multiplication...
libMesh::DenseMatrix< Real > _Wij_old
libMesh::DenseMatrix< Real > _DP
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(...
const PostprocessorValue & _P_out
Outlet pressure postprocessor value.
SubChannelMesh & _subchannel_mesh
void computeT(int iblock)
Computes Temperature per channel for block iblock.
virtual void zero() override final
static constexpr Real TOLERANCE
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 const std::vector< Real > & getZGrid() const
Get axial location of layers.
Vec _amc_pressure_force_rhs
void computeMdot(int iblock)
Computes mass flow per channel for block iblock.
virtual const Real & getPitch() const
Return the undeformed pitch between 2 subchannels.
virtual EChannelType getSubchannelType(unsigned int index) const =0
Return the type of the subchannel for given subchannel index.
std::unique_ptr< SolutionHandle > _S_flow_soln
const SCMHTCClosureBase * _pin_HTC_closure
HTC closure objects.
Vec _hc_time_derivative_rhs
const bool _compute_density
Flag that activates or deactivates the calculation of density.
Vec _mc_axial_convection_rhs
Mat _amc_friction_force_mat
Axial momentum conservation - friction force.
static const std::string PIN_DIAMETER
PetscScalar _added_K
Added resistances for monolithic convergence.
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.
PetscErrorCode createPetscVector(Vec &v, PetscInt n)
Petsc Functions.
const SCMMixingClosureBase * _mixing_closure
Turbulent Mixing closure object.
static InputParameters validParams()
Vec _cmc_advective_derivative_rhs
const Parallel::Communicator & comm() const
const bool _duct_mesh_exist
Flag that informs if there is a duct mesh or not.
static InputParameters validParams()
const Real & _T_tol
Convergence tolerance for the temperature loop in internal solve.
Vec _amc_time_derivative_rhs
void computeMu(int iblock)
Computes Viscosity per channel for block iblock.
The following methods are specializations for using the Parallel::packed_range_* routines for a vecto...
structure with the needed information to compute the friction factor at a specific subchannel cell ...
PetscScalar computeInterpolatedValue(PetscScalar topValue, PetscScalar botValue, PetscScalar Peclet=0.0)
virtual unsigned int getNumOfPins() const =0
Return the number of pins.
Real getAssemblyHydraulicDiameter() const
Return undeformed bundle-average hydraulic diameter.
bool isRestarting() const
const bool _segregated_bool
Segregated solve.
Mat _cmc_sys_Wij_mat
Lateral momentum system matrix.
Vec _amc_advective_derivative_rhs
bool _converged
Variable that informs whether we exited external solve with a converged solution or not...
virtual const std::vector< unsigned int > & getChannelGaps(unsigned int i_chan) const =0
Return a vector of gap indices for a given channel index.
Vec _hc_cross_derivative_rhs
const bool _staggered_pressure_bool
Flag to define the usage of staggered or collocated pressure.
virtual void initializeSolution()=0
Function to initialize the solution & geometry fields.
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
auto max(const L &left, const R &right)
Mat _mc_sumWij_mat
Matrices and vectors to be used in implicit assembly Mass conservation Mass conservation - sum of cro...
PetscErrorCode populateVectorFromDense(Vec &x, const T &solution, const unsigned int first_axial_level, const unsigned int last_axial_level, const unsigned int cross_dimension)
static const std::string DUCT_HEAT_FLUX
static const std::string DUCT_TEMPERATURE
SubChannel1PhaseProblem * schp
const SCMHTCClosureBase * _duct_HTC_closure
Real computeMixingParameter(unsigned int i_gap, unsigned int iz) const
Computes and validates the turbulent mixing parameter.
static const std::string WETTED_PERIMETER
virtual void computeh(int iblock)=0
Computes Enthalpy per channel for block iblock.
std::unique_ptr< SolutionHandle > _rho_soln
Mat _amc_turbulent_cross_flows_mat
Mass conservation - density time derivative No implicit matrix.
static const std::string cp
Mat _amc_advective_derivative_mat
Axial momentum conservation - advective (Eulerian) derivative.
static const std::string VISCOSITY
Vec _hc_added_heat_rhs
Enthalpy conservation - source and sink.
std::unique_ptr< SolutionHandle > _HTC_soln
std::vector< Real > _z_grid
axial location of nodes
const std::string & name() const
static const std::string PIN_TEMPERATURE
virtual Real computeFrictionFactor(const FrictionStruct &friction_info) const =0
Computes the friction factor for the local conditions.
Vec _cmc_time_derivative_rhs
const int & _T_maxit
Maximum iterations for the inner temperature loop.
Mat _amc_pressure_force_mat
Axial momentum conservation - pressure force.
static const std::string LINEAR_HEAT_RATE
const std::vector< Node * > & getDuctNodes() const
Function that returns the vector with the duct nodes.
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
bool _time_integrator_checked
Whether the time integrator has been checked for consistency with the implementation.
void computeWijResidual(int iblock)
Computes Residual Matrix based on the lateral momentum conservation equation for block iblock...
const std::vector< double > x
static const std::string S
Real f(Real x)
Test function for Brents method.
std::unique_ptr< SolutionHandle > _q_prime_soln
virtual void syncSolutions(Direction direction) override
static const std::string pitch
virtual unsigned int getNumOfChannels() const =0
Return the number of channels per layer.
const PetscReal & _atol
The absolute convergence tolerance for the ksp linear solver.
PetscScalar computeInterpolationCoefficients(PetscScalar Peclet=0.0)
Functions that computes the interpolation scheme given the Peclet number.
Node * getChannelNodeFromDuct(Node *duct_node) const
Function that gets the channel node from the duct node.
static const std::string ENTHALPY
Real root(std::function< Real(Real)> const &f, Real x1, Real x2, Real tol=1.0e-12)
Finds the root of a function using Brent's method.
std::shared_ptr< AuxiliarySystem > _aux
Mat _hc_cross_derivative_mat
Enthalpy conservation - cross flux derivative.
Mat _mc_axial_convection_mat
Mass conservation - axial convection.
void initialSetup() override
auto Peclet(const T1 &volume_fraction, const T2 &cp, const T3 &rho, const T4 &vel, const T5 &D_h, const T6 &k)
Compute Peclet number.
virtual ~SubChannel1PhaseProblem()
const PetscInt & _maxit
The maximum number of iterations to use for the ksp linear solver.
PetscErrorCode createPetscMatrix(Mat &M, PetscInt n, PetscInt m)
virtual Real computeSweepFlowMixingParameter(const unsigned int i_gap, const unsigned int iz) const
Computes the wire-wrap sweep-flow coefficient for peripheral gaps.
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.
virtual const std::vector< std::vector< Real > > & getKGrid() const
Get axial cell location and value of loss coefficient.
Real computeSweepFlowMixingParameter(unsigned int i_gap, unsigned int iz) const
Computes and validates the sweep-flow mixing parameter.
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.
const MooseEnum _interpolation_scheme
The interpolation method used in constructing the systems.
virtual Real getCT() const
Return the Turbulent modeling parameter.
const SCMFrictionClosureBase * _friction_closure
Friction closure object.
std::unique_ptr< SolutionHandle > _Dpin_soln
Real getAssemblyFlowArea() const
Return undeformed bundle inlet flow area.
bool _deformation
Flag that activates the effect of deformation (pin/duct) based on the auxvalues for displacement...
Executioner * getExecutioner() const
virtual unsigned int getNumOfAxialCells() const
Return the number of axial cells.
Base class for the 1-phase steady-state/transient subchannel solver.
libMesh::DenseMatrix< Real > _Wij_residual_matrix
std::unique_ptr< SolutionHandle > _mdot_soln
Solutions handles and link to TH tables properties.
PetscErrorCode populateDenseFromVector(const Vec &x, T &solution, const unsigned int first_axial_level, const unsigned int last_axial_level, const unsigned int cross_dimension)
static const std::string SUM_CROSSFLOW
virtual Real getGapWidth(unsigned int axial_index, unsigned int gap_index) const =0
Return gap width for a given gap index.
LibmeshPetscCallQ(DMShellGetContext(dm, &ctx))
virtual unsigned int channelIndex(const Point &point) const =0
const PetscReal & _rtol
The relative convergence tolerance, (relative decrease) for the ksp linear solver.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
std::unique_ptr< SolutionHandle > _displacement_soln
PetscErrorCode formFunction(SNES, Vec x, Vec f, void *ctx)
std::unique_ptr< SolutionHandle > _DP_soln
const bool _compute_viscosity
Flag that activates or deactivates the calculation of viscosity.
static const std::string PRESSURE
libMesh::DenseMatrix< Real > & _Wij
virtual void externalSolve() override
void max(const T &r, T &o, Request &req) const
void computeWijPrime(int iblock)
Computes turbulent crossflow per gap for block iblock.
static const std::string alpha
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.
std::unique_ptr< SolutionHandle > _SumWij_soln
void detectDeformation()
Detects whether pin diameter or duct displacement fields require geometry recalculation.
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.
Vec _hc_advective_derivative_rhs
libMesh::DenseVector< Real > residualFunction(int iblock, libMesh::DenseVector< Real > solution)
Computes Residual Vector based on the lateral momentum conservation equation for block iblock & updat...
static const std::string SURFACE_AREA
Real _CT
Turbulent modeling parameter used in axial momentum equation.
void mooseWarning(Args &&... args) const
void resize(const unsigned int new_m, const unsigned int new_n)
const bool _verbose_subchannel
Boolean to printout information related to subchannel solve.
PetscScalar _correction_factor
virtual void transient(bool trans)
Mat _amc_cross_derivative_mat
Axial momentum conservation - cross flux derivative.
void mooseError(Args &&... args) const
const Real & _P_tol
Convergence tolerance for the pressure loop in external solve.
std::unique_ptr< SolutionHandle > _ff_soln
virtual bool solverSystemConverged(const unsigned int) override
struct SubChannel1PhaseProblem::FrictionStruct _friction_args
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
Mat _hc_advective_derivative_mat
Enthalpy conservation - advective (Eulerian) derivative;.
Base class for subchannel meshes.
void computeWijFromSolve(int iblock)
Computes diversion crossflow per gap for block iblock.
static const std::string HEAT_TRANSFER_COEFFICIENT
const bool _implicit_bool
Flag to define the usage of a implicit or explicit solution.
Mat _amc_time_derivative_mat
Axial momentum conservation - time derivative.
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...
bool isParamValid(const std::string &name) const
const ConsoleStream _console
static const std::string DISPLACEMENT
Mat _hc_time_derivative_mat
Enthalpy Enthalpy conservation - time derivative.
virtual bool isTransient() const override
PetscErrorCode implicitPetscSolve(int iblock)
Computes implicit solve using PetSc.
void computeDP(int iblock)
Computes Pressure Drop per channel for block iblock.
SubChannel1PhaseProblem(const InputParameters ¶ms)
Mat _cmc_time_derivative_mat
Cross momentum Cross momentum conservation - time derivative.
libMesh::DenseMatrix< Real > _WijPrime
virtual void initialSetup() override
PetscFunctionReturn(LIBMESH_PETSC_SUCCESS)
Vec _cmc_friction_force_rhs
processor_id_type processor_id() const
bool isRecovering() const
static const std::string TEMPERATURE
Mat _cmc_pressure_force_mat
Cross momentum conservation - pressure force.
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 computeAddedHeatDuct(unsigned int i_ch, unsigned int iz) const
Non-pure: implemented in the base (or override in a child if needed)
virtual Real & dt() const
Vec _amc_turbulent_cross_flows_rhs
std::unique_ptr< SolutionHandle > _P_soln
virtual unsigned int getZIndex(const Point &point) const
Get axial index of point.
static const std::string k
std::unique_ptr< SolutionHandle > _w_perim_soln
void ErrorVector unsigned int
Vec _cmc_pressure_force_rhs
Vec _amc_cross_derivative_rhs
Mat _cmc_advective_derivative_mat
Cross momentum conservation - advective (Eulerian) derivative.
struct SubChannel1PhaseProblem::NusseltStruct _nusselt_args
const SinglePhaseFluidProperties * _fp
Non-owning pointer to fluid properties user object.
structure with the needed information to compute the Nusselt number at a specific subchannel cell and...
Mat _hc_sys_h_mat
System matrices.
std::unique_ptr< SolutionHandle > _mu_soln
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.
std::unique_ptr< SolutionHandle > _Tpin_soln