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")),
174 _duct_heat_flux_soln(nullptr),
175 _Tduct_soln(nullptr),
180 "You are using a deprecated parameter. Please use the mixing_closure system.");
182 paramError(
"pin_HTC_closure",
"required when a pin mesh exists.");
184 paramError(
"duct_HTC_closure",
"required when a duct mesh exists.");
279 ": When implicit number of blocks can't be equal to number of cells. This will " 280 "cause problems with the subchannel interpolation scheme.");
289 _fp = &getUserObject<SinglePhaseFluidProperties>(getParam<UserObjectName>(
"fp"));
291 &getUserObject<SCMFrictionClosureBase>(getParam<UserObjectName>(
"friction_closure"));
293 &getUserObject<SCMMixingClosureBase>(getParam<UserObjectName>(
"mixing_closure"));
302 if (getParam<bool>(
"full_output"))
316 &getUserObject<SCMHTCClosureBase>(getParam<UserObjectName>(
"pin_HTC_closure"));
331 &getUserObject<SCMHTCClosureBase>(getParam<UserObjectName>(
"duct_HTC_closure"));
343 for (
unsigned int iz = 0; iz <
_n_cells + 1; iz++)
344 for (
unsigned int i_pin = 0; i_pin <
_n_pins; i_pin++)
347 const Real Dpin = (*_Dpin_soln)(node);
348 if (std::abs(Dpin) <=
tol)
351 ". You must initialize Dpin to a non-zero value.");
352 if (std::abs(Dpin - pin_diameter) >
tol)
371 PetscErrorCode ierr =
cleanUp();
383 LibmeshPetscCall(VecDestroy(&
_Wij_vec));
384 LibmeshPetscCall(VecDestroy(&
_prod));
385 LibmeshPetscCall(VecDestroy(&
_prodp));
453 ": Interpolation scheme should be a string: upwind, downwind, central_difference, " 460 PetscScalar botValue,
464 return alpha * botValue + (1.0 -
alpha) * topValue;
470 const unsigned int last_node = (iblock + 1) *
_block_size;
471 const unsigned int first_node = iblock *
_block_size + 1;
474 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
476 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
478 int i =
_n_gaps * (iz - first_node) + i_gap;
479 solution_seed(i) =
_Wij(i_gap, iz);
490 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
492 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
503 const unsigned int last_node = (iblock + 1) *
_block_size;
504 const unsigned int first_node = iblock *
_block_size + 1;
508 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
510 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
515 unsigned int counter = 0;
529 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
531 unsigned int iz_ind = iz - first_node;
532 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
535 unsigned int counter = 0;
539 PetscInt col = i_gap +
_n_gaps * iz_ind;
546 LibmeshPetscCall(MatAssemblyBegin(
_mc_sumWij_mat, MAT_FINAL_ASSEMBLY));
547 LibmeshPetscCall(MatAssemblyEnd(
_mc_sumWij_mat, MAT_FINAL_ASSEMBLY));
553 LibmeshPetscCall(VecDuplicate(
_Wij_vec, &loc_Wij));
557 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
559 LibmeshPetscCall(VecDestroy(&loc_prod));
560 LibmeshPetscCall(VecDestroy(&loc_Wij));
568 const unsigned int last_node = (iblock + 1) *
_block_size;
569 const unsigned int first_node = iblock *
_block_size + 1;
572 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
575 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
579 auto volume = dz * (*_S_flow_soln)(node_in);
582 auto mdot_out = (*_mdot_soln)(node_in) - (*
_SumWij_soln)(node_out)-time_term;
587 " : Calculation of negative mass flow mdot_out = : ",
591 " - Implicit solves are required for recirculating flow.");
599 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
602 auto iz_ind = iz - first_node;
603 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
607 auto volume = dz * (*_S_flow_soln)(node_in);
612 PetscScalar value_vec = -1.0 * time_term;
617 if (iz == first_node)
619 PetscScalar value_vec = (*_mdot_soln)(node_in);
628 PetscScalar
value = -1.0;
636 PetscScalar
value = 1.0;
643 PetscScalar value_vec_2 = -1.0 * (*_SumWij_soln)(node_out);
659 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksploc));
661 LibmeshPetscCall(KSPGetPC(ksploc, &pc));
662 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
664 LibmeshPetscCall(KSPSetFromOptions(ksploc));
666 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
669 LibmeshPetscCall(KSPDestroy(&ksploc));
670 LibmeshPetscCall(VecDestroy(&sol));
678 const unsigned int last_node = (iblock + 1) *
_block_size;
679 const unsigned int first_node = iblock *
_block_size + 1;
682 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
686 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
690 auto rho_in = (*_rho_soln)(node_in);
691 auto rho_out = (*_rho_soln)(node_out);
692 auto mu_in = (*_mu_soln)(node_in);
693 auto S = (*_S_flow_soln)(node_in);
694 auto w_perim = (*_w_perim_soln)(node_in);
696 auto Dh_i = 4.0 *
S / w_perim;
697 auto time_term =
_TR * ((*_mdot_soln)(node_out)-
_mdot_soln->old(node_out)) * dz /
_dt -
701 Utility::pow<2>((*_mdot_soln)(node_out)) * (1.0 /
S / rho_out - 1.0 /
S / rho_in);
702 auto mass_term2 = -2.0 * (*_mdot_soln)(node_out) * (*
_SumWij_soln)(node_out) /
S / rho_in;
703 auto crossflow_term = 0.0;
704 auto turbulent_term = 0.0;
705 unsigned int counter = 0;
709 unsigned int ii_ch = chans.first;
710 unsigned int jj_ch = chans.second;
715 auto rho_i = (*_rho_soln)(node_in_i);
716 auto rho_j = (*_rho_soln)(node_in_j);
717 auto Si = (*_S_flow_soln)(node_in_i);
718 auto Sj = (*_S_flow_soln)(node_in_j);
721 if (
_Wij(i_gap, iz) > 0.0)
722 u_star = (*_mdot_soln)(node_out_i) / Si / rho_i;
724 u_star = (*_mdot_soln)(node_out_j) / Sj / rho_j;
729 turbulent_term +=
_WijPrime(i_gap, iz) * (2 * (*_mdot_soln)(node_out) / rho_in /
S -
734 turbulent_term *=
_CT;
735 auto Re = (((*_mdot_soln)(node_in) /
S) * Dh_i / mu_in);
743 ki = k_grid[i_ch][iz - 1];
745 ki = k_grid[i_ch][iz];
746 auto friction_term = (ff * dz / Dh_i + ki) * 0.5 *
748 (
S * (*_rho_soln)(node_out));
750 auto DP = (1 /
S) * (time_term + mass_term1 + mass_term2 + crossflow_term + turbulent_term +
751 friction_term + gravity_term);
771 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
775 auto iz_ind = iz - first_node;
776 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
783 PetscScalar Pe = 0.5;
787 auto S_in = (*_S_flow_soln)(node_in);
788 auto S_out = (*_S_flow_soln)(node_out);
790 auto w_perim_in = (*_w_perim_soln)(node_in);
791 auto w_perim_out = (*_w_perim_soln)(node_out);
795 auto mu_in = (*_mu_soln)(node_in);
796 auto mu_out = (*_mu_soln)(node_out);
798 auto Dh_i = 4.0 * S_interp / w_perim_interp;
800 auto Re = ((mdot_loc / S_interp) * Dh_i / mu_interp);
808 ki = k_grid[i_ch][iz - 1];
810 ki = k_grid[i_ch][iz];
811 Pe = 1.0 / ((ff * dz / Dh_i + ki) * 0.5) * mdot_loc / std::abs(mdot_loc);
816 auto rho_in = (*_rho_soln)(node_in);
817 auto rho_out = (*_rho_soln)(node_out);
821 auto mu_in = (*_mu_soln)(node_in);
822 auto mu_out = (*_mu_soln)(node_out);
826 auto S_in = (*_S_flow_soln)(node_in);
827 auto S_out = (*_S_flow_soln)(node_out);
831 auto w_perim_in = (*_w_perim_soln)(node_in);
832 auto w_perim_out = (*_w_perim_soln)(node_out);
836 auto Dh_i = 4.0 * S_interp / w_perim_interp;
839 if (iz == first_node)
841 PetscScalar value_vec_tt = -1.0 *
_TR *
alpha * (*_mdot_soln)(node_in)*dz /
_dt;
849 PetscInt col_tt = i_ch +
_n_channels * (iz_ind - 1);
851 LibmeshPetscCall(MatSetValues(
858 PetscScalar value_tt =
_TR * (1.0 -
alpha) * dz /
_dt;
859 LibmeshPetscCall(MatSetValues(
863 PetscScalar mdot_old_interp =
865 PetscScalar value_vec_tt =
_TR * mdot_old_interp * dz /
_dt;
871 if (iz == first_node)
873 PetscScalar value_vec_at = Utility::pow<2>((*_mdot_soln)(node_in)) / (S_in * rho_in);
875 LibmeshPetscCall(VecSetValues(
881 PetscInt col_at = i_ch +
_n_channels * (iz_ind - 1);
882 PetscScalar value_at = -1.0 * std::abs((*
_mdot_soln)(node_in)) / (S_in * rho_in);
883 LibmeshPetscCall(MatSetValues(
890 PetscScalar value_at = std::abs((*
_mdot_soln)(node_out)) / (S_out * rho_out);
891 LibmeshPetscCall(MatSetValues(
895 unsigned int counter = 0;
896 unsigned int cross_index = iz;
900 unsigned int ii_ch = chans.first;
901 unsigned int jj_ch = chans.second;
916 if (
_Wij(i_gap, cross_index) > 0.0)
918 if (iz == first_node)
920 u_star = (*_mdot_soln)(node_in_i) / S_i / rho_i;
921 PetscScalar value_vec_ct = -1.0 *
alpha *
923 _Wij(i_gap, cross_index) * u_star;
925 LibmeshPetscCall(VecSetValues(
931 _Wij(i_gap, cross_index) / S_i / rho_i;
933 PetscInt col_ct = ii_ch +
_n_channels * (iz_ind - 1);
934 LibmeshPetscCall(MatSetValues(
937 PetscScalar value_ct = (1.0 -
alpha) *
939 _Wij(i_gap, cross_index) / S_i / rho_i;
942 LibmeshPetscCall(MatSetValues(
945 else if (
_Wij(i_gap, cross_index) < 0.0)
947 if (iz == first_node)
949 u_star = (*_mdot_soln)(node_in_j) / S_j / rho_j;
950 PetscScalar value_vec_ct = -1.0 *
alpha *
952 _Wij(i_gap, cross_index) * u_star;
954 LibmeshPetscCall(VecSetValues(
960 _Wij(i_gap, cross_index) / S_j / rho_j;
962 PetscInt col_ct = jj_ch +
_n_channels * (iz_ind - 1);
963 LibmeshPetscCall(MatSetValues(
966 PetscScalar value_ct = (1.0 -
alpha) *
968 _Wij(i_gap, cross_index) / S_j / rho_j;
971 LibmeshPetscCall(MatSetValues(
975 if (iz == first_node)
977 PetscScalar value_vec_ct = -2.0 *
alpha * (*_mdot_soln)(node_in)*
_CT *
978 _WijPrime(i_gap, cross_index) / (rho_interp * S_interp);
979 value_vec_ct +=
alpha * (*_mdot_soln)(node_in_j)*
_CT *
_WijPrime(i_gap, cross_index) /
981 value_vec_ct +=
alpha * (*_mdot_soln)(node_in_i)*
_CT *
_WijPrime(i_gap, cross_index) /
989 PetscScalar value_center_ct =
992 PetscInt col_ct = i_ch +
_n_channels * (iz_ind - 1);
993 LibmeshPetscCall(MatSetValues(
996 PetscScalar value_left_ct =
1000 LibmeshPetscCall(MatSetValues(
1003 PetscScalar value_right_ct =
1007 LibmeshPetscCall(MatSetValues(
1011 PetscScalar value_center_ct =
1012 2.0 * (1.0 -
alpha) *
_CT *
_WijPrime(i_gap, cross_index) / (rho_interp * S_interp);
1015 LibmeshPetscCall(MatSetValues(
1018 PetscScalar value_left_ct =
1022 LibmeshPetscCall(MatSetValues(
1025 PetscScalar value_right_ct =
1029 LibmeshPetscCall(MatSetValues(
1035 PetscScalar mdot_interp =
1037 auto Re = ((mdot_interp / S_interp) * Dh_i / mu_interp);
1045 ki = k_grid[i_ch][iz - 1];
1047 ki = k_grid[i_ch][iz];
1048 auto coef = (ff * dz / Dh_i + ki) * 0.5 * std::abs((*
_mdot_soln)(node_out)) /
1049 (S_interp * rho_interp);
1050 if (iz == first_node)
1052 PetscScalar value_vec = -1.0 *
alpha * coef * (*_mdot_soln)(node_in);
1074 PetscScalar value_vec =
_dir_grav * -1.0 *
_g_grav * rho_interp * dz * S_interp;
1076 LibmeshPetscCall(VecSetValues(
_amc_gravity_rhs, 1, &row_vec, &value_vec, ADD_VALUES));
1093 #if !PETSC_VERSION_LESS_THAN(3, 15, 0) 1135 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
1142 LibmeshPetscCall(VecGetArray(ls, &xx));
1143 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1145 auto iz_ind = iz - first_node;
1146 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1153 auto S_in = (*_S_flow_soln)(node_in);
1154 auto S_out = (*_S_flow_soln)(node_out);
1160 auto DP = (1 / S_interp) * xx[iz_ind *
_n_channels + i_ch];
1174 LibmeshPetscCall(VecDestroy(&ls));
1182 const unsigned int last_node = (iblock + 1) *
_block_size;
1183 const unsigned int first_node = iblock *
_block_size + 1;
1188 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1191 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1202 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1205 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1213 PetscScalar Pe = 0.5;
1215 if (iz == last_node)
1234 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1236 auto iz_ind = iz - first_node;
1238 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1244 auto S_in = (*_S_flow_soln)(node_in);
1245 auto S_out = (*_S_flow_soln)(node_out);
1251 PetscScalar
value = -1.0 * S_interp;
1255 if (iz == last_node)
1257 PetscScalar
value = -1.0 * (*_P_soln)(node_out)*S_interp;
1265 PetscScalar
value = 1.0 * S_interp;
1272 auto dp_out =
_DP(i_ch, iz);
1273 PetscScalar value_v = -1.0 * dp_out * S_interp;
1289 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksploc));
1291 LibmeshPetscCall(KSPGetPC(ksploc, &pc));
1292 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
1294 LibmeshPetscCall(KSPSetFromOptions(ksploc));
1297 LibmeshPetscCall(VecGetArray(sol, &xx));
1299 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1301 auto iz_ind = iz - first_node;
1302 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1310 LibmeshPetscCall(KSPDestroy(&ksploc));
1311 LibmeshPetscCall(VecDestroy(&sol));
1317 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1319 auto iz_ind = iz - first_node;
1321 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1327 auto S_in = (*_S_flow_soln)(node_in);
1328 auto S_out = (*_S_flow_soln)(node_out);
1334 PetscScalar
value = -1.0 * S_interp;
1338 if (iz == last_node)
1340 PetscScalar
value = -1.0 * (*_P_soln)(node_out)*S_interp;
1344 auto dp_out =
_DP(i_ch, iz);
1345 PetscScalar value_v = -1.0 * dp_out / 2.0 * S_interp;
1354 PetscScalar
value = 1.0 * S_interp;
1360 auto dp_in =
_DP(i_ch, iz - 1);
1361 auto dp_out =
_DP(i_ch, iz);
1363 PetscScalar value_v = -1.0 * dp_interp * S_interp;
1375 _console <<
"Block: " << iblock <<
" - Axial momentum pressure force matrix assembled" 1384 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksploc));
1386 LibmeshPetscCall(KSPGetPC(ksploc, &pc));
1387 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
1389 LibmeshPetscCall(KSPSetFromOptions(ksploc));
1392 LibmeshPetscCall(VecGetArray(sol, &xx));
1394 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
1396 auto iz_ind = iz - first_node;
1397 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1405 LibmeshPetscCall(KSPDestroy(&ksploc));
1406 LibmeshPetscCall(VecDestroy(&sol));
1415 const unsigned int last_node = (iblock + 1) *
_block_size;
1416 const unsigned int first_node = iblock *
_block_size + 1;
1417 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1419 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1430 const unsigned int last_node = (iblock + 1) *
_block_size;
1431 const unsigned int first_node = iblock *
_block_size + 1;
1434 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1440 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1442 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1453 const unsigned int last_node = (iblock + 1) *
_block_size;
1454 const unsigned int first_node = iblock *
_block_size + 1;
1457 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1463 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1465 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
1476 const unsigned int last_node = (iblock + 1) *
_block_size;
1477 const unsigned int first_node = iblock *
_block_size + 1;
1482 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1485 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1488 unsigned int i_ch = chans.first;
1489 unsigned int j_ch = chans.second;
1494 auto rho_i = (*_rho_soln)(node_in_i);
1495 auto rho_j = (*_rho_soln)(node_in_j);
1496 auto Si = (*_S_flow_soln)(node_in_i);
1497 auto Sj = (*_S_flow_soln)(node_in_j);
1501 auto friction_term =
_kij *
_Wij(i_gap, iz) * std::abs(
_Wij(i_gap, iz));
1502 auto DPij = (*_P_soln)(node_in_i) - (*
_P_soln)(node_in_j);
1504 auto rho_star = 0.0;
1505 if (
_Wij(i_gap, iz) > 0.0)
1507 else if (
_Wij(i_gap, iz) < 0.0)
1510 rho_star = (rho_i + rho_j) / 2.0;
1511 auto mass_term_out =
1515 (*_mdot_soln)(node_in_i) / Si / rho_i + (*
_mdot_soln)(node_in_j) / Sj / rho_j;
1516 auto term_out = Sij * rho_star * (Lij / dz) * mass_term_out *
_Wij(i_gap, iz);
1517 auto term_in = Sij * rho_star * (Lij / dz) * mass_term_in *
_Wij(i_gap, iz - 1);
1518 auto inertia_term = term_out - term_in;
1519 auto pressure_term = 2 * Utility::pow<2>(Sij) * DPij * rho_star;
1524 time_term + friction_term + inertia_term - pressure_term;
1542 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1545 auto iz_ind = iz - first_node;
1546 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1549 unsigned int i_ch = chans.first;
1550 unsigned int j_ch = chans.second;
1557 auto rho_i_in = (*_rho_soln)(node_in_i);
1558 auto rho_i_out = (*_rho_soln)(node_out_i);
1560 auto rho_j_in = (*_rho_soln)(node_in_j);
1561 auto rho_j_out = (*_rho_soln)(node_out_j);
1565 auto S_i_in = (*_S_flow_soln)(node_in_i);
1566 auto S_i_out = (*_S_flow_soln)(node_out_i);
1567 auto S_j_in = (*_S_flow_soln)(node_in_j);
1568 auto S_j_out = (*_S_flow_soln)(node_out_j);
1575 auto rho_star = 0.0;
1576 if (
_Wij(i_gap, iz) > 0.0)
1577 rho_star = rho_i_interp;
1578 else if (
_Wij(i_gap, iz) < 0.0)
1579 rho_star = rho_j_interp;
1581 rho_star = (rho_i_interp + rho_j_interp) / 2.0;
1584 PetscScalar time_factor =
_TR * Lij * Sij * rho_star /
_dt;
1585 PetscInt row_td = i_gap +
_n_gaps * iz_ind;
1586 PetscInt col_td = i_gap +
_n_gaps * iz_ind;
1587 PetscScalar value_td = time_factor;
1588 LibmeshPetscCall(MatSetValues(
1590 PetscScalar value_td_rhs = time_factor *
_Wij_old(i_gap, iz);
1595 PetscScalar Pe = 0.5;
1597 auto mass_term_out = (*_mdot_soln)(node_out_i) / S_i_out / rho_i_out +
1598 (*
_mdot_soln)(node_out_j) / S_j_out / rho_j_out;
1599 auto mass_term_in = (*_mdot_soln)(node_in_i) / S_i_in / rho_i_in +
1600 (*
_mdot_soln)(node_in_j) / S_j_in / rho_j_in;
1601 auto term_out = Sij * rho_star * (Lij / dz) * mass_term_out / 2.0;
1602 auto term_in = Sij * rho_star * (Lij / dz) * mass_term_in / 2.0;
1603 if (iz == first_node)
1605 PetscInt row_ad = i_gap +
_n_gaps * iz_ind;
1606 PetscScalar value_ad = term_in *
alpha *
_Wij(i_gap, iz - 1);
1610 PetscInt col_ad = i_gap +
_n_gaps * iz_ind;
1611 value_ad = -1.0 * term_in * (1.0 -
alpha) + term_out *
alpha;
1612 LibmeshPetscCall(MatSetValues(
1615 col_ad = i_gap +
_n_gaps * (iz_ind + 1);
1616 value_ad = term_out * (1.0 -
alpha);
1617 LibmeshPetscCall(MatSetValues(
1620 else if (iz == last_node)
1622 PetscInt row_ad = i_gap +
_n_gaps * iz_ind;
1623 PetscInt col_ad = i_gap +
_n_gaps * (iz_ind - 1);
1624 PetscScalar value_ad = -1.0 * term_in *
alpha;
1625 LibmeshPetscCall(MatSetValues(
1628 col_ad = i_gap +
_n_gaps * iz_ind;
1629 value_ad = -1.0 * term_in * (1.0 -
alpha) + term_out *
alpha;
1630 LibmeshPetscCall(MatSetValues(
1633 value_ad = -1.0 * term_out * (1.0 -
alpha) *
_Wij(i_gap, iz);
1639 PetscInt row_ad = i_gap +
_n_gaps * iz_ind;
1640 PetscInt col_ad = i_gap +
_n_gaps * (iz_ind - 1);
1641 PetscScalar value_ad = -1.0 * term_in *
alpha;
1642 LibmeshPetscCall(MatSetValues(
1645 col_ad = i_gap +
_n_gaps * iz_ind;
1646 value_ad = -1.0 * term_in * (1.0 -
alpha) + term_out *
alpha;
1647 LibmeshPetscCall(MatSetValues(
1650 col_ad = i_gap +
_n_gaps * (iz_ind + 1);
1651 value_ad = term_out * (1.0 -
alpha);
1652 LibmeshPetscCall(MatSetValues(
1656 PetscInt row_ff = i_gap +
_n_gaps * iz_ind;
1657 PetscInt col_ff = i_gap +
_n_gaps * iz_ind;
1658 PetscScalar value_ff =
_kij * std::abs(
_Wij(i_gap, iz)) / 2.0;
1659 LibmeshPetscCall(MatSetValues(
1667 PetscScalar pressure_factor = Utility::pow<2>(Sij) * rho_star;
1668 PetscInt row_pf = i_gap +
_n_gaps * iz_ind;
1670 PetscScalar value_pf = -1.0 *
alpha * pressure_factor;
1674 value_pf =
alpha * pressure_factor;
1678 if (iz == last_node)
1680 PetscInt row_pf = i_gap +
_n_gaps * iz_ind;
1681 PetscScalar value_pf = (1.0 -
alpha) * pressure_factor * (*
_P_soln)(node_out_i);
1684 value_pf = -1.0 * (1.0 -
alpha) * pressure_factor * (*
_P_soln)(node_out_j);
1690 row_pf = i_gap +
_n_gaps * iz_ind;
1692 value_pf = -1.0 * (1.0 -
alpha) * pressure_factor;
1693 LibmeshPetscCall(MatSetValues(
1696 value_pf = (1.0 -
alpha) * pressure_factor;
1697 LibmeshPetscCall(MatSetValues(
1703 PetscScalar pressure_factor = Utility::pow<2>(Sij) * rho_star;
1704 PetscInt row_pf = i_gap +
_n_gaps * iz_ind;
1706 PetscScalar value_pf = -1.0 * pressure_factor;
1710 value_pf = pressure_factor;
1730 #if !PETSC_VERSION_LESS_THAN(3, 15, 0) 1767 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
1775 LibmeshPetscCall(VecAXPY(sol_holder_W, 1.0, sol_holder_P));
1777 LibmeshPetscCall(VecGetArray(sol_holder_W, &xx));
1778 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1780 auto iz_ind = iz - first_node;
1781 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1786 LibmeshPetscCall(VecDestroy(&sol_holder_P));
1787 LibmeshPetscCall(VecDestroy(&sol_holder_W));
1795 const unsigned int last_node = (iblock + 1) *
_block_size;
1796 const unsigned int first_node = iblock *
_block_size + 1;
1797 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1800 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1803 unsigned int i_ch = chans.first;
1804 unsigned int j_ch = chans.second;
1809 auto Si_in = (*_S_flow_soln)(node_in_i);
1810 auto Sj_in = (*_S_flow_soln)(node_in_j);
1811 auto Si_out = (*_S_flow_soln)(node_out_i);
1812 auto Sj_out = (*_S_flow_soln)(node_out_j);
1814 auto Sij = dz * gap;
1816 0.5 * (((*_mdot_soln)(node_in_i) + (*
_mdot_soln)(node_in_j)) / (Si_in + Sj_in) +
1822 _WijPrime(i_gap, iz) = beta * avg_massflux * Sij;
1826 auto iz_ind = iz - first_node;
1827 PetscScalar base_value = beta * 0.5 * Sij;
1830 if (iz == first_node)
1832 PetscScalar value_tl = -1.0 * base_value / (Si_in + Sj_in) *
1834 PetscInt row = i_gap +
_n_gaps * iz_ind;
1840 PetscScalar value_tl = base_value / (Si_in + Sj_in);
1841 PetscInt row = i_gap +
_n_gaps * iz_ind;
1843 PetscInt col_ich = i_ch +
_n_channels * (iz_ind - 1);
1844 LibmeshPetscCall(MatSetValues(
1847 PetscInt col_jch = j_ch +
_n_channels * (iz_ind - 1);
1848 LibmeshPetscCall(MatSetValues(
1853 PetscScalar value_bl = base_value / (Si_out + Sj_out);
1854 PetscInt row = i_gap +
_n_gaps * iz_ind;
1857 LibmeshPetscCall(MatSetValues(
1861 LibmeshPetscCall(MatSetValues(
1876 LibmeshPetscCall(VecDuplicate(
_Wij_vec, &loc_Wij));
1877 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
1883 LibmeshPetscCall(VecDestroy(&loc_prod));
1884 LibmeshPetscCall(VecDestroy(&loc_Wij));
1892 if (!std::isfinite(beta) || beta < 0.0)
1894 ": Mixing closure returned invalid beta = ",
1900 ". Beta must be finite and non-negative.");
1909 if (!std::isfinite(beta) || beta < 0.0)
1911 ": Mixing closure returned invalid sweep-flow coefficient = ",
1917 ". sweep-flow coefficient must be finite and non-negative.");
1925 const unsigned int last_node = (iblock + 1) *
_block_size;
1926 const unsigned int first_node = iblock *
_block_size + 1;
1930 for (
unsigned int iz = first_node; iz < last_node + 1; iz++)
1932 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1934 _Wij(i_gap, iz) = solution(i);
1955 for (
unsigned int i_gap = 0; i_gap <
_n_gaps; i_gap++)
1961 return Wij_residual_vector;
1976 LibmeshPetscCall(SNESCreate(PETSC_COMM_SELF, &snes));
1977 LibmeshPetscCall(VecCreate(PETSC_COMM_SELF, &
x));
1979 LibmeshPetscCall(VecSetFromOptions(
x));
1980 LibmeshPetscCall(VecDuplicate(
x, &r));
1982 #if PETSC_VERSION_LESS_THAN(3, 13, 0) 1983 LibmeshPetscCall(PetscOptionsSetValue(PETSC_NULL,
"-snes_mf", PETSC_NULL));
1985 LibmeshPetscCall(SNESSetUseMatrixFree(snes, PETSC_FALSE, PETSC_TRUE));
1988 ctx.iblock = iblock;
1991 LibmeshPetscCall(SNESGetKSP(snes, &ksp));
1992 LibmeshPetscCall(KSPGetPC(ksp, &pc));
1993 LibmeshPetscCall(PCSetType(pc, PCNONE));
1995 LibmeshPetscCall(SNESSetFromOptions(snes));
1996 LibmeshPetscCall(VecGetArray(
x, &xx));
1999 xx[i] = solution(i);
2001 LibmeshPetscCall(VecRestoreArray(
x, &xx));
2003 LibmeshPetscCall(SNESSolve(snes, NULL,
x));
2004 LibmeshPetscCall(VecGetArray(
x, &xx));
2008 LibmeshPetscCall(VecRestoreArray(
x, &xx));
2009 LibmeshPetscCall(VecDestroy(&
x));
2010 LibmeshPetscCall(VecDestroy(&r));
2011 LibmeshPetscCall(SNESDestroy(&snes));
2017 Mat
A, Vec rhs,
unsigned int first_node,
unsigned int last_node,
const char * ksp_prefix)
2023 LibmeshPetscCall(VecDuplicate(rhs, &
x));
2028 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksp));
2029 LibmeshPetscCall(KSPSetOperators(ksp,
A,
A));
2030 LibmeshPetscCall(KSPGetPC(ksp, &pc));
2031 LibmeshPetscCall(PCSetType(pc, PCJACOBI));
2033 if (ksp_prefix && *ksp_prefix)
2034 LibmeshPetscCall(KSPSetOptionsPrefix(ksp, ksp_prefix));
2035 LibmeshPetscCall(KSPSetFromOptions(ksp));
2038 LibmeshPetscCall(KSPSolve(ksp, rhs,
x));
2041 PetscScalar * xx =
nullptr;
2042 LibmeshPetscCall(VecGetArray(
x, &xx));
2043 for (
unsigned int iz = first_node; iz <= last_node; ++iz)
2045 const unsigned int iz_ind = iz - first_node;
2046 for (
unsigned int i_ch = 0; i_ch <
_n_channels; ++i_ch)
2049 const PetscScalar h_out = xx[iz_ind *
_n_channels + i_ch];
2052 name(),
" : Calculation of negative Enthalpy h_out = ", h_out,
" Axial Level = ", iz);
2053 _h_soln->set(node_out, h_out);
2056 LibmeshPetscCall(VecRestoreArray(
x, &xx));
2059 LibmeshPetscCall(KSPDestroy(&ksp));
2060 LibmeshPetscCall(VecDestroy(&
x));
2068 mooseAssert(iz > 0,
"Trapezoidal rule requires starting at index 1 at least");
2079 auto heat_rate_in = (*_duct_heat_flux_soln)(node_in_duct);
2080 auto heat_rate_out = (*_duct_heat_flux_soln)(node_out_duct);
2082 return 0.5 * (heat_rate_in + heat_rate_out) * dz * width;
2100 auto V = [&](
const std::string & s)
2106 auto DupMatAssembled = [&](Mat src, Mat * dst)
2110 LibmeshPetscCall(MatDuplicate(src, MAT_COPY_VALUES, dst));
2111 LibmeshPetscCall(MatAssemblyBegin(*dst, MAT_FINAL_ASSEMBLY));
2112 LibmeshPetscCall(MatAssemblyEnd(*dst, MAT_FINAL_ASSEMBLY));
2118 auto DupVecCopy = [&](Vec src, Vec * dst)
2120 LibmeshPetscCall(VecDuplicate(src, dst));
2121 LibmeshPetscCall(VecCopy(src, *dst));
2124 const PetscInt Q = 3;
2127 auto Idx = [&](PetscInt r, PetscInt
c) {
return Q * r +
c; };
2130 std::vector<Mat> mat_array(Q * Q, NULL);
2131 std::vector<Vec> vec_array(Q, NULL);
2134 auto AssembleEquation = [&](PetscInt
f,
2142 DupMatAssembled(
A0, &mat_array[Idx(
f, 0)]);
2143 DupMatAssembled(
A1, &mat_array[Idx(
f, 1)]);
2144 DupMatAssembled(
A2, &mat_array[Idx(
f, 2)]);
2145 DupVecCopy(rhs, &vec_array[
f]);
2147 LibmeshPetscCall(VecAXPY(vec_array[
f], 1.0, rhs_add));
2148 V(std::string(label) +
" system assembled");
2166 auto RelaxEquation =
2167 [&](Mat A_ff, Vec rhs_f, Vec like_vec, Vec work, PetscScalar
alpha,
auto && populate)
2170 LibmeshPetscCall(VecDuplicate(like_vec, &
d));
2173 LibmeshPetscCall(MatGetDiagonal(A_ff,
d));
2174 LibmeshPetscCall(VecScale(
d, 1.0 /
alpha));
2175 LibmeshPetscCall(MatDiagonalSet(A_ff,
d, INSERT_VALUES));
2178 LibmeshPetscCall(populate(work));
2181 LibmeshPetscCall(VecScale(
d, (1.0 -
alpha)));
2182 LibmeshPetscCall(VecPointwiseMult(work, work,
d));
2183 LibmeshPetscCall(VecAXPY(rhs_f, 1.0, work));
2185 LibmeshPetscCall(VecDestroy(&
d));
2189 const unsigned int first_node = iblock *
_block_size + 1;
2190 const unsigned int last_node = (iblock + 1) *
_block_size;
2200 V(
"Starting nested system.");
2233 LibmeshPetscCall(populateVectorFromHandle<SolutionHandle>(
2244 LibmeshPetscCall(VecSet(unity_vec, 1.0));
2249 LibmeshPetscCall(VecSet(unity_vec_Wij, 1.0));
2252 Vec _Wij_old_loc_vec;
2257 LibmeshPetscCall(MatMult(mat_array[Q ],
_prod, mdot_estimate));
2260 LibmeshPetscCall(MatGetDiagonal(mat_array[Q + 1], pmat_diag));
2261 LibmeshPetscCall(VecAXPY(pmat_diag, 1e-10, unity_vec));
2262 LibmeshPetscCall(VecPointwiseDivide(p_estimate, mdot_estimate, pmat_diag));
2265 LibmeshPetscCall(MatMult(mat_array[2 * Q + 1], p_estimate, sol_holder_P));
2271 for (
unsigned int iz = first_node; iz <= last_node; ++iz)
2273 const auto iz_ind = iz - first_node;
2274 for (
unsigned int i_ch = 0; i_ch <
_n_channels; ++i_ch)
2276 PetscScalar sumWij = 0.0;
2277 unsigned int counter = 0;
2281 unsigned int i_ch_loc = chans.first;
2282 PetscInt row_vec = i_ch_loc +
_n_channels * iz_ind;
2283 PetscScalar loc_Wij_value;
2284 LibmeshPetscCall(VecGetValues(sol_holder_P, 1, &row_vec, &loc_Wij_value));
2289 LibmeshPetscCall(VecSetValues(sumWij_loc, 1, &row_vec, &sumWij, INSERT_VALUES));
2292 LibmeshPetscCall(VecAssemblyBegin(sumWij_loc));
2293 LibmeshPetscCall(VecAssemblyEnd(sumWij_loc));
2296 PetscScalar min_mdot;
2297 LibmeshPetscCall(VecAbs(
_prod));
2298 LibmeshPetscCall(VecMin(
_prod, NULL, &min_mdot));
2299 V(
"Minimum estimated mdot: " + std::to_string(min_mdot));
2301 LibmeshPetscCall(VecAbs(sumWij_loc));
2302 LibmeshPetscCall(VecMax(sumWij_loc, NULL, &
_max_sumWij));
2304 V(
"Maximum estimated Wij: " + std::to_string(
_max_sumWij));
2307 _Wij_loc_vec,
_Wij, first_node, last_node,
_n_gaps));
2308 LibmeshPetscCall(VecAbs(_Wij_loc_vec));
2311 LibmeshPetscCall(VecAbs(_Wij_old_loc_vec));
2312 LibmeshPetscCall(VecAXPY(_Wij_loc_vec, -1.0, _Wij_old_loc_vec));
2314 PetscScalar relax_factor;
2315 LibmeshPetscCall(VecAbs(_Wij_loc_vec));
2316 #if !PETSC_VERSION_LESS_THAN(3, 16, 0) 2317 LibmeshPetscCall(VecMean(_Wij_loc_vec, &relax_factor));
2319 VecSum(_Wij_loc_vec, &relax_factor);
2323 V(
"Relax base value: " + std::to_string(relax_factor));
2326 const PetscScalar resistance_relaxation = 0.9;
2328 V(
"New cross resistance: " + std::to_string(
_added_K));
2331 V(
"Relaxed cross resistance: " + std::to_string(
_added_K));
2334 if (_added_K < 10 && _added_K >= 1.0)
2336 if (_added_K < 1.0 && _added_K >= 0.1)
2338 if (_added_K < 0.1 && _added_K >= 0.01)
2340 if (_added_K < 1e-2 && _added_K >= 1e-3)
2342 V(
"Actual added cross resistance: " + std::to_string(
_added_K));
2343 LibmeshPetscCall(VecScale(unity_vec_Wij,
_added_K));
2346 LibmeshPetscCall(MatDiagonalSet(mat_array[2 * Q + 2], unity_vec_Wij, ADD_VALUES));
2349 LibmeshPetscCall(VecDestroy(&mdot_estimate));
2350 LibmeshPetscCall(VecDestroy(&pmat_diag));
2351 LibmeshPetscCall(VecDestroy(&unity_vec));
2352 LibmeshPetscCall(VecDestroy(&p_estimate));
2353 LibmeshPetscCall(VecDestroy(&sol_holder_P));
2354 LibmeshPetscCall(VecDestroy(&unity_vec_Wij));
2355 LibmeshPetscCall(VecDestroy(&sumWij_loc));
2356 LibmeshPetscCall(VecDestroy(&_Wij_loc_vec));
2357 LibmeshPetscCall(VecDestroy(&_Wij_old_loc_vec));
2360 const PetscScalar relaxation_factor_mdot = 1.0;
2361 const PetscScalar relaxation_factor_P = 1.0;
2362 const PetscScalar relaxation_factor_Wij = 0.1;
2364 V(
"Relax mdot: " + std::to_string(relaxation_factor_mdot));
2365 V(
"Relax P: " + std::to_string(relaxation_factor_P));
2366 V(
"Relax Wij: " + std::to_string(relaxation_factor_Wij));
2369 RelaxEquation(mat_array[Idx(0, 0)],
2373 relaxation_factor_mdot,
2376 return populateVectorFromHandle<SolutionHandle>(
2382 RelaxEquation(mat_array[Idx(1, 1)],
2386 relaxation_factor_P,
2389 return populateVectorFromHandle<SolutionHandle>(
2395 RelaxEquation(mat_array[Idx(2, 2)],
2399 relaxation_factor_Wij,
2402 return populateVectorFromDense<libMesh::DenseMatrix<Real>>(
2407 V(
"Linear solver relaxed");
2413 LibmeshPetscCall(MatCreateNest(PETSC_COMM_SELF, Q, NULL, Q, NULL, mat_array.data(), &A_nest));
2414 LibmeshPetscCall(VecCreateNest(PETSC_COMM_SELF, Q, NULL, vec_array.data(), &b_nest));
2415 V(
"Nested system created");
2419 LibmeshPetscCall(KSPCreate(PETSC_COMM_SELF, &ksp));
2420 LibmeshPetscCall(KSPSetType(ksp, KSPFGMRES));
2421 LibmeshPetscCall(KSPSetOperators(ksp, A_nest, A_nest));
2422 LibmeshPetscCall(KSPGetPC(ksp, &pc));
2423 LibmeshPetscCall(PCSetType(pc, PCFIELDSPLIT));
2427 std::vector<IS> rows(Q);
2428 LibmeshPetscCall(MatNestGetISs(A_nest, rows.data(), NULL));
2429 for (PetscInt
j = 0;
j < Q; ++
j)
2432 LibmeshPetscCall(ISDuplicate(rows[
j], &part));
2433 LibmeshPetscCall(PCFieldSplitSetIS(pc, NULL, part));
2434 LibmeshPetscCall(ISDestroy(&part));
2436 V(
"Linear solver assembled");
2439 LibmeshPetscCall(VecDuplicate(b_nest, &x_nest));
2440 LibmeshPetscCall(VecSet(x_nest, 0.0));
2441 LibmeshPetscCall(KSPSolve(ksp, b_nest, x_nest));
2444 LibmeshPetscCall(VecDestroy(&b_nest));
2445 LibmeshPetscCall(MatDestroy(&A_nest));
2446 LibmeshPetscCall(KSPDestroy(&ksp));
2447 for (PetscInt i = 0; i < Q * Q; i++)
2448 LibmeshPetscCall(MatDestroy(&mat_array[i]));
2449 for (PetscInt i = 0; i < Q; i++)
2450 LibmeshPetscCall(VecDestroy(&vec_array[i]));
2451 V(
"Solver elements destroyed");
2454 Vec sol_mdot, sol_p, sol_Wij;
2455 V(
"Vectors to hold solution created");
2458 LibmeshPetscCall(VecNestGetSubVecs(x_nest, &num_vecs, &loc_vecs));
2460 LibmeshPetscCall(VecCopy(loc_vecs[0], sol_mdot));
2462 LibmeshPetscCall(VecCopy(loc_vecs[1], sol_p));
2464 LibmeshPetscCall(VecCopy(loc_vecs[2], sol_Wij));
2465 V(
"Solution from coupled solver copied to solution vectors");
2468 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
2473 PetscScalar * sol_p_array;
2474 LibmeshPetscCall(VecGetArray(sol_p, &sol_p_array));
2475 for (
unsigned int iz = last_node; iz > first_node - 1; iz--)
2477 const auto iz_ind = iz - first_node;
2478 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
2485 LibmeshPetscCall(VecRestoreArray(sol_p, &sol_p_array));
2493 LibmeshPetscCall(populateSolutionChan<SolutionHandle>(
2496 LibmeshPetscCall(VecAbs(
_prod));
2501 V(
"Solutions assigned to MOOSE variables.");
2504 LibmeshPetscCall(VecDestroy(&x_nest));
2505 LibmeshPetscCall(VecDestroy(&sol_mdot));
2506 LibmeshPetscCall(VecDestroy(&sol_p));
2507 LibmeshPetscCall(VecDestroy(&sol_Wij));
2508 V(
"Solutions destroyed.");
2516 _console <<
"Executing subchannel solver\n";
2527 for (
const auto * ti :
transient->getTimeIntegrators())
2528 if (!dynamic_cast<const ImplicitEuler *>(ti))
2529 mooseWarning(
"The subchannel solver always uses implicit (backward) Euler time " 2530 "integration; the requested '",
2532 "' time integrator is ignored.");
2538 auto V = [&](
const std::string & s)
2543 V(
"Solution initialized");
2545 unsigned int P_it = 0;
2546 unsigned int P_it_max;
2556 while ((P_error >
_P_tol && P_it < P_it_max))
2561 _console <<
"Reached maximum number of axial pressure iterations" << std::endl;
2564 _console <<
"Solving Outer Iteration : " << P_it << std::endl;
2565 auto P_L2norm_old_axial =
_P_soln->L2norm();
2566 for (
unsigned int iblock = 0; iblock <
_n_blocks; iblock++)
2570 Real T_block_error = 1.0;
2572 _console <<
"Solving Block: " << iblock <<
" From first level: " << first_level
2573 <<
" to last level: " << last_level << std::endl;
2579 _console <<
"Reached maximum number of temperature iterations for block: " << iblock
2583 auto T_L2norm_old_block =
_T_soln->L2norm();
2601 V(
"Done with main solve.");
2607 V(
"Done with thermal solve.");
2610 V(
"Start updating thermophysical properties.");
2615 V(
"Done updating thermophysical properties.");
2620 _aux->solution().close();
2622 auto T_L2norm_new =
_T_soln->L2norm();
2624 std::abs((T_L2norm_new - T_L2norm_old_block) / (T_L2norm_old_block + 1E-14));
2625 _console <<
"T_block_error: " << T_block_error << std::endl;
2631 auto P_L2norm_new_axial =
_P_soln->L2norm();
2633 std::abs((P_L2norm_new_axial - P_L2norm_old_axial) / (P_L2norm_old_axial +
_P_out + 1E-14));
2634 _console <<
"P_error :" << P_error << std::endl;
2635 V(
"Iteration: " + std::to_string(P_it));
2636 V(
"Maximum iterations: " + std::to_string(P_it_max));
2640 _console <<
"Finished executing subchannel solver\n";
2643 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
2653 for (
unsigned int iz = 0; iz <
_n_cells + 1; ++iz)
2655 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
2658 auto mu = (*_mu_soln)(node);
2659 auto S = (*_S_flow_soln)(node);
2660 auto w_perim = (*_w_perim_soln)(node);
2661 auto Dh_i = 4.0 *
S / w_perim;
2662 auto Re = (((*_mdot_soln)(node) /
S) * Dh_i /
mu);
2665 auto Pr = (*_mu_soln)(node)*
cp /
k;
2685 _console <<
"Commencing calculation of Pin surface temperature \n";
2686 for (
unsigned int i_pin = 0; i_pin <
_n_pins; i_pin++)
2688 for (
unsigned int iz = 0; iz <
_n_cells + 1; ++iz)
2696 auto mu = (*_mu_soln)(node);
2697 auto S = (*_S_flow_soln)(node);
2698 auto w_perim = (*_w_perim_soln)(node);
2699 auto Dh_i = 4.0 *
S / w_perim;
2700 auto Re = (((*_mdot_soln)(node) /
S) * Dh_i /
mu);
2703 auto Pr = (*_mu_soln)(node)*
cp /
k;
2712 (*_q_prime_soln)(pin_node) / ((*
_Dpin_soln)(pin_node)*M_PI * hw) + (*_T_soln)(node);
2717 mooseError(
"Pin was not found for pin index: " + std::to_string(i_pin));
2725 _console <<
"Commencing calculation of duct surface temperature " << std::endl;
2727 for (Node * dn : duct_nodes)
2730 auto mu = (*_mu_soln)(node_chan);
2731 auto S = (*_S_flow_soln)(node_chan);
2732 auto w_perim = (*_w_perim_soln)(node_chan);
2733 auto Dh_i = 4.0 *
S / w_perim;
2734 auto Re = (((*_mdot_soln)(node_chan) /
S) * Dh_i /
mu);
2737 auto Pr = (*_mu_soln)(node_chan)*
cp /
k;
2754 auto T_chan = (*_duct_heat_flux_soln)(dn) / hw + (*
_T_soln)(node_chan);
2758 _aux->solution().close();
2763 Real power_in = 0.0;
2764 Real power_out = 0.0;
2765 Real viscosity_in = 0.0;
2766 Real mass_flow_in = 0.0;
2767 Real mass_flow_out = 0.0;
2768 for (
unsigned int i_ch = 0; i_ch <
_n_channels; i_ch++)
2772 const Real mdot_in = (*_mdot_soln)(node_in);
2773 power_in += mdot_in * (*_h_soln)(node_in);
2774 power_out += (*_mdot_soln)(node_out) * (*
_h_soln)(node_out);
2775 viscosity_in += mdot_in * (*_mu_soln)(node_in);
2776 mass_flow_in += mdot_in;
2777 mass_flow_out += (*_mdot_soln)(node_out);
2779 auto h_bulk_out = power_out / mass_flow_out;
2780 auto T_bulk_out =
_fp->T_from_p_h(
_P_out, h_bulk_out);
2783 Real inlet_mu = viscosity_in / mass_flow_in;
2787 _console <<
" ======================================= " << std::endl;
2788 _console <<
" ======== Subchannel Print Outs ======== " << std::endl;
2789 _console <<
" ======================================= " << std::endl;
2792 _console <<
"Assembly hydraulic diameter :" << bulk_Dh <<
" m" << std::endl;
2793 _console <<
"Assembly Re number :" << bulk_Re <<
" [-]" << std::endl;
2794 _console <<
"Bulk coolant temperature at outlet :" << T_bulk_out <<
" K" << std::endl;
2795 _console <<
"Power added to coolant is : " << power_out - power_in <<
" Watt" << std::endl;
2796 _console <<
"Mass flow rate in is : " << mass_flow_in <<
" kg/sec" << std::endl;
2797 _console <<
"Mass balance is : " << mass_flow_out - mass_flow_in <<
" kg/sec" << std::endl;
2798 _console <<
"User defined outlet pressure is : " <<
_P_out <<
" Pa" << std::endl;
2799 _console <<
" ======================================= " << std::endl;
2802 if (MooseUtils::absoluteFuzzyLessEqual((power_out - power_in), -1.0))
2804 "Energy conservation equation might not be solved correctly, Power added to coolant: " +
2805 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