ryujin 2.1.1 revision 71cdc42292164f8095c0bd62c4ea75ebcfac58fa
Loading...
Searching...
No Matches
discretization.template.h
Go to the documentation of this file.
1//
2// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3// Copyright (C) 2020 - 2026 by the ryujin authors
4//
5
6#pragma once
7
8#include <boost/random/detail/polynomial.hpp>
9#include <compile_time_options.h>
10
11#include "discretization.h"
13
14#include <deal.II/base/quadrature_lib.h>
15#include <deal.II/fe/fe_dgq.h>
16#include <deal.II/fe/fe_nothing.h>
17#include <deal.II/fe/fe_q.h>
18#include <deal.II/fe/fe_simplex_p.h>
19#include <deal.II/fe/fe_tools.h>
20#include <deal.II/fe/mapping_fe.h>
21#if DEAL_II_VERSION_GTE(9, 7, 0)
22#include <deal.II/fe/mapping_p1.h>
23#endif
24#include <deal.II/fe/mapping_q.h>
25#include <deal.II/grid/grid_out.h>
26
27#include <random>
28
29namespace ryujin
30{
31 using namespace dealii;
32
33 template <int dim>
35 const std::string &subsection)
36 : ParameterAcceptor(subsection)
37 , mpi_ensemble_(mpi_ensemble)
38 {
39 /* Options: */
40
41 ansatz_ = Ansatz::cg_q1;
42 add_parameter("finite element ansatz",
43 ansatz_,
44 "The finite element ansatz used for discretization. Valid "
45 "choices are cG Q1, cG Q2, cG Q3.");
46
47 mesh_type_ =
49 add_parameter("mesh type",
50 mesh_type_,
51 "The triangulation class used. Valid choices are \"serial\", "
52 "\"parallel shared\", \"parallel distributed\", \"parallel "
53 "fullydistributed\".");
54
55 if constexpr (dim == 1) {
56 geometry_ = "rectangular domain";
57 } else {
58 geometry_ = "cylinder";
59 }
60 add_parameter("geometry",
61 geometry_,
62 "Name of the geometry used to create the mesh. Valid names "
63 "are given by any of the subsections defined below.");
64
65 refinement_ = 5;
66 add_parameter("mesh refinement",
67 refinement_,
68 "number of refinement of global refinement steps");
69
70 mesh_writeout_ = true;
71 add_parameter("mesh writeout",
72 mesh_writeout_,
73 "Write out shared coarse mesh to a GMSH *.msh file.");
74
75 mesh_distortion_ = 0.;
76 add_parameter(
77 "mesh distortion", mesh_distortion_, "Strength of mesh distortion");
78
79 Geometries::populate_geometry_list<dim>(geometry_list_, subsection);
80 }
81
82
83 template <int dim>
84 void Discretization<dim>::prepare(const std::string &base_name)
85 {
86#ifdef DEBUG_OUTPUT
87 std::cout << "Discretization<dim>::prepare()" << std::endl;
88#endif
89
90 AssertThrow(
91 mesh_type_ != MeshType::parallel_fullydistributed || refinement_ == 0,
92 ExcMessage("The fully distributed mesh type does not support global "
93 "refinement. The geometry must create a properly refined "
94 "mesh."));
95
96 /* Select geometry: */
97
98 {
99 bool initialized = false;
100 for (auto &it : geometry_list_)
101 if (it->name() == geometry_) {
102 selected_geometry_ = it;
103 initialized = true;
104 break;
105 }
106
107 AssertThrow(
108 initialized,
109 ExcMessage("Could not find a geometry description with name \"" +
110 geometry_ + "\""));
111 }
112
113 /* Set up Triangulation object: */
114
115 const auto smoothing =
116 dealii::Triangulation<dim>::limit_level_difference_at_vertices;
117
118 switch (mesh_type_) {
120 const auto settings = dealii::TriangulationDescription::Settings::
121 construct_multigrid_hierarchy;
122 auto triangulation = std::make_unique<
123 dealii::parallel::fullydistributed::Triangulation<dim>>(
124 mpi_ensemble_.ensemble_communicator());
125 triangulation->set_mesh_smoothing(smoothing);
126 triangulation->set_partitioner(
127 [](dealii::Triangulation<dim> &tria,
128 const unsigned int n_partitions) {
129 GridTools::partition_triangulation_zorder(n_partitions, tria);
130 },
131 settings);
132 triangulation_ = std::move(triangulation);
133 } break;
134
136 const auto settings = dealii::parallel::distributed::Triangulation<
137 dim>::Settings::construct_multigrid_hierarchy;
138 triangulation_ =
139 std::make_unique<dealii::parallel::distributed::Triangulation<dim>>(
140 mpi_ensemble_.ensemble_communicator(), smoothing, settings);
141 } break;
142
144 const auto settings = static_cast<
145 typename dealii::parallel::shared::Triangulation<dim>::Settings>(
146 dealii::parallel::shared::Triangulation<dim>::partition_auto |
147 dealii::parallel::shared::Triangulation<
148 dim>::construct_multigrid_hierarchy);
149 /* Beware of the boolean: */
150 triangulation_ =
151 std::make_unique<dealii::parallel::shared::Triangulation<dim>>(
152 mpi_ensemble_.ensemble_communicator(),
153 smoothing,
154 /*artificial cells*/ true,
155 settings);
156 } break;
157
158 case MeshType::serial: {
159 AssertThrow(
160 mpi_ensemble_.n_ensemble_ranks() == 1,
161 ExcMessage(
162 "The serial triangulation can only be used for serial "
163 "computations. If you want to run simulations with more than one "
164 "rank per ensemble, then please set \"mesh type\" to one of the "
165 "parallel triangulations supported by deal.II"));
166
167 triangulation_ = std::make_unique<dealii::Triangulation<dim>>(smoothing);
168
169 } break;
170
171 default:
172 __builtin_trap();
173 }
174
175 /* Create and distribute mesh: */
176
177 auto &triangulation = *triangulation_;
178 selected_geometry_->create_coarse_triangulation(triangulation);
179
180 if (mesh_writeout_ && dealii::Utilities::MPI::this_mpi_process(
181 mpi_ensemble_.ensemble_communicator()) == 0) {
182#ifdef DEAL_II_GMSH_WITH_API
183 GridOut grid_out;
184 grid_out.write_msh(triangulation, base_name + "-coarse_grid.msh");
185#else
186 GridOut grid_out;
187 GridOutFlags::Msh flags(/* write faces */ true, /* write lines */ true);
188 grid_out.set_flags(flags);
189 std::ofstream file(base_name + "-coarse_grid.msh");
190 grid_out.write_msh(triangulation, file);
191#endif
192 }
193
194 triangulation.refine_global(refinement_);
195
196 if (std::abs(mesh_distortion_) > 1.0e-10)
197 GridTools::distort_random(
198 mesh_distortion_, triangulation, false, std::random_device()());
199
200 const auto fe_degree = polynomial_degree();
201 const auto mapping_degree = fe_degree;
202 const auto quadrature_degree = fe_degree + 1;
203
204 /*
205 * First, let the selected geometry populate our hp::*Collection
206 * objects. If the method returns standard_quarilaterls, or
207 * standard_simplices, however, we need to do the setup ourselves:
208 */
209
210 const auto collection_type =
211 selected_geometry_->populate_hp_collections(fe_degree, collection_);
212
213 switch (collection_type) {
215 /*
216 * The geometry already populated the hp::*Collections
217 */
218
219 Assert(collection_.mapping, dealii::ExcInternalError());
220 Assert(collection_.finite_element_cg, dealii::ExcInternalError());
221 Assert(collection_.finite_element_dg, dealii::ExcInternalError());
222 Assert(collection_.quadrature, dealii::ExcInternalError());
223 Assert(collection_.quadrature_high_order, dealii::ExcInternalError());
224 Assert(collection_.nodal_quadrature, dealii::ExcInternalError());
225 Assert(collection_.quadrature_1d, dealii::ExcInternalError());
226 Assert(collection_.nodal_quadrature_1d, dealii::ExcInternalError());
227 Assert(collection_.face_quadrature, dealii::ExcInternalError());
228 Assert(collection_.face_nodal_quadrature, dealii::ExcInternalError());
229 } break;
230
232 /*
233 * Populate all collections with appropriate objects for the cG Qk, dG
234 * Qk finite element on purely quadrilateral, or hexahedral meshes:
235 */
236
237 collection_.finite_element_cg =
238 std::make_unique<hp::FECollection<dim>>(FE_Q<dim>(fe_degree));
239 collection_.finite_element_dg =
240 std::make_unique<hp::FECollection<dim>>(FE_DGQ<dim>(fe_degree));
241
242 /*
243 * If the geometry describes the mesh via a forward transformation of
244 * the undeformed triangulation we use a MappingQCache that is filled
245 * in update_mapping(). The cache is stored by pointer (and not
246 * cloned) so that the collection always refers to the current cache:
247 */
248 if (selected_geometry_->transformation()) {
249 mapping_cache_ = std::make_shared<MappingQCache<dim>>(mapping_degree);
250 auto mapping = std::make_unique<hp::MappingCollection<dim>>();
251 hp::Collection<Mapping<dim>> &base = *mapping;
252 base.push_back(mapping_cache_);
253 collection_.mapping = std::move(mapping);
254 } else {
255 collection_.mapping =
256 std::make_unique<dealii::hp::MappingCollection<dim>>(
257 MappingQ<dim>(mapping_degree));
258 }
259
260 collection_.quadrature = std::make_unique<hp::QCollection<dim>>(
261 QGauss<dim>(quadrature_degree));
262 collection_.quadrature_high_order =
263 std::make_unique<hp::QCollection<dim>>(
264 QGauss<dim>(quadrature_degree + 1));
265 collection_.nodal_quadrature = std::make_unique<hp::QCollection<dim>>(
266 QGaussLobatto<dim>(quadrature_degree));
267 collection_.quadrature_1d =
268 std::make_unique<hp::QCollection<1>>(QGauss<1>(quadrature_degree));
269 collection_.nodal_quadrature_1d = std::make_unique<hp::QCollection<1>>(
270 QGaussLobatto<1>(quadrature_degree));
271 using QCF = hp::QCollection<dim - 1>;
272 collection_.face_quadrature = std::make_unique<std::vector<QCF>>(
273 1, QCF(QGauss<dim - 1>(quadrature_degree)));
274 collection_.face_nodal_quadrature = std::make_unique<std::vector<QCF>>(
275 1, QCF(QGaussLobatto<dim - 1>(quadrature_degree)));
276 } break;
277
279 /*
280 * Populate all collections with appropriate objects for the cG Pk, dG
281 * Pk finite element on purely quadrilateral, or hexahedral meshes:
282 */
283
284 collection_.finite_element_cg =
285 std::make_unique<hp::FECollection<dim>>(FE_SimplexP<dim>(fe_degree));
286 collection_.finite_element_dg = std::make_unique<hp::FECollection<dim>>(
287 FE_SimplexDGP<dim>(fe_degree));
288
289 if (mapping_degree == 1) {
290#if DEAL_II_VERSION_GTE(9, 7, 0)
291 collection_.mapping =
292 std::make_unique<hp::MappingCollection<dim>>(MappingP1<dim>());
293#else
294 collection_.mapping = std::make_unique<hp::MappingCollection<dim>>(
295 MappingFE<dim>(FE_SimplexP<dim>(fe_degree)));
296#endif
297 } else {
298 collection_.mapping = std::make_unique<hp::MappingCollection<dim>>(
299 MappingFE<dim>(FE_SimplexP<dim>(fe_degree)));
300 }
301
302 collection_.quadrature = std::make_unique<hp::QCollection<dim>>(
303 QGaussSimplex<dim>(quadrature_degree));
304 collection_.quadrature_high_order =
305 std::make_unique<hp::QCollection<dim>>(
306 QGaussSimplex<dim>(quadrature_degree + 1));
307#if DEAL_II_VERSION_GTE(9, 7, 0)
308 collection_.nodal_quadrature = std::make_unique<hp::QCollection<dim>>(
309 FETools::compute_nodal_quadrature(
310 FE_SimplexP<dim>(quadrature_degree)));
311#else
312 AssertThrow(false,
313 dealii::ExcMessage("Discretization: Simplex support requires "
314 "deal.II version 9.7.0 or newer"));
315#endif
316 collection_.quadrature_1d = std::make_unique<hp::QCollection<1>>(
317 QGaussSimplex<1>(quadrature_degree));
318#if DEAL_II_VERSION_GTE(9, 7, 0)
319 collection_.nodal_quadrature_1d = std::make_unique<hp::QCollection<1>>(
320 QGaussLobatto<1>(quadrature_degree));
321#endif
322 using QCF = hp::QCollection<dim - 1>;
323 collection_.face_quadrature = std::make_unique<std::vector<QCF>>(
324 1, QCF(QGaussSimplex<dim - 1>(quadrature_degree)));
325 if constexpr (dim == 1) {
326 collection_.face_nodal_quadrature = std::make_unique<std::vector<QCF>>(
327 1, QCF(QGaussLobatto<dim - 1>(quadrature_degree)));
328 } else {
329#if DEAL_II_VERSION_GTE(9, 7, 0)
330 const auto quadrature = FETools::compute_nodal_quadrature(
331 FE_SimplexP<dim - 1>(quadrature_degree));
332 collection_.face_nodal_quadrature =
333 std::make_unique<std::vector<QCF>>(1, QCF(quadrature));
334#endif
335 }
336
337 return;
338 } break;
339 default:
340 __builtin_trap();
341 }
342 }
343
344
345 template <int dim>
347 {
348 if (!mapping_cache_)
349 return;
350
351 mapping_cache_->initialize(MappingQ<dim>(mapping_cache_->get_degree()),
352 *triangulation_,
353 selected_geometry_->transformation(),
354 /*function_describes_relative_displacement*/
355 false);
356 }
357
358} /* namespace ryujin */
Discretization(const MPIEnsemble &mpi_ensemble, const std::string &subsection="/Discretization")
void prepare(const std::string &base_name)