https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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{
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
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
103 if (_n_radial > 1 && MooseUtils::absoluteFuzzyEqual(_min_r, _max_r))
104 paramError("n_radial", "Zero-thickness cylinder cannot be subdivided radially");
105 if (_n_axial > 1 && MooseUtils::absoluteFuzzyEqual(_min_z, _max_z))
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() ||
110 _max_z == std::numeric_limits<Real>::max()) &&
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
117void
119{
122 else
124
125 // Check that the grid is well-defined
127 {
128 Real min_dist = 2 * _max_r;
129 Real min_center_dist = _center_positions->getMinDistanceBetweenPositions();
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))
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
147unsigned int
149{
150 return divisionIndex(elem.vertex_average());
151}
152
153unsigned 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 {
182 if (MooseUtils::absoluteFuzzyLessThan(pc(0), _min_r) ||
183 MooseUtils::absoluteFuzzyGreaterThan(pc(0), _max_r))
185 if (MooseUtils::absoluteFuzzyLessThan(pc(2), _min_z) ||
186 MooseUtils::absoluteFuzzyGreaterThan(pc(2), _max_z))
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)))
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
236 if (MooseUtils::absoluteFuzzyGreaterEqual(pc(0), _max_r))
237 ir = _n_radial - 1;
238 if (MooseUtils::absoluteFuzzyGreaterEqual(pc(2), _max_z))
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}
registerMooseObject("MooseApp", CylindricalGridDivision)
const ExecFlagType EXEC_INITIAL
Definition Moose.C:30
void ErrorVector unsigned int
Divides the mesh based on a cylindrical grid.
virtual unsigned int divisionIndex(const Point &pt) const override
Return the index of the division to which the point belongs.
static InputParameters validParams()
const Real _min_r
Minimal radial extent of the cylinder.
const unsigned int _n_azim
Number of divisions in the azimuthal direction.
const Real _min_z
Minimal axial extent of the cylinder.
const Point *const _center
Point at the center of the cylinder, serving as the coordinate frame center.
const Point _direction
Axis direction of the cylinder.
const unsigned int _n_axial
Number of divisions in the cylinder axial direction.
const unsigned int _n_radial
Number of divisions in the radial direction.
const bool _outside_grid_counts_as_border
Whether to map outside the grid onto the inner/outer crowns (radially) or top/bottom bins (axially)
const Positions *const _center_positions
Positions giving all the centers of the cylinders, serving as the coordinate frame center.
const Real _max_r
Maximal radial extent of the cylinder.
const Real _max_z
Maximal axial extent of the cylinder.
CylindricalGridDivision(const InputParameters &parameters)
const Point _azim_dir
Azimuthal axis direction (angle = 0)
virtual void initialize() override
Set up any data members that would be necessary to obtain the division indices.
const ExecFlagType & getCurrentExecuteOnFlag() const
Return/set the current execution flag.
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
void addRequiredRangeCheckedParam(const std::string &name, const std::string &parsed_function, const std::string &doc_string)
These methods add an range checked parameters.
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 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...
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 addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
Base class for MeshDivision objects.
static InputParameters validParams()
Class constructor.
const FEProblemBase *const _fe_problem
Pointer to the problem, needed to retrieve pointers to various objects.
void setNumDivisions(const unsigned int ndivs)
Set the number of divisions.
bool _mesh_fully_indexed
Whether the mesh is fully covered / indexed, all elements and points have a valid index.
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:457
const Point & getPosition(unsigned int index, bool initial) const
Getter for a single position at a known index.
Definition Positions.C:59
unsigned int getNearestPositionIndex(const Point &target, bool initial) const
Find the nearest Position index for a given point.
Definition Positions.C:96
unsigned int getNumPositions(bool initial=false) const
}
Definition Positions.h:37
Real getMinDistanceBetweenPositions() const
Find the minimum distance between positions.
Definition Positions.C:242
void mooseWarning(Args &&... args) const
unsigned int INVALID_DIVISION_INDEX
Invalid subdomain id to return when outside the mesh division.
std::string stringify(const T &t)
conversion to string
Definition Conversion.h:64
const Real pi