ryujin 2.5.0 revision c64172211cf21344cb9b9b0f3a1266aa6400d392
Loading...
Searching...
No Matches
geometry_annulus.h
Go to the documentation of this file.
1//
2// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3// Copyright (C) 2023 - 2026 by the ryujin authors
4//
5
6#pragma once
7
8#include <ryujin/base/compile_time_options.h>
10
11namespace ryujin
12{
13 namespace GridGenerator
14 {
23 template <int dim, int spacedim, template <int, int> class Triangulation>
24 void annulus(Triangulation<dim, spacedim> &,
25 const double /*length*/,
26 const double /*inner_radius*/,
27 const double /*outer_radius*/,
28 const double /*angle*/)
29 {
30 AssertThrow(false, dealii::ExcNotImplemented());
31 __builtin_trap();
32 }
33
34
35#ifndef DOXYGEN
36 template <template <int, int> class Triangulation>
37 void annulus(Triangulation<2, 2> &triangulation,
38 const double length,
39 const double inner_radius,
40 const double outer_radius,
41 const double angle)
42 {
43 constexpr int dim = 2;
44 constexpr double eps = 1.0e-10;
45
46 using namespace dealii;
47
48 /*
49 * A lambda that conveniently sets and assigns manifold IDs and that
50 * we need a couple of times during the construction process of the
51 * triangulation:
52 */
53 const auto assign_manifolds = [&](auto &tria) {
54 for (const auto &cell : tria.cell_iterators()) {
55 /*
56 * Mark all cells that will comprise the annulus. That is, all
57 * cells whose vertices lie betwenn the two radii.
58 */
59 bool cell_on_annulus = true;
60 for (unsigned int v : cell->vertex_indices()) {
61 const auto vertex = cell->vertex(v);
62 const auto distance = vertex.norm();
63 if (!(inner_radius - eps <= distance && distance <= outer_radius)) {
64 cell_on_annulus = false;
65 break;
66 }
67 }
68 if (cell_on_annulus)
69 cell->set_all_manifold_ids(1);
70
71 /*
72 * Separately, mark all faces that touch the annulus.
73 */
74 for (const unsigned int f : cell->face_indices()) {
75 const auto face = cell->face(f);
76
77 bool face_on_annulus = true;
78 for (unsigned int v : face->vertex_indices()) {
79 const auto vertex = face->vertex(v);
80 const auto distance = vertex.norm();
81 if (!(inner_radius - eps <= distance &&
82 distance <= outer_radius)) {
83 face_on_annulus = false;
84 break;
85 }
86 }
87 if (face_on_annulus)
88 face->set_all_manifold_ids(1);
89 }
90 }
91
92 tria.set_manifold(1, SphericalManifold<dim>());
93 dealii::TransfiniteInterpolationManifold<dim> transfinite_manifold;
94 transfinite_manifold.initialize(tria);
95 tria.set_manifold(0, transfinite_manifold);
96 };
97
98 /* Create inner ball with radius=inner_radius: */
99 dealii::Triangulation<dim> tria_inner;
100 {
101 dealii::Triangulation<dim> temp;
102 GridGenerator::hyper_ball_balanced(
103 temp, dealii::Point<dim>(), inner_radius);
104 temp.refine_global(2);
105 GridGenerator::flatten_triangulation(temp, tria_inner);
106 }
107
108 /* Create outer annulus. Note part of this will be removed. */
109 dealii::Triangulation<dim> annulus;
110 GridGenerator::hyper_shell(
111 annulus, dealii::Point<dim>(), inner_radius, outer_radius, 32);
112
113 /* Create outside shell */
114 dealii::Triangulation<dim> tria_outer;
115 {
116 dealii::Triangulation<dim> temp;
117 GridGenerator::hyper_shell(temp,
118 dealii::Point<dim>(),
119 outer_radius,
120 length / 2. * std::sqrt(2),
121 8);
122 /* Fix up vertices so that we get back a unit square: */
123 for (const auto &cell : temp.cell_iterators()) {
124 static_assert(dim == 2, "not implemented");
125 for (unsigned int i = 0; i < 4; ++i) {
126 auto &vertex = cell->vertex(i);
127 if (std::abs(vertex[0]) < eps && std::abs(vertex[1]) > length / 2.)
128 vertex[1] = std::copysign(length / 2., vertex[1]);
129 if (std::abs(vertex[1]) < eps && std::abs(vertex[0]) > length / 2.)
130 vertex[0] = std::copysign(length / 2., vertex[0]);
131 }
132 }
133 assign_manifolds(temp);
134 temp.refine_global(2);
135 GridGenerator::flatten_triangulation(temp, tria_outer);
136 }
137
138 /* Create triangulation to merge: */
139 dealii::Triangulation<dim, dim> coarse_triangulation;
140 coarse_triangulation.set_mesh_smoothing(
141 triangulation.get_mesh_smoothing());
142 GridGenerator::merge_triangulations(
143 {&tria_inner, &annulus, &tria_outer}, coarse_triangulation, 1.e-12);
144
145 /*
146 * Set manifold IDs:
147 */
148
149 coarse_triangulation.reset_all_manifolds();
150 coarse_triangulation.set_all_manifold_ids(0);
151
152 assign_manifolds(coarse_triangulation);
153 coarse_triangulation.refine_global(2);
154
155 /* Remove mesh cells in the annulus */
156
157 std::set<typename dealii::Triangulation<dim>::active_cell_iterator>
158 cells_to_remove;
159
160 for (const auto &cell : coarse_triangulation.active_cell_iterators()) {
161 for (auto f : cell->face_indices()) {
162 auto face = cell->face(f);
163 const auto position = face->center();
164 const auto radius = position.norm();
165 const auto inner_value = inner_radius;
166 const auto outer_value = outer_radius;
167
168 bool in_anulus =
169 radius - inner_value > 1.e-8 && outer_value - radius > 1.e-3;
170
171 bool partial_annulus =
172 std::abs(position[1]) -
173 std::abs(position[0]) *
174 std::tan(dealii::numbers::PI / 180. * angle) <
175 1.e-8;
176
177 if (in_anulus && partial_annulus) {
178 cells_to_remove.insert(cell);
179 }
180 }
181 }
182
183 GridGenerator::create_triangulation_with_removed_cells(
184 coarse_triangulation, cells_to_remove, coarse_triangulation);
185
186 /*
187 * Flatten triangulation and copy over to distributed triangulation:
188 */
189 dealii::Triangulation<dim> flattened_triangulation;
190 flattened_triangulation.set_mesh_smoothing(
191 triangulation.get_mesh_smoothing());
192 GridGenerator::flatten_triangulation(coarse_triangulation,
193 flattened_triangulation);
194 triangulation.copy_triangulation(flattened_triangulation);
195 assign_manifolds(triangulation);
196
197
198 /*
199 * Set boundary ids:
200 */
201
202 for (auto cell : triangulation.active_cell_iterators()) {
203 for (auto f : cell->face_indices()) {
204 const auto face = cell->face(f);
205
206 if (!face->at_boundary())
207 continue;
208
209 /*
210 * We want slip boundary conditions everywhere.
211 */
212 face->set_boundary_id(Boundary::slip);
213 }
214 }
215 }
216
217
218 template <template <int, int> class Triangulation>
219 void annulus(Triangulation<3, 3> & /* triangulation */,
220 const double /* length */,
221 const double /* inner_radius */,
222 const double /* outer_radius */,
223 const double /* angle */)
224 {
225 using namespace dealii;
226 AssertThrow(false, dealii::ExcNotImplemented());
227 __builtin_trap();
228 }
229#endif
230 } // namespace GridGenerator
231
232
233 namespace Geometries
234 {
241 template <int dim>
242 class Annulus : public Geometry<dim>
243 {
244 public:
245 Annulus(const std::string &subsection)
246 : Geometry<dim>("annulus", subsection)
247 {
248 length_ = 2.;
249 this->add_parameter(
250 "length", length_, "length of computational domain [-L/2,L/2]^d");
251
252 inner_radius_ = 0.6;
253 this->add_parameter(
254 "inner radius", inner_radius_, "inner radius of partial annulus");
255
256 outer_radius_ = 0.7;
257 this->add_parameter(
258 "outer radius", outer_radius_, "outer radius of partial annulus");
259
260 angle_ = 45.;
261 this->add_parameter("coverage angle",
262 angle_,
263 "angle coverage of partial annulus above y-axis");
264 }
265
267 dealii::Triangulation<dim> &triangulation) const final
268 {
270 triangulation, length_, inner_radius_, outer_radius_, angle_);
271 }
272
273 private:
274 double length_;
275 double inner_radius_;
276 double outer_radius_;
277 double angle_;
278 };
279 } // namespace Geometries
280} // namespace ryujin
Annulus(const std::string &subsection)
void create_coarse_triangulation(dealii::Triangulation< dim > &triangulation) const final
void annulus(Triangulation< dim, spacedim > &, const double, const double, const double, const double)