https://mooseframework.inl.gov
SCMMixingChengTodreas.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 "SCMMixingChengTodreas.h"
11 
13 
16 {
18  params.addClassDescription("Class that models the turbulent mixing coefficient for wire-wrapped "
19  "triangular assemblies using the Cheng Todreas correlations.");
20  return params;
21 }
22 
24  : SCMMixingClosureBase(parameters),
25  _is_tri_lattice(dynamic_cast<const TriSubChannelMesh *>(&_subchannel_mesh) != nullptr),
26  _tri_sch_mesh(dynamic_cast<const TriSubChannelMesh *>(&_subchannel_mesh)),
27  _S_soln(_subproblem.getVariable(0, "S")),
28  _mdot_soln(_subproblem.getVariable(0, "mdot")),
29  _w_perim_soln(_subproblem.getVariable(0, "w_perim")),
30  _mu_soln(_subproblem.getVariable(0, "mu"))
31 {
32  if (!_is_tri_lattice)
33  mooseError("This correlation applies only for triangular assemblies");
34 
36  mooseError("This correlation applies only for wire-wrapped assemblies");
37 
39  const Real pin_diameter = _subchannel_mesh.getPinDiameter();
40  const Real pitch_to_diameter = pitch / pin_diameter;
41  const Real wire_lead_to_diameter = _tri_sch_mesh->getWireLeadLength() / pin_diameter;
42  const unsigned int Nr = _tri_sch_mesh->getNumOfRings();
43  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  if (pitch_to_diameter < 1.067 || pitch_to_diameter > 1.35)
48  flagSolutionWarning("Pitch-over-pin diameter ratio (P/D) outside the Cheng-Todreas "
49  "wire-wrapped mixing correlation data range.");
50  if (wire_lead_to_diameter < 4.0 || wire_lead_to_diameter > 52.0)
51  flagSolutionWarning("Wire lead length-over-pin diameter ratio (H/D) outside the "
52  "Cheng-Todreas wire-wrapped mixing correlation data range.");
53  if (num_pins < 7 || num_pins > 217)
54  flagSolutionWarning("Number of pins outside the Cheng-Todreas wire-wrapped mixing "
55  "correlation data range.");
56 }
57 
58 Real
59 SCMMixingChengTodreas::computeMixingParameter(const unsigned int i_gap, const unsigned int iz) const
60 {
61  Real beta = 0.0;
62 
64  const Real pin_diameter = _subchannel_mesh.getPinDiameter();
65 
66  const Real wire_lead_length = _tri_sch_mesh->getWireLeadLength();
67  const Real wire_diameter = _tri_sch_mesh->getWireDiameter();
68  const unsigned int Nr = _tri_sch_mesh->getNumOfRings();
69 
70  const auto chans = _subchannel_mesh.getGapChannels(i_gap);
71  const unsigned int i_ch = chans.first;
72  const unsigned int j_ch = chans.second;
73 
74  const auto subch_type_i = _subchannel_mesh.getSubchannelType(i_ch);
75  const auto subch_type_j = _subchannel_mesh.getSubchannelType(j_ch);
76 
77  const Node * const node_in_i = _subchannel_mesh.getChannelNode(i_ch, iz - 1);
78  const Node * const node_out_i = _subchannel_mesh.getChannelNode(i_ch, iz);
79  const Node * const node_in_j = _subchannel_mesh.getChannelNode(j_ch, iz - 1);
80  const Node * const node_out_j = _subchannel_mesh.getChannelNode(j_ch, iz);
81 
82  const Real Si_in = _S_soln(node_in_i);
83  const Real Sj_in = _S_soln(node_in_j);
84  const Real Si_out = _S_soln(node_out_i);
85  const Real Sj_out = _S_soln(node_out_j);
86 
87  const Real S_total = Si_in + Sj_in + Si_out + Sj_out;
88  const Real Si = 0.5 * (Si_in + Si_out);
89  const Real Sj = 0.5 * (Sj_in + Sj_out);
90 
91  const Real w_perim_i = 0.5 * (_w_perim_soln(node_in_i) + _w_perim_soln(node_out_i));
92  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  (1.0 / S_total) * (_mu_soln(node_out_i) * Si_out + _mu_soln(node_in_i) * Si_in +
96  _mu_soln(node_out_j) * Sj_out + _mu_soln(node_in_j) * Sj_in);
97 
98  const Real avg_hD = 4.0 * (Si + Sj) / (w_perim_i + w_perim_j);
99 
100  const Real avg_massflux =
101  0.5 * ((_mdot_soln(node_in_i) + _mdot_soln(node_in_j)) / (Si_in + Sj_in) +
102  (_mdot_soln(node_out_i) + _mdot_soln(node_out_j)) / (Si_out + Sj_out));
103 
104  const Real Re = avg_massflux * avg_hD / avg_mu;
105  if (Re < 400.0 || Re > 1.0e6)
106  flagSolutionWarning("Reynolds number (Re) outside the Cheng-Todreas wire-wrapped mixing "
107  "correlation data range.");
108 
109  // Calculation of flow regime
110  const Real ReL = 320.0 * std::pow(10.0, pitch / pin_diameter - 1.0);
111  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  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  std::acos(wire_lead_length /
122  std::sqrt(Utility::pow<2>(wire_lead_length) +
123  Utility::pow<2>(libMesh::pi * (pin_diameter + wire_diameter))));
124 
125  // projected area of wire on subchannel
126  const Real Ar1 = libMesh::pi * (pin_diameter + wire_diameter) * wire_diameter / 6.0;
127 
128  // bare subchannel flow area
129  const Real A1prime = (std::sqrt(3.0) / 4.0) * Utility::pow<2>(pitch) -
130  libMesh::pi * Utility::pow<2>(pin_diameter) / 8.0;
131 
132  // wire-wrapped subchannel flow area
133  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  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  const Real CmT = CmT_constant * std::pow((pitch - pin_diameter) / pin_diameter, -0.5);
152  const Real CmL = CmL_constant * std::pow((pitch - pin_diameter) / pin_diameter, -0.5);
153 
154  if (Re < ReL)
155  {
156  Cm = CmL;
157  }
158  else if (Re > ReT)
159  {
160  Cm = CmT;
161  }
162  else
163  {
164  const Real psi = (std::log(Re) - std::log(ReL)) / (std::log(ReT) - std::log(ReL));
165  const Real gamma = 2.0 / 3.0;
166  Cm = CmL + (CmT - CmL) * std::pow(psi, gamma);
167  }
168 
169  // mixing parameter
170  beta = Cm * std::sqrt(Ar1 / A1) * std::tan(theta);
171  }
172  return beta;
173 }
174 
175 Real
177  const unsigned int iz) const
178 {
179  Real beta = 0.0;
180 
182  const Real pin_diameter = _subchannel_mesh.getPinDiameter();
183 
184  const Real wire_lead_length = _tri_sch_mesh->getWireLeadLength();
185  const Real wire_diameter = _tri_sch_mesh->getWireDiameter();
186  const unsigned int Nr = _tri_sch_mesh->getNumOfRings();
187 
188  const auto chans = _subchannel_mesh.getGapChannels(i_gap);
189  const unsigned int i_ch = chans.first;
190  const unsigned int j_ch = chans.second;
191 
192  const auto subch_type_i = _subchannel_mesh.getSubchannelType(i_ch);
193  const auto subch_type_j = _subchannel_mesh.getSubchannelType(j_ch);
194 
195  const Node * const node_in_i = _subchannel_mesh.getChannelNode(i_ch, iz - 1);
196  const Node * const node_out_i = _subchannel_mesh.getChannelNode(i_ch, iz);
197  const Node * const node_in_j = _subchannel_mesh.getChannelNode(j_ch, iz - 1);
198  const Node * const node_out_j = _subchannel_mesh.getChannelNode(j_ch, iz);
199 
200  const Real Si_in = _S_soln(node_in_i);
201  const Real Sj_in = _S_soln(node_in_j);
202  const Real Si_out = _S_soln(node_out_i);
203  const Real Sj_out = _S_soln(node_out_j);
204 
205  const Real S_total = Si_in + Sj_in + Si_out + Sj_out;
206  const Real Si = 0.5 * (Si_in + Si_out);
207  const Real Sj = 0.5 * (Sj_in + Sj_out);
208 
209  const Real w_perim_i = 0.5 * (_w_perim_soln(node_in_i) + _w_perim_soln(node_out_i));
210  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  (1.0 / S_total) * (_mu_soln(node_out_i) * Si_out + _mu_soln(node_in_i) * Si_in +
214  _mu_soln(node_out_j) * Sj_out + _mu_soln(node_in_j) * Sj_in);
215 
216  const Real avg_hD = 4.0 * (Si + Sj) / (w_perim_i + w_perim_j);
217 
218  const Real avg_massflux =
219  0.5 * ((_mdot_soln(node_in_i) + _mdot_soln(node_in_j)) / (Si_in + Sj_in) +
220  (_mdot_soln(node_out_i) + _mdot_soln(node_out_j)) / (Si_out + Sj_out));
221 
222  const Real Re = avg_massflux * avg_hD / avg_mu;
223  if (Re < 400.0 || Re > 1.0e6)
224  flagSolutionWarning("Reynolds number (Re) outside the Cheng-Todreas wire-wrapped mixing "
225  "correlation data range.");
226 
227  // Calculation of flow regime
228  const Real ReL = 320.0 * std::pow(10.0, pitch / pin_diameter - 1.0);
229  const Real ReT = 10000.0 * std::pow(10.0, 0.7 * (pitch / pin_diameter - 1.0));
230 
231  if ((subch_type_i == EChannelType::CORNER || subch_type_i == EChannelType::EDGE) &&
232  (subch_type_j == EChannelType::CORNER || subch_type_j == EChannelType::EDGE))
233  {
234  const Real theta =
235  std::acos(wire_lead_length /
236  std::sqrt(Utility::pow<2>(wire_lead_length) +
237  Utility::pow<2>(libMesh::pi * (pin_diameter + wire_diameter))));
238 
239  // Calculation of geometric parameters
240  // distance from pin surface to duct
241  const Real dpgap = _tri_sch_mesh->getDuctToPinGap();
242 
243  // Edge pitch parameter defined as pin diameter plus distance to duct wall
244  const Real w = pin_diameter + dpgap;
245 
246  const Real Ar2 = libMesh::pi * (pin_diameter + wire_diameter) * wire_diameter / 4.0;
247 
248  const Real A2prime =
249  pitch * (w - pin_diameter / 2.0) - libMesh::pi * Utility::pow<2>(pin_diameter) / 8.0;
250 
251  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  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  const Real CsL = CsL_constant * std::pow(wire_lead_length / pin_diameter, 0.3);
270  const Real CsT = CsT_constant * std::pow(wire_lead_length / pin_diameter, 0.3);
271 
272  if (Re < ReL)
273  {
274  Cs = CsL;
275  }
276  else if (Re > ReT)
277  {
278  Cs = CsT;
279  }
280  else
281  {
282  const Real psi = (std::log(Re) - std::log(ReL)) / (std::log(ReT) - std::log(ReL));
283  const Real gamma = 2.0 / 3.0;
284  Cs = CsL + (CsT - CsL) * std::pow(psi, gamma);
285  }
286 
287  // Sweep-flow coefficient used only by the peripheral enthalpy calculation.
288  beta = Cs * std::sqrt(Ar2 / A2) * std::tan(theta);
289  }
290 
291  return beta;
292 }
const Real & getWireDiameter() const
Return wire diameter.
virtual const Real & getPinDiameter() const
Return undeformed Pin diameter.
virtual const Real & getPitch() const
Return the undeformed pitch between 2 subchannels.
virtual EChannelType getSubchannelType(unsigned int index) const =0
Return the type of the subchannel for given subchannel index.
Base class for turbulent mixing closures used in SCM.
const unsigned int & getNumOfRings() const
Return the number of rings.
const TriSubChannelMesh *const _tri_sch_mesh
Pointer to the tri lattice mesh.
const Real & getDuctToPinGap() const
Return the the gap thickness between the duct and peripheral fuel pins.
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(...
static const std::string pitch
Class that calculates turbulent mixing and sweep-flow coefficients based on the Cheng & Todreas corre...
const double Re
bool _is_tri_lattice
Keep track of the lattice type.
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.
static InputParameters validParams()
Mesh class for triangular, edge and corner subchannels for hexagonal lattice fuel assemblies...
SCMMixingChengTodreas(const InputParameters &parameters)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
static InputParameters validParams()
const SubChannelMesh & _subchannel_mesh
Reference to the subchannel mesh.
void mooseError(Args &&... args) const
registerMooseObject("SubChannelApp", SCMMixingChengTodreas)
void addClassDescription(const std::string &doc_string)
Real computeSweepFlowMixingParameter(const unsigned int i_gap, const unsigned int iz) const override
Computes the wire-wrap sweep-flow coefficient for peripheral gaps.
const Real & getWireLeadLength() const
Return the wire lead length.
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.