https://mooseframework.inl.gov
SCMMixingKimAndChung.C
Go to the documentation of this file.
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 "SCMMixingKimAndChung.h"
11 #include "SCMFrictionClosureBase.h"
13 #include "TriSubChannelMesh.h"
14 #include "QuadSubChannelMesh.h"
15 
17 
20 {
22  params.addClassDescription(
23  "Class that models the turbulent mixing coefficient using the Kim and Chung correlations.");
24  return params;
25 }
26 
28  : SCMMixingClosureBase(parameters),
29  _is_tri_lattice(dynamic_cast<const TriSubChannelMesh *>(&_subchannel_mesh) != nullptr),
30  _sch_mesh(_subchannel_mesh),
31  _S_soln(_subproblem.getVariable(0, "S")),
32  _mdot_soln(_subproblem.getVariable(0, "mdot")),
33  _w_perim_soln(_subproblem.getVariable(0, "w_perim")),
34  _mu_soln(_subproblem.getVariable(0, "mu")),
35  _P_soln(_subproblem.getVariable(0, "P")),
36  _T_soln(_subproblem.getVariable(0, "T"))
37 {
38  if (_is_tri_lattice)
39  {
40  const auto & tri_mesh = static_cast<const TriSubChannelMesh &>(_subchannel_mesh);
41  if (tri_mesh.getWireDiameter() != 0.0 || tri_mesh.getWireLeadLength() != 0.0)
42  mooseError("SCMMixingKimAndChung applies only to bare-pin assemblies and cannot be used "
43  "with wire-wrapped triangular bundles.");
44  }
45 }
46 
47 Real
48 SCMMixingKimAndChung::computeMixingParameter(const unsigned int i_gap, const unsigned int iz) const
49 {
50  if (_is_tri_lattice)
51  return computeTriLatticeMixingParameter(i_gap, iz);
52  else
53  return computeQuadLatticeMixingParameter(i_gap, iz);
54 }
55 
60 Real
62  const unsigned int iz,
63  const Real delta,
64  const Real sf) const
65 {
66  const Real P_out = _scm_problem.getOutletPressure();
68  const Real pin_diameter = _sch_mesh.getPinDiameter();
69 
70  const auto chans = _sch_mesh.getGapChannels(i_gap);
71  const unsigned int i_ch = chans.first;
72  const unsigned int j_ch = chans.second;
73 
74  const Node * const node_in_i = _sch_mesh.getChannelNode(i_ch, iz - 1);
75  const Node * const node_out_i = _sch_mesh.getChannelNode(i_ch, iz);
76  const Node * const node_in_j = _sch_mesh.getChannelNode(j_ch, iz - 1);
77  const Node * const node_out_j = _sch_mesh.getChannelNode(j_ch, iz);
78 
79  const Real Si_in = _S_soln(node_in_i);
80  const Real Sj_in = _S_soln(node_in_j);
81  const Real Si_out = _S_soln(node_out_i);
82  const Real Sj_out = _S_soln(node_out_j);
83 
84  const Real Si = 0.5 * (Si_in + Si_out);
85  const Real Sj = 0.5 * (Sj_in + Sj_out);
86  const Real S_total = Si_in + Sj_in + Si_out + Sj_out;
87 
88  // crossflow area between channels i,j (dz*gap_width)
89  const Real gap = _sch_mesh.getGapWidth(iz, i_gap);
90 
91  const Real massflux_i = 0.5 * (_mdot_soln(node_in_i) + _mdot_soln(node_out_i)) / Si;
92  const Real massflux_j = 0.5 * (_mdot_soln(node_in_j) + _mdot_soln(node_out_j)) / Sj;
93 
94  // average massflux definition
95  const Real avg_massflux =
96  0.5 * ((_mdot_soln(node_in_i) + _mdot_soln(node_in_j)) / (Si_in + Sj_in) +
97  (_mdot_soln(node_out_i) + _mdot_soln(node_out_j)) / (Si_out + Sj_out));
98 
99  const Real w_perim_i = 0.5 * (_w_perim_soln(node_in_i) + _w_perim_soln(node_out_i));
100  const Real w_perim_j = 0.5 * (_w_perim_soln(node_in_j) + _w_perim_soln(node_out_j));
101 
102  const Real mu_i = 0.5 * (_mu_soln(node_in_i) + _mu_soln(node_out_i));
103  const Real mu_j = 0.5 * (_mu_soln(node_in_j) + _mu_soln(node_out_j));
104  const Real avg_mu = 0.5 * (mu_i + mu_j);
105 
106  const Real avg_hD = 4.0 * (Si + Sj) / (w_perim_i + w_perim_j);
107  const Real hD_i = 4.0 * Si / w_perim_i;
108  const Real hD_j = 4.0 * Sj / w_perim_j;
109 
110  const Real Re_i = massflux_i * hD_i / mu_i;
111  const Real Re_j = massflux_j * hD_j / mu_j;
112  const Real Re = avg_massflux * avg_hD / avg_mu;
113 
114  constexpr Real gamma = 20.0; // empirical constant
115  constexpr Real a = 0.18;
116  constexpr Real b = 0.2;
117 
118  const auto friction_args_i = FrictionStruct(i_ch, Re_i, Si, w_perim_i);
119  const auto friction_args_j = FrictionStruct(j_ch, Re_j, Sj, w_perim_j);
120 
121  const Real fi = _scm_problem.getFrictionClosure()->computeFrictionFactor(friction_args_i);
122  const Real fj = _scm_problem.getFrictionClosure()->computeFrictionFactor(friction_args_j);
123  const Real f = 0.5 * (fi + fj);
124 
125  // average heat conduction
126  const Real avg_k =
127  (1.0 / S_total) * (fp->k_from_p_T(_P_soln(node_out_i) + P_out, _T_soln(node_out_i)) * Si_out +
128  fp->k_from_p_T(_P_soln(node_in_i) + P_out, _T_soln(node_in_i)) * Si_in +
129  fp->k_from_p_T(_P_soln(node_out_j) + P_out, _T_soln(node_out_j)) * Sj_out +
130  fp->k_from_p_T(_P_soln(node_in_j) + P_out, _T_soln(node_in_j)) * Sj_in);
131 
132  // average specific heat capacity
133  const Real avg_cp = (1.0 / S_total) *
134  (fp->cp_from_p_T(_P_soln(node_out_i) + P_out, _T_soln(node_out_i)) * Si_out +
135  fp->cp_from_p_T(_P_soln(node_in_i) + P_out, _T_soln(node_in_i)) * Si_in +
136  fp->cp_from_p_T(_P_soln(node_out_j) + P_out, _T_soln(node_out_j)) * Sj_out +
137  fp->cp_from_p_T(_P_soln(node_in_j) + P_out, _T_soln(node_in_j)) * Sj_in);
138 
139  const Real Pr = avg_mu * avg_cp / avg_k; // Prandtl number
140  const Real Pr_t = Pr * (Re / gamma) * std::sqrt(f / 8.0); // Turbulent Prandtl number
141 
142  // This form is intended for liquid-metal applications; warn when the local average Prandtl
143  // number is outside the usual low-Pr liquid-metal regime.
144  if (Pr >= 0.1)
145  flagSolutionWarning("Prandtl number (Pr) outside the low-Prandtl-number liquid-metal range "
146  "expected by the Kim-Chung turbulent mixing closure.");
147 
148  const Real L_x = sf * delta; // axial length scale (gap is the lateral length scale)
149  const Real lamda = gap / L_x; // aspect ratio
150  const Real a_x = 1.0 - 2.0 * lamda * lamda / libMesh::pi; // velocity coefficient
151 
152  const Real z_FP_over_D =
153  (2.0 * L_x / pin_diameter) *
154  (1.0 + (-0.5 * std::log(lamda) + 0.5 * std::log(4.0) - 0.25) * lamda * lamda);
155 
156  const Real Str =
157  1.0 / (0.822 * (gap / pin_diameter) + 0.144); // Strouhal number (Wu & Trupp 1994)
158 
159  const Real freq_factor = 2.0 / Utility::pow<2>(gamma) * std::sqrt(a / 8.0) * (avg_hD / gap);
160 
161  const Real rod_mixing = (1.0 / Pr_t) * lamda;
162  const Real axial_mixing = a_x * z_FP_over_D * Str;
163 
164  // Mixing Stanton number following Kim and Chung (2001), Eq. 25, as used by
165  // Jeong et al. (2005), Eq. 19:
166  //
167  // St_g = 2/gamma^2 * sqrt(a/8) * (D_h/g)
168  // * [lambda/Pr_t + a_x * (z_FP/D) * Str] * Re^(-b/2).
169  //
170  // The subchannel problem converts St_g to the turbulent interchange flow through
171  // w'_ij = beta * S_ij * G_bar (St_g = beta). This correlation doesn't include the
172  // molecular diffusion term which represents the conductive heat transfer,
173  // which is separately modeled in the subchannel energy equation.
174  return freq_factor * (rod_mixing + axial_mixing) * std::pow(Re, -b / 2.0);
175 }
176 
177 Real
179  const unsigned int iz) const
180 {
181  // main differences for tri lattice: delta and sf
182  const Real pitch = _sch_mesh.getPitch();
183  const Real delta = pitch / std::sqrt(3.0); // centroid to centroid distance
184  constexpr Real sf = 2.0 / 3.0; // shape factor
185  return computeLatticeMixingParameter(i_gap, iz, delta, sf);
186 }
187 
188 Real
190  const unsigned int iz) const
191 {
192  // main differences for quad lattice: delta and sf
193  const Real pitch = _sch_mesh.getPitch();
194  const Real delta = pitch; // centroid to centroid distance
195  constexpr Real sf = 1.0; // shape factor
196  return computeLatticeMixingParameter(i_gap, iz, delta, sf);
197 }
Class that calculates the turbulent mixing coefficient based on the Kim and Chung (2001) correllation...
virtual const Real & getPinDiameter() const
Return undeformed Pin diameter.
SubChannel1PhaseProblem::FrictionStruct FrictionStruct
virtual const Real & getPitch() const
Return the undeformed pitch between 2 subchannels.
Base class for turbulent mixing closures used in SCM.
Real computeTriLatticeMixingParameter(const unsigned int i_gap, const unsigned int iz) const
const SinglePhaseFluidProperties * getSinglePhaseFluidProperties() const
Get fluid properties object.
int delta(unsigned int i, unsigned int j)
Delta function, which returns zero if $i j$ and unity if $i=j$.
registerMooseObject("SubChannelApp", SCMMixingKimAndChung)
Real computeQuadLatticeMixingParameter(const unsigned int i_gap, const unsigned int iz) const
Real computeLatticeMixingParameter(const unsigned int i_gap, const unsigned int iz, const Real delta, const Real sf) const
Common implementation for both tri and quad lattices.
bool _is_tri_lattice
Keep track of the lattice type.
const SubChannelMesh & _sch_mesh
Pointer to the base subchannel mesh.
const SubChannel1PhaseProblem & _scm_problem
Reference to the subchannel problem.
virtual Real computeFrictionFactor(const FrictionStruct &friction_info) const =0
Computes the friction factor for the local conditions.
virtual Real computeMixingParameter(const unsigned int i_gap, const unsigned int iz) const override
Computes the turbulent mixing coefficient for the local conditions around gap(i_gap) and axial level(...
Real f(Real x)
Test function for Brents method.
static const std::string pitch
const double Re
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 SCMFrictionClosureBase * getFrictionClosure() const
static InputParameters validParams()
Mesh class for triangular, edge and corner subchannels for hexagonal lattice fuel assemblies...
static InputParameters validParams()
virtual Real getGapWidth(unsigned int axial_index, unsigned int gap_index) const =0
Return gap width for a given gap index.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const SubChannelMesh & _subchannel_mesh
Reference to the subchannel mesh.
void mooseError(Args &&... args) const
const PostprocessorValue & getOutletPressure() const
Get outlet pressure.
void addClassDescription(const std::string &doc_string)
SCMMixingKimAndChung(const InputParameters &parameters)
SolutionHandle _w_perim_soln
MooseUnits pow(const MooseUnits &, int)
const Real pi
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.