LCOV - code coverage report
Current view: top level - src/scmclosures - SCMMixingChengTodreas.C (source / functions) Hit Total Coverage
Test: idaholab/moose subchannel: #33416 (b10b36) with base 9fbd27 Lines: 126 131 96.2 %
Date: 2026-07-23 16:21:31 Functions: 4 4 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 "SCMMixingChengTodreas.h"
      11             : 
      12             : registerMooseObject("SubChannelApp", SCMMixingChengTodreas);
      13             : 
      14             : InputParameters
      15         258 : SCMMixingChengTodreas::validParams()
      16             : {
      17         258 :   InputParameters params = SCMMixingClosureBase::validParams();
      18         258 :   params.addClassDescription("Class that models the turbulent mixing coefficient for wire-wrapped "
      19             :                              "triangular assemblies using the Cheng Todreas correlations.");
      20         258 :   return params;
      21           0 : }
      22             : 
      23         138 : SCMMixingChengTodreas::SCMMixingChengTodreas(const InputParameters & parameters)
      24             :   : SCMMixingClosureBase(parameters),
      25         138 :     _is_tri_lattice(dynamic_cast<const TriSubChannelMesh *>(&_subchannel_mesh) != nullptr),
      26         138 :     _tri_sch_mesh(dynamic_cast<const TriSubChannelMesh *>(&_subchannel_mesh)),
      27         138 :     _S_soln(_subproblem.getVariable(0, "S")),
      28         138 :     _mdot_soln(_subproblem.getVariable(0, "mdot")),
      29         138 :     _w_perim_soln(_subproblem.getVariable(0, "w_perim")),
      30         276 :     _mu_soln(_subproblem.getVariable(0, "mu"))
      31             : {
      32         138 :   if (!_is_tri_lattice)
      33           0 :     mooseError("This correlation applies only for triangular assemblies");
      34             : 
      35         138 :   if (_tri_sch_mesh->getWireLeadLength() == 0 || _tri_sch_mesh->getWireDiameter() == 0)
      36           0 :     mooseError("This correlation applies only for wire-wrapped assemblies");
      37             : 
      38         138 :   const Real pitch = _subchannel_mesh.getPitch();
      39         138 :   const Real pin_diameter = _subchannel_mesh.getPinDiameter();
      40         138 :   const Real pitch_to_diameter = pitch / pin_diameter;
      41         138 :   const Real wire_lead_to_diameter = _tri_sch_mesh->getWireLeadLength() / pin_diameter;
      42         138 :   const unsigned int Nr = _tri_sch_mesh->getNumOfRings();
      43         138 :   const unsigned int num_pins = 1 + 3 * Nr * (Nr - 1);
      44             : 
      45             :   // Cheng and Todreas (1986) fitted the wire-wrapped mixing parameters over the ranges
      46             :   // 1.067 <= P/D <= 1.35, 4 <= H/D <= 52, and 7 <= Npin <= 217.
      47         138 :   if (pitch_to_diameter < 1.067 || pitch_to_diameter > 1.35)
      48           0 :     flagSolutionWarning("Pitch-over-pin diameter ratio (P/D) outside the Cheng-Todreas "
      49             :                         "wire-wrapped mixing correlation data range.");
      50         138 :   if (wire_lead_to_diameter < 4.0 || wire_lead_to_diameter > 52.0)
      51         102 :     flagSolutionWarning("Wire lead length-over-pin diameter ratio (H/D) outside the "
      52             :                         "Cheng-Todreas wire-wrapped mixing correlation data range.");
      53         138 :   if (num_pins < 7 || num_pins > 217)
      54           0 :     flagSolutionWarning("Number of pins outside the Cheng-Todreas wire-wrapped mixing "
      55             :                         "correlation data range.");
      56         138 : }
      57             : 
      58             : Real
      59    10052160 : SCMMixingChengTodreas::computeMixingParameter(const unsigned int i_gap, const unsigned int iz) const
      60             : {
      61             :   Real beta = 0.0;
      62             : 
      63    10052160 :   const Real pitch = _subchannel_mesh.getPitch();
      64    10052160 :   const Real pin_diameter = _subchannel_mesh.getPinDiameter();
      65             : 
      66    10052160 :   const Real wire_lead_length = _tri_sch_mesh->getWireLeadLength();
      67    10052160 :   const Real wire_diameter = _tri_sch_mesh->getWireDiameter();
      68    10052160 :   const unsigned int Nr = _tri_sch_mesh->getNumOfRings();
      69             : 
      70    10052160 :   const auto chans = _subchannel_mesh.getGapChannels(i_gap);
      71    10052160 :   const unsigned int i_ch = chans.first;
      72    10052160 :   const unsigned int j_ch = chans.second;
      73             : 
      74    10052160 :   const auto subch_type_i = _subchannel_mesh.getSubchannelType(i_ch);
      75    10052160 :   const auto subch_type_j = _subchannel_mesh.getSubchannelType(j_ch);
      76             : 
      77    10052160 :   const Node * const node_in_i = _subchannel_mesh.getChannelNode(i_ch, iz - 1);
      78    10052160 :   const Node * const node_out_i = _subchannel_mesh.getChannelNode(i_ch, iz);
      79    10052160 :   const Node * const node_in_j = _subchannel_mesh.getChannelNode(j_ch, iz - 1);
      80    10052160 :   const Node * const node_out_j = _subchannel_mesh.getChannelNode(j_ch, iz);
      81             : 
      82    10052160 :   const Real Si_in = _S_soln(node_in_i);
      83    10052160 :   const Real Sj_in = _S_soln(node_in_j);
      84    10052160 :   const Real Si_out = _S_soln(node_out_i);
      85    10052160 :   const Real Sj_out = _S_soln(node_out_j);
      86             : 
      87    10052160 :   const Real S_total = Si_in + Sj_in + Si_out + Sj_out;
      88    10052160 :   const Real Si = 0.5 * (Si_in + Si_out);
      89    10052160 :   const Real Sj = 0.5 * (Sj_in + Sj_out);
      90             : 
      91    10052160 :   const Real w_perim_i = 0.5 * (_w_perim_soln(node_in_i) + _w_perim_soln(node_out_i));
      92    10052160 :   const Real w_perim_j = 0.5 * (_w_perim_soln(node_in_j) + _w_perim_soln(node_out_j));
      93             : 
      94             :   const Real avg_mu =
      95    10052160 :       (1.0 / S_total) * (_mu_soln(node_out_i) * Si_out + _mu_soln(node_in_i) * Si_in +
      96    10052160 :                          _mu_soln(node_out_j) * Sj_out + _mu_soln(node_in_j) * Sj_in);
      97             : 
      98    10052160 :   const Real avg_hD = 4.0 * (Si + Sj) / (w_perim_i + w_perim_j);
      99             : 
     100             :   const Real avg_massflux =
     101    10052160 :       0.5 * ((_mdot_soln(node_in_i) + _mdot_soln(node_in_j)) / (Si_in + Sj_in) +
     102    10052160 :              (_mdot_soln(node_out_i) + _mdot_soln(node_out_j)) / (Si_out + Sj_out));
     103             : 
     104    10052160 :   const Real Re = avg_massflux * avg_hD / avg_mu;
     105    10052160 :   if (Re < 400.0 || Re > 1.0e6)
     106       53013 :     flagSolutionWarning("Reynolds number (Re) outside the Cheng-Todreas wire-wrapped mixing "
     107             :                         "correlation data range.");
     108             : 
     109             :   // Calculation of flow regime
     110    10052160 :   const Real ReL = 320.0 * std::pow(10.0, pitch / pin_diameter - 1.0);
     111    10052160 :   const Real ReT = 10000.0 * std::pow(10.0, 0.7 * (pitch / pin_diameter - 1.0));
     112             : 
     113             :   // This beta is used by the global turbulent crossflow relation:
     114             :   // w'_ij = beta * S_ij * G_bar. Peripheral sweep flow is handled separately by
     115             :   // computeSweepFlowMixingParameter().
     116    10052160 :   if (subch_type_i == EChannelType::CENTER || subch_type_j == EChannelType::CENTER)
     117             :   {
     118             :     // Calculation of geometric parameters
     119             :     // wire angle
     120             :     const Real theta =
     121     7712280 :         std::acos(wire_lead_length /
     122     7712280 :                   std::sqrt(Utility::pow<2>(wire_lead_length) +
     123     7712280 :                             Utility::pow<2>(libMesh::pi * (pin_diameter + wire_diameter))));
     124             : 
     125             :     // projected area of wire on subchannel
     126     7712280 :     const Real Ar1 = libMesh::pi * (pin_diameter + wire_diameter) * wire_diameter / 6.0;
     127             : 
     128             :     // bare subchannel flow area
     129     7712280 :     const Real A1prime = (std::sqrt(3.0) / 4.0) * Utility::pow<2>(pitch) -
     130     7712280 :                          libMesh::pi * Utility::pow<2>(pin_diameter) / 8.0;
     131             : 
     132             :     // empirical constant for mixing parameter
     133             :     Real Cm = 0.0;
     134             :     Real CmL_constant = 0.0;
     135             :     Real CmT_constant = 0.0;
     136             : 
     137     7712280 :     if (Nr == 1)
     138             :     {
     139             :       CmT_constant = 0.1;
     140             :       CmL_constant = 0.055;
     141             :     }
     142             :     else
     143             :     {
     144             :       CmT_constant = 0.14;
     145             :       CmL_constant = 0.077;
     146             :     }
     147             : 
     148     7712280 :     const Real CmT = CmT_constant * std::pow((pitch - pin_diameter) / pin_diameter, -0.5);
     149     7712280 :     const Real CmL = CmL_constant * std::pow((pitch - pin_diameter) / pin_diameter, -0.5);
     150             : 
     151     7712280 :     if (Re < ReL)
     152             :     {
     153             :       Cm = CmL;
     154             :     }
     155     7667820 :     else if (Re > ReT)
     156             :     {
     157             :       Cm = CmT;
     158             :     }
     159             :     else
     160             :     {
     161             :       // Simplified intermittency factor; see SCMMixingChengTodreas.md.
     162             :       // Cheng and Todreas (1986) use a more detailed expression for psi.
     163     1537751 :       const Real psi = (std::log(Re) - std::log(ReL)) / (std::log(ReT) - std::log(ReL));
     164             :       const Real gamma = 2.0 / 3.0;
     165     1537751 :       Cm = CmL + (CmT - CmL) * std::pow(psi, gamma);
     166             :     }
     167             : 
     168             :     // mixing parameter
     169     7712280 :     beta = Cm * std::sqrt(Ar1 / A1prime) * std::tan(theta);
     170             :   }
     171    10052160 :   return beta;
     172             : }
     173             : 
     174             : Real
     175     1765680 : SCMMixingChengTodreas::computeSweepFlowMixingParameter(const unsigned int i_gap,
     176             :                                                        const unsigned int iz) const
     177             : {
     178             :   Real beta = 0.0;
     179             : 
     180     1765680 :   const Real pitch = _subchannel_mesh.getPitch();
     181     1765680 :   const Real pin_diameter = _subchannel_mesh.getPinDiameter();
     182             : 
     183     1765680 :   const Real wire_lead_length = _tri_sch_mesh->getWireLeadLength();
     184     1765680 :   const Real wire_diameter = _tri_sch_mesh->getWireDiameter();
     185     1765680 :   const unsigned int Nr = _tri_sch_mesh->getNumOfRings();
     186             : 
     187     1765680 :   const auto chans = _subchannel_mesh.getGapChannels(i_gap);
     188     1765680 :   const unsigned int i_ch = chans.first;
     189     1765680 :   const unsigned int j_ch = chans.second;
     190             : 
     191     1765680 :   const auto subch_type_i = _subchannel_mesh.getSubchannelType(i_ch);
     192     1765680 :   const auto subch_type_j = _subchannel_mesh.getSubchannelType(j_ch);
     193             : 
     194     1765680 :   const Node * const node_in_i = _subchannel_mesh.getChannelNode(i_ch, iz - 1);
     195     1765680 :   const Node * const node_out_i = _subchannel_mesh.getChannelNode(i_ch, iz);
     196     1765680 :   const Node * const node_in_j = _subchannel_mesh.getChannelNode(j_ch, iz - 1);
     197     1765680 :   const Node * const node_out_j = _subchannel_mesh.getChannelNode(j_ch, iz);
     198             : 
     199     1765680 :   const Real Si_in = _S_soln(node_in_i);
     200     1765680 :   const Real Sj_in = _S_soln(node_in_j);
     201     1765680 :   const Real Si_out = _S_soln(node_out_i);
     202     1765680 :   const Real Sj_out = _S_soln(node_out_j);
     203             : 
     204     1765680 :   const Real S_total = Si_in + Sj_in + Si_out + Sj_out;
     205     1765680 :   const Real Si = 0.5 * (Si_in + Si_out);
     206     1765680 :   const Real Sj = 0.5 * (Sj_in + Sj_out);
     207             : 
     208     1765680 :   const Real w_perim_i = 0.5 * (_w_perim_soln(node_in_i) + _w_perim_soln(node_out_i));
     209     1765680 :   const Real w_perim_j = 0.5 * (_w_perim_soln(node_in_j) + _w_perim_soln(node_out_j));
     210             : 
     211             :   const Real avg_mu =
     212     1765680 :       (1.0 / S_total) * (_mu_soln(node_out_i) * Si_out + _mu_soln(node_in_i) * Si_in +
     213     1765680 :                          _mu_soln(node_out_j) * Sj_out + _mu_soln(node_in_j) * Sj_in);
     214             : 
     215     1765680 :   const Real avg_hD = 4.0 * (Si + Sj) / (w_perim_i + w_perim_j);
     216             : 
     217             :   const Real avg_massflux =
     218     1765680 :       0.5 * ((_mdot_soln(node_in_i) + _mdot_soln(node_in_j)) / (Si_in + Sj_in) +
     219     1765680 :              (_mdot_soln(node_out_i) + _mdot_soln(node_out_j)) / (Si_out + Sj_out));
     220             : 
     221     1765680 :   const Real Re = avg_massflux * avg_hD / avg_mu;
     222     1765680 :   if (Re < 400.0 || Re > 1.0e6)
     223       10263 :     flagSolutionWarning("Reynolds number (Re) outside the Cheng-Todreas wire-wrapped mixing "
     224             :                         "correlation data range.");
     225             : 
     226             :   // Calculation of flow regime
     227     1765680 :   const Real ReL = 320.0 * std::pow(10.0, pitch / pin_diameter - 1.0);
     228     1765680 :   const Real ReT = 10000.0 * std::pow(10.0, 0.7 * (pitch / pin_diameter - 1.0));
     229             : 
     230     1765680 :   if ((subch_type_i == EChannelType::CORNER || subch_type_i == EChannelType::EDGE) &&
     231     1765680 :       (subch_type_j == EChannelType::CORNER || subch_type_j == EChannelType::EDGE))
     232             :   {
     233             :     const Real theta =
     234     1765680 :         std::acos(wire_lead_length /
     235     1765680 :                   std::sqrt(Utility::pow<2>(wire_lead_length) +
     236     1765680 :                             Utility::pow<2>(libMesh::pi * (pin_diameter + wire_diameter))));
     237             : 
     238             :     // Calculation of geometric parameters
     239             :     // distance from pin surface to duct
     240     1765680 :     const Real dpgap = _tri_sch_mesh->getDuctToPinGap();
     241             : 
     242             :     // Edge pitch parameter defined as pin diameter plus distance to duct wall
     243     1765680 :     const Real w = pin_diameter + dpgap;
     244             : 
     245     1765680 :     const Real Ar2 = libMesh::pi * (pin_diameter + wire_diameter) * wire_diameter / 4.0;
     246             : 
     247             :     const Real A2prime =
     248     1765680 :         pitch * (w - pin_diameter / 2.0) - libMesh::pi * Utility::pow<2>(pin_diameter) / 8.0;
     249             : 
     250             :     // empirical constant for mixing parameter
     251             :     Real Cs = 0.0;
     252             :     Real CsL_constant = 0.0;
     253             :     Real CsT_constant = 0.0;
     254             : 
     255     1765680 :     if (Nr == 1)
     256             :     {
     257             :       CsT_constant = 0.6;
     258             :       CsL_constant = 0.33;
     259             :     }
     260             :     else
     261             :     {
     262             :       CsT_constant = 0.75;
     263             :       CsL_constant = 0.413;
     264             :     }
     265             : 
     266     1765680 :     const Real CsL = CsL_constant * std::pow(wire_lead_length / pin_diameter, 0.3);
     267     1765680 :     const Real CsT = CsT_constant * std::pow(wire_lead_length / pin_diameter, 0.3);
     268             : 
     269     1765680 :     if (Re < ReL)
     270             :     {
     271             :       Cs = CsL;
     272             :     }
     273     1755420 :     else if (Re > ReT)
     274             :     {
     275             :       Cs = CsT;
     276             :     }
     277             :     else
     278             :     {
     279             :       // Simplified intermittency factor; see SCMMixingChengTodreas.md.
     280             :       // Cheng and Todreas (1986) use a more detailed expression for psi.
     281      399096 :       const Real psi = (std::log(Re) - std::log(ReL)) / (std::log(ReT) - std::log(ReL));
     282             :       const Real gamma = 2.0 / 3.0;
     283      399096 :       Cs = CsL + (CsT - CsL) * std::pow(psi, gamma);
     284             :     }
     285             : 
     286             :     // Sweep-flow coefficient used only by the peripheral enthalpy calculation.
     287     1765680 :     beta = Cs * std::sqrt(Ar2 / A2prime) * std::tan(theta);
     288             :   }
     289             : 
     290     1765680 :   return beta;
     291             : }

Generated by: LCOV version 1.14