https://mooseframework.inl.gov
CylindricalGridDivision.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 "MooseMesh.h"
12 #include "FEProblemBase.h"
13 #include "Positions.h"
14 
15 #include "libmesh/elem.h"
16 #include <math.h>
17 
19 
22 {
24  params.addClassDescription(
25  "Divide the mesh along a cylindrical grid. The innermost numbering of divisions is the "
26  "radial bins, then comes the azimuthal bins, then the axial bins");
27 
28  // Definition of the cylinder(s)
29  params.addRequiredParam<Point>("axis_direction", "Direction of the cylinder's axis");
30  params.addRequiredParam<Point>(
31  "azimuthal_start",
32  "Direction of the 0-azimuthal-angle vector, normal to the cylinder's axis");
33  params.addParam<Point>("center",
34  "Point on the cylinder's axis, acting as the center of this local "
35  "R-theta-Z coordinate based division");
36  params.addParam<PositionsName>("center_positions",
37  "Positions of the points on the cylinders' respective axis, "
38  "acting as the center of the local "
39  "R-theta-Z coordinate based divisions");
40 
41  // Spatial bounds of the cylinder(s)
42  params.addRangeCheckedParam<Real>(
43  "r_min", 0, "r_min>=0", "Minimum radial coordinate (for a hollow cylinder)");
44  params.addRequiredRangeCheckedParam<Real>("r_max", "r_max>0", "Maximum radial coordinate");
45  params.addParam<Real>(
46  "cylinder_axial_min", std::numeric_limits<Real>::lowest(), "Minimum axial coordinate");
47  params.addParam<Real>(
48  "cylinder_axial_max", std::numeric_limits<Real>::max(), "Maximum axial coordinate");
49 
50  // Number of bins
51  params.addRequiredRangeCheckedParam<unsigned int>(
52  "n_radial", "n_radial>0", "Number of divisions in the cylinder radial direction");
53  params.addRangeCheckedParam<unsigned int>(
54  "n_azimuthal", 1, "n_azimuthal>0", "Number of divisions in the azimuthal direction");
55  params.addRangeCheckedParam<unsigned int>(
56  "n_axial", 1, "n_axial>0", "Number of divisions in the cylinder axial direction");
57 
58  params.addParam<bool>("assign_domain_outside_grid_to_border",
59  false,
60  "Whether to map the domain outside the grid back to the border of the grid "
61  "(radially or axially)");
62 
63  return params;
64 }
65 
67  : MeshDivision(parameters),
68  _direction(getParam<Point>("axis_direction")),
69  _center(isParamValid("center") ? &getParam<Point>("center") : nullptr),
70  _center_positions(
71  isParamValid("center_positions")
72  ? &_fe_problem->getPositionsObject(getParam<PositionsName>("center_positions"))
73  : nullptr),
74  _azim_dir(getParam<Point>("azimuthal_start")),
75  _min_r(getParam<Real>("r_min")),
76  _max_r(getParam<Real>("r_max")),
77  _min_z(getParam<Real>("cylinder_axial_min")),
78  _max_z(getParam<Real>("cylinder_axial_max")),
79  _n_radial(getParam<unsigned int>("n_radial")),
80  _n_azim(getParam<unsigned int>("n_azimuthal")),
81  _n_axial(getParam<unsigned int>("n_axial")),
82  _outside_grid_counts_as_border(getParam<bool>("assign_domain_outside_grid_to_border"))
83 {
85 
86  // Check that we know the centers
87  if (!_center && !_center_positions)
88  paramError("center", "You must pass a parameter for the center of the cylindrical frame");
89 
90  // Check axis
91  if (!MooseUtils::absoluteFuzzyEqual(_direction.norm_sq(), 1))
92  paramError("axis_direction", "Axis must have a norm of 1");
93  if (!MooseUtils::absoluteFuzzyEqual(_azim_dir.norm_sq(), 1))
94  paramError("azimuthal_start", "Azimuthal axis must have a norm of 1");
95 
96  // Check non-negative size
97  if (_max_r < _min_r)
98  paramError("r_min", "Maximum radius must be larger than minimum radius");
99  if (_max_z < _min_z)
100  paramError("cylinder_axial_min", "Maximum axial extent must be larger than minimum");
101 
102  // Check non-zero size if subdivided
104  paramError("n_radial", "Zero-thickness cylinder cannot be subdivided radially");
106  paramError("n_axial", "Zero-height cylinder cannot be subdivided axially");
107 
108  // Check non-infinite size if subdivided
109  if ((_min_z == std::numeric_limits<Real>::lowest() ||
111  _n_axial > 1)
112  paramError("n_axial",
113  "Infinite-height cylinder cannot be subdivided axially. Please specify both a "
114  "cylinder axial minimum and maximum extent");
115 }
116 
117 void
119 {
120  if (!_center_positions)
122  else
124 
125  // Check that the grid is well-defined
126  if (_center_positions)
127  {
128  Real min_dist = 2 * _max_r;
130  // Note that if the positions are not co-planar, the distance reported would be bigger but there
131  // could still be an overlap. Looking at min_center_dist is not enough
132  if (MooseUtils::absoluteFuzzyGreaterThan(min_dist, min_center_dist))
133  mooseWarning(
134  "Cylindrical grids centered on the positions are too close to each other (min distance: ",
135  min_center_dist,
136  "), closer than the radial extent of each grid. Mesh division is ill-defined");
137  }
138 
139  // We could alternatively check every point in the mesh but it seems expensive
140  // A bounding box check could also suffice but the cylinders would need to be excessively large to
141  // enclose the entire mesh
142  _mesh_fully_indexed = true;
144  _mesh_fully_indexed = false;
145 }
146 
147 unsigned int
149 {
150  return divisionIndex(elem.vertex_average());
151 }
152 
153 unsigned int
155 {
156  // Compute coordinates of the point in the cylindrical coordinates
157  Point pc;
158  Point in_plane;
159  unsigned int offset = 0;
160  if (_center)
161  {
162  pc(2) = (pt - *_center) * _direction;
163  in_plane = (pt - *_center) - pc(2) * _direction;
164  }
165  else
166  {
167  // If dividing using positions, find the closest position
168  const bool initial = _fe_problem->getCurrentExecuteOnFlag() == EXEC_INITIAL;
169  const auto nearest_center_index = _center_positions->getNearestPositionIndex(pt, initial);
170  offset = nearest_center_index * _n_radial * _n_azim * _n_axial;
171  const auto new_center = _center_positions->getPosition(nearest_center_index, initial);
172  pc(2) = (pt - new_center) * _direction;
173  in_plane = (pt - new_center) - pc(2) * _direction;
174  }
175 
176  pc(0) = in_plane.norm();
177  const Point pi2_dir = _azim_dir.cross(_direction);
178  pc(1) = std::atan2(in_plane * pi2_dir, in_plane * _azim_dir) + libMesh::pi;
179 
181  {
188  }
189 
190  const auto not_found = MooseMeshDivision::INVALID_DIVISION_INDEX;
191  auto ir = not_found, ia = not_found, iz = not_found;
192  const Point widths(_max_r - _min_r, 2 * libMesh::pi, _max_z - _min_z);
193 
194  // Look inside the grid and on the left / back / bottom
195  for (const auto jr : make_range(_n_radial + 1))
196  {
197  const auto border_r = _min_r + widths(0) * jr / _n_radial;
198  if (jr > 0 && jr < _n_radial && MooseUtils::absoluteFuzzyEqual(border_r, pc(0)))
199  mooseWarning(
200  "Querying the division index for a point of a boundary between two regions radially: " +
201  Moose::stringify(pt));
202  if (border_r >= pc(0))
203  {
204  ir = jr > 0 ? jr - 1 : 0;
205  break;
206  }
207  }
208  for (const auto ja : make_range(_n_azim + 1))
209  {
210  const auto border_a = widths(1) * ja / _n_azim;
211  if (ja > 0 && ja < _n_azim && MooseUtils::absoluteFuzzyEqual(border_a, pc(1)))
212  mooseWarning("Querying the division index for a point of a boundary between two regions "
213  "azimuthally : " +
214  Moose::stringify(pt));
215  if (border_a >= pc(1))
216  {
217  ia = ja > 0 ? ja - 1 : 0;
218  break;
219  }
220  }
221  for (const auto jz : make_range(_n_axial + 1))
222  {
223  const auto border_z = _min_z + widths(2) * jz / _n_axial;
224  if (jz > 0 && jz < _n_axial && MooseUtils::absoluteFuzzyEqual(border_z, pc(2)))
225  mooseWarning("Querying the division index for a point of a boundary between two axial "
226  "regions along the cylinder axis: " +
227  Moose::stringify(pt));
228  if (border_z >= pc(2))
229  {
230  iz = jz > 0 ? jz - 1 : 0;
231  break;
232  }
233  }
234 
235  // Look beyond the edges of the grid
237  ir = _n_radial - 1;
239  iz = _n_axial - 1;
240 
241  // Handle edge case on widths
242  if (ir == not_found && MooseUtils::absoluteFuzzyEqual(widths(0), 0))
243  ir = 0;
244  if (iz == not_found && MooseUtils::absoluteFuzzyEqual(widths(2), 0))
245  iz = 0;
246  mooseAssert(ir != not_found, "We should have found a mesh division bin radially");
247  mooseAssert(ia != not_found, "We should have found a mesh division bin azimuthally");
248  mooseAssert(iz != not_found, "We should have found a mesh division bin axially");
249 
250  return offset + ir + _n_radial * ia + iz * _n_radial * _n_azim;
251 }
static InputParameters validParams()
void addRequiredRangeCheckedParam(const std::string &name, const std::string &parsed_function, const std::string &doc_string)
These methods add an range checked parameters.
const unsigned int _n_radial
Number of divisions in the radial direction.
CylindricalGridDivision(const InputParameters &parameters)
bool absoluteFuzzyEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
Function to check whether two variables are equal within an absolute tolerance.
Definition: MooseUtils.h:380
Divides the mesh based on a cylindrical grid.
const Point *const _center
Point at the center of the cylinder, serving as the coordinate frame center.
const Real _min_r
Minimal radial extent of the cylinder.
void paramError(const std::string &param, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
Definition: MooseBase.h:435
const ExecFlagType & getCurrentExecuteOnFlag() const
Return/set the current execution flag.
registerMooseObject("MooseApp", CylindricalGridDivision)
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
const Positions *const _center_positions
Positions giving all the centers of the cylinders, serving as the coordinate frame center...
const Point & getPosition(unsigned int index, bool initial) const
Getter for a single position at a known index.
Definition: Positions.C:59
const bool _outside_grid_counts_as_border
Whether to map outside the grid onto the inner/outer crowns (radially) or top/bottom bins (axially) ...
virtual void initialize() override
Set up any data members that would be necessary to obtain the division indices.
Base class for MeshDivision objects.
Definition: MeshDivision.h:35
void addRequiredParam(const std::string &name, const std::string &doc_string)
This method adds a parameter and documentation string to the InputParameters object that will be extr...
auto max(const L &left, const R &right)
unsigned int getNearestPositionIndex(const Point &target, bool initial) const
Find the nearest Position index for a given point.
Definition: Positions.C:96
const Point _azim_dir
Azimuthal axis direction (angle = 0)
const unsigned int _n_axial
Number of divisions in the cylinder axial direction.
bool absoluteFuzzyLessThan(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
Function to check whether a variable is less than another variable within an absolute tolerance...
Definition: MooseUtils.h:475
unsigned int getNumPositions(bool initial=false) const
}
Definition: Positions.h:37
const Real _max_z
Maximal axial extent of the cylinder.
std::string stringify(const T &t)
conversion to string
Definition: Conversion.h:64
unsigned int INVALID_DIVISION_INDEX
Invalid subdomain id to return when outside the mesh division.
Definition: MeshDivision.h:28
bool _mesh_fully_indexed
Whether the mesh is fully covered / indexed, all elements and points have a valid index...
Definition: MeshDivision.h:77
const unsigned int _n_azim
Number of divisions in the azimuthal direction.
const Point _direction
Axis direction of the cylinder.
void setNumDivisions(const unsigned int ndivs)
Set the number of divisions.
Definition: MeshDivision.h:65
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const FEProblemBase *const _fe_problem
Pointer to the problem, needed to retrieve pointers to various objects.
Definition: MeshDivision.h:71
void mooseWarning(Args &&... args) const
Emits a warning prefixed with object name and type.
Definition: MooseBase.h:295
const Real _max_r
Maximal radial extent of the cylinder.
IntRange< T > make_range(T beg, T end)
bool absoluteFuzzyGreaterEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
Function to check whether a variable is greater than or equal to another variable within an absolute ...
Definition: MooseUtils.h:404
void addClassDescription(const std::string &doc_string)
This method adds a description of the class that will be displayed in the input file syntax dump...
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an optional parameter and a documentation string to the InputParameters object...
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
Real getMinDistanceBetweenPositions() const
Find the minimum distance between positions.
Definition: Positions.C:242
static InputParameters validParams()
Class constructor.
Definition: MeshDivision.C:14
void ErrorVector unsigned int
bool absoluteFuzzyGreaterThan(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
Function to check whether a variable is greater than another variable within an absolute tolerance...
Definition: MooseUtils.h:428
virtual unsigned int divisionIndex(const Point &pt) const override
Return the index of the division to which the point belongs.
const Real _min_z
Minimal axial extent of the cylinder.
const Real pi
const ExecFlagType EXEC_INITIAL
Definition: Moose.C:30