https://mooseframework.inl.gov
SCMTriSubChannelMeshGenerator.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 
11 #include "TriSubChannelMesh.h"
12 #include <cmath>
13 #include "libmesh/edge_edge2.h"
14 #include "libmesh/unstructured_mesh.h"
15 
17 
20 {
22  params.addClassDescription(
23  "Creates a mesh of 1D subchannels in a triangular lattice arrangement");
24  params.addRequiredParam<unsigned int>("n_cells", "The number of cells in the axial direction");
25  params.addRequiredParam<Real>("pitch", "Pitch [m]");
26  params.addRequiredParam<Real>("pin_diameter", "Rod diameter [m]");
27  params.addParam<Real>("unheated_length_entry", 0.0, "Unheated length at entry [m]");
28  params.addRequiredParam<Real>("heated_length", "Heated length [m]");
29  params.addParam<Real>("unheated_length_exit", 0.0, "Unheated length at exit [m]");
30  params.addRequiredParam<unsigned int>("nrings", "Number of fuel Pin rings per assembly [-]");
31  params.addRequiredParam<Real>("flat_to_flat",
32  "Flat to flat distance for the hexagonal assembly [m]");
33  params.addRequiredParam<Real>("dwire", "Wire diameter [m]");
34  params.addRequiredParam<Real>("hwire", "Wire lead length [m]");
35  params.addParam<std::vector<Real>>(
36  "spacer_z", {}, "Axial location of spacers/vanes/mixing_vanes [m]");
37  params.addParam<std::vector<Real>>(
38  "spacer_k", {}, "K-loss coefficient of spacers/vanes/mixing_vanes [-]");
39  params.addParam<Real>("Kij", 0.5, "Lateral form loss coefficient [-]");
40  params.addParam<std::vector<Real>>("z_blockage",
41  std::vector<Real>({0.0, 0.0}),
42  "axial location of blockage (inlet, outlet) [m]");
43  params.addParam<std::vector<unsigned int>>("index_blockage",
44  std::vector<unsigned int>({0}),
45  "index of subchannels affected by blockage");
46  params.addParam<std::vector<Real>>(
47  "reduction_blockage",
48  std::vector<Real>({1.0}),
49  "Area reduction of subchannels affected by blockage (number to muliply the area)");
50  params.addParam<std::vector<Real>>("k_blockage",
51  std::vector<Real>({0.0}),
52  "Form loss coefficient of subchannels affected by blockage");
53  params.addParam<unsigned int>("block_id", 0, "Domain Index");
54  return params;
55 }
56 
58  : MeshGenerator(params),
59  _unheated_length_entry(getParam<Real>("unheated_length_entry")),
60  _heated_length(getParam<Real>("heated_length")),
61  _unheated_length_exit(getParam<Real>("unheated_length_exit")),
62  _block_id(getParam<unsigned int>("block_id")),
63  _spacer_z(getParam<std::vector<Real>>("spacer_z")),
64  _spacer_k(getParam<std::vector<Real>>("spacer_k")),
65  _z_blockage(getParam<std::vector<Real>>("z_blockage")),
66  _index_blockage(getParam<std::vector<unsigned int>>("index_blockage")),
67  _reduction_blockage(getParam<std::vector<Real>>("reduction_blockage")),
68  _k_blockage(getParam<std::vector<Real>>("k_blockage")),
69  _pitch(getParam<Real>("pitch")),
70  _kij(getParam<Real>("Kij")),
71  _pin_diameter(getParam<Real>("pin_diameter")),
72  _n_cells(getParam<unsigned int>("n_cells")),
73  _n_rings(getParam<unsigned int>("nrings")),
74  _flat_to_flat(getParam<Real>("flat_to_flat")),
75  _dwire(getParam<Real>("dwire")),
76  _hwire(getParam<Real>("hwire")),
77  _duct_to_pin_gap(0.5 *
78  (_flat_to_flat - (_n_rings - 1) * _pitch * std::sqrt(3.0) - _pin_diameter))
79 {
80  if (_spacer_z.size() != _spacer_k.size())
81  mooseError(name(), ": Size of vector spacer_z should be equal to size of vector spacer_k");
82 
83  if (_spacer_z.size() &&
85  mooseError(name(), ": Location of spacers should be less than the total bundle length");
86 
87  if (_z_blockage.size() != 2)
88  mooseError(name(), ": Size of vector z_blockage must be 2");
89 
90  if (*max_element(_reduction_blockage.begin(), _reduction_blockage.end()) > 1)
91  mooseError(name(), ": The area reduction of the blocked subchannels cannot be more than 1");
92 
93  if ((_index_blockage.size() != _reduction_blockage.size()) ||
94  (_index_blockage.size() != _k_blockage.size()) ||
95  (_reduction_blockage.size() != _k_blockage.size()))
96  mooseError(name(),
97  ": Size of vectors: index_blockage, reduction_blockage, k_blockage, must be equal "
98  "to eachother");
99 
102 
103  // Defining the total length from 3 axial sections
105 
106  // Defining the position of the spacer grid in the numerical solution array
107  std::vector<int> spacer_cell;
108  for (const auto & elem : _spacer_z)
109  spacer_cell.emplace_back(std::round(elem * _n_cells / L));
110 
111  // Defining the array for axial resistances
112  std::vector<Real> kgrid;
113  kgrid.resize(_n_cells + 1, 0.0);
114 
115  // Summing the spacer resistance to the grid resistance array
116  for (unsigned int index = 0; index < spacer_cell.size(); index++)
117  kgrid[spacer_cell[index]] += _spacer_k[index];
118 
119  // compute the hex mesh variables
120  // -------------------------------------------
121 
122  // x coordinate for the first position
123  Real x0 = 0.0;
124  // y coordinate for the first position
125  Real y0 = 0.0;
126  // x coordinate for the second position
127  Real x1 = 0.0;
128  // y coordinate for the second position dummy variable
129  Real y1 = 0.0;
130  // dummy variable
131  Real a1 = 0.0;
132  // dummy variable
133  Real a2 = 0.0;
134  // average x coordinate
135  Real avg_coor_x = 0.0;
136  // average y coordinate
137  Real avg_coor_y = 0.0;
138  // distance between two points
139  Real dist = 0.0;
140  // distance between two points
141  Real dist0 = 0.0;
142  // integer counter
143  unsigned int kgap = 0;
144  // dummy integer
145  unsigned int icorner = 0;
146  // used to defined global direction of the cross_flow_map coefficients for each subchannel and gap
147  const Real positive_flow = 1.0;
148  // used to defined global direction of the cross_flow_map coefficients for each subchannel and gap
149  const Real negative_flow = -1.0;
150  // the indicator used while setting _gap_to_chan_map array
151  std::vector<std::pair<unsigned int, unsigned int>> gap_fill;
153  _npins = _pin_position.size();
154  // assign the pins to the corresponding rings
155  unsigned int k = 0; // initialize the fuel Pin counter index
156  _pins_in_rings.resize(_n_rings);
157  _pins_in_rings[0].push_back(k++);
158  for (unsigned int i = 1; i < _n_rings; i++)
159  for (unsigned int j = 0; j < i * 6; j++)
160  _pins_in_rings[i].push_back(k++);
161  // Given the number of pins and number of fuel Pin rings, the number of subchannels can be
162  // computed as follows:
163  unsigned int chancount = 0.0;
164  // Summing internal channels
165  for (unsigned int j = 0; j < _n_rings - 1; j++)
166  chancount += j * 6;
167  // Adding external channels to the total count
168  _n_channels = chancount + _npins - 1 + (_n_rings - 1) * 6 + 6;
169 
170  if (*max_element(_index_blockage.begin(), _index_blockage.end()) > (_n_channels - 1))
171  mooseError(name(),
172  ": The index of the blocked subchannel cannot be more than the max index of the "
173  "subchannels");
174 
175  if ((_index_blockage.size() > _n_channels) || (_reduction_blockage.size() > _n_channels) ||
176  (_k_blockage.size() > _n_channels))
177  mooseError(name(),
178  ": Size of vectors: index_blockage, reduction_blockage, k_blockage, cannot be more "
179  "than the total number of subchannels");
180 
181  // Defining the 2D array for axial resistances
182  _k_grid.resize(_n_channels, std::vector<Real>(_n_cells + 1));
183  for (unsigned int i = 0; i < _n_channels; i++)
184  _k_grid[i] = kgrid;
185 
186  // Add blockage resistance to the 2D grid resistane array
187  Real dz = L / _n_cells;
188  for (unsigned int i = 0; i < _n_cells + 1; i++)
189  {
190  if ((dz * i >= _z_blockage.front() && dz * i <= _z_blockage.back()))
191  {
192  unsigned int index(0);
193  for (const auto & i_ch : _index_blockage)
194  {
195  _k_grid[i_ch][i] += _k_blockage[index];
196  index++;
197  }
198  }
199  }
200 
202  _pin_to_chan_map.resize(_npins);
203  _subch_type.resize(_n_channels);
204  _n_gaps = _n_channels + _npins - 1;
205  _gap_to_chan_map.resize(_n_gaps);
206  _gap_to_pin_map.resize(_n_gaps);
207  gap_fill.resize(_n_gaps);
209  _gap_pairs_sf.resize(_n_channels);
210  _chan_pairs_sf.resize(_n_channels);
211  _gij_map.resize(_n_cells + 1);
213  _gap_type.resize(_n_gaps);
215 
216  for (unsigned int i = 0; i < _n_channels; i++)
217  {
218  _chan_to_pin_map[i].reserve(3);
219  _chan_to_gap_map[i].reserve(3);
220  _sign_id_crossflow_map[i].reserve(3);
221  _subchannel_position[i].reserve(3);
222  for (unsigned int j = 0; j < 3; j++)
223  {
224  _sign_id_crossflow_map.at(i).push_back(positive_flow);
225  _subchannel_position.at(i).push_back(0.0);
226  }
227  }
228 
229  for (unsigned int iz = 0; iz < _n_cells + 1; iz++)
230  {
231  _gij_map[iz].reserve(_n_gaps);
232  }
233 
234  for (unsigned int i = 0; i < _npins; i++)
235  _pin_to_chan_map[i].reserve(6);
236 
237  // create the subchannels
238  k = 0; // initialize the subchannel counter index
239  kgap = 0;
240  // for each ring we trace the subchannels by pairing up to neighbor pins and looking for the third
241  // Pin at inner or outer ring compared to the current ring.
242  for (unsigned int i = 1; i < _n_rings; i++)
243  {
244  // find the closest Pin at back ring
245  for (unsigned int j = 0; j < _pins_in_rings[i].size(); j++)
246  {
247  if (j == _pins_in_rings[i].size() - 1)
248  {
249  _chan_to_pin_map[k].push_back(_pins_in_rings[i][j]);
250  _chan_to_pin_map[k].push_back(_pins_in_rings[i][0]);
251  avg_coor_x =
252  0.5 * (_pin_position[_pins_in_rings[i][j]](0) + _pin_position[_pins_in_rings[i][0]](0));
253  avg_coor_y =
254  0.5 * (_pin_position[_pins_in_rings[i][j]](1) + _pin_position[_pins_in_rings[i][0]](1));
255  _gap_to_pin_map[kgap].first = _pins_in_rings[i][0];
256  _gap_to_pin_map[kgap].second = _pins_in_rings[i][j];
258  kgap = kgap + 1;
259  }
260  else
261  {
262  _chan_to_pin_map[k].push_back(_pins_in_rings[i][j]);
263  _chan_to_pin_map[k].push_back(_pins_in_rings[i][j + 1]);
264  avg_coor_x = 0.5 * (_pin_position[_pins_in_rings[i][j]](0) +
265  _pin_position[_pins_in_rings[i][j + 1]](0));
266  avg_coor_y = 0.5 * (_pin_position[_pins_in_rings[i][j]](1) +
267  _pin_position[_pins_in_rings[i][j + 1]](1));
268  _gap_to_pin_map[kgap].first = _pins_in_rings[i][j];
269  _gap_to_pin_map[kgap].second = _pins_in_rings[i][j + 1];
271  kgap = kgap + 1;
272  }
273 
274  dist0 = 1.0e+5;
275 
276  _chan_to_pin_map[k].push_back(_pins_in_rings[i - 1][0]);
277  unsigned int l0 = 0;
278 
279  for (unsigned int l = 0; l < _pins_in_rings[i - 1].size(); l++)
280  {
281  dist = std::sqrt(pow(_pin_position[_pins_in_rings[i - 1][l]](0) - avg_coor_x, 2) +
282  pow(_pin_position[_pins_in_rings[i - 1][l]](1) - avg_coor_y, 2));
283 
284  if (dist < dist0)
285  {
286  _chan_to_pin_map[k][2] = _pins_in_rings[i - 1][l];
287  l0 = l;
288  dist0 = dist;
289  } // if
290  } // l
291 
292  _gap_to_pin_map[kgap].first = _pins_in_rings[i][j];
293  _gap_to_pin_map[kgap].second = _pins_in_rings[i - 1][l0];
295  kgap = kgap + 1;
297  k = k + 1;
298 
299  } // for j
300 
301  // find the closest Pin at front ring
302 
303  for (unsigned int j = 0; j < _pins_in_rings[i].size(); j++)
304  {
305  if (j == _pins_in_rings[i].size() - 1)
306  {
307  _chan_to_pin_map[k].push_back(_pins_in_rings[i][j]);
308  _chan_to_pin_map[k].push_back(_pins_in_rings[i][0]);
309  avg_coor_x =
310  0.5 * (_pin_position[_pins_in_rings[i][j]](0) + _pin_position[_pins_in_rings[i][0]](0));
311  avg_coor_y =
312  0.5 * (_pin_position[_pins_in_rings[i][j]](1) + _pin_position[_pins_in_rings[i][0]](1));
313  }
314  else
315  {
316  _chan_to_pin_map[k].push_back(_pins_in_rings[i][j]);
317  _chan_to_pin_map[k].push_back(_pins_in_rings[i][j + 1]);
318  avg_coor_x = 0.5 * (_pin_position[_pins_in_rings[i][j]](0) +
319  _pin_position[_pins_in_rings[i][j + 1]](0));
320  avg_coor_y = 0.5 * (_pin_position[_pins_in_rings[i][j]](1) +
321  _pin_position[_pins_in_rings[i][j + 1]](1));
322  }
323 
324  // if the outermost ring, set the edge subchannels first... then the corner subchannels
325  if (i == _n_rings - 1)
326  {
327  // add edges
328  _subch_type[k] = EChannelType::EDGE; // an edge subchannel is created
329  _gap_to_pin_map[kgap].first = _pins_in_rings[i][j];
330  _gap_to_pin_map[kgap].second = _pins_in_rings[i][j];
332  _chan_to_gap_map[k].push_back(kgap);
333  kgap = kgap + 1;
334  k = k + 1;
335 
336  if (j % i == 0)
337  {
338  // generate a corner subchannel, generate the additional gap and fix chan_to_gap_map
339  _gap_to_pin_map[kgap].first = _pins_in_rings[i][j];
340  _gap_to_pin_map[kgap].second = _pins_in_rings[i][j];
342 
343  // corner subchannel
344  _chan_to_pin_map[k].push_back(_pins_in_rings[i][j]);
345  _chan_to_gap_map[k].push_back(kgap - 1);
346  _chan_to_gap_map[k].push_back(kgap);
348 
349  kgap = kgap + 1;
350  k = k + 1;
351  }
352  // if not the outer most ring
353  }
354  else
355  {
356  dist0 = 1.0e+5;
357  unsigned int l0 = 0;
358  _chan_to_pin_map[k].push_back(_pins_in_rings[i + 1][0]);
359  for (unsigned int l = 0; l < _pins_in_rings[i + 1].size(); l++)
360  {
361  dist = std::sqrt(pow(_pin_position[_pins_in_rings[i + 1][l]](0) - avg_coor_x, 2) +
362  pow(_pin_position[_pins_in_rings[i + 1][l]](1) - avg_coor_y, 2));
363  if (dist < dist0)
364  {
365  _chan_to_pin_map[k][2] = _pins_in_rings[i + 1][l];
366  dist0 = dist;
367  l0 = l;
368  } // if
369  } // l
370 
371  _gap_to_pin_map[kgap].first = _pins_in_rings[i][j];
372  _gap_to_pin_map[kgap].second = _pins_in_rings[i + 1][l0];
374  kgap = kgap + 1;
376  k = k + 1;
377  } // if
378  } // for j
379  } // for i
380 
381  // Constructing pins to channels mao
382  for (unsigned int loc_rod = 0; loc_rod < _npins; loc_rod++)
383  {
384  for (unsigned int i = 0; i < _n_channels; i++)
385  {
386  bool rod_in_sc = false;
387  for (unsigned int j : _chan_to_pin_map[i])
388  {
389  if (j == loc_rod)
390  rod_in_sc = true;
391  }
392  if (rod_in_sc)
393  {
394  _pin_to_chan_map[loc_rod].push_back(i);
395  }
396  }
397  }
398 
399  // find the _gap_to_chan_map and _chan_to_gap_map using the gap_to_rod and subchannel_to_rod_maps
400 
401  for (unsigned int i = 0; i < _n_channels; i++)
402  {
404  {
405  for (unsigned int j = 0; j < _n_gaps; j++)
406  {
408  {
409  if (((_chan_to_pin_map[i][0] == _gap_to_pin_map[j].first) &&
410  (_chan_to_pin_map[i][1] == _gap_to_pin_map[j].second)) ||
411  ((_chan_to_pin_map[i][0] == _gap_to_pin_map[j].second) &&
412  (_chan_to_pin_map[i][1] == _gap_to_pin_map[j].first)))
413  {
414  _chan_to_gap_map[i].push_back(j);
415  }
416 
417  if (((_chan_to_pin_map[i][0] == _gap_to_pin_map[j].first) &&
418  (_chan_to_pin_map[i][2] == _gap_to_pin_map[j].second)) ||
419  ((_chan_to_pin_map[i][0] == _gap_to_pin_map[j].second) &&
420  (_chan_to_pin_map[i][2] == _gap_to_pin_map[j].first)))
421  {
422  _chan_to_gap_map[i].push_back(j);
423  }
424 
425  if (((_chan_to_pin_map[i][1] == _gap_to_pin_map[j].first) &&
426  (_chan_to_pin_map[i][2] == _gap_to_pin_map[j].second)) ||
427  ((_chan_to_pin_map[i][1] == _gap_to_pin_map[j].second) &&
428  (_chan_to_pin_map[i][2] == _gap_to_pin_map[j].first)))
429  {
430  _chan_to_gap_map[i].push_back(j);
431  }
432  }
433  } // for j
434  }
435  else if (_subch_type[i] == EChannelType::EDGE)
436  {
437  for (unsigned int j = 0; j < _n_gaps; j++)
438  {
440  {
441  if (((_chan_to_pin_map[i][0] == _gap_to_pin_map[j].first) &&
442  (_chan_to_pin_map[i][1] == _gap_to_pin_map[j].second)) ||
443  ((_chan_to_pin_map[i][0] == _gap_to_pin_map[j].second) &&
444  (_chan_to_pin_map[i][1] == _gap_to_pin_map[j].first)))
445  {
446  _chan_to_gap_map[i].push_back(j);
447  }
448  }
449  }
450 
451  icorner = 0;
452  for (unsigned int k = 0; k < _n_channels; k++)
453  {
455  _chan_to_pin_map[i][1] == _chan_to_pin_map[k][0])
456  {
457  _chan_to_gap_map[i].push_back(_chan_to_gap_map[k][1]);
458  icorner = 1;
459  break;
460  } // if
461  } // for
462 
463  for (unsigned int k = 0; k < _n_channels; k++)
464  {
466  _chan_to_pin_map[i][0] == _chan_to_pin_map[k][0])
467  {
468  _chan_to_gap_map[i].push_back(_chan_to_gap_map[k][1] + 1);
469  icorner = 1;
470  break;
471  }
472  }
473 
474  if (icorner == 0)
475  {
476  _chan_to_gap_map[i].push_back(_chan_to_gap_map[i][0] + 1);
477  }
478  }
479  }
480 
481  // find gap_to_chan_map pair
482 
483  for (unsigned int j = 0; j < _n_gaps; j++)
484  {
485  for (unsigned int i = 0; i < _n_channels; i++)
486  {
488  {
489  if ((j == _chan_to_gap_map[i][0]) || (j == _chan_to_gap_map[i][1]) ||
490  (j == _chan_to_gap_map[i][2]))
491  {
492  if (_gap_to_chan_map[j].first == 0 && gap_fill[j].first == 0)
493  {
494  _gap_to_chan_map[j].first = i;
495  gap_fill[j].first = 1;
496  }
497  else if (_gap_to_chan_map[j].second == 0 && gap_fill[j].second == 0)
498  {
499  _gap_to_chan_map[j].second = i;
500  gap_fill[j].second = 1;
501  }
502  else
503  {
504  }
505  }
506  }
507  else if (_subch_type[i] == EChannelType::CORNER)
508  {
509  if ((j == _chan_to_gap_map[i][0]) || (j == _chan_to_gap_map[i][1]))
510  {
511  if (_gap_to_chan_map[j].first == 0 && gap_fill[j].first == 0)
512  {
513  _gap_to_chan_map[j].first = i;
514  gap_fill[j].first = 1;
515  }
516  else if (_gap_to_chan_map[j].second == 0 && gap_fill[j].second == 0)
517  {
518  _gap_to_chan_map[j].second = i;
519  gap_fill[j].second = 1;
520  }
521  else
522  {
523  }
524  }
525  }
526  } // i
527  } // j
528 
529  for (unsigned int k = 0; k < _n_channels; k++)
530  {
532  {
533  _gap_pairs_sf[k].first = _chan_to_gap_map[k][0];
534  _gap_pairs_sf[k].second = _chan_to_gap_map[k][2];
535  auto k1 = _gap_pairs_sf[k].first;
536  auto k2 = _gap_pairs_sf[k].second;
537  if (_gap_to_chan_map[k1].first == k)
538  {
539  _chan_pairs_sf[k].first = _gap_to_chan_map[k1].second;
540  }
541  else
542  {
543  _chan_pairs_sf[k].first = _gap_to_chan_map[k1].first;
544  }
545 
546  if (_gap_to_chan_map[k2].first == k)
547  {
548  _chan_pairs_sf[k].second = _gap_to_chan_map[k2].second;
549  }
550  else
551  {
552  _chan_pairs_sf[k].second = _gap_to_chan_map[k2].first;
553  }
554  }
555  else if (_subch_type[k] == EChannelType::CORNER)
556  {
557  _gap_pairs_sf[k].first = _chan_to_gap_map[k][1];
558  _gap_pairs_sf[k].second = _chan_to_gap_map[k][0];
559 
560  auto k1 = _gap_pairs_sf[k].first;
561  auto k2 = _gap_pairs_sf[k].second;
562 
563  if (_gap_to_chan_map[k1].first == k)
564  {
565  _chan_pairs_sf[k].first = _gap_to_chan_map[k1].second;
566  }
567  else
568  {
569  _chan_pairs_sf[k].first = _gap_to_chan_map[k1].first;
570  }
571 
572  if (_gap_to_chan_map[k2].first == k)
573  {
574  _chan_pairs_sf[k].second = _gap_to_chan_map[k2].second;
575  }
576  else
577  {
578  _chan_pairs_sf[k].second = _gap_to_chan_map[k2].first;
579  }
580  }
581  }
582 
583  // set the _gij_map
584  for (unsigned int iz = 0; iz < _n_cells + 1; iz++)
585  {
586  for (unsigned int i_gap = 0; i_gap < _n_gaps; i_gap++)
587  {
588  if (_gap_type[i_gap] == EChannelType::CENTER)
589  {
590  _gij_map[iz].push_back(_pitch - _pin_diameter);
591  }
592  else if (_gap_type[i_gap] == EChannelType::EDGE || _gap_type[i_gap] == EChannelType::CORNER)
593  {
594  _gij_map[iz].push_back(_duct_to_pin_gap);
595  }
596  }
597  }
598 
599  for (unsigned int i = 0; i < _n_channels; i++)
600  {
602  {
603  for (unsigned int k = 0; k < 3; k++)
604  {
605  for (unsigned int j = 0; j < _n_gaps; j++)
606  {
607  if (_chan_to_gap_map[i][k] == j && i == _gap_to_chan_map[j].first)
608  {
609  if (i > _gap_to_chan_map[j].second)
610  {
611  _sign_id_crossflow_map[i][k] = negative_flow;
612  }
613  else
614  {
615  _sign_id_crossflow_map[i][k] = positive_flow;
616  }
617  }
618  else if (_chan_to_gap_map[i][k] == j && i == _gap_to_chan_map[j].second)
619  {
620  if (i > _gap_to_chan_map[j].first)
621  {
622  _sign_id_crossflow_map[i][k] = negative_flow;
623  }
624  else
625  {
626  _sign_id_crossflow_map[i][k] = positive_flow;
627  }
628  }
629  } // j
630  } // k
631  }
632  else if (_subch_type[i] == EChannelType::CORNER)
633  {
634  for (unsigned int k = 0; k < 2; k++)
635  {
636  for (unsigned int j = 0; j < _n_gaps; j++)
637  {
638  if (_chan_to_gap_map[i][k] == j && i == _gap_to_chan_map[j].first)
639  {
640  if (i > _gap_to_chan_map[j].second)
641  {
642  _sign_id_crossflow_map[i][k] = negative_flow;
643  }
644  else
645  {
646  _sign_id_crossflow_map[i][k] = positive_flow;
647  }
648  }
649  else if (_chan_to_gap_map[i][k] == j && i == _gap_to_chan_map[j].second)
650  {
651  if (i > _gap_to_chan_map[j].first)
652  {
653  _sign_id_crossflow_map[i][k] = negative_flow;
654  }
655  else
656  {
657  _sign_id_crossflow_map[i][k] = positive_flow;
658  }
659  }
660  } // j
661  } // k
662  } // subch_type =2
663  } // i
664 
665  // set the subchannel positions
666  for (unsigned int i = 0; i < _n_channels; i++)
667  {
669  {
670  _subchannel_position[i][0] =
672  _pin_position[_chan_to_pin_map[i][2]](0)) /
673  3.0;
674  _subchannel_position[i][1] =
676  _pin_position[_chan_to_pin_map[i][2]](1)) /
677  3.0;
678  }
679  else if (_subch_type[i] == EChannelType::EDGE)
680  {
681  for (unsigned int j = 0; j < _n_channels; j++)
682  {
684  ((_chan_to_pin_map[i][0] == _chan_to_pin_map[j][0] &&
685  _chan_to_pin_map[i][1] == _chan_to_pin_map[j][1]) ||
686  (_chan_to_pin_map[i][0] == _chan_to_pin_map[j][1] &&
687  _chan_to_pin_map[i][1] == _chan_to_pin_map[j][0])))
688  {
689  x0 = _pin_position[_chan_to_pin_map[j][2]](0);
690  y0 = _pin_position[_chan_to_pin_map[j][2]](1);
691  }
692  else if (_subch_type[j] == EChannelType::CENTER &&
693  ((_chan_to_pin_map[i][0] == _chan_to_pin_map[j][0] &&
694  _chan_to_pin_map[i][1] == _chan_to_pin_map[j][2]) ||
695  (_chan_to_pin_map[i][0] == _chan_to_pin_map[j][2] &&
696  _chan_to_pin_map[i][1] == _chan_to_pin_map[j][0])))
697  {
698  x0 = _pin_position[_chan_to_pin_map[j][1]](0);
699  y0 = _pin_position[_chan_to_pin_map[j][1]](1);
700  }
701  else if (_subch_type[j] == EChannelType::CENTER &&
702  ((_chan_to_pin_map[i][0] == _chan_to_pin_map[j][1] &&
703  _chan_to_pin_map[i][1] == _chan_to_pin_map[j][2]) ||
704  (_chan_to_pin_map[i][0] == _chan_to_pin_map[j][2] &&
705  _chan_to_pin_map[i][1] == _chan_to_pin_map[j][1])))
706  {
707  x0 = _pin_position[_chan_to_pin_map[j][0]](0);
708  y0 = _pin_position[_chan_to_pin_map[j][0]](1);
709  }
710  x1 = 0.5 *
712  y1 = 0.5 *
714  a1 = _pin_diameter / 2.0 + _duct_to_pin_gap / 2.0;
715  a2 = std::sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)) + a1;
716  _subchannel_position[i][0] = (a2 * x1 - a1 * x0) / (a2 - a1);
717  _subchannel_position[i][1] = (a2 * y1 - a1 * y0) / (a2 - a1);
718  } // j
719  }
720  else if (_subch_type[i] == EChannelType::CORNER)
721  {
722  x0 = _pin_position[0](0);
723  y0 = _pin_position[0](1);
724  x1 = _pin_position[_chan_to_pin_map[i][0]](0);
725  y1 = _pin_position[_chan_to_pin_map[i][0]](1);
726  a1 = _pin_diameter / 2.0 + _duct_to_pin_gap / 2.0;
727  a2 = std::sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)) + a1;
728  _subchannel_position[i][0] = (a2 * x1 - a1 * x0) / (a2 - a1);
729  _subchannel_position[i][1] = (a2 * y1 - a1 * y0) / (a2 - a1);
730  }
731  }
732 
734  if (_n_rings == 1)
735  {
736  for (unsigned int i = 0; i < _n_channels; i++)
737  {
738  Real angle = (2 * i + 1) * libMesh::pi / 6.0;
740  _subchannel_position[i][0] = std::cos(angle) * _flat_to_flat / 2.0;
741  _subchannel_position[i][1] = std::sin(angle) * _flat_to_flat / 2.0;
742  }
743  }
744 
745  // Reduce reserved memory in the channel-to-gap map.
746  for (auto & gap : _chan_to_gap_map)
747  {
748  gap.shrink_to_fit();
749  }
750 }
751 
752 std::unique_ptr<MeshBase>
754 {
755  auto mesh_base = buildMeshBaseObject();
756 
757  BoundaryInfo & boundary_info = mesh_base->get_boundary_info();
758  mesh_base->set_spatial_dimension(3);
759  mesh_base->reserve_elem(_n_cells * _n_channels);
760  mesh_base->reserve_nodes((_n_cells + 1) * _n_channels);
761  _nodes.resize(_n_channels);
762  // Add the points for the give x,y subchannel positions. The grid is hexagonal.
763  // The grid along
764  // z is irregular to account for Pin spacers. Store pointers in the _nodes
765  // array so we can keep track of which points are in which channels.
766  unsigned int node_id = 0;
767  for (unsigned int i = 0; i < _n_channels; i++)
768  {
769  _nodes[i].reserve(_n_cells + 1);
770  for (unsigned int iz = 0; iz < _n_cells + 1; iz++)
771  {
772  _nodes[i].push_back(mesh_base->add_point(
773  Point(_subchannel_position[i][0], _subchannel_position[i][1], _z_grid[iz]), node_id++));
774  }
775  }
776 
777  // Add the elements which in this case are 2-node edges that link each
778  // subchannel's nodes vertically.
779  unsigned int elem_id = 0;
780  for (unsigned int i = 0; i < _n_channels; i++)
781  {
782  for (unsigned int iz = 0; iz < _n_cells; iz++)
783  {
784  Elem * elem = new Edge2;
785  elem->set_id(elem_id++);
786  elem = mesh_base->add_elem(elem);
787  const int indx1 = (_n_cells + 1) * i + iz;
788  const int indx2 = (_n_cells + 1) * i + (iz + 1);
789  elem->set_node(0, mesh_base->node_ptr(indx1));
790  elem->set_node(1, mesh_base->node_ptr(indx2));
791 
792  if (iz == 0)
793  boundary_info.add_side(elem, 0, 0);
794  if (iz == _n_cells - 1)
795  boundary_info.add_side(elem, 1, 1);
796  }
797  }
798  boundary_info.sideset_name(0) = "inlet";
799  boundary_info.sideset_name(1) = "outlet";
800  boundary_info.nodeset_name(0) = "inlet";
801  boundary_info.nodeset_name(1) = "outlet";
802 
803  // Naming the block
804  mesh_base->subdomain_name(_block_id) = name();
805 
806  mesh_base->prepare_for_use();
807 
808  // move the meta data into TriSubChannelMesh
809  auto & sch_mesh = static_cast<TriSubChannelMesh &>(*_mesh);
811  sch_mesh._heated_length = _heated_length;
812  sch_mesh._unheated_length_exit = _unheated_length_exit;
813  sch_mesh._z_grid = _z_grid;
814  sch_mesh._k_grid = _k_grid;
815  sch_mesh._spacer_z = _spacer_z;
816  sch_mesh._spacer_k = _spacer_k;
817  sch_mesh._z_blockage = _z_blockage;
818  sch_mesh._index_blockage = _index_blockage;
819  sch_mesh._reduction_blockage = _reduction_blockage;
820  sch_mesh._kij = _kij;
821  sch_mesh._pitch = _pitch;
822  sch_mesh._pin_diameter = _pin_diameter;
823  sch_mesh._n_cells = _n_cells;
824  sch_mesh._n_rings = _n_rings;
825  sch_mesh._n_channels = _n_channels;
826  sch_mesh._flat_to_flat = _flat_to_flat;
827  sch_mesh._dwire = _dwire;
828  sch_mesh._hwire = _hwire;
829  sch_mesh._duct_to_pin_gap = _duct_to_pin_gap;
830  sch_mesh._nodes = _nodes;
831  sch_mesh._gap_to_chan_map = _gap_to_chan_map;
832  sch_mesh._gap_to_pin_map = _gap_to_pin_map;
833  sch_mesh._chan_to_gap_map = _chan_to_gap_map;
834  sch_mesh._sign_id_crossflow_map = _sign_id_crossflow_map;
835  sch_mesh._gij_map = _gij_map;
836  sch_mesh._subchannel_position = _subchannel_position;
837  sch_mesh._pin_position = _pin_position;
838  sch_mesh._pins_in_rings = _pins_in_rings;
839  sch_mesh._chan_to_pin_map = _chan_to_pin_map;
840  sch_mesh._npins = _npins;
841  sch_mesh._n_gaps = _n_gaps;
842  sch_mesh._subch_type = _subch_type;
843  sch_mesh._gap_type = _gap_type;
844  sch_mesh._gap_pairs_sf = _gap_pairs_sf;
845  sch_mesh._chan_pairs_sf = _chan_pairs_sf;
846  sch_mesh._pin_to_chan_map = _pin_to_chan_map;
847  sch_mesh.computeAssemblyHydraulicParameters();
848 
849  return mesh_base;
850 }
unsigned int _npins
number of fuel pins
std::vector< EChannelType > _gap_type
gap type
std::vector< std::vector< Real > > _pins_in_rings
fuel pins that are belonging to each ring
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
std::vector< std::pair< unsigned int, unsigned int > > _chan_pairs_sf
sweeping flow model channel pairs to specify directional edge flow
std::vector< std::pair< unsigned int, unsigned int > > _gap_to_chan_map
stores the channel pairs for each gap
std::vector< EChannelType > _subch_type
subchannel type
std::vector< std::pair< unsigned int, unsigned int > > _gap_pairs_sf
sweeping flow model gap pairs per channel to specify directional edge flow
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 ...
const unsigned int _n_cells
number of axial cells
std::vector< Real > _z_grid
axial location of nodes
Real _unheated_length_entry
unheated length of the fuel Pin at the entry of the assembly
const std::vector< unsigned int > _index_blockage
index of subchannels affected by blockage
const std::vector< Real > _z_blockage
axial location of blockage (inlet, outlet) [m]
const std::vector< Real > & _spacer_z
axial location of the spacers
const unsigned int _block_id
block index
const Real _flat_to_flat
the distance between flat surfaces of the duct facing each other
void addRequiredParam(const std::string &name, const std::string &doc_string)
unsigned int _n_channels
number of subchannels
std::vector< std::vector< Real > > _sign_id_crossflow_map
Defines the global cross-flow direction -1 or 1 for each subchannel and for all gaps that are belongi...
static void generateZGrid(Real unheated_length_entry, Real heated_length, Real unheated_length_exit, unsigned int n_cells, std::vector< Real > &z_grid)
Generate the spacing in z-direction using heated and unteaded lengths.
const Real _pitch
Distance between the neighbor fuel pins, pitch.
const unsigned int _n_rings
number of rings of fuel pins
const std::string & name() const
const std::vector< Real > _k_blockage
form loss coefficient of subchannels affected by blockage
std::vector< std::vector< Real > > _subchannel_position
x,y coordinates of the subchannel centroids
Mesh class for triangular, edge and corner subchannels for hexagonal lattice fuel assemblies...
std::vector< Point > _pin_position
x,y coordinates of the fuel pins
std::vector< std::vector< Real > > _gij_map
gap size
const Real _pin_diameter
fuel Pin diameter
static InputParameters validParams()
registerMooseObject("SubChannelApp", SCMTriSubChannelMeshGenerator)
const Real _heated_length
heated length of the fuel Pin
Mesh class for triangular, edge and corner subchannels for hexagonal lattice fuel assemblies...
std::vector< std::vector< unsigned int > > _chan_to_pin_map
stores the fuel pins belonging to each subchannel
const std::vector< Real > _reduction_blockage
area reduction of subchannels affected by blockage
const Real _unheated_length_entry
unheated length of the fuel Pin at the entry of the assembly
ExpressionBuilder::EBTerm pow(const ExpressionBuilder::EBTerm &left, T exponent)
std::unique_ptr< MeshBase > generate() override
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
std::vector< std::vector< Real > > _k_grid
axial form loss coefficient per computational cell
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template * sqrt(_arg)) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(tanh
std::vector< std::pair< unsigned int, unsigned int > > _gap_to_pin_map
stores the fuel pin pairs for each gap each gap
void mooseError(Args &&... args) const
SCMTriSubChannelMeshGenerator(const InputParameters &parameters)
const Real _duct_to_pin_gap
the gap thickness between the duct and peripheral fuel pins
void addClassDescription(const std::string &doc_string)
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
const Real & _kij
Lateral form loss coefficient.
std::vector< std::vector< unsigned int > > _pin_to_chan_map
stores the map from pins to channels
std::unique_ptr< MeshBase > buildMeshBaseObject(unsigned int dim=libMesh::invalid_uint)
const std::vector< Real > & _spacer_k
form loss coefficient of the spacers
std::vector< std::vector< Node * > > _nodes
nodes
const Real _unheated_length_exit
unheated length of the fuel Pin at the exit of the assembly
std::vector< std::vector< unsigned int > > _chan_to_gap_map
stores the gaps that forms each subchannel
static const std::string k
Definition: NS.h:134
void ErrorVector unsigned int
const Real pi