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 
17 template <>
20 {
22  params.addRangeCheckedParam<unsigned int>(
23  "nr", 1, "nr>0", "Number of elements in the radial direction");
24  params.addRequiredRangeCheckedParam<unsigned int>(
25  "nt", "nt>0", "Number of elements in the angular direction");
26  params.addRequiredRangeCheckedParam<Real>(
27  "rmin",
28  "rmin>=0.0",
29  "Inner radius. If rmin=0 then a disc mesh (with no central hole) will be created.");
30  params.addRequiredParam<Real>("rmax", "Outer radius");
31  params.addParam<Real>("tmin", 0.0, "Minimum angle, measured anticlockwise from x axis");
32  params.addParam<Real>("tmax",
33  2 * M_PI,
34  "Maximum angle, measured anticlockwise from x axis. If "
35  "tmin=0 and tmax=2Pi an annular mesh is created. "
36  "Otherwise, only a sector of an annulus is created");
37  params.addRangeCheckedParam<Real>(
38  "growth_r", 1.0, "growth_r>0.0", "The ratio of radial sizes of successive rings of elements");
39  params.addParam<SubdomainID>(
40  "quad_subdomain_id", 0, "The subdomain ID given to the QUAD4 elements");
41  params.addParam<SubdomainID>("tri_subdomain_id",
42  1,
43  "The subdomain ID given to the TRI3 elements "
44  "(these exist only if rmin=0, and they exist "
45  "at the center of the disc");
46  params.addClassDescription("For rmin>0: creates an annular mesh of QUAD4 elements. For rmin=0: "
47  "creates a disc mesh of QUAD4 and TRI3 elements. Boundary sidesets "
48  "are created at rmax and rmin, and given these names. If tmin!=0 and "
49  "tmax!=2Pi, a sector of an annulus or disc is created. In this case "
50  "boundary sidesets are also created a tmin and tmax, and "
51  "given these names");
52  return params;
53 }
54 
56  : MooseMesh(parameters),
57  _nr(getParam<unsigned int>("nr")),
58  _nt(getParam<unsigned int>("nt")),
59  _rmin(getParam<Real>("rmin")),
60  _rmax(getParam<Real>("rmax")),
61  _tmin(getParam<Real>("tmin")),
62  _tmax(getParam<Real>("tmax")),
63  _growth_r(getParam<Real>("growth_r")),
64  _len(_growth_r == 1.0 ? (_rmax - _rmin) / _nr
65  : (_rmax - _rmin) * (1.0 - _growth_r) / (1.0 - std::pow(_growth_r, _nr))),
66  _full_annulus(_tmin == 0.0 && _tmax == 2 * M_PI),
67  _quad_subdomain_id(getParam<SubdomainID>("quad_subdomain_id")),
68  _tri_subdomain_id(getParam<SubdomainID>("tri_subdomain_id")),
69  _dims_may_have_changed(false)
70 {
71  // catch likely user errors
72  if (_rmax <= _rmin)
73  mooseError("AnnularMesh: rmax must be greater than rmin");
74  if (_tmax <= _tmin)
75  mooseError("AnnularMesh: tmax must be greater than tmin");
76  if (_tmax - _tmin > 2 * M_PI)
77  mooseError("AnnularMesh: tmax - tmin must be <= 2 Pi");
78  if (_nt <= (_tmax - _tmin) / M_PI)
79  mooseError("AnnularMesh: nt must be greater than (tmax - tmin) / Pi in order to avoid inverted "
80  "elements");
82  mooseError("AnnularMesh: quad_subdomain_id must not equal tri_subdomain_id");
83 }
84 
85 void
87 {
88  MooseMesh::prepared(state);
89 
90  // Fall back on scanning the mesh for coordinates instead of using input parameters for queries
91  if (!state)
93 }
94 
95 Real
96 AnnularMesh::getMinInDimension(unsigned int component) const
97 {
99  return MooseMesh::getMinInDimension(component);
100 
101  switch (component)
102  {
103  case 0:
104  return -_rmax;
105  case 1:
106  return -_rmax;
107  case 2:
108  return 0.0;
109  default:
110  mooseError("Invalid component");
111  }
112 }
113 
114 Real
115 AnnularMesh::getMaxInDimension(unsigned int component) const
116 {
118  return MooseMesh::getMaxInDimension(component);
119 
120  switch (component)
121  {
122  case 0:
123  return _rmax;
124  case 1:
125  return _rmax;
126  case 2:
127  return 0.0;
128  default:
129  mooseError("Invalid component");
130  }
131 }
132 
133 std::unique_ptr<MooseMesh>
135 {
136  return libmesh_make_unique<AnnularMesh>(*this);
137 }
138 
139 void
141 {
142  const Real dt = (_tmax - _tmin) / _nt;
143 
144  MeshBase & mesh = getMesh();
145  mesh.clear();
146  mesh.set_mesh_dimension(2);
147  mesh.set_spatial_dimension(2);
148  BoundaryInfo & boundary_info = mesh.get_boundary_info();
149 
150  const unsigned num_angular_nodes = (_full_annulus ? _nt : _nt + 1);
151  const unsigned num_nodes =
152  (_rmin > 0.0 ? (_nr + 1) * num_angular_nodes : _nr * num_angular_nodes + 1);
153  const unsigned min_nonzero_layer_num = (_rmin > 0.0 ? 0 : 1);
154  std::vector<Node *> nodes(num_nodes);
155  unsigned node_id = 0;
156 
157  // add nodes at rmax that aren't yet connected to any elements
158  Real current_r = _rmax;
159  for (unsigned angle_num = 0; angle_num < num_angular_nodes; ++angle_num)
160  {
161  const Real angle = _tmin + angle_num * dt;
162  const Real x = current_r * std::cos(angle);
163  const Real y = current_r * std::sin(angle);
164  nodes[node_id] = mesh.add_point(Point(x, y, 0.0), node_id);
165  node_id++;
166  }
167 
168  // add nodes at smaller radii, and connect them with elements
169  for (unsigned layer_num = _nr; layer_num > min_nonzero_layer_num; --layer_num)
170  {
171  if (layer_num == 1)
172  current_r = _rmin; // account for precision loss
173  else
174  current_r -= _len * std::pow(_growth_r, layer_num - 1);
175 
176  // add node at angle = _tmin
177  nodes[node_id] = mesh.add_point(
178  Point(current_r * std::cos(_tmin), current_r * std::sin(_tmin), 0.0), node_id);
179  node_id++;
180  for (unsigned angle_num = 1; angle_num < num_angular_nodes; ++angle_num)
181  {
182  const Real angle = _tmin + angle_num * dt;
183  const Real x = current_r * std::cos(angle);
184  const Real y = current_r * std::sin(angle);
185  nodes[node_id] = mesh.add_point(Point(x, y, 0.0), node_id);
186  Elem * elem = mesh.add_elem(new Quad4);
187  elem->set_node(0) = nodes[node_id];
188  elem->set_node(1) = nodes[node_id - 1];
189  elem->set_node(2) = nodes[node_id - num_angular_nodes - 1];
190  elem->set_node(3) = nodes[node_id - num_angular_nodes];
191  elem->subdomain_id() = _quad_subdomain_id;
192  node_id++;
193 
194  if (layer_num == _nr)
195  // add outer boundary (boundary_id = 1)
196  boundary_info.add_side(elem, 2, 1);
197  if (layer_num == 1)
198  // add inner boundary (boundary_id = 0)
199  boundary_info.add_side(elem, 0, 0);
200  if (!_full_annulus && angle_num == 1)
201  // add tmin boundary (boundary_id = 2)
202  boundary_info.add_side(elem, 1, 2);
203  if (!_full_annulus && angle_num == num_angular_nodes - 1)
204  // add tmin boundary (boundary_id = 3)
205  boundary_info.add_side(elem, 3, 3);
206  }
207  if (_full_annulus)
208  {
209  // add element connecting to node at angle=0
210  Elem * elem = mesh.add_elem(new Quad4);
211  elem->set_node(0) = nodes[node_id - num_angular_nodes];
212  elem->set_node(1) = nodes[node_id - 1];
213  elem->set_node(2) = nodes[node_id - num_angular_nodes - 1];
214  elem->set_node(3) = nodes[node_id - 2 * num_angular_nodes];
215  elem->subdomain_id() = _quad_subdomain_id;
216 
217  if (layer_num == _nr)
218  // add outer boundary (boundary_id = 1)
219  boundary_info.add_side(elem, 2, 1);
220  if (layer_num == 1)
221  // add inner boundary (boundary_id = 0)
222  boundary_info.add_side(elem, 0, 0);
223  }
224  }
225 
226  // add single node at origin, if relevant
227  if (_rmin == 0.0)
228  {
229  nodes[node_id] = mesh.add_point(Point(0.0, 0.0, 0.0), node_id);
230  boundary_info.add_node(node_id, 0); // boundary_id=0 is centre
231  for (unsigned angle_num = 0; angle_num < num_angular_nodes - 1; ++angle_num)
232  {
233  Elem * elem = mesh.add_elem(new Tri3);
234  elem->set_node(0) = nodes[node_id];
235  elem->set_node(1) = nodes[node_id - num_angular_nodes + angle_num];
236  elem->set_node(2) = nodes[node_id - num_angular_nodes + angle_num + 1];
237  elem->subdomain_id() = _tri_subdomain_id;
238  }
239  if (_full_annulus)
240  {
241  Elem * elem = mesh.add_elem(new Tri3);
242  elem->set_node(0) = nodes[node_id];
243  elem->set_node(1) = nodes[node_id - 1];
244  elem->set_node(2) = nodes[node_id - num_angular_nodes];
245  elem->subdomain_id() = _tri_subdomain_id;
246  }
247  }
248 
249  boundary_info.sideset_name(0) = "rmin";
250  boundary_info.sideset_name(1) = "rmax";
251  boundary_info.nodeset_name(0) = "rmin";
252  boundary_info.nodeset_name(1) = "rmax";
253  if (!_full_annulus)
254  {
255  boundary_info.sideset_name(2) = "tmin";
256  boundary_info.sideset_name(3) = "tmax";
257  boundary_info.nodeset_name(2) = "tmin";
258  boundary_info.nodeset_name(3) = "tmax";
259  }
260 
261  mesh.prepare_for_use(false);
262 }
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:134
virtual void buildMesh() override
Must be overridden by child classes.
Definition: AnnularMesh.C:140
virtual Real getMaxInDimension(unsigned int component) const
Definition: MooseMesh.C:1475
virtual Real getMinInDimension(unsigned int component) const
Returns the min or max of the requested dimension respectively.
Definition: MooseMesh.C:1466
bool prepared() const
Setter/getter for the _is_prepared flag.
Definition: MooseMesh.C:2291
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:96
const SubdomainID _tri_subdomain_id
Subdomain ID of created tri elements (that only exist if rmin=0)
Definition: AnnularMesh.h:70
const Real _rmin
Minimum radius.
Definition: AnnularMesh.h:46
const Real _rmax
Maximum radius.
Definition: AnnularMesh.h:49
const unsigned _nr
Number of elements in radial direction.
Definition: AnnularMesh.h:40
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
InputParameters validParams< AnnularMesh >()
Definition: AnnularMesh.C:19
void mooseError(Args &&... args) const
Definition: MooseObject.h:147
AnnularMesh(const InputParameters &parameters)
Definition: AnnularMesh.C:55
static PetscErrorCode Vec x
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...
registerMooseObject("MooseApp", AnnularMesh)
const bool _full_annulus
Whether a full annulus (as opposed to a sector) will needs to generate.
Definition: AnnularMesh.h:64
Real pow(Real x, int e)
Definition: MathUtils.C:211
InputParameters validParams< MooseMesh >()
Definition: MooseMesh.C:63
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
Definition: MooseMesh.C:2567
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:74
subdomain_id_type SubdomainID
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:22
virtual Real getMaxInDimension(unsigned int component) const override
Definition: AnnularMesh.C:115
const Real _tmin
Minimum angle.
Definition: AnnularMesh.h:52
const Real _tmax
Maximum angle.
Definition: AnnularMesh.h:55
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 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:2253
bool _dims_may_have_changed
Boolean to indicate that dimensions may have changed.
Definition: AnnularMesh.h:73
const unsigned _nt
Number of elements in angular direction.
Definition: AnnularMesh.h:43