www.mooseframework.org
AnnularMesh.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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 "AnnularMesh.h"
11 
12 #include "libmesh/face_quad4.h"
13 #include "libmesh/face_tri3.h"
14 
15 registerMooseObject("MooseApp", AnnularMesh);
16 
19 {
21  params.addRangeCheckedParam<unsigned int>(
22  "nr", 1, "nr>0", "Number of elements in the radial direction");
23  params.addRequiredRangeCheckedParam<unsigned int>(
24  "nt", "nt>0", "Number of elements in the angular direction");
26  "rmin",
27  "rmin>=0.0",
28  "Inner radius. If rmin=0 then a disc mesh (with no central hole) will be created.");
29  params.addRequiredParam<Real>("rmax", "Outer radius");
30  params.addDeprecatedParam<Real>("tmin",
31  0.0,
32  "Minimum angle, measured in radians anticlockwise from x axis",
33  "Use dmin instead");
34  params.addDeprecatedParam<Real>(
35  "tmax",
36  2 * M_PI,
37  "Maximum angle, measured in radians anticlockwise from x axis. If "
38  "tmin=0 and tmax=2Pi an annular mesh is created. "
39  "Otherwise, only a sector of an annulus is created",
40  "Use dmin instead");
41  params.addParam<Real>(
42  "dmin", 0.0, "Minimum degree, measured in degrees anticlockwise from x axis");
43  params.addParam<Real>("dmax",
44  360.0,
45  "Maximum angle, measured in degrees anticlockwise from x axis. If "
46  "dmin=0 and dmax=360 an annular mesh is created. "
47  "Otherwise, only a sector of an annulus is created");
48  params.addRangeCheckedParam<Real>(
49  "growth_r", 1.0, "growth_r>0.0", "The ratio of radial sizes of successive rings of elements");
50  params.addParam<SubdomainID>(
51  "quad_subdomain_id", 0, "The subdomain ID given to the QUAD4 elements");
52  params.addParam<SubdomainID>("tri_subdomain_id",
53  1,
54  "The subdomain ID given to the TRI3 elements "
55  "(these exist only if rmin=0, and they exist "
56  "at the center of the disc");
57  params.addClassDescription("For rmin>0: creates an annular mesh of QUAD4 elements. For rmin=0: "
58  "creates a disc mesh of QUAD4 and TRI3 elements. Boundary sidesets "
59  "are created at rmax and rmin, and given these names. If dmin!=0 and "
60  "dmax!=360, a sector of an annulus or disc is created. In this case "
61  "boundary sidesets are also created a dmin and dmax, and "
62  "given these names");
63  return params;
64 }
65 
67  : MooseMesh(parameters),
68  _nr(getParam<unsigned int>("nr")),
69  _nt(getParam<unsigned int>("nt")),
70  _rmin(getParam<Real>("rmin")),
71  _rmax(getParam<Real>("rmax")),
72  _dmin(parameters.isParamSetByUser("tmin") ? getParam<Real>("tmin") / M_PI * 180.0
73  : getParam<Real>("dmin")),
74  _dmax(parameters.isParamSetByUser("tmax") ? getParam<Real>("tmax") / M_PI * 180.0
75  : getParam<Real>("dmax")),
76  _radians((parameters.isParamSetByUser("tmin") || parameters.isParamSetByUser("tmax")) ? true
77  : false),
78  _growth_r(getParam<Real>("growth_r")),
79  _len(_growth_r == 1.0 ? (_rmax - _rmin) / _nr
80  : (_rmax - _rmin) * (1.0 - _growth_r) / (1.0 - std::pow(_growth_r, _nr))),
81  _full_annulus(_dmin == 0.0 && _dmax == 360),
82  _quad_subdomain_id(getParam<SubdomainID>("quad_subdomain_id")),
83  _tri_subdomain_id(getParam<SubdomainID>("tri_subdomain_id")),
84  _dims_may_have_changed(false)
85 {
86  if ((parameters.isParamSetByUser("tmin") || parameters.isParamSetByUser("tmax")) &&
88  paramError("tmin",
89  "You specified the angles using both degrees and radians. Please use degrees.");
90 
91  if (_rmax <= _rmin)
92  paramError("rmax", "rmax must be greater than rmin");
93  if (_dmax <= _dmin)
94  paramError("dmax", "dmax must be greater than dmin");
95  if (_dmax - _dmin > 360)
96  paramError("dmax", "dmax - dmin must be <= 360");
97  if (_nt <= (_dmax - _dmin) / 180.0)
98  paramError("nt",
99  "nt must be greater than (dmax - dmin) / 180 in order to avoid inverted "
100  "elements");
102  paramError("quad_subdomain_id", "quad_subdomain_id must not equal tri_subdomain_id");
103 }
104 
105 void
107 {
108  MooseMesh::prepared(state);
109 
110  // Fall back on scanning the mesh for coordinates instead of using input parameters for queries
111  if (!state)
112  _dims_may_have_changed = true;
113 }
114 
115 Real
116 AnnularMesh::getMinInDimension(unsigned int component) const
117 {
119  return MooseMesh::getMinInDimension(component);
120 
121  switch (component)
122  {
123  case 0:
124  return -_rmax;
125  case 1:
126  return -_rmax;
127  case 2:
128  return 0.0;
129  default:
130  mooseError("Invalid component");
131  }
132 }
133 
134 Real
135 AnnularMesh::getMaxInDimension(unsigned int component) const
136 {
138  return MooseMesh::getMaxInDimension(component);
139 
140  switch (component)
141  {
142  case 0:
143  return _rmax;
144  case 1:
145  return _rmax;
146  case 2:
147  return 0.0;
148  default:
149  mooseError("Invalid component");
150  }
151 }
152 
153 std::unique_ptr<MooseMesh>
155 {
156  return std::make_unique<AnnularMesh>(*this);
157 }
158 
159 void
161 {
162  const Real dt = (_dmax - _dmin) / _nt;
163 
164  MeshBase & mesh = getMesh();
165  mesh.clear();
166  mesh.set_mesh_dimension(2);
167  mesh.set_spatial_dimension(2);
168  BoundaryInfo & boundary_info = mesh.get_boundary_info();
169 
170  const unsigned num_angular_nodes = (_full_annulus ? _nt : _nt + 1);
171  const unsigned num_nodes =
172  (_rmin > 0.0 ? (_nr + 1) * num_angular_nodes : _nr * num_angular_nodes + 1);
173  const unsigned min_nonzero_layer_num = (_rmin > 0.0 ? 0 : 1);
174  std::vector<Node *> nodes(num_nodes);
175  unsigned node_id = 0;
176 
177  // add nodes at rmax that aren't yet connected to any elements
178  Real current_r = _rmax;
179  for (unsigned angle_num = 0; angle_num < num_angular_nodes; ++angle_num)
180  {
181  const Real angle = _dmin + angle_num * dt;
182  const Real x = current_r * std::cos(angle * M_PI / 180.0);
183  const Real y = current_r * std::sin(angle * M_PI / 180.0);
184  nodes[node_id] = mesh.add_point(Point(x, y, 0.0), node_id);
185  node_id++;
186  }
187 
188  // add nodes at smaller radii, and connect them with elements
189  for (unsigned layer_num = _nr; layer_num > min_nonzero_layer_num; --layer_num)
190  {
191  if (layer_num == 1)
192  current_r = _rmin; // account for precision loss
193  else
194  current_r -= _len * std::pow(_growth_r, layer_num - 1);
195 
196  // add node at angle = _dmin
197  nodes[node_id] = mesh.add_point(Point(current_r * std::cos(_dmin * M_PI / 180.0),
198  current_r * std::sin(_dmin * M_PI / 180.0),
199  0.0),
200  node_id);
201  node_id++;
202  for (unsigned angle_num = 1; angle_num < num_angular_nodes; ++angle_num)
203  {
204  const Real angle = _dmin + angle_num * dt;
205  const Real x = current_r * std::cos(angle * M_PI / 180.0);
206  const Real y = current_r * std::sin(angle * M_PI / 180.0);
207  nodes[node_id] = mesh.add_point(Point(x, y, 0.0), node_id);
208  Elem * elem = mesh.add_elem(new Quad4);
209  elem->set_node(0) = nodes[node_id];
210  elem->set_node(1) = nodes[node_id - 1];
211  elem->set_node(2) = nodes[node_id - num_angular_nodes - 1];
212  elem->set_node(3) = nodes[node_id - num_angular_nodes];
213  elem->subdomain_id() = _quad_subdomain_id;
214  node_id++;
215 
216  if (layer_num == _nr)
217  // add outer boundary (boundary_id = 1)
218  boundary_info.add_side(elem, 2, 1);
219  if (layer_num == 1)
220  // add inner boundary (boundary_id = 0)
221  boundary_info.add_side(elem, 0, 0);
222  if (!_full_annulus && angle_num == 1)
223  // add tmin boundary (boundary_id = 2)
224  boundary_info.add_side(elem, 1, 2);
225  if (!_full_annulus && angle_num == num_angular_nodes - 1)
226  // add tmin boundary (boundary_id = 3)
227  boundary_info.add_side(elem, 3, 3);
228  }
229  if (_full_annulus)
230  {
231  // add element connecting to node at angle=0
232  Elem * elem = mesh.add_elem(new Quad4);
233  elem->set_node(0) = nodes[node_id - num_angular_nodes];
234  elem->set_node(1) = nodes[node_id - 1];
235  elem->set_node(2) = nodes[node_id - num_angular_nodes - 1];
236  elem->set_node(3) = nodes[node_id - 2 * num_angular_nodes];
237  elem->subdomain_id() = _quad_subdomain_id;
238 
239  if (layer_num == _nr)
240  // add outer boundary (boundary_id = 1)
241  boundary_info.add_side(elem, 2, 1);
242  if (layer_num == 1)
243  // add inner boundary (boundary_id = 0)
244  boundary_info.add_side(elem, 0, 0);
245  }
246  }
247 
248  // add single node at origin, if relevant
249  if (_rmin == 0.0)
250  {
251  nodes[node_id] = mesh.add_point(Point(0.0, 0.0, 0.0), node_id);
252  boundary_info.add_node(node_id, 0); // boundary_id=0 is centre
253  for (unsigned angle_num = 0; angle_num < num_angular_nodes - 1; ++angle_num)
254  {
255  Elem * elem = mesh.add_elem(new Tri3);
256  elem->set_node(0) = nodes[node_id];
257  elem->set_node(1) = nodes[node_id - num_angular_nodes + angle_num];
258  elem->set_node(2) = nodes[node_id - num_angular_nodes + angle_num + 1];
259  elem->subdomain_id() = _tri_subdomain_id;
260  }
261  if (_full_annulus)
262  {
263  Elem * elem = mesh.add_elem(new Tri3);
264  elem->set_node(0) = nodes[node_id];
265  elem->set_node(1) = nodes[node_id - 1];
266  elem->set_node(2) = nodes[node_id - num_angular_nodes];
267  elem->subdomain_id() = _tri_subdomain_id;
268  }
269  }
270 
271  boundary_info.sideset_name(0) = "rmin";
272  boundary_info.sideset_name(1) = "rmax";
273  boundary_info.nodeset_name(0) = "rmin";
274  boundary_info.nodeset_name(1) = "rmax";
275  if (!_full_annulus)
276  {
277  if (_radians)
278  {
279  boundary_info.sideset_name(2) = "tmin";
280  boundary_info.sideset_name(3) = "tmax";
281  boundary_info.nodeset_name(2) = "tmin";
282  boundary_info.nodeset_name(3) = "tmax";
283  }
284  else
285  {
286  boundary_info.sideset_name(2) = "dmin";
287  boundary_info.sideset_name(3) = "dmax";
288  boundary_info.nodeset_name(2) = "dmin";
289  boundary_info.nodeset_name(3) = "dmax";
290  }
291  }
292 
293  mesh.prepare_for_use();
294 }
virtual std::unique_ptr< MooseMesh > safeClone() const override
A safer version of the clone() method that hands back an allocated object wrapped in a smart pointer...
Definition: AnnularMesh.C:154
static InputParameters validParams()
Typical "Moose-style" constructor and copy constructor.
Definition: MooseMesh.C:78
virtual void buildMesh() override
Must be overridden by child classes.
Definition: AnnularMesh.C:160
static InputParameters validParams()
Definition: AnnularMesh.C:18
virtual Real getMaxInDimension(unsigned int component) const
Definition: MooseMesh.C:1964
virtual Real getMinInDimension(unsigned int component) const
Returns the min or max of the requested dimension respectively.
Definition: MooseMesh.C:1955
bool prepared() const
Setter/getter for whether the mesh is prepared.
Definition: MooseMesh.C:2887
const Real _growth_r
Bias on radial meshing.
Definition: AnnularMesh.h:58
void addRequiredRangeCheckedParam(const std::string &name, const std::string &parsed_function, const std::string &doc_string)
These methods add an range checked parameters.
virtual Real getMinInDimension(unsigned int component) const override
Returns the min or max of the requested dimension respectively.
Definition: AnnularMesh.C:116
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template * sin(_arg) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(tan
const SubdomainID _tri_subdomain_id
Subdomain ID of created tri elements (that only exist if rmin=0)
Definition: AnnularMesh.h:70
void addDeprecatedParam(const std::string &name, const T &value, const std::string &doc_string, const std::string &deprecation_message)
const Real _rmin
Minimum radius.
Definition: AnnularMesh.h:43
const Real _rmax
Maximum radius.
Definition: AnnularMesh.h:46
MeshBase & mesh
const unsigned _nr
Number of elements in radial direction.
Definition: AnnularMesh.h:37
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
AnnularMesh(const InputParameters &parameters)
Definition: AnnularMesh.C:66
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...
const bool _radians
Bool to check if radians are given in the input file.
Definition: AnnularMesh.h:55
registerMooseObject("MooseApp", AnnularMesh)
T pow(const T &x)
const bool _full_annulus
Whether a full annulus (as opposed to a sector) will needs to generate.
Definition: AnnularMesh.h:64
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template cos(_arg) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(cos
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
Definition: MooseMesh.C:3198
const SubdomainID _quad_subdomain_id
Subdomain ID of created quad elements.
Definition: AnnularMesh.h:67
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
Definition: MooseMesh.h:88
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 ...
const Real _len
rmax = rmin + len + len*g + len*g^2 + len*g^3 + ... + len*g^(nr-1) = rmin + len*(1 - g^nr)/(1 - g) ...
Definition: AnnularMesh.h:61
Mesh generated from parameters.
Definition: AnnularMesh.h:17
virtual Real getMaxInDimension(unsigned int component) const override
Definition: AnnularMesh.C:135
bool isParamSetByUser(const std::string &name) const
Method returns true if the parameter was by the user.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const Real _dmin
Minimum angle in degrees.
Definition: AnnularMesh.h:49
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type.
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...
const InputParameters & parameters() const
Get the parameters of the object.
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an option 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)
virtual Elem * elem(const dof_id_type i)
Various accessors (pointers/references) for Elem "i".
Definition: MooseMesh.C:2849
bool _dims_may_have_changed
Boolean to indicate that dimensions may have changed.
Definition: AnnularMesh.h:73
const Real _dmax
Maximum angle in degrees.
Definition: AnnularMesh.h:52
MooseUnits pow(const MooseUnits &, int)
Definition: Units.C:537
void ErrorVector unsigned int
const unsigned _nt
Number of elements in angular direction.
Definition: AnnularMesh.h:40