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

Generated by: LCOV version 1.14