LCOV - code coverage report
Current view: top level - src/problems - QuadSubChannel1PhaseProblem.C (source / functions) Hit Total Coverage
Test: idaholab/moose subchannel: #31405 (292dce) with base fef103 Lines: 395 415 95.2 %
Date: 2025-09-04 07:58:06 Functions: 7 7 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "QuadSubChannel1PhaseProblem.h"
      11             : #include "AuxiliarySystem.h"
      12             : #include "SCM.h"
      13             : 
      14             : registerMooseObject("SubChannelApp", QuadSubChannel1PhaseProblem);
      15             : 
      16             : InputParameters
      17         284 : QuadSubChannel1PhaseProblem::validParams()
      18             : {
      19         284 :   InputParameters params = SubChannel1PhaseProblem::validParams();
      20         284 :   params.addClassDescription(
      21             :       "Solver class for subchannels in a square lattice assembly and bare fuel pins");
      22         568 :   params.addRequiredParam<Real>("beta",
      23             :                                 "Thermal diffusion coefficient used in turbulent crossflow.");
      24         568 :   params.addParam<bool>(
      25             :       "default_friction_model",
      26         568 :       true,
      27             :       "Boolean to define which friction model to use (default: Pang, B. et al. "
      28             :       "KIT, 2013. / non-default: Todreas-Kazimi NUCLEAR SYSTEMS, second edition, Volume 1, 2011)");
      29         568 :   params.addParam<bool>(
      30             :       "constant_beta",
      31         568 :       true,
      32             :       "Boolean to define the use of a constant beta or beta correlation (Kim and Chung, 2001)");
      33         284 :   return params;
      34           0 : }
      35             : 
      36         142 : QuadSubChannel1PhaseProblem::QuadSubChannel1PhaseProblem(const InputParameters & params)
      37             :   : SubChannel1PhaseProblem(params),
      38         284 :     _subchannel_mesh(SCM::getMesh<QuadSubChannelMesh>(_mesh)),
      39         284 :     _beta(getParam<Real>("beta")),
      40         284 :     _default_friction_model(getParam<bool>("default_friction_model")),
      41         426 :     _constant_beta(getParam<bool>("constant_beta"))
      42             : {
      43         142 : }
      44             : 
      45             : void
      46         190 : QuadSubChannel1PhaseProblem::initializeSolution()
      47             : {
      48             :   /// update surface area, wetted perimeter based on: Dpin, displacement
      49         190 :   if (_deformation)
      50             :   {
      51             :     Real standard_area, additional_area, wetted_perimeter, displaced_area;
      52           6 :     auto pitch = _subchannel_mesh.getPitch();
      53           6 :     auto side_gap = _subchannel_mesh.getSideGap();
      54           6 :     auto z_blockage = _subchannel_mesh.getZBlockage();
      55           6 :     auto index_blockage = _subchannel_mesh.getIndexBlockage();
      56           6 :     auto reduction_blockage = _subchannel_mesh.getReductionBlockage();
      57         132 :     for (unsigned int iz = 0; iz < _n_cells + 1; iz++)
      58             :     {
      59        4662 :       for (unsigned int i_ch = 0; i_ch < _n_channels; i_ch++)
      60             :       {
      61        4536 :         auto * node = _subchannel_mesh.getChannelNode(i_ch, iz);
      62        4536 :         auto subch_type = _subchannel_mesh.getSubchannelType(i_ch);
      63        4536 :         auto Z = _z_grid[iz];
      64             :         Real rod_area = 0.0;
      65             :         Real rod_perimeter = 0.0;
      66       17136 :         for (auto i_pin : _subchannel_mesh.getChannelPins(i_ch))
      67             :         {
      68       12600 :           auto * pin_node = _subchannel_mesh.getPinNode(i_pin, iz);
      69       12600 :           rod_area += 0.25 * 0.25 * M_PI * (*_Dpin_soln)(pin_node) * (*_Dpin_soln)(pin_node);
      70       12600 :           rod_perimeter += 0.25 * M_PI * (*_Dpin_soln)(pin_node);
      71             :         }
      72             : 
      73        4536 :         if (subch_type == EChannelType::CORNER)
      74             :         {
      75         504 :           standard_area = 0.25 * pitch * pitch;
      76         504 :           displaced_area = (2 * side_gap + pitch) * (*_displacement_soln)(node) / sqrt(2) +
      77         504 :                            (*_displacement_soln)(node) * (*_displacement_soln)(node) / 2;
      78         504 :           additional_area = pitch * side_gap + side_gap * side_gap;
      79         504 :           wetted_perimeter =
      80         504 :               rod_perimeter + pitch + 2 * side_gap + 2 * (*_displacement_soln)(node) / sqrt(2);
      81             :         }
      82        4032 :         else if (subch_type == EChannelType::EDGE)
      83             :         {
      84        2016 :           standard_area = 0.5 * pitch * pitch;
      85        2016 :           additional_area = pitch * side_gap;
      86        2016 :           displaced_area = pitch * (*_displacement_soln)(node);
      87        2016 :           wetted_perimeter = rod_perimeter + pitch;
      88             :         }
      89             :         else
      90             :         {
      91        2016 :           standard_area = pitch * pitch;
      92             :           displaced_area = 0.0;
      93             :           additional_area = 0.0;
      94             :           wetted_perimeter = rod_perimeter;
      95             :         }
      96             : 
      97             :         /// Calculate subchannel area
      98        4536 :         auto subchannel_area = displaced_area + standard_area + additional_area - rod_area;
      99             : 
     100             :         /// Correct subchannel area and wetted perimeter in case of overlapping pins
     101             :         auto overlapping_pin_area = 0.0;
     102             :         auto overlapping_wetted_perimeter = 0.0;
     103       19656 :         for (auto i_gap : _subchannel_mesh.getChannelGaps(i_ch))
     104             :         {
     105       15120 :           auto gap_pins = _subchannel_mesh.getGapPins(i_gap);
     106             :           auto pin_1 = gap_pins.first;
     107             :           auto pin_2 = gap_pins.second;
     108       15120 :           auto * pin_node_1 = _subchannel_mesh.getPinNode(pin_1, iz);
     109       15120 :           auto * pin_node_2 = _subchannel_mesh.getPinNode(pin_2, iz);
     110       15120 :           auto Diameter1 = (*_Dpin_soln)(pin_node_1);
     111       15120 :           auto Radius1 = Diameter1 / 2.0;
     112       15120 :           auto Diameter2 = (*_Dpin_soln)(pin_node_2);
     113       15120 :           auto Radius2 = Diameter2 / 2.0;
     114       15120 :           auto pitch = _subchannel_mesh.getPitch();
     115             : 
     116       15120 :           if (pitch < (Radius1 + Radius2)) // overlapping pins
     117             :           {
     118           0 :             mooseWarning(" The gap of index : '", i_gap, " at axial cell ", iz, " ' is blocked.");
     119           0 :             auto cos1 =
     120           0 :                 (pitch * pitch + Radius1 * Radius1 - Radius2 * Radius2) / (2 * pitch * Radius1);
     121           0 :             auto cos2 =
     122           0 :                 (pitch * pitch + Radius2 * Radius2 - Radius1 * Radius1) / (2 * pitch * Radius2);
     123           0 :             auto angle1 = 2.0 * acos(cos1);
     124           0 :             auto angle2 = 2.0 * acos(cos2);
     125             :             // half of the intersecting arc-length
     126           0 :             overlapping_wetted_perimeter += 0.5 * angle1 * Radius1 + 0.5 * angle2 * Radius2;
     127             :             // Half of the overlapping area
     128           0 :             overlapping_pin_area +=
     129           0 :                 0.5 * Radius1 * Radius1 * acos(cos1) + 0.5 * Radius2 * Radius2 * acos(cos2) -
     130           0 :                 0.25 * sqrt((-pitch + Radius1 + Radius2) * (pitch + Radius1 - Radius2) *
     131           0 :                             (pitch - Radius1 + Radius2) * (pitch + Radius1 + Radius2));
     132             :           }
     133             :         }
     134        4536 :         subchannel_area += overlapping_pin_area;           // correct surface area
     135        4536 :         wetted_perimeter += -overlapping_wetted_perimeter; // correct wetted perimeter
     136             : 
     137             :         /// Apply area reduction on subchannels affected by blockage
     138             :         auto index = 0;
     139        9072 :         for (const auto & i_blockage : index_blockage)
     140             :         {
     141        4536 :           if (i_ch == i_blockage && (Z >= z_blockage.front() && Z <= z_blockage.back()))
     142             :           {
     143           6 :             subchannel_area *= reduction_blockage[index];
     144             :           }
     145        4536 :           index++;
     146             :         }
     147             : 
     148        4536 :         _S_flow_soln->set(node, subchannel_area);
     149        4536 :         _w_perim_soln->set(node, wetted_perimeter);
     150             :       }
     151             :     }
     152             :     /// update map of gap between pins (gij) based on: Dpin, displacement
     153         132 :     for (unsigned int iz = 0; iz < _n_cells + 1; iz++)
     154             :     {
     155        7686 :       for (unsigned int i_gap = 0; i_gap < _n_gaps; i_gap++)
     156             :       {
     157        7560 :         auto gap_pins = _subchannel_mesh.getGapPins(i_gap);
     158             :         auto pin_1 = gap_pins.first;
     159             :         auto pin_2 = gap_pins.second;
     160        7560 :         auto * pin_node_1 = _subchannel_mesh.getPinNode(pin_1, iz);
     161        7560 :         auto * pin_node_2 = _subchannel_mesh.getPinNode(pin_2, iz);
     162        7560 :         if (pin_1 == pin_2) // Corner or edge gap
     163             :         {
     164             :           auto displacement = 0.0;
     165             :           auto counter = 0.0;
     166       12600 :           for (auto i_ch : _subchannel_mesh.getPinChannels(pin_1))
     167             :           {
     168       10080 :             auto subch_type = _subchannel_mesh.getSubchannelType(i_ch);
     169       10080 :             auto * node = _subchannel_mesh.getChannelNode(i_ch, iz);
     170       10080 :             if (subch_type == EChannelType::EDGE || subch_type == EChannelType::CORNER)
     171             :             {
     172        6048 :               displacement += (*_displacement_soln)(node);
     173        6048 :               counter += 1.0;
     174             :             }
     175             :           }
     176        2520 :           displacement = displacement / counter;
     177        2520 :           _subchannel_mesh._gij_map[iz][i_gap] =
     178        2520 :               (pitch - (*_Dpin_soln)(pin_node_1)) / 2.0 + side_gap + displacement;
     179             :         }
     180             :         else // center gap
     181             :         {
     182        5040 :           _subchannel_mesh._gij_map[iz][i_gap] =
     183        5040 :               pitch - (*_Dpin_soln)(pin_node_1) / 2.0 - (*_Dpin_soln)(pin_node_2) / 2.0;
     184             :         }
     185             :         // if pins come in contact, the gap is zero
     186        7560 :         if (_subchannel_mesh._gij_map[iz][i_gap] <= 0.0)
     187           0 :           _subchannel_mesh._gij_map[iz][i_gap] = 0.0;
     188             :       }
     189             :     }
     190           6 :   }
     191             : 
     192        7180 :   for (unsigned int iz = 1; iz < _n_cells + 1; iz++)
     193             :   {
     194      118856 :     for (unsigned int i_ch = 0; i_ch < _n_channels; i_ch++)
     195             :     {
     196      111866 :       auto * node_out = _subchannel_mesh.getChannelNode(i_ch, iz);
     197      111866 :       auto * node_in = _subchannel_mesh.getChannelNode(i_ch, iz - 1);
     198      111866 :       _mdot_soln->set(node_out, (*_mdot_soln)(node_in));
     199             :     }
     200             :   }
     201             : 
     202             :   // We must do a global assembly to make sure data is parallel consistent before we do things
     203             :   // like compute L2 norms
     204         190 :   _aux->solution().close();
     205         190 : }
     206             : 
     207             : Real
     208    13201524 : QuadSubChannel1PhaseProblem::computeFrictionFactor(FrictionStruct friction_args)
     209             : {
     210    13201524 :   auto Re = friction_args.Re;
     211    13201524 :   auto i_ch = friction_args.i_ch;
     212             :   /// Pang, B. et al. KIT, 2013
     213    13201524 :   if (_default_friction_model)
     214             :   {
     215             :     Real a, b;
     216    10780404 :     if (Re < 1)
     217             :     {
     218             :       return 64.0;
     219             :     }
     220    10780404 :     else if (Re >= 1 and Re < 5000)
     221             :     {
     222             :       a = 64.0;
     223             :       b = -1.0;
     224             :     }
     225     8072964 :     else if (Re >= 5000 and Re < 30000)
     226             :     {
     227             :       a = 0.316;
     228             :       b = -0.25;
     229             :     }
     230             :     else
     231             :     {
     232             :       a = 0.184;
     233             :       b = -0.20;
     234             :     }
     235    10780404 :     return a * std::pow(Re, b);
     236             :   }
     237             :   /// Todreas-Kazimi NUCLEAR SYSTEMS, second edition, Volume 1, 2011
     238             :   else
     239             :   {
     240             :     Real aL, b1L, b2L, cL;
     241             :     Real aT, b1T, b2T, cT;
     242     2421120 :     auto pitch = _subchannel_mesh.getPitch();
     243     2421120 :     auto pin_diameter = _subchannel_mesh.getPinDiameter();
     244             :     // This gap is a constant value for the whole assembly. Might want to make it
     245             :     // subchannel specific in the future if we have duct deformation.
     246     2421120 :     auto side_gap = _subchannel_mesh.getSideGap();
     247     2421120 :     auto w = (pin_diameter / 2.0) + (pitch / 2.0) + side_gap;
     248     2421120 :     auto p_over_d = pitch / pin_diameter;
     249     2421120 :     auto w_over_d = w / pin_diameter;
     250     2421120 :     auto ReL = std::pow(10, (p_over_d - 1)) * 320.0;
     251     2421120 :     auto ReT = std::pow(10, 0.7 * (p_over_d - 1)) * 1.0E+4;
     252     2421120 :     auto psi = std::log(Re / ReL) / std::log(ReT / ReL);
     253     2421120 :     auto subch_type = _subchannel_mesh.getSubchannelType(i_ch);
     254             :     const Real lambda = 7.0;
     255             : 
     256             :     // Find the coefficients of bare Pin bundle friction factor
     257             :     // correlations for turbulent and laminar flow regimes. Todreas & Kazimi, Nuclear Systems Volume
     258             :     // 1
     259     2421120 :     if (subch_type == EChannelType::CENTER)
     260             :     {
     261     1116720 :       if (p_over_d < 1.1)
     262             :       {
     263             :         aL = 26.37;
     264             :         b1L = 374.2;
     265             :         b2L = -493.9;
     266             :         aT = 0.09423;
     267             :         b1T = 0.5806;
     268             :         b2T = -1.239;
     269             :       }
     270             :       else
     271             :       {
     272             :         aL = 35.55;
     273             :         b1L = 263.7;
     274             :         b2L = -190.2;
     275             :         aT = 0.1339;
     276             :         b1T = 0.09059;
     277             :         b2T = -0.09926;
     278             :       }
     279             :       // laminar flow friction factor for bare Pin bundle - Center subchannel
     280     1116720 :       cL = aL + b1L * (p_over_d - 1) + b2L * std::pow((p_over_d - 1), 2);
     281             :       // turbulent flow friction factor for bare Pin bundle - Center subchannel
     282     1116720 :       cT = aT + b1T * (p_over_d - 1) + b2T * std::pow((p_over_d - 1), 2);
     283             :     }
     284     1304400 :     else if (subch_type == EChannelType::EDGE)
     285             :     {
     286     1043520 :       if (p_over_d < 1.1)
     287             :       {
     288             :         aL = 26.18;
     289             :         b1L = 554.5;
     290             :         b2L = -1480;
     291             :         aT = 0.09377;
     292             :         b1T = 0.8732;
     293             :         b2T = -3.341;
     294             :       }
     295             :       else
     296             :       {
     297             :         aL = 44.40;
     298             :         b1L = 256.7;
     299             :         b2L = -267.6;
     300             :         aT = 0.1430;
     301             :         b1T = 0.04199;
     302             :         b2T = -0.04428;
     303             :       }
     304             :       // laminar flow friction factor for bare Pin bundle - Edge subchannel
     305     1043520 :       cL = aL + b1L * (w_over_d - 1) + b2L * std::pow((w_over_d - 1), 2);
     306             :       // turbulent flow friction factor for bare Pin bundle - Edge subchannel
     307     1043520 :       cT = aT + b1T * (w_over_d - 1) + b2T * std::pow((w_over_d - 1), 2);
     308             :     }
     309             :     else
     310             :     {
     311      260880 :       if (p_over_d < 1.1)
     312             :       {
     313             :         aL = 28.62;
     314             :         b1L = 715.9;
     315             :         b2L = -2807;
     316             :         aT = 0.09755;
     317             :         b1T = 1.127;
     318             :         b2T = -6.304;
     319             :       }
     320             :       else
     321             :       {
     322             :         aL = 58.83;
     323             :         b1L = 160.7;
     324             :         b2L = -203.5;
     325             :         aT = 0.1452;
     326             :         b1T = 0.02681;
     327             :         b2T = -0.03411;
     328             :       }
     329             :       // laminar flow friction factor for bare Pin bundle - Corner subchannel
     330      260880 :       cL = aL + b1L * (w_over_d - 1) + b2L * std::pow((w_over_d - 1), 2);
     331             :       // turbulent flow friction factor for bare Pin bundle - Corner subchannel
     332      260880 :       cT = aT + b1T * (w_over_d - 1) + b2T * std::pow((w_over_d - 1), 2);
     333             :     }
     334             : 
     335             :     // laminar friction factor
     336     2421120 :     auto fL = cL / Re;
     337             :     // turbulent friction factor
     338     2421120 :     auto fT = cT / std::pow(Re, 0.18);
     339             : 
     340     2421120 :     if (Re < ReL)
     341             :     {
     342             :       // laminar flow
     343             :       return fL;
     344             :     }
     345     2421120 :     else if (Re > ReT)
     346             :     {
     347             :       // turbulent flow
     348             :       return fT;
     349             :     }
     350             :     else
     351             :     {
     352             :       // transient flow: psi definition uses a Bulk ReT/ReL number, same for all channels
     353           0 :       return fL * std::pow((1 - psi), 1.0 / 3.0) * (1 - std::pow(psi, lambda)) +
     354           0 :              fT * std::pow(psi, 1.0 / 3.0);
     355             :     }
     356             :   }
     357             : }
     358             : 
     359             : Real
     360    21571344 : QuadSubChannel1PhaseProblem::computeBeta(unsigned int i_gap, unsigned int iz, bool /*enthalpy*/)
     361             : {
     362    21571344 :   auto beta = _beta;
     363    21571344 :   if (!_constant_beta)
     364             :   {
     365     3913200 :     const Real & pitch = _subchannel_mesh.getPitch();
     366     3913200 :     const Real & pin_diameter = _subchannel_mesh.getPinDiameter();
     367     3913200 :     auto chans = _subchannel_mesh.getGapChannels(i_gap);
     368             :     unsigned int i_ch = chans.first;
     369             :     unsigned int j_ch = chans.second;
     370     3913200 :     auto * node_in_i = _subchannel_mesh.getChannelNode(i_ch, iz - 1);
     371     3913200 :     auto * node_out_i = _subchannel_mesh.getChannelNode(i_ch, iz);
     372     3913200 :     auto * node_in_j = _subchannel_mesh.getChannelNode(j_ch, iz - 1);
     373     3913200 :     auto * node_out_j = _subchannel_mesh.getChannelNode(j_ch, iz);
     374     3913200 :     auto Si_in = (*_S_flow_soln)(node_in_i);
     375     3913200 :     auto Sj_in = (*_S_flow_soln)(node_in_j);
     376     3913200 :     auto Si_out = (*_S_flow_soln)(node_out_i);
     377     3913200 :     auto Sj_out = (*_S_flow_soln)(node_out_j);
     378             :     // crossflow area between channels i,j (dz*gap_width)
     379     3913200 :     auto gap = _subchannel_mesh.getGapWidth(iz, i_gap);
     380             :     auto avg_massflux =
     381     3913200 :         0.5 * (((*_mdot_soln)(node_in_i) + (*_mdot_soln)(node_in_j)) / (Si_in + Sj_in) +
     382     3913200 :                ((*_mdot_soln)(node_out_i) + (*_mdot_soln)(node_out_j)) / (Si_out + Sj_out));
     383     3913200 :     auto S_total = Si_in + Sj_in + Si_out + Sj_out;
     384     3913200 :     auto Si = 0.5 * (Si_in + Si_out);
     385     3913200 :     auto Sj = 0.5 * (Sj_in + Sj_out);
     386     3913200 :     auto w_perim_i = 0.5 * ((*_w_perim_soln)(node_in_i) + (*_w_perim_soln)(node_out_i));
     387     3913200 :     auto w_perim_j = 0.5 * ((*_w_perim_soln)(node_in_j) + (*_w_perim_soln)(node_out_j));
     388     3913200 :     auto avg_mu = (1 / S_total) * ((*_mu_soln)(node_out_i)*Si_out + (*_mu_soln)(node_in_i)*Si_in +
     389     3913200 :                                    (*_mu_soln)(node_out_j)*Sj_out + (*_mu_soln)(node_in_j)*Sj_in);
     390     3913200 :     auto avg_hD = 4.0 * (Si + Sj) / (w_perim_i + w_perim_j);
     391     3913200 :     auto Re = avg_massflux * avg_hD / avg_mu;
     392             :     Real gamma = 20.0; // empirical constant
     393             :     Real sf = 1.0;     // shape factor
     394             :     Real a = 0.18;
     395             :     Real b = 0.2;
     396     3913200 :     auto f = a * std::pow(Re, -b); // Rehme 1992 circular tube friction factor
     397             :     auto k = (1 / S_total) *
     398     3913200 :              (_fp->k_from_p_T((*_P_soln)(node_out_i) + _P_out, (*_T_soln)(node_out_i)) * Si_out +
     399     3913200 :               _fp->k_from_p_T((*_P_soln)(node_in_i) + _P_out, (*_T_soln)(node_in_i)) * Si_in +
     400     3913200 :               _fp->k_from_p_T((*_P_soln)(node_out_j) + _P_out, (*_T_soln)(node_out_j)) * Sj_out +
     401     3913200 :               _fp->k_from_p_T((*_P_soln)(node_in_j) + _P_out, (*_T_soln)(node_in_j)) * Sj_in);
     402             :     auto cp = (1 / S_total) *
     403     3913200 :               (_fp->cp_from_p_T((*_P_soln)(node_out_i) + _P_out, (*_T_soln)(node_out_i)) * Si_out +
     404     3913200 :                _fp->cp_from_p_T((*_P_soln)(node_in_i) + _P_out, (*_T_soln)(node_in_i)) * Si_in +
     405     3913200 :                _fp->cp_from_p_T((*_P_soln)(node_out_j) + _P_out, (*_T_soln)(node_out_j)) * Sj_out +
     406     3913200 :                _fp->cp_from_p_T((*_P_soln)(node_in_j) + _P_out, (*_T_soln)(node_in_j)) * Sj_in);
     407     3913200 :     auto Pr = avg_mu * cp / k;                          // Prandtl number
     408     3913200 :     auto Pr_t = Pr * (Re / gamma) * std::sqrt(f / 8.0); // Turbulent Prandtl number
     409     3913200 :     auto delta = pitch;                                 // centroid to centroid distance
     410             :     auto L_x = sf * delta;  // axial length scale (gap is the lateral length scale)
     411     3913200 :     auto lamda = gap / L_x; // aspect ratio
     412     3913200 :     auto a_x = 1.0 - 2.0 * lamda * lamda / libMesh::pi; // velocity coefficient
     413     3913200 :     auto z_FP_over_D = (2.0 * L_x / pin_diameter) *
     414     3913200 :                        (1 + (-0.5 * std::log(lamda) + 0.5 * std::log(4.0) - 0.25) * lamda * lamda);
     415     3913200 :     auto Str = 1.0 / (0.822 * (gap / pin_diameter) + 0.144); // Strouhal number (Wu & Trupp 1994)
     416     3913200 :     auto freq_factor = 2.0 / std::pow(gamma, 2) * std::sqrt(a / 8.0) * (avg_hD / gap);
     417     3913200 :     auto rod_mixing = (1 / Pr_t) * lamda;
     418     3913200 :     auto axial_mixing = a_x * z_FP_over_D * Str;
     419             :     // Mixing Stanton number: Stg (eq 25,Kim and Chung (2001), eq 19 (Jeong et. al 2005)
     420     3913200 :     beta = freq_factor * (rod_mixing + axial_mixing) * std::pow(Re, -b / 2.0);
     421             :   }
     422             :   mooseAssert(beta > 0, "beta should be positive");
     423    21571344 :   return beta;
     424             : }
     425             : 
     426             : Real
     427      328272 : QuadSubChannel1PhaseProblem::computeAddedHeatPin(unsigned int i_ch, unsigned int iz)
     428             : {
     429             :   // Compute axial location of nodes.
     430      328272 :   auto z2 = _z_grid[iz];
     431      328272 :   auto z1 = _z_grid[iz - 1];
     432      328272 :   auto heated_length = _subchannel_mesh.getHeatedLength();
     433      328272 :   auto unheated_length_entry = _subchannel_mesh.getHeatedLengthEntry();
     434      328272 :   if (MooseUtils::absoluteFuzzyGreaterThan(z2, unheated_length_entry) &&
     435      324006 :       MooseUtils::absoluteFuzzyLessThan(z1, unheated_length_entry + heated_length))
     436             :   {
     437             :     // Compute the height of this element.
     438      319740 :     auto dz = z2 - z1;
     439      319740 :     if (_pin_mesh_exist)
     440             :     {
     441             :       auto heat_rate_in = 0.0;
     442             :       auto heat_rate_out = 0.0;
     443     1044720 :       for (auto i_pin : _subchannel_mesh.getChannelPins(i_ch))
     444             :       {
     445      743520 :         auto * node_in = _subchannel_mesh.getPinNode(i_pin, iz - 1);
     446      743520 :         auto * node_out = _subchannel_mesh.getPinNode(i_pin, iz);
     447      743520 :         heat_rate_out += 0.25 * (*_q_prime_soln)(node_out);
     448      743520 :         heat_rate_in += 0.25 * (*_q_prime_soln)(node_in);
     449             :       }
     450      301200 :       return (heat_rate_in + heat_rate_out) * dz / 2.0;
     451             :     }
     452             :     else
     453             :     {
     454       18540 :       auto * node_in = _subchannel_mesh.getChannelNode(i_ch, iz - 1);
     455       18540 :       auto * node_out = _subchannel_mesh.getChannelNode(i_ch, iz);
     456       18540 :       return ((*_q_prime_soln)(node_out) + (*_q_prime_soln)(node_in)) * dz / 2.0;
     457             :     }
     458             :   }
     459             :   else
     460             :     return 0.0;
     461             : }
     462             : 
     463             : void
     464         668 : QuadSubChannel1PhaseProblem::computeh(int iblock)
     465             : {
     466         668 :   unsigned int last_node = (iblock + 1) * _block_size;
     467         668 :   unsigned int first_node = iblock * _block_size + 1;
     468         668 :   if (iblock == 0)
     469             :   {
     470       15794 :     for (unsigned int i_ch = 0; i_ch < _n_channels; i_ch++)
     471             :     {
     472       15126 :       auto * node = _subchannel_mesh.getChannelNode(i_ch, 0);
     473       15126 :       auto h_out = _fp->h_from_p_T((*_P_soln)(node) + _P_out, (*_T_soln)(node));
     474       15126 :       if (h_out < 0)
     475             :       {
     476           0 :         mooseError(
     477           0 :             name(), " : Calculation of negative Enthalpy h_out = : ", h_out, " Axial Level= : ", 0);
     478             :       }
     479       15126 :       _h_soln->set(node, h_out);
     480             :     }
     481             :   }
     482             : 
     483         668 :   if (!_implicit_bool)
     484             :   {
     485        7174 :     for (unsigned int iz = first_node; iz < last_node + 1; iz++)
     486             :     {
     487        6980 :       auto dz = _z_grid[iz] - _z_grid[iz - 1];
     488       45380 :       for (unsigned int i_ch = 0; i_ch < _n_channels; i_ch++)
     489             :       {
     490       38400 :         auto * node_in = _subchannel_mesh.getChannelNode(i_ch, iz - 1);
     491       38400 :         auto * node_out = _subchannel_mesh.getChannelNode(i_ch, iz);
     492       38400 :         auto mdot_in = (*_mdot_soln)(node_in);
     493       38400 :         auto h_in = (*_h_soln)(node_in); // J/kg
     494       38400 :         auto volume = dz * (*_S_flow_soln)(node_in);
     495       38400 :         auto mdot_out = (*_mdot_soln)(node_out);
     496       38400 :         auto h_out = 0.0;
     497             :         Real sumWijh = 0.0;
     498             :         Real sumWijPrimeDhij = 0.0;
     499       38400 :         Real added_enthalpy = computeAddedHeatPin(i_ch, iz);
     500             :         // Calculate sum of crossflow into channel i from channels j around i
     501             :         unsigned int counter = 0;
     502      135120 :         for (auto i_gap : _subchannel_mesh.getChannelGaps(i_ch))
     503             :         {
     504       96720 :           auto chans = _subchannel_mesh.getGapChannels(i_gap);
     505             :           unsigned int ii_ch = chans.first;
     506             :           // i is always the smallest and first index in the mapping
     507             :           unsigned int jj_ch = chans.second;
     508       96720 :           auto * node_in_i = _subchannel_mesh.getChannelNode(ii_ch, iz - 1);
     509       96720 :           auto * node_in_j = _subchannel_mesh.getChannelNode(jj_ch, iz - 1);
     510             :           // Define donor enthalpy
     511             :           Real h_star = 0.0;
     512       96720 :           if (_Wij(i_gap, iz) > 0.0)
     513       42408 :             h_star = (*_h_soln)(node_in_i);
     514       54312 :           else if (_Wij(i_gap, iz) < 0.0)
     515       35352 :             h_star = (*_h_soln)(node_in_j);
     516             :           // take care of the sign by applying the map, use donor cell
     517       96720 :           sumWijh += _subchannel_mesh.getCrossflowSign(i_ch, counter) * _Wij(i_gap, iz) * h_star;
     518       96720 :           sumWijPrimeDhij += _WijPrime(i_gap, iz) * (2 * (*_h_soln)(node_in) -
     519       96720 :                                                      (*_h_soln)(node_in_j) - (*_h_soln)(node_in_i));
     520       96720 :           counter++;
     521             :         }
     522      115200 :         h_out = (mdot_in * h_in - sumWijh - sumWijPrimeDhij + added_enthalpy +
     523       38400 :                  _TR * _rho_soln->old(node_out) * _h_soln->old(node_out) * volume / _dt) /
     524       38400 :                 (mdot_out + _TR * (*_rho_soln)(node_out)*volume / _dt);
     525       38400 :         if (h_out < 0)
     526             :         {
     527           0 :           mooseError(name(),
     528             :                      " : Calculation of negative Enthalpy h_out = : ",
     529             :                      h_out,
     530             :                      " Axial Level= : ",
     531             :                      iz);
     532             :         }
     533       38400 :         _h_soln->set(node_out, h_out); // J/kg
     534             :       }
     535             :     }
     536             :   }
     537             :   else
     538             :   {
     539         474 :     LibmeshPetscCall(MatZeroEntries(_hc_time_derivative_mat));
     540         474 :     LibmeshPetscCall(MatZeroEntries(_hc_advective_derivative_mat));
     541         474 :     LibmeshPetscCall(MatZeroEntries(_hc_cross_derivative_mat));
     542         474 :     LibmeshPetscCall(VecZeroEntries(_hc_time_derivative_rhs));
     543         474 :     LibmeshPetscCall(VecZeroEntries(_hc_advective_derivative_rhs));
     544         474 :     LibmeshPetscCall(VecZeroEntries(_hc_cross_derivative_rhs));
     545         474 :     LibmeshPetscCall(VecZeroEntries(_hc_added_heat_rhs));
     546         474 :     LibmeshPetscCall(MatZeroEntries(_hc_sys_h_mat));
     547         474 :     LibmeshPetscCall(VecZeroEntries(_hc_sys_h_rhs));
     548       12750 :     for (unsigned int iz = first_node; iz < last_node + 1; iz++)
     549             :     {
     550       12276 :       auto dz = _z_grid[iz] - _z_grid[iz - 1];
     551       12276 :       auto iz_ind = iz - first_node;
     552      299340 :       for (unsigned int i_ch = 0; i_ch < _n_channels; i_ch++)
     553             :       {
     554      287064 :         auto * node_in = _subchannel_mesh.getChannelNode(i_ch, iz - 1);
     555      287064 :         auto * node_out = _subchannel_mesh.getChannelNode(i_ch, iz);
     556      287064 :         auto S_in = (*_S_flow_soln)(node_in);
     557      287064 :         auto S_out = (*_S_flow_soln)(node_out);
     558      287064 :         auto S_interp = computeInterpolatedValue(S_out, S_in, 0.5);
     559      287064 :         auto volume = dz * S_interp;
     560             : 
     561             :         // interpolation weight coefficient
     562      287064 :         auto alpha = computeInterpolationCoefficients(0.5);
     563             : 
     564             :         /// Time derivative term
     565      287064 :         if (iz == first_node)
     566             :         {
     567             :           PetscScalar value_vec_tt =
     568       12420 :               -1.0 * _TR * alpha * (*_rho_soln)(node_in) * (*_h_soln)(node_in)*volume / _dt;
     569       12420 :           PetscInt row_vec_tt = i_ch + _n_channels * iz_ind;
     570       12420 :           LibmeshPetscCall(
     571             :               VecSetValues(_hc_time_derivative_rhs, 1, &row_vec_tt, &value_vec_tt, ADD_VALUES));
     572             :         }
     573             :         else
     574             :         {
     575      274644 :           PetscInt row_tt = i_ch + _n_channels * iz_ind;
     576      274644 :           PetscInt col_tt = i_ch + _n_channels * (iz_ind - 1);
     577      274644 :           PetscScalar value_tt = _TR * alpha * (*_rho_soln)(node_in)*volume / _dt;
     578      274644 :           LibmeshPetscCall(MatSetValues(
     579             :               _hc_time_derivative_mat, 1, &row_tt, 1, &col_tt, &value_tt, INSERT_VALUES));
     580             :         }
     581             : 
     582             :         // Adding diagonal elements
     583      287064 :         PetscInt row_tt = i_ch + _n_channels * iz_ind;
     584      287064 :         PetscInt col_tt = i_ch + _n_channels * iz_ind;
     585      287064 :         PetscScalar value_tt = _TR * (1.0 - alpha) * (*_rho_soln)(node_out)*volume / _dt;
     586      287064 :         LibmeshPetscCall(MatSetValues(
     587             :             _hc_time_derivative_mat, 1, &row_tt, 1, &col_tt, &value_tt, INSERT_VALUES));
     588             : 
     589             :         // Adding RHS elements
     590             :         PetscScalar rho_old_interp =
     591      287064 :             computeInterpolatedValue(_rho_soln->old(node_out), _rho_soln->old(node_in), 0.5);
     592             :         PetscScalar h_old_interp =
     593      287064 :             computeInterpolatedValue(_h_soln->old(node_out), _h_soln->old(node_in), 0.5);
     594      287064 :         PetscScalar value_vec_tt = _TR * rho_old_interp * h_old_interp * volume / _dt;
     595      287064 :         PetscInt row_vec_tt = i_ch + _n_channels * iz_ind;
     596      287064 :         LibmeshPetscCall(
     597             :             VecSetValues(_hc_time_derivative_rhs, 1, &row_vec_tt, &value_vec_tt, ADD_VALUES));
     598             : 
     599             :         /// Advective derivative term
     600      287064 :         if (iz == first_node)
     601             :         {
     602       12420 :           PetscScalar value_vec_at = (*_mdot_soln)(node_in) * (*_h_soln)(node_in);
     603       12420 :           PetscInt row_vec_at = i_ch + _n_channels * iz_ind;
     604       12420 :           LibmeshPetscCall(VecSetValues(
     605             :               _hc_advective_derivative_rhs, 1, &row_vec_at, &value_vec_at, ADD_VALUES));
     606             :         }
     607             :         else
     608             :         {
     609      274644 :           PetscInt row_at = i_ch + _n_channels * iz_ind;
     610      274644 :           PetscInt col_at = i_ch + _n_channels * (iz_ind - 1);
     611      274644 :           PetscScalar value_at = -1.0 * (*_mdot_soln)(node_in);
     612      274644 :           LibmeshPetscCall(MatSetValues(
     613             :               _hc_advective_derivative_mat, 1, &row_at, 1, &col_at, &value_at, INSERT_VALUES));
     614             :         }
     615             : 
     616             :         // Adding diagonal elements
     617      287064 :         PetscInt row_at = i_ch + _n_channels * iz_ind;
     618      287064 :         PetscInt col_at = i_ch + _n_channels * iz_ind;
     619      287064 :         PetscScalar value_at = (*_mdot_soln)(node_out);
     620      287064 :         LibmeshPetscCall(MatSetValues(
     621             :             _hc_advective_derivative_mat, 1, &row_at, 1, &col_at, &value_at, INSERT_VALUES));
     622             : 
     623             :         /// Cross derivative term
     624             :         unsigned int counter = 0;
     625             :         unsigned int cross_index = iz; // iz-1;
     626     1186488 :         for (auto i_gap : _subchannel_mesh.getChannelGaps(i_ch))
     627             :         {
     628      899424 :           auto chans = _subchannel_mesh.getGapChannels(i_gap);
     629             :           unsigned int ii_ch = chans.first;
     630             :           unsigned int jj_ch = chans.second;
     631      899424 :           auto * node_in_i = _subchannel_mesh.getChannelNode(ii_ch, iz - 1);
     632      899424 :           auto * node_in_j = _subchannel_mesh.getChannelNode(jj_ch, iz - 1);
     633             :           PetscScalar h_star;
     634             :           // figure out donor axial velocity
     635      899424 :           if (_Wij(i_gap, cross_index) > 0.0)
     636             :           {
     637      529524 :             if (iz == first_node)
     638             :             {
     639       22320 :               h_star = (*_h_soln)(node_in_i);
     640       44640 :               PetscScalar value_vec_ct = -1.0 * alpha *
     641       22320 :                                          _subchannel_mesh.getCrossflowSign(i_ch, counter) *
     642       22320 :                                          _Wij(i_gap, cross_index) * h_star;
     643       22320 :               PetscInt row_vec_ct = i_ch + _n_channels * iz_ind;
     644       22320 :               LibmeshPetscCall(VecSetValues(
     645             :                   _hc_cross_derivative_rhs, 1, &row_vec_ct, &value_vec_ct, ADD_VALUES));
     646             :             }
     647             :             else
     648             :             {
     649      507204 :               PetscScalar value_ct = alpha * _subchannel_mesh.getCrossflowSign(i_ch, counter) *
     650      507204 :                                      _Wij(i_gap, cross_index);
     651      507204 :               PetscInt row_ct = i_ch + _n_channels * iz_ind;
     652      507204 :               PetscInt col_ct = ii_ch + _n_channels * (iz_ind - 1);
     653      507204 :               LibmeshPetscCall(MatSetValues(
     654             :                   _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_ct, ADD_VALUES));
     655             :             }
     656      529524 :             PetscScalar value_ct = (1.0 - alpha) *
     657      529524 :                                    _subchannel_mesh.getCrossflowSign(i_ch, counter) *
     658      529524 :                                    _Wij(i_gap, cross_index);
     659      529524 :             PetscInt row_ct = i_ch + _n_channels * iz_ind;
     660      529524 :             PetscInt col_ct = ii_ch + _n_channels * iz_ind;
     661      529524 :             LibmeshPetscCall(MatSetValues(
     662             :                 _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_ct, ADD_VALUES));
     663             :           }
     664      369900 :           else if (_Wij(i_gap, cross_index) < 0.0) // _Wij=0 operations not necessary
     665             :           {
     666      319212 :             if (iz == first_node)
     667             :             {
     668       16128 :               h_star = (*_h_soln)(node_in_j);
     669       32256 :               PetscScalar value_vec_ct = -1.0 * alpha *
     670       16128 :                                          _subchannel_mesh.getCrossflowSign(i_ch, counter) *
     671       16128 :                                          _Wij(i_gap, cross_index) * h_star;
     672       16128 :               PetscInt row_vec_ct = i_ch + _n_channels * iz_ind;
     673       16128 :               LibmeshPetscCall(VecSetValues(
     674             :                   _hc_cross_derivative_rhs, 1, &row_vec_ct, &value_vec_ct, ADD_VALUES));
     675             :             }
     676             :             else
     677             :             {
     678      303084 :               PetscScalar value_ct = alpha * _subchannel_mesh.getCrossflowSign(i_ch, counter) *
     679      303084 :                                      _Wij(i_gap, cross_index);
     680      303084 :               PetscInt row_ct = i_ch + _n_channels * iz_ind;
     681      303084 :               PetscInt col_ct = jj_ch + _n_channels * (iz_ind - 1);
     682      303084 :               LibmeshPetscCall(MatSetValues(
     683             :                   _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_ct, ADD_VALUES));
     684             :             }
     685      319212 :             PetscScalar value_ct = (1.0 - alpha) *
     686      319212 :                                    _subchannel_mesh.getCrossflowSign(i_ch, counter) *
     687      319212 :                                    _Wij(i_gap, cross_index);
     688      319212 :             PetscInt row_ct = i_ch + _n_channels * iz_ind;
     689      319212 :             PetscInt col_ct = jj_ch + _n_channels * iz_ind;
     690      319212 :             LibmeshPetscCall(MatSetValues(
     691             :                 _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_ct, ADD_VALUES));
     692             :           }
     693             : 
     694             :           // Turbulent cross flows
     695      899424 :           if (iz == first_node)
     696             :           {
     697             :             PetscScalar value_vec_ct =
     698       39888 :                 -2.0 * alpha * (*_h_soln)(node_in)*_WijPrime(i_gap, cross_index);
     699       39888 :             value_vec_ct += alpha * (*_h_soln)(node_in_j)*_WijPrime(i_gap, cross_index);
     700       39888 :             value_vec_ct += alpha * (*_h_soln)(node_in_i)*_WijPrime(i_gap, cross_index);
     701       39888 :             PetscInt row_vec_ct = i_ch + _n_channels * iz_ind;
     702       39888 :             LibmeshPetscCall(
     703             :                 VecSetValues(_hc_cross_derivative_rhs, 1, &row_vec_ct, &value_vec_ct, ADD_VALUES));
     704             :           }
     705             :           else
     706             :           {
     707      859536 :             PetscScalar value_center_ct = 2.0 * alpha * _WijPrime(i_gap, cross_index);
     708      859536 :             PetscInt row_ct = i_ch + _n_channels * iz_ind;
     709      859536 :             PetscInt col_ct = i_ch + _n_channels * (iz_ind - 1);
     710      859536 :             LibmeshPetscCall(MatSetValues(
     711             :                 _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_center_ct, ADD_VALUES));
     712             : 
     713      859536 :             PetscScalar value_left_ct = -1.0 * alpha * _WijPrime(i_gap, cross_index);
     714      859536 :             row_ct = i_ch + _n_channels * iz_ind;
     715      859536 :             col_ct = jj_ch + _n_channels * (iz_ind - 1);
     716      859536 :             LibmeshPetscCall(MatSetValues(
     717             :                 _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_left_ct, ADD_VALUES));
     718             : 
     719      859536 :             PetscScalar value_right_ct = -1.0 * alpha * _WijPrime(i_gap, cross_index);
     720      859536 :             row_ct = i_ch + _n_channels * iz_ind;
     721      859536 :             col_ct = ii_ch + _n_channels * (iz_ind - 1);
     722      859536 :             LibmeshPetscCall(MatSetValues(
     723             :                 _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_right_ct, ADD_VALUES));
     724             :           }
     725      899424 :           PetscScalar value_center_ct = 2.0 * (1.0 - alpha) * _WijPrime(i_gap, cross_index);
     726      899424 :           PetscInt row_ct = i_ch + _n_channels * iz_ind;
     727      899424 :           PetscInt col_ct = i_ch + _n_channels * iz_ind;
     728      899424 :           LibmeshPetscCall(MatSetValues(
     729             :               _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_center_ct, ADD_VALUES));
     730             : 
     731      899424 :           PetscScalar value_left_ct = -1.0 * (1.0 - alpha) * _WijPrime(i_gap, cross_index);
     732      899424 :           row_ct = i_ch + _n_channels * iz_ind;
     733      899424 :           col_ct = jj_ch + _n_channels * iz_ind;
     734      899424 :           LibmeshPetscCall(MatSetValues(
     735             :               _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_left_ct, ADD_VALUES));
     736             : 
     737      899424 :           PetscScalar value_right_ct = -1.0 * (1.0 - alpha) * _WijPrime(i_gap, cross_index);
     738      899424 :           row_ct = i_ch + _n_channels * iz_ind;
     739      899424 :           col_ct = ii_ch + _n_channels * iz_ind;
     740      899424 :           LibmeshPetscCall(MatSetValues(
     741             :               _hc_cross_derivative_mat, 1, &row_ct, 1, &col_ct, &value_right_ct, ADD_VALUES));
     742      899424 :           counter++;
     743             :         }
     744             : 
     745             :         /// Added heat enthalpy
     746      287064 :         PetscScalar added_enthalpy = computeAddedHeatPin(i_ch, iz);
     747      287064 :         PetscInt row_vec_ht = i_ch + _n_channels * iz_ind;
     748      287064 :         LibmeshPetscCall(
     749             :             VecSetValues(_hc_added_heat_rhs, 1, &row_vec_ht, &added_enthalpy, ADD_VALUES));
     750             :       }
     751             :     }
     752             :     /// Assembling system
     753         474 :     LibmeshPetscCall(MatAssemblyBegin(_hc_time_derivative_mat, MAT_FINAL_ASSEMBLY));
     754         474 :     LibmeshPetscCall(MatAssemblyEnd(_hc_time_derivative_mat, MAT_FINAL_ASSEMBLY));
     755         474 :     LibmeshPetscCall(MatAssemblyBegin(_hc_advective_derivative_mat, MAT_FINAL_ASSEMBLY));
     756         474 :     LibmeshPetscCall(MatAssemblyEnd(_hc_advective_derivative_mat, MAT_FINAL_ASSEMBLY));
     757         474 :     LibmeshPetscCall(MatAssemblyBegin(_hc_cross_derivative_mat, MAT_FINAL_ASSEMBLY));
     758         474 :     LibmeshPetscCall(MatAssemblyEnd(_hc_cross_derivative_mat, MAT_FINAL_ASSEMBLY));
     759         474 :     LibmeshPetscCall(MatAssemblyBegin(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
     760         474 :     LibmeshPetscCall(MatAssemblyEnd(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
     761             :     // Matrix
     762             : #if !PETSC_VERSION_LESS_THAN(3, 15, 0)
     763         474 :     LibmeshPetscCall(MatAXPY(_hc_sys_h_mat, 1.0, _hc_time_derivative_mat, UNKNOWN_NONZERO_PATTERN));
     764         474 :     LibmeshPetscCall(MatAssemblyBegin(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
     765         474 :     LibmeshPetscCall(MatAssemblyEnd(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
     766         474 :     LibmeshPetscCall(
     767             :         MatAXPY(_hc_sys_h_mat, 1.0, _hc_advective_derivative_mat, UNKNOWN_NONZERO_PATTERN));
     768         474 :     LibmeshPetscCall(MatAssemblyBegin(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
     769         474 :     LibmeshPetscCall(MatAssemblyEnd(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
     770         474 :     LibmeshPetscCall(
     771             :         MatAXPY(_hc_sys_h_mat, 1.0, _hc_cross_derivative_mat, UNKNOWN_NONZERO_PATTERN));
     772             : #else
     773             :     LibmeshPetscCall(
     774             :         MatAXPY(_hc_sys_h_mat, 1.0, _hc_time_derivative_mat, DIFFERENT_NONZERO_PATTERN));
     775             :     LibmeshPetscCall(MatAssemblyBegin(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
     776             :     LibmeshPetscCall(MatAssemblyEnd(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
     777             :     LibmeshPetscCall(
     778             :         MatAXPY(_hc_sys_h_mat, 1.0, _hc_advective_derivative_mat, DIFFERENT_NONZERO_PATTERN));
     779             :     LibmeshPetscCall(MatAssemblyBegin(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
     780             :     LibmeshPetscCall(MatAssemblyEnd(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
     781             :     LibmeshPetscCall(
     782             :         MatAXPY(_hc_sys_h_mat, 1.0, _hc_cross_derivative_mat, DIFFERENT_NONZERO_PATTERN));
     783             : #endif
     784         474 :     LibmeshPetscCall(MatAssemblyBegin(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
     785         474 :     LibmeshPetscCall(MatAssemblyEnd(_hc_sys_h_mat, MAT_FINAL_ASSEMBLY));
     786         474 :     if (_verbose_subchannel)
     787         294 :       _console << "Block: " << iblock << " - Enthalpy conservation matrix assembled" << std::endl;
     788             :     // RHS
     789         474 :     LibmeshPetscCall(VecAXPY(_hc_sys_h_rhs, 1.0, _hc_time_derivative_rhs));
     790         474 :     LibmeshPetscCall(VecAXPY(_hc_sys_h_rhs, 1.0, _hc_advective_derivative_rhs));
     791         474 :     LibmeshPetscCall(VecAXPY(_hc_sys_h_rhs, 1.0, _hc_cross_derivative_rhs));
     792         474 :     LibmeshPetscCall(VecAXPY(_hc_sys_h_rhs, 1.0, _hc_added_heat_rhs));
     793             : 
     794         474 :     if (_segregated_bool || (!_monolithic_thermal_bool))
     795             :     {
     796             :       // Assembly the matrix system
     797             :       KSP ksploc;
     798             :       PC pc;
     799             :       Vec sol;
     800         360 :       LibmeshPetscCall(VecDuplicate(_hc_sys_h_rhs, &sol));
     801         360 :       LibmeshPetscCall(KSPCreate(PETSC_COMM_WORLD, &ksploc));
     802         360 :       LibmeshPetscCall(KSPSetOperators(ksploc, _hc_sys_h_mat, _hc_sys_h_mat));
     803         360 :       LibmeshPetscCall(KSPGetPC(ksploc, &pc));
     804         360 :       LibmeshPetscCall(PCSetType(pc, PCJACOBI));
     805         360 :       LibmeshPetscCall(KSPSetTolerances(ksploc, _rtol, _atol, _dtol, _maxit));
     806         360 :       LibmeshPetscCall(KSPSetOptionsPrefix(ksploc, "h_sys_"));
     807         360 :       LibmeshPetscCall(KSPSetFromOptions(ksploc));
     808         360 :       LibmeshPetscCall(KSPSolve(ksploc, _hc_sys_h_rhs, sol));
     809             :       PetscScalar * xx;
     810         360 :       LibmeshPetscCall(VecGetArray(sol, &xx));
     811       11496 :       for (unsigned int iz = first_node; iz < last_node + 1; iz++)
     812             :       {
     813       11136 :         auto iz_ind = iz - first_node;
     814      257160 :         for (unsigned int i_ch = 0; i_ch < _n_channels; i_ch++)
     815             :         {
     816      246024 :           auto * node_out = _subchannel_mesh.getChannelNode(i_ch, iz);
     817      246024 :           auto h_out = xx[iz_ind * _n_channels + i_ch];
     818      246024 :           if (h_out < 0)
     819             :           {
     820           0 :             mooseError(name(),
     821             :                        " : Calculation of negative Enthalpy h_out = : ",
     822             :                        h_out,
     823             :                        " Axial Level= : ",
     824             :                        iz);
     825             :           }
     826      246024 :           _h_soln->set(node_out, h_out);
     827             :         }
     828             :       }
     829         360 :       LibmeshPetscCall(KSPDestroy(&ksploc));
     830         360 :       LibmeshPetscCall(VecDestroy(&sol));
     831             :     }
     832             :   }
     833         668 : }

Generated by: LCOV version 1.14