https://mooseframework.inl.gov
HexagonalGridDivision.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 "HexagonalGridDivision.h"
11 #include "MooseMesh.h"
12 #include "HexagonalLatticeUtils.h"
13 #include "Positions.h"
14 
15 #include "libmesh/elem.h"
16 
18 
21 {
23  params.addClassDescription(
24  "Divide the mesh along a hexagonal grid. Numbering of pin divisions increases first "
25  "counterclockwise, then expanding outwards from the inner ring, then axially. "
26  "Inner-numbering is within a radial ring, outer-numbering is axial divisions");
27 
28  params.addParam<Point>("center", "Center of the hexagonal grid");
29  params.addParam<PositionsName>("center_positions", "Centers of the hexagonal grids");
30 
32  "lattice_flat_to_flat",
33  "lattice_flat_to_flat>0",
34  "Distance between two (inner) opposite sides of a lattice. Also known as bundle pitch or "
35  "inner flat-to-flat distance");
36  params.addRequiredRangeCheckedParam<Real>("pin_pitch", "pin_pitch>0", "Distance between pins");
37 
38  params.addRequiredParam<Real>("z_min", "Minimal axial extent of the lattice");
39  params.addRequiredParam<Real>("z_max", "Maximum axial extent of the lattice");
40  params.addRequiredRangeCheckedParam<unsigned int>("nr", "nr>0", "Number of hexagonal rings");
41  params.addRequiredRangeCheckedParam<unsigned int>("nz", "nz>0", "Number of divisions in Z");
42  params.addParam<bool>(
43  "assign_domain_outside_grid_to_border",
44  false,
45  "Whether to map the domain outside the grid back to the border of the grid");
46  params.addParam<Real>("rotation_around_axis",
47  0.,
48  "Rotation angle to apply to the underlying hexagonal lattice (in degrees)");
49 
50  return params;
51 }
52 
54  : MeshDivision(parameters),
55  _center(isParamValid("center") ? getParam<Point>("center") : Point(0, 0, 0)),
56  _center_positions(
57  isParamValid("center_positions")
58  ? &_fe_problem->getPositionsObject(getParam<PositionsName>("center_positions"))
59  : nullptr),
60  _lattice_flat_to_flat(getParam<Real>("lattice_flat_to_flat")),
61  _pin_pitch(getParam<Real>("pin_pitch")),
62  _z_axis_index(MooseEnum("X Y Z", "Z")),
63  _min_z(getParam<Real>("z_min")),
64  _max_z(getParam<Real>("z_max")),
65  _nr(getParam<unsigned int>("nr")),
66  _nz(getParam<unsigned int>("nz")),
67  _outside_grid_counts_as_border(getParam<bool>("assign_domain_outside_grid_to_border"))
68 {
70 
71  if (!isParamValid("center") && !_center_positions)
72  paramError("center", "A center must be provided, or a Positions object for the centers");
74  mooseError("lattice_flat_to_flat", "Pin pitch should be smaller than bundle pitch");
76  paramError("nz", "Subdivision number must be 1 if width is 0 in Z direction");
77 }
78 
79 void
81 {
82  // We make very large pins so they cover the entire position
83  _hex_latt = std::make_unique<HexagonalLatticeUtils>(_lattice_flat_to_flat,
84  _pin_pitch,
85  _pin_pitch,
86  0.,
87  1.,
88  _nr,
90  getParam<Real>("rotation_around_axis"));
91 
92  if (!_center_positions)
93  setNumDivisions(_hex_latt->totalPins(_nr) * _nz);
94  else
96 
97  // Check that the grid is well-defined
99  {
100  const Real min_center_dist = _center_positions->getMinDistanceBetweenPositions();
101  // Note that if the positions are not aligned on a hexagonal lattice themselves,
102  // this bound is not sufficiently strict. The simplest example would be non-coplanar
103  // points, which can be a great distance away axially but be on the same axis
105  mooseWarning(
106  "Hexagonal grids centered on the positions are too close to each other (min distance: ",
107  min_center_dist,
108  "), closer than the extent of each grid (",
110  "). Mesh division is ill-defined ");
111  }
112 }
113 
114 unsigned int
115 HexagonalGridDivision::divisionIndex(const Elem & elem) const
116 {
117  return divisionIndex(elem.vertex_average());
118 }
119 
120 unsigned int
122 {
123  unsigned int offset = 0;
124 
125  // Get point in the coordinates of the lattice. This can involve a projection due to
126  // the axis of the lattice, or simply a translation if there are lattices distributed
127  // using positions
128  Point pc;
129  if (_center_positions)
130  {
131  // If dividing using positions, find the closest position and
132  // look at the relative position of the point compared to that position
133  const bool initial = _fe_problem->getCurrentExecuteOnFlag() == EXEC_INITIAL;
134  const auto nearest_grid_center_index = _center_positions->getNearestPositionIndex(pt, initial);
135  offset = nearest_grid_center_index * _hex_latt->totalPins(_nr) * _nz;
136  const auto nearest_grid_center =
137  _center_positions->getPosition(nearest_grid_center_index, initial);
138 
139  // Project in local hexagonal grid
140  pc = pt - nearest_grid_center;
141  }
142  else
143  pc = pt - _center;
144 
145  // Get radial division index, using the channel as the pins are 0-radius
146  // The logic in get pin index requires getting the point in the plane of the pin centers
147  auto ir = _hex_latt->pinIndex(pc);
148  const auto n_pins = _hex_latt->nPins();
149 
151  {
152  if (ir == n_pins)
157  }
158 
159  // If too far from the grid to have a valid radial index, use the closest pin
160  if (ir == n_pins)
161  ir = _hex_latt->closestPinIndex(pc);
162 
163  // Find axial index
164  const auto not_found = MooseMeshDivision::INVALID_DIVISION_INDEX;
165  auto iz = not_found;
166  for (const auto jz : make_range(_nz + 1))
167  {
168  const auto border_z = _min_z + (_max_z - _min_z) * jz / _nz;
169  if (jz > 0 && jz < _nz && MooseUtils::absoluteFuzzyEqual(border_z, pc(_z_axis_index)))
170  mooseWarning(
171  "Querying the division index for a point of a boundary between two regions in Z: " +
172  Moose::stringify(pt),
173  ", in local hex grid frame: ",
174  Moose::stringify(pc));
175  if (border_z >= pc(_z_axis_index))
176  {
177  iz = (jz > 0) ? jz - 1 : 0;
178  break;
179  }
180  }
181 
182  // Look on the top of the grid
184  iz = _nz - 1;
185 
186  // Handle edge case on widths
187  if (iz == not_found && MooseUtils::absoluteFuzzyEqual(_max_z - _min_z, 0))
188  iz = 0;
189  mooseAssert(ir != not_found, "We should have found a mesh division bin radially");
190  mooseAssert(iz != not_found, "We should have found a mesh division bin in Z");
191 
192  const auto n_radial = _hex_latt->totalPins(_nr);
193  return offset + ir + iz * n_radial;
194 }
void addRequiredRangeCheckedParam(const std::string &name, const std::string &parsed_function, const std::string &doc_string)
bool absoluteFuzzyEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
void paramError(const std::string &param, Args... args) const
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
const Point _center
Center of the lattice (single lattice)
const ExecFlagType & getCurrentExecuteOnFlag() const
const unsigned int _nr
Number of rings in the radial direction.
const Positions * _center_positions
Centers of the lattices (lattices centered around positions)
registerMooseObject("ReactorApp", HexagonalGridDivision)
virtual unsigned int divisionIndex(const Point &pt) const override
Divides the mesh based on a hexagonal grid.
const Real _pin_pitch
Pitch between fuel pins.
const Point & getPosition(unsigned int index, bool initial) const
const unsigned int _nz
Number of divisions in the Z direction.
void addRequiredParam(const std::string &name, const std::string &doc_string)
const MooseEnum _z_axis_index
Axial component for the Z axis.
virtual void initialize() override
unsigned int getNearestPositionIndex(const Point &target, bool initial) const
const Real _min_z
Minimal axial coordinate.
HexagonalGridDivision(const InputParameters &parameters)
const bool _outside_grid_counts_as_border
Whether to map outside the grid onto the corner.
bool absoluteFuzzyLessThan(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
unsigned int getNumPositions(bool initial=false) const
const Real _max_z
Maximal axial coordinate.
static InputParameters validParams()
std::string stringify(const T &t)
unsigned int INVALID_DIVISION_INDEX
std::unique_ptr< HexagonalLatticeUtils > _hex_latt
Hexagonal lattice utility object.
void setNumDivisions(const unsigned int ndivs)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const FEProblemBase *const _fe_problem
void mooseWarning(Args &&... args) const
IntRange< T > make_range(T beg, T end)
void mooseError(Args &&... args) const
bool absoluteFuzzyGreaterEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
void addClassDescription(const std::string &doc_string)
bool isParamValid(const std::string &name) const
Real getMinDistanceBetweenPositions() const
static InputParameters validParams()
void ErrorVector unsigned int
bool absoluteFuzzyGreaterThan(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
const Real _lattice_flat_to_flat
Distance from one side to the one facing it of the lattice.
const ExecFlagType EXEC_INITIAL