ryujin 2.1.1 revision 0348cbb53a3e4b1da2a4c037e81f88f2d21ce219
mesh_adaptor.template.h
Go to the documentation of this file.
1//
2// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3// Copyright (C) 2024 by the ryujin authors
4//
5
6#pragma once
7
8#include "mesh_adaptor.h"
10
11#include <deal.II/base/array_view.h>
12#include <deal.II/grid/grid_refinement.h>
13#include <deal.II/numerics/error_estimator.h>
14
15namespace ryujin
16{
17 template <typename Description, int dim, typename Number>
19 const MPIEnsemble &mpi_ensemble,
20 const OfflineData<dim, Number> &offline_data,
21 const HyperbolicSystem &hyperbolic_system,
22 const ParabolicSystem &parabolic_system,
23 const InitialPrecomputedVector &initial_precomputed,
24 const ScalarVector &alpha,
25 const std::string &subsection /*= "MeshAdaptor"*/)
26 : ParameterAcceptor(subsection)
27 , mpi_ensemble_(mpi_ensemble)
28 , offline_data_(&offline_data)
29 , hyperbolic_system_(&hyperbolic_system)
30 , parabolic_system_(&parabolic_system)
31 , need_mesh_adaptation_(false)
32 , initial_precomputed_(initial_precomputed)
33 , alpha_(alpha)
34 {
35 adaptation_strategy_ = AdaptationStrategy::global_refinement;
36 add_parameter("adaptation strategy",
37 adaptation_strategy_,
38 "The chosen adaptation strategy. Possible values are: global "
39 "refinement, random adaptation, kelly estimator");
40
41 marking_strategy_ = MarkingStrategy::fixed_number;
42 add_parameter("marking strategy",
43 marking_strategy_,
44 "The chosen marking strategy. Possible values are: fixed "
45 "number, fixed fraction");
46
47 time_point_selection_strategy_ =
49 add_parameter("time point selection strategy",
50 time_point_selection_strategy_,
51 "The chosen time point selection strategy. Possible values "
52 "are: fixed time points, simulation cycle");
53
54 /* Options for various adaptation strategies: */
55 enter_subsection("adaptation strategies");
56 random_adaptation_mersenne_twister_seed_ = 42u;
57 add_parameter("random adaptation: mersenne_twister_seed",
58 random_adaptation_mersenne_twister_seed_,
59 "Seed for 64bit Mersenne Twister used for random refinement");
60
61 add_parameter(
62 "kelly estimator: quantities",
63 kelly_quantities_,
64 "List of conserved, primitive or precomputed quantities that will be "
65 "used for the Kelly error estimator for refinement and coarsening.");
66 leave_subsection();
67
68 /* Options for various marking strategies: */
69
70 enter_subsection("marking strategies");
71 refinement_fraction_ = 0.3;
72 add_parameter("refinement fraction",
73 refinement_fraction_,
74 "Marking: fraction of cells selected for refinement.");
75
76 coarsening_fraction_ = 0.3;
77 add_parameter("coarsening fraction",
78 coarsening_fraction_,
79 "Marking: fraction of cells selected for coarsening.");
80
81 min_refinement_level_ = 0;
82 add_parameter("minimal refinement level",
83 min_refinement_level_,
84 "Marking: minimal refinement level of cells that will be "
85 "maintained while coarsening cells.");
86
87 max_refinement_level_ = 1000;
88 add_parameter("maximal refinement level",
89 max_refinement_level_,
90 "Marking: maximal refinement level of cells that will be "
91 "maintained while refininig cells.");
92
93 max_num_cells_ = 100000;
94 add_parameter(
95 "maximal number of cells",
96 max_num_cells_,
97 "Marking: maximal number of cells used for the fixed fraction "
98 "strategy. Note this is only an indicator and not strictly enforced.");
99
100 leave_subsection();
101
102 /* Options for various time point selection strategies: */
103
104 enter_subsection("time point selection strategies");
105 adaptation_time_points_ = {};
106 add_parameter("fixed time points",
107 adaptation_time_points_,
108 "List of time points in (simulation) time at which we will "
109 "perform a mesh adaptation cycle.");
110
111 adaptation_cycle_interval_ = 5;
112 add_parameter("simulation cycle: interval",
113 adaptation_cycle_interval_,
114 "The nth simulation cycle at which we will "
115 "perform mesh adapation.");
116 leave_subsection();
117
118 const auto call_back = [this] {
119 /* Initialize Mersenne Twister with configured seed: */
120 mersenne_twister_.seed(random_adaptation_mersenne_twister_seed_);
121 };
122
123 call_back();
124 ParameterAcceptor::parse_parameters_call_back.connect(call_back);
125 }
126
127
128 template <typename Description, int dim, typename Number>
130 {
131#ifdef DEBUG_OUTPUT
132 std::cout << "MeshAdaptor<dim, Number>::prepare()" << std::endl;
133#endif
134
135 if (time_point_selection_strategy_ ==
137 /* Remove outdated refinement timestamps: */
138 const auto new_end = std::remove_if(
139 adaptation_time_points_.begin(),
140 adaptation_time_points_.end(),
141 [&](const Number &t_refinement) { return (t > t_refinement); });
142 adaptation_time_points_.erase(new_end, adaptation_time_points_.end());
143 }
144
145 if (adaptation_strategy_ == AdaptationStrategy::kelly_estimator) {
147 kelly_quantities_);
148 }
149
150 /* toggle mesh adaptation flag to off. */
151 need_mesh_adaptation_ = false;
152 }
153
154
155 template <typename Description, int dim, typename Number>
158 std::generate(std::begin(indicators_), std::end(indicators_), [&]() {
159 static std::uniform_real_distribution<double> distribution(0.0, 10.0);
160 return distribution(mersenne_twister_);
161 });
162 }
163
164
165 template <typename Description, int dim, typename Number>
167 const StateVector &state_vector) const
168 {
169 /* Populate Kelly quantities: */
170 const auto &affine_constraints = offline_data_->affine_constraints();
171
172 kelly_components_ =
174 *hyperbolic_system_,
175 state_vector,
176 initial_precomputed_,
177 alpha_,
178 kelly_quantities_);
179
180 for (auto &it : kelly_components_) {
181 affine_constraints.distribute(it);
182 it.update_ghost_values();
183 }
184 }
185
186
187 template <typename Description, int dim, typename Number>
188 void MeshAdaptor<Description, dim, Number>::compute_kelly_indicators() const
189 {
190#if !DEAL_II_VERSION_GTE(9, 6, 0)
191 AssertThrow(
192 false,
193 dealii::ExcMessage("The MeshAdaptor::compute_kelly_indicators() method "
194 "needs deal.II version 9.6.0 or newer"));
195#else
196
197 /*
198 * Calculate a Kelly error estimator for each configured quantitity:
199 */
200
201 std::vector<dealii::Vector<float>> kelly_errors;
202 std::vector<dealii::Vector<float> *> ptr_kelly_errors;
203
204 const auto size = indicators_.size();
205 kelly_errors.resize(kelly_components_.size());
206
207 for (auto &it : kelly_errors) {
208 it.reinit(size);
209 ptr_kelly_errors.push_back(&it);
210 }
211
212 auto array_view_kelly_errors = dealii::make_array_view(ptr_kelly_errors);
213 std::vector<const dealii::ReadVector<Number> *> ptr_kelly_components;
214 for (const auto &it : kelly_components_)
215 ptr_kelly_components.push_back(&it);
216
217 const auto array_view_kelly_components =
218 dealii::make_array_view(ptr_kelly_components);
219
220 dealii::KellyErrorEstimator<dim>::estimate(
221 offline_data_->discretization().mapping(),
222 offline_data_->dof_handler(),
223 offline_data_->discretization().face_quadrature(),
224 {},
225 array_view_kelly_components,
226 array_view_kelly_errors);
227
228 indicators_ = 0.;
229 for (const auto &it : kelly_errors)
230 indicators_ += it;
231#endif
232 }
233
234
235 template <typename Description, int dim, typename Number>
237 const StateVector &state_vector, const Number t, unsigned int cycle)
238 {
239#ifdef DEBUG_OUTPUT
240 std::cout << "MeshAdaptor<dim, Number>::analyze()" << std::endl;
241#endif
242
243 /*
244 * Decide whether we perform an adaptation cycle with the chosen time
245 * point selection strategy:
246 */
247
248 switch (time_point_selection_strategy_) {
250 /* Remove all refinement points from the vector that lie in the past: */
251 const auto new_end = std::remove_if( //
252 adaptation_time_points_.begin(),
253 adaptation_time_points_.end(),
254 [&](const Number &t_refinement) {
255 if (t < t_refinement)
256 return false;
257 need_mesh_adaptation_ = true;
258 return true;
259 });
260 adaptation_time_points_.erase(new_end, adaptation_time_points_.end());
261 } break;
262
264 /* check whether we reached a cycle interval: */
265 if (cycle % adaptation_cycle_interval_ == 0)
266 need_mesh_adaptation_ = true;
267 } break;
268
269 default:
270 AssertThrow(false, dealii::ExcInternalError());
271 __builtin_trap();
272 }
273
274 if (!need_mesh_adaptation_)
275 return;
276
277 /*
278 * Some adaptation strategies require us to prepare some internal
279 * data fields:
280 */
281
282 switch (adaptation_strategy_) {
284 /* do nothing */
285 break;
286
288 /* do nothing */
289 break;
290
292 populate_kelly_quantities(state_vector);
293 break;
294
295 default:
296 AssertThrow(false, dealii::ExcInternalError());
297 __builtin_trap();
298 }
299 }
300
301
302 template <typename Description, int dim, typename Number>
305 Triangulation &triangulation) const
306 {
307 auto &discretization [[maybe_unused]] = offline_data_->discretization();
308 Assert(&triangulation == &discretization.triangulation(),
309 dealii::ExcInternalError());
310
311 /*
312 * Compute an indicator with the chosen adaptation strategy:
313 */
314
315 switch (adaptation_strategy_) {
317 /* Simply mark all cells for refinement and return: */
318 for (auto &cell : triangulation.active_cell_iterators())
319 cell->set_refine_flag();
320 return;
321 } break;
322
324 indicators_.reinit(triangulation.n_active_cells());
325 compute_random_indicators();
326 } break;
327
329 indicators_.reinit(triangulation.n_active_cells());
330 compute_kelly_indicators();
331 } break;
332
333 default:
334 AssertThrow(false, dealii::ExcInternalError());
335 __builtin_trap();
336 }
337
338 /*
339 * Mark cells with chosen marking strategy:
340 */
341
342 Assert(indicators_.size() == triangulation.n_active_cells(),
343 dealii::ExcInternalError());
344
345 switch (marking_strategy_) {
347 dealii::GridRefinement::refine_and_coarsen_fixed_number(
348 triangulation,
349 indicators_,
350 refinement_fraction_,
351 coarsening_fraction_);
352 } break;
354 dealii::GridRefinement::refine_and_coarsen_fixed_fraction(
355 triangulation,
356 indicators_,
357 refinement_fraction_,
358 coarsening_fraction_,
359 max_num_cells_);
360 } break;
361
362 default:
363 AssertThrow(false, dealii::ExcInternalError());
364 __builtin_trap();
365 }
366
367 /*
368 * Constrain refinement and coarsening to maximum and minimum
369 * refinement levels:
370 */
371
372 if (triangulation.n_levels() > max_refinement_level_)
373 for (const auto &cell :
374 triangulation.active_cell_iterators_on_level(max_refinement_level_))
375 cell->clear_refine_flag();
376
377 for (const auto &cell :
378 triangulation.active_cell_iterators_on_level(min_refinement_level_))
379 cell->clear_coarsen_flag();
380 }
381} // namespace ryujin
typename View::StateVector StateVector
Definition: mesh_adaptor.h:125
typename Discretization< dim >::Triangulation Triangulation
Definition: mesh_adaptor.h:118
Vectors::ScalarVector< Number > ScalarVector
Definition: mesh_adaptor.h:127
MeshAdaptor(const MPIEnsemble &mpi_ensemble, const OfflineData< dim, Number > &offline_data, const HyperbolicSystem &hyperbolic_system, const ParabolicSystem &parabolic_system, const InitialPrecomputedVector &initial_precomputed, const ScalarVector &alpha, const std::string &subsection="/MeshAdaptor")
void analyze(const StateVector &state_vector, const Number t, unsigned int cycle)
typename View::InitialPrecomputedVector InitialPrecomputedVector
Definition: mesh_adaptor.h:126
typename Description::ParabolicSystem ParabolicSystem
Definition: mesh_adaptor.h:116
typename Description::HyperbolicSystem HyperbolicSystem
Definition: mesh_adaptor.h:115
void prepare(const Number t)
void mark_cells_for_coarsening_and_refinement(Triangulation &triangulation) const
std::tuple< MultiComponentVector< Number, problem_dim >, MultiComponentVector< Number, prec_dim >, BlockVector< Number > > StateVector
Definition: state_vector.h:51
static std::vector< ScalarVector > extract(const HyperbolicSystem &hyperbolic_system, const StateVector &state_vector, const InitialPrecomputedVector &initial_precomputed, const ScalarVector &alpha, const std::vector< std::string > &selected)
static void check(const std::vector< std::string > &selected)