https://mooseframework.inl.gov
Loading...
Searching...
No Matches
TriSubChannelMesh.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 "TriSubChannelMesh.h"
11#include <cmath>
12#include "libmesh/node.h"
13
15
18{
20 params.addClassDescription("Creates an subchannel mesh container for a triangular "
21 "lattice arrangement");
22 return params;
23}
24
26
28 : SubChannelMesh(other_mesh),
29 _n_rings(other_mesh._n_rings),
30 _n_channels(other_mesh._n_channels),
31 _flat_to_flat(other_mesh._flat_to_flat),
32 _dwire(other_mesh._dwire),
33 _hwire(other_mesh._hwire),
34 _duct_to_pin_gap(other_mesh._duct_to_pin_gap),
35 _nodes(other_mesh._nodes),
36 _pin_nodes(other_mesh._pin_nodes),
37 _gap_to_chan_map(other_mesh._gap_to_chan_map),
38 _gap_to_pin_map(other_mesh._gap_to_pin_map),
39 _chan_to_gap_map(other_mesh._chan_to_gap_map),
40 _sign_id_crossflow_map(other_mesh._sign_id_crossflow_map),
41 _gij_map(other_mesh._gij_map),
42 _pin_position(other_mesh._pin_position),
43 _pins_in_rings(other_mesh._pins_in_rings),
44 _chan_to_pin_map(other_mesh._chan_to_pin_map),
45 _npins(other_mesh._npins),
46 _n_gaps(other_mesh._n_gaps),
47 _subch_type(other_mesh._subch_type),
48 _gap_type(other_mesh._gap_type),
49 _gap_pairs_sf(other_mesh._gap_pairs_sf),
50 _chan_pairs_sf(other_mesh._chan_pairs_sf),
51 _pin_to_chan_map(other_mesh._pin_to_chan_map)
52{
53}
54
55std::unique_ptr<MooseMesh>
57{
58 return _app.getFactory().copyConstruct(*this);
59}
60
61unsigned int
63{
65 return this->channelIndex(p);
66}
67
68unsigned int
70{
75
76 // Distances to determine the closest subchannel
77 Real distance0 = 1.0e+8; // Dummy distance to keep updating the closes distance found
78 Real distance1; // Distance to be updated with the current subchannel distance
79 unsigned int j = 0; // Index to keep track of the closest point to subchannel
80
81 // Projecting point into hexahedral coordinated to determine if the point belongs to a center
82 // subchannel
83 Real distance_outer_ring = _flat_to_flat / 2 - _duct_to_pin_gap - _pin_diameter / 2;
84 Real channel_distance = std::sqrt(std::pow(p(0), 2) + std::pow(p(1), 2));
85 Real angle = std::abs(std::atan2(p(1), p(0)));
86 Real projection_angle =
87 angle - libMesh::pi / 6 - std::trunc(angle / (libMesh::pi / 3)) * (libMesh::pi / 3);
88 channel_distance = channel_distance * std::cos(projection_angle);
89
90 // Projecting point on top edge to determine if the point is a corner or edge subchannel by x
91 // coordinate
92 Real loc_angle = std::atan2(p(1), p(0));
93 if (loc_angle < 0.0)
94 loc_angle += 2 * libMesh::pi;
95 Real rem_ang = std::trunc(loc_angle / (libMesh::pi / 3)) * (libMesh::pi / 3) - libMesh::pi / 3;
96 Real x_coord_new = (std::cos(-rem_ang) * p(0) - std::sin(-rem_ang) * p(1));
97 Real x_lim = (_n_rings - 1) * _pitch / 2.0;
98
99 // looping over all channels
100 for (unsigned int i = 0; i < _n_channels; i++)
101 {
102 // Distance from the point to subchannel
103 distance1 = std::sqrt(std::pow((p(0) - _subchannel_position[i][0]), 2.0) +
104 std::pow((p(1) - _subchannel_position[i][1]), 2.0));
105
106 // If subchannel belongs to center ring
107 if (channel_distance < distance_outer_ring)
108 {
109 if ((distance1 < distance0) && (_subch_type[i] == EChannelType::CENTER))
110 {
111 j = i;
112 distance0 = distance1;
113 } // if
114 } // if
115 // If subchannel belongs to outer ring
116 else
117 {
118 if ((distance1 < distance0) &&
120 {
121 if (((x_coord_new > x_lim) || (x_coord_new < -x_lim)) &&
123 {
124 j = i;
125 distance0 = distance1;
126 } // if
127 else if ((x_coord_new <= x_lim && x_coord_new >= -x_lim) &&
129 {
130 j = i;
131 distance0 = distance1;
132 }
133 }
134 }
135 }
136 return j;
137}
138
139void
143
144void
146{
150
151 const Real z = _z_grid.empty() ? 0.0 : _z_grid.front();
152
153 for (unsigned int i_ch = 0; i_ch < _n_channels; i_ch++)
154 {
157 }
158
160 mooseError(name(), ": Assembly wetted perimeter is zero; cannot compute hydraulic diameter.");
161
163}
164
165Real
166TriSubChannelMesh::getSubchannelFlowArea(unsigned int i_chan, Real z) const
167{
168 Real standard_area = 0.0;
169 Real rod_area = 0.0;
170 Real wire_area = 0.0;
171
172 const Real theta =
173 std::acos(_hwire / std::sqrt(std::pow(_hwire, 2) +
174 std::pow(libMesh::pi * (_pin_diameter + _dwire), 2)));
175 const auto subch_type = getSubchannelType(i_chan);
176 if (subch_type == EChannelType::CENTER)
177 {
178 standard_area = std::pow(_pitch, 2) * std::sqrt(3.0) / 4.0;
179 rod_area = libMesh::pi * std::pow(_pin_diameter, 2) / 8.0;
180 wire_area = libMesh::pi * std::pow(_dwire, 2) / 8.0 / std::cos(theta);
181 }
182 else if (subch_type == EChannelType::EDGE)
183 {
184 standard_area = _pitch * (_pin_diameter / 2.0 + _duct_to_pin_gap);
185 rod_area = libMesh::pi * std::pow(_pin_diameter, 2) / 8.0;
186 wire_area = libMesh::pi * std::pow(_dwire, 2) / 8.0 / std::cos(theta);
187 }
188 else
189 {
190 standard_area = 1.0 / std::sqrt(3.0) * std::pow(_pin_diameter / 2.0 + _duct_to_pin_gap, 2);
191 rod_area = libMesh::pi * std::pow(_pin_diameter, 2) / 24.0;
192 wire_area = libMesh::pi * std::pow(_dwire, 2) / 24.0 / std::cos(theta);
193 }
194
195 Real flow_area = standard_area - rod_area - wire_area;
196
197 unsigned int blockage_index = 0;
198 for (const auto & i_blockage : _index_blockage)
199 {
200 if (i_chan == i_blockage && z >= _z_blockage.front() && z <= _z_blockage.back())
201 flow_area *= _reduction_blockage[blockage_index];
202 blockage_index++;
203 }
204
205 return flow_area;
206}
207
208Real
210{
211 const Real theta =
212 std::acos(_hwire / std::sqrt(std::pow(_hwire, 2) +
213 std::pow(libMesh::pi * (_pin_diameter + _dwire), 2)));
214 const Real rod_circumference = libMesh::pi * _pin_diameter;
215 const Real wire_circumference = libMesh::pi * _dwire;
216 const auto subch_type = getSubchannelType(i_chan);
217
218 if (subch_type == EChannelType::CENTER)
219 return 0.5 * rod_circumference + 0.5 * wire_circumference / std::cos(theta);
220 else if (subch_type == EChannelType::EDGE)
221 return 0.5 * rod_circumference + 0.5 * wire_circumference / std::cos(theta) + _pitch;
222 else
223 return (rod_circumference + wire_circumference / std::cos(theta)) / 6.0 +
224 2.0 / std::sqrt(3.0) * (_pin_diameter / 2.0 + _duct_to_pin_gap);
225}
226
227unsigned int
229{
231
232 return this->pinIndex(p);
233}
234
235unsigned int
236TriSubChannelMesh::pinIndex(const Point & p) const
237{
239
240 // Define the current ring
241 Real distance_rod;
242 Real d0 = 1e5;
243 unsigned int current_rod = 0;
244
245 std::vector<Point> positions;
246 Point center(0, 0);
247 this->pinPositions(positions, _n_rings, _pitch, center);
248 for (unsigned int i = 0; i < _npins; i++)
249 {
250 Real x_dist = positions[i](0) - p(0);
251 Real y_dist = positions[i](1) - p(1);
252 distance_rod = std::sqrt(std::pow(x_dist, 2) + std::pow(y_dist, 2));
253 if (distance_rod < d0)
254 {
255 d0 = distance_rod;
256 current_rod = i;
257 }
258 }
259
260 return current_rod;
261}
262
263void
264TriSubChannelMesh::pinPositions(std::vector<Point> & positions,
265 unsigned int nrings,
266 Real pitch,
267 Point center)
268{
270 // distance: it is the distance to the next Pin
271 //
272 Real theta = 0.0;
273 Real dtheta = 0.0;
274 Real distance = 0.0;
275 Real theta1 = 0.0;
276 Real theta_corrected = 0.0;
277 Real pi = libMesh::pi;
278 unsigned int k = 0;
279 positions.emplace_back(center(0), center(1));
280 for (unsigned int i = 1; i < nrings; i++)
281 {
282 dtheta = 2.0 * pi / (i * 6);
283 theta = 0.0;
284 for (unsigned int j = 0; j < i * 6; j++)
285 {
286 k = k + 1;
287 theta1 = fmod(theta + 1.0e-10, pi / 3.0);
288 distance = std::sqrt((pow(i * pitch, 2) + pow(theta1 / dtheta * pitch, 2) -
289 2.0 * i * pitch * (theta1 / dtheta * pitch) * std::cos(pi / 3.0)));
290 double argument = 1.0 / (i * pitch) / distance / 2.0 *
291 (std::pow(i * pitch, 2.0) + std::pow(distance, 2.0) -
292 std::pow(theta1 / dtheta * pitch, 2.0));
293 // Check if the argument to std::acos() is within the valid range [-1, 1]
294 if (argument >= -1.0 && argument <= 1.0)
295 {
296 theta_corrected = std::acos(argument);
297 }
298 else if (argument > 1.0)
299 {
300 theta_corrected = 0.0;
301 }
302 else
303 {
304 theta_corrected = pi;
305 }
306 if (theta1 < 1.0e-6)
307 {
308 theta_corrected = theta;
309 }
310 else
311 {
312 if (theta > pi / 3.0 && theta <= 2.0 / 3.0 * pi)
313 theta_corrected = theta_corrected + pi / 3.0;
314 else if (theta > 2.0 / 3.0 * pi && theta <= pi)
315 theta_corrected = theta_corrected + 2.0 / 3.0 * pi;
316 else if (theta > pi && theta <= 4.0 / 3.0 * pi)
317 theta_corrected = theta_corrected + pi;
318 else if (theta > 4.0 / 3.0 * pi && theta <= 5.0 / 3.0 * pi)
319 theta_corrected = theta_corrected + 4.0 / 3.0 * pi;
320 else if (theta > 5.0 / 3.0 * pi && theta <= 2.0 * pi)
321 theta_corrected = theta_corrected + 5.0 / 3.0 * pi;
322 }
323 positions.emplace_back(center(0) + distance * std::cos(theta_corrected),
324 center(1) + distance * std::sin(theta_corrected));
325 theta = theta + dtheta;
326 } // j
327 } // i
328}
ExpressionBuilder::EBTerm pow(const ExpressionBuilder::EBTerm &left, T exponent)
const Real p
Point center
registerMooseObject("SubChannelApp", TriSubChannelMesh)
std::unique_ptr< T > copyConstruct(const T &object)
void addClassDescription(const std::string &doc_string)
Factory & getFactory()
const std::string & name() const
void mooseError(Args &&... args) const
MooseApp & _app
Base class for subchannel meshes.
std::vector< unsigned int > _index_blockage
index of subchannels affected by blockage
std::vector< Real > _z_grid
axial location of nodes
Real _assembly_wetted_perimeter
Undeformed bundle inlet wetted perimeter.
std::vector< Real > _reduction_blockage
area reduction of subchannels affected by blockage
static InputParameters validParams()
std::vector< Real > _z_blockage
axial location of blockage (inlet, outlet) [m]
Real _assembly_flow_area
Undeformed bundle inlet flow area.
std::vector< std::vector< Real > > _subchannel_position
x,y coordinates of the subchannel centroids
Real _pin_diameter
fuel Pin diameter
Real _assembly_hydraulic_diameter
Undeformed bundle-average hydraulic diameter.
Real _pitch
Distance between the neighbor fuel pins, pitch.
Mesh class for triangular, edge and corner subchannels for hexagonal lattice fuel assemblies.
unsigned int _npins
number of fuel pins
unsigned int getPinIndexFromPoint(const Point &p) const override
Return a pin index for a given physical point p
Real _duct_to_pin_gap
the gap thickness between the duct and peripheral fuel pins
Real _dwire
wire diameter
Real _flat_to_flat
the distance between flat surfaces of the duct facing each other
void buildMesh() override
void computeAssemblyHydraulicParameters()
Compute undeformed bundle-average inlet hydraulic quantities from generated mesh geometry.
unsigned int getSubchannelIndexFromPoint(const Point &p) const override
Return a subchannel index for a given physical point p
TriSubChannelMesh(const InputParameters &parameters)
unsigned int pinIndex(const Point &p) const override
unsigned int channelIndex(const Point &point) const override
Real _hwire
wire lead length
std::unique_ptr< MooseMesh > safeClone() const override
Real getSubchannelWettedPerimeter(unsigned int i_chan) const override
Return undeformed wetted perimeter for a subchannel.
static InputParameters validParams()
std::vector< EChannelType > _subch_type
subchannel type
EChannelType getSubchannelType(unsigned int index) const override
Return the type of the subchannel for given subchannel index.
static void pinPositions(std::vector< Point > &positions, unsigned int nrings, Real pitch, Point center)
Calculates and stores the pin positions/centers for a hexagonal assembly containing the given number ...
unsigned int _n_channels
number of subchannels
unsigned int _n_rings
number of fuel-pin rings, counting the center pin as the first ring
Real getSubchannelFlowArea(unsigned int i_chan, Real z) const override
Return undeformed flow area for a subchannel at an axial location, including any blockage reduction.
const Real pi
Real distance(const Point &p)