12 #include "libmesh/face_quad4.h"
13 #include "libmesh/face_tri3.h"
24 "inner_radius",
"inner_radius>0.",
"The size of the inner circle.");
27 "The size of the outer circle."
28 " Logically, it has to be greater than inner_radius");
30 "nodes_per_ring",
"nodes_per_ring>5",
"Number of nodes on each ring.");
32 "use_tri6",
false,
"Generate mesh of TRI6 elements instead of TRI3 elements.");
34 "num_rings",
"num_rings>1",
"The number of rings.");
36 "cylinder_bid", 1,
"The boundary id to use for the cylinder (inner circle)");
38 "exterior_bid", 2,
"The boundary id to use for the exterior (outer circle)");
39 params.
addParam<Real>(
"initial_delta_r",
40 "Width of the initial layer of elements around the cylinder."
41 "This number should be approximately"
42 " 2 * pi * inner_radius / nodes_per_ring to ensure that the"
43 " initial layer of elements is almost equilateral");
45 " (it can also be TRI6 elements) on several rings.");
52 _inner_radius(getParam<Real>(
"inner_radius")),
53 _outer_radius(getParam<Real>(
"outer_radius")),
55 _nodes_per_ring(getParam<unsigned int>(
"nodes_per_ring")),
56 _use_tri6(getParam<bool>(
"use_tri6")),
57 _num_rings(getParam<unsigned int>(
"num_rings")),
58 _cylinder_bid(getParam<boundary_id_type>(
"cylinder_bid")),
59 _exterior_bid(getParam<boundary_id_type>(
"exterior_bid")),
60 _initial_delta_r(2 *
libMesh::pi * _inner_radius / _nodes_per_ring)
64 mooseError(
"SpiralAnnularMesh: outer_radius must be greater than inner_radius");
67 std::unique_ptr<MooseMesh>
70 return libmesh_make_unique<SpiralAnnularMesh>(*
this);
91 auto newton = [
this,
n](Real & f, Real & df,
const Real & alpha) {
92 f = (1. -
std::pow(alpha,
n + 1)) / (1. - alpha) -
95 (1. - alpha) / (1. - alpha);
100 newton(f, df, alpha);
102 while (
std::abs(f) > 1.e-9 && num_iter <= 25)
107 newton(f, df, alpha);
113 mooseError(
"Newton iteration failed to converge (more than 25 iterations).");
127 std::vector<std::vector<Node *>> ring_nodes(
_num_rings);
134 unsigned int current_node_id = 0;
144 ring_nodes[r][
n] = mesh.add_point(Point(radius * std::cos(theta), radius * std::sin(theta)),
156 for (std::size_t r = 0; r <
_num_rings - 1; ++r)
167 Elem *
elem = mesh.add_elem(
new Tri3);
168 elem->set_node(0) = ring_nodes[r][
n];
169 elem->set_node(1) = ring_nodes[r + 1][
n];
170 elem->set_node(2) = ring_nodes[r][np1];
182 Elem *
elem = mesh.add_elem(
new Tri3);
183 elem->set_node(0) = ring_nodes[r + 1][
n];
184 elem->set_node(1) = ring_nodes[r + 1][np1];
185 elem->set_node(2) = ring_nodes[r][np1];
201 Elem *
elem = mesh.add_elem(
new Tri3);
202 elem->set_node(0) = ring_nodes[r][
n];
203 elem->set_node(1) = ring_nodes[r + 1][np1];
204 elem->set_node(2) = ring_nodes[r][np1];
212 Elem *
elem = mesh.add_elem(
new Tri3);
213 elem->set_node(0) = ring_nodes[r + 1][
n];
214 elem->set_node(1) = ring_nodes[r + 1][np1];
215 elem->set_node(2) = ring_nodes[r][
n];
228 for (
const auto &
elem : mesh.element_ptr_range())
230 Point cp = (
elem->point(1) -
elem->point(0)).cross(
elem->point(2) -
elem->point(0));
232 mooseError(
"Invalid elem found with negative area");
236 mesh.boundary_info->sideset_name(
_cylinder_bid) =
"cylinder";
237 mesh.boundary_info->sideset_name(
_exterior_bid) =
"exterior";
240 mesh.prepare_for_use();
244 mesh.all_second_order(
true);
245 std::vector<unsigned int> nos;
251 for (
const auto &
elem : mesh.element_ptr_range())
254 libmesh_assert(
elem->n_vertices() == 3);
257 Real radii[3] = {
elem->point(0).norm(),
elem->point(1).norm(),
elem->point(2).norm()};
261 Real dr[3] = {
std::abs(radii[0] - radii[1]),
266 auto index = std::distance(std::begin(dr), std::min_element(std::begin(dr), std::end(dr)));
269 if (dr[index] > TOLERANCE)
270 mooseError(
"Error: element had no sides with nodes on same radius.");
275 nos =
elem->nodes_on_side(index);
278 Real theta0 = std::atan2(
elem->point(nos[0])(1),
elem->point(nos[0])(0)),
279 theta1 = std::atan2(
elem->point(nos[1])(1),
elem->point(nos[1])(0));
289 Real new_theta = 0.5 * (theta0 + theta1);
295 if ((theta0 * theta1 < 0) && (
std::abs(theta0) > 0.5 * libMesh::pi) &&
296 (
std::abs(theta1) > 0.5 * libMesh::pi))
297 new_theta = 0.5 * (theta0 + theta1 + 2 * libMesh::pi);
300 Real new_r =
elem->point(nos[0]).norm();
303 elem->point(nos[2]) = Point(new_r * std::cos(new_theta), new_r * std::sin(new_theta), 0.);