14#include <deal.II/base/array_view.h>
15#include <deal.II/distributed/grid_refinement.h>
17#include <boost/container/small_vector.hpp>
21 template <
typename Description,
int dim,
typename Number>
29 const std::string &subsection )
30 : ParameterAcceptor(subsection)
31 , mpi_ensemble_(mpi_ensemble)
32 , offline_data_(&offline_data)
33 , hyperbolic_system_(&hyperbolic_system)
34 , parabolic_system_(¶bolic_system)
35 , initial_precomputed_(initial_precomputed)
37 , need_mesh_adaptation_(false)
40 add_parameter(
"adaptation strategy",
42 "The chosen adaptation strategy. Possible values are: global "
43 "refinement, random adaptation, smoothness indicators");
49 "The chosen marking strategy. Possible values are: fixed threshold.");
51 time_point_selection_strategy_ =
53 add_parameter(
"time point selection strategy",
54 time_point_selection_strategy_,
55 "The chosen time point selection strategy. Possible values "
56 "are: fixed time points, simulation cycle");
59 enter_subsection(
"adaptation strategies");
60 random_adaptation_mersenne_twister_seed_ = 42u;
61 add_parameter(
"random adaptation: mersenne_twister_seed",
62 random_adaptation_mersenne_twister_seed_,
63 "Seed for 64bit Mersenne Twister used for random refinement");
66 "smoothness indicators: quantities",
67 smoothness_selected_quantities_,
68 "List of conserved, primitive or precomputed quantities that will be "
69 "used for constructing the smoothness indicator.");
71 smoothness_local_global_ratio_ = 0.5;
73 "smoothness indicators: local global ratio",
74 smoothness_local_global_ratio_,
75 "Ratio between local and global denominator value used for normalizing "
76 "the smoothness indicator. A value of 1 indicates pure global "
77 "normalization, a value of 0 indicates pure local normalization.");
79 smoothness_min_cutoff_ = 0.0;
80 add_parameter(
"smoothness indicators: min cutoff",
81 smoothness_min_cutoff_,
82 "minimal cutoff for the smoothness indicator: values below "
83 "this threshold will be set to the cutoff value.");
85 smoothness_max_cutoff_ = 1.0e16;
86 add_parameter(
"smoothness indicators: max cutoff",
87 smoothness_max_cutoff_,
88 "minimal cutoff for the smoothness indicator: values above "
89 "this threshold will be set to the cutoff value.");
91 smoothness_widen_stencil_ = 15;
93 "smoothness indicators: stencil size",
94 smoothness_widen_stencil_,
95 "Number of layers to widen the smoothness indicator stencil.");
100 enter_subsection(
"marking strategies");
102 coarsening_threshold_ = 0.25;
104 "coarsening threshold",
105 coarsening_threshold_,
106 "Marking: normalized or absolute threshold for selecting cells for "
107 "coarsening (used in \"fixed threshhold\" marking strategy).");
109 refinement_threshold_ = 0.75;
111 "refinement threshold",
112 refinement_threshold_,
113 "Marking: normalized or absolute threshold for selecting cells for "
114 "refinement (used in \"fixed threshold\" marking strategy).");
116 absolute_threshold_ =
false;
117 add_parameter(
"absolute threshold",
119 "Marking: if set to true use an absolute threshold for the "
120 "\"refinement threshold\" and \"coarsening threshold\" "
121 "values instead of a relative one. If this parameter is set "
122 "to false then the smoothness indicator is normalized into "
123 "the number range of [0., 1] and the threshold parameters "
124 "are also expected to be a value in this interval.");
126 min_refinement_level_ = 0;
127 add_parameter(
"minimal refinement level",
128 min_refinement_level_,
129 "Marking: minimal refinement level of cells that will be "
130 "maintained while coarsening cells.");
132 max_refinement_level_ = 1000;
133 add_parameter(
"maximal refinement level",
134 max_refinement_level_,
135 "Marking: maximal refinement level of cells that will be "
136 "maintained while refininig cells.");
141 enter_subsection(
"time point selection strategies");
142 adaptation_time_points_ = {};
143 add_parameter(
"fixed time points",
144 adaptation_time_points_,
145 "List of time points in (simulation) time at which we will "
146 "perform a mesh adaptation cycle.");
148 adaptation_cycle_interval_ = 10;
149 add_parameter(
"simulation cycle: interval",
150 adaptation_cycle_interval_,
151 "The nth simulation cycle at which we will "
152 "perform mesh adapation.");
155 const auto call_back = [
this] {
157 mersenne_twister_.seed(random_adaptation_mersenne_twister_seed_);
161 ParameterAcceptor::parse_parameters_call_back.connect(call_back);
165 template <
typename Description,
int dim,
typename Number>
169 std::cout <<
"MeshAdaptor<dim, Number>::prepare()" << std::endl;
172 if (time_point_selection_strategy_ ==
175 const auto new_end = std::remove_if(
176 adaptation_time_points_.begin(),
177 adaptation_time_points_.end(),
178 [&](
const Number &t_refinement) { return (t > t_refinement); });
179 adaptation_time_points_.erase(new_end, adaptation_time_points_.end());
183 {
"alpha"}, smoothness_selected_quantities_);
186 need_mesh_adaptation_ =
false;
190 template <
typename Description,
int dim,
typename Number>
194 const auto &affine_constraints = offline_data_->affine_constraints();
195 const unsigned int n_internal = offline_data_->n_locally_internal();
196 const unsigned int n_owned = offline_data_->n_locally_owned();
197 const auto &sparsity_simd = offline_data_->sparsity_pattern_simd();
198 const auto &betaij_matrix = offline_data_->betaij_matrix();
199 using VA = dealii::VectorizedArray<Number>;
210 initial_precomputed_,
213 smoothness_selected_quantities_);
215 for (
auto &it : quantities) {
216 it.update_ghost_values();
217 affine_constraints.distribute(it);
218 it.update_ghost_values();
225 const unsigned int n_entries = quantities.size();
226 const auto &scalar_partitioner = offline_data_->scalar_partitioner();
228 std::vector<ScalarVector> numerator(n_entries);
229 std::vector<ScalarVector> denominator(std::max(1u, n_entries));
230 for (
auto &it : numerator)
231 it.reinit(scalar_partitioner);
232 for (
auto &it : denominator)
233 it.reinit(scalar_partitioner);
241 auto loop = [&](
auto sentinel,
unsigned int left,
unsigned int right) {
242 using T =
decltype(sentinel);
243 unsigned int stride_size = get_stride_size<T>;
246 for (
unsigned int i = left; i < right; i += stride_size) {
249 const unsigned int row_length = sparsity_simd.row_length(i);
253 boost::container::small_vector<T, 10> value_i(n_entries, T(0.));
254 for (
unsigned int k = 0; k < n_entries; ++k) {
255 value_i[k] = get_entry<T>(quantities[k], i);
258 boost::container::small_vector<T, 10> numerator_i(n_entries, T(0.));
259 boost::container::small_vector<T, 10> denominator_i(n_entries, T(0.));
261 const unsigned int *js = sparsity_simd.columns(i);
262 for (
unsigned int col_idx = 0; col_idx < row_length;
263 ++col_idx, js += stride_size) {
269 const auto beta_ij = betaij_matrix.template get_entry<T>(i, col_idx);
271 for (
unsigned int k = 0; k < n_entries; ++k) {
272 const auto value_j_k = get_entry<T>(quantities[k], js);
273 numerator_i[k] += beta_ij * (value_j_k - value_i[k]);
276 std::max(std::abs(value_j_k), std::abs(value_i[k]));
279 for (
unsigned int k = 0; k < n_entries; ++k) {
280 write_entry<T>(numerator[k], numerator_i[k], i);
281 write_entry<T>(denominator[k], denominator_i[k], i);
288 loop(Number(), n_internal, n_owned);
290 loop(VA(), 0, n_internal);
298 smoothness_indicators_.reinit(scalar_partitioner);
300 constexpr Number eps = std::numeric_limits<Number>::epsilon();
302 std::vector<Number> denominator_global_maximum(n_entries);
303 for (
unsigned int k = 0; k < n_entries; ++k) {
304 denominator_global_maximum[k] = dealii::Utilities::MPI::max(
305 denominator[k].linfty_norm(), mpi_ensemble_.ensemble_communicator());
307 denominator_global_maximum[k] =
308 std::max(denominator_global_maximum[k], eps);
313 auto loop = [&](
auto sentinel,
unsigned int left,
unsigned int right) {
314 using T =
decltype(sentinel);
315 unsigned int stride_size = get_stride_size<T>;
318 for (
unsigned int i = left; i < right; i += stride_size) {
321 const unsigned int row_length = sparsity_simd.row_length(i);
325 auto alpha_i = T(0.);
326 for (
unsigned int k = 0; k < n_entries; ++k) {
327 const auto numerator_i = get_entry<T>(numerator[k], i);
328 const auto denominator_i = get_entry<T>(denominator[k], i);
331 (Number(1.) - smoothness_local_global_ratio_) * denominator_i +
332 smoothness_local_global_ratio_ * denominator_global_maximum[k];
333 denominator = std::max(T(eps), denominator);
335 alpha_i += std::abs(numerator_i) / denominator;
338 alpha_i = std::min(alpha_i, T(smoothness_max_cutoff_));
339 alpha_i = std::max(alpha_i, T(smoothness_min_cutoff_));
340 write_entry<T>(smoothness_indicators_, alpha_i, i);
345 loop(Number(), n_internal, n_owned);
347 loop(VA(), 0, n_internal);
355 for (
unsigned int cycle = 0; cycle < smoothness_widen_stencil_; ++cycle) {
356 smoothness_indicators_.update_ghost_values();
360 auto loop = [&](
auto sentinel,
unsigned int left,
unsigned int right) {
363 using T =
decltype(sentinel);
364 unsigned int stride_size = get_stride_size<T>;
369 for (
unsigned int i = left; i < right; i += stride_size) {
372 const unsigned int row_length = sparsity_simd.row_length(i);
376 auto alpha_i = get_entry<T>(smoothness_indicators_, i);
378 const unsigned int *js = sparsity_simd.columns(i);
379 for (
unsigned int col_idx = 0; col_idx < row_length;
380 ++col_idx, js += stride_size) {
386 const auto alpha_j = get_entry<T>(smoothness_indicators_, js);
388 alpha_i = std::max(alpha_i, alpha_j);
391 write_entry<T>( denominator[0], alpha_i, i);
396 loop(Number(), n_internal, n_owned);
398 loop(VA(), 0, n_internal);
402 smoothness_indicators_ = denominator[0];
405 smoothness_indicators_.update_ghost_values();
406 affine_constraints.distribute(smoothness_indicators_);
407 smoothness_indicators_.update_ghost_values();
411 template <
typename Description,
int dim,
typename Number>
413 const StateVector &state_vector,
const Number t,
unsigned int cycle)
416 std::cout <<
"MeshAdaptor<dim, Number>::analyze()" << std::endl;
424 switch (time_point_selection_strategy_) {
427 const auto new_end = std::remove_if(
428 adaptation_time_points_.begin(),
429 adaptation_time_points_.end(),
430 [&](
const Number &t_refinement) {
431 if (t < t_refinement)
433 need_mesh_adaptation_ = true;
436 adaptation_time_points_.erase(new_end, adaptation_time_points_.end());
441 if (cycle % adaptation_cycle_interval_ == 0)
442 need_mesh_adaptation_ =
true;
446 AssertThrow(
false, dealii::ExcInternalError());
450 if (!need_mesh_adaptation_)
458 switch (adaptation_strategy_) {
468 compute_smoothness_indicators(state_vector);
473 AssertThrow(
false, dealii::ExcInternalError());
479 template <
typename Description,
int dim,
typename Number>
483 std::generate(std::begin(indicators_), std::end(indicators_), [&]() {
484 static std::uniform_real_distribution<double> distribution(0.0, 10.0);
485 return distribution(mersenne_twister_);
490 template <
typename Description,
int dim,
typename Number>
491 void MeshAdaptor<Description, dim, Number>::
492 populate_cell_indicators_from_smoothness_indicators()
const
494 const auto &scalar_partitioner = offline_data_->scalar_partitioner();
500 std::vector<dealii::types::global_dof_index> local_dof_indices;
502 const auto &dof_handler = offline_data_->dof_handler();
503 for (
const auto &cell : dof_handler.active_cell_iterators()) {
504 if (!cell->is_locally_owned())
507 const unsigned int dofs_per_cell = cell->get_fe().n_dofs_per_cell();
508 const auto scale = Number(1. / dofs_per_cell);
509 local_dof_indices.resize(dofs_per_cell);
510 cell->get_dof_indices(local_dof_indices);
512 auto alpha_cell = Number(0.);
514 for (
unsigned int i = 0; i < dofs_per_cell; ++i) {
515 const auto global_i = local_dof_indices[i];
516 const auto local_i = scalar_partitioner->global_to_local(global_i);
517 auto alpha_i = get_entry<Number>(smoothness_indicators_, local_i);
518 alpha_cell += alpha_i;
522 indicators_[cell->active_cell_index()] =
static_cast<float>(alpha_cell);
527 template <
typename Description,
int dim,
typename Number>
530 dealii::Triangulation<dim> &triangulation [[maybe_unused]])
const
532 auto &discretization [[maybe_unused]] = offline_data_->discretization();
533 Assert(&triangulation == &discretization.triangulation(),
534 dealii::ExcInternalError());
536#if !DEAL_II_VERSION_GTE(9, 6, 0)
540 "The MeshAdaptor class needs deal.II version 9.6.0 or newer"));
548 switch (adaptation_strategy_) {
551 for (
auto &cell : triangulation.active_cell_iterators())
552 cell->set_refine_flag();
557 indicators_.reinit(triangulation.n_active_cells());
558 populate_cell_indicators_with_random_values();
562 indicators_.reinit(triangulation.n_active_cells());
563 populate_cell_indicators_from_smoothness_indicators();
567 AssertThrow(
false, dealii::ExcInternalError());
575 switch (marking_strategy_) {
578 float inv_denominator = 1.f;
581 if (!absolute_threshold_) {
586 float minimum = std::numeric_limits<float>::max();
588 for (
const auto &cell : triangulation.active_cell_iterators()) {
589 if (!cell->is_locally_owned())
591 const auto indicator = indicators_[cell->active_cell_index()];
595 minimum = dealii::Utilities::MPI::min(
596 minimum, mpi_ensemble_.ensemble_communicator());
597 maximum = dealii::Utilities::MPI::max(
598 maximum, mpi_ensemble_.ensemble_communicator());
600 constexpr float eps = std::numeric_limits<float>::epsilon();
603 bias = (
minimum + 5.f * eps) * inv_denominator;
610 for (
const auto &cell : triangulation.active_cell_iterators()) {
611 if (!cell->is_locally_owned())
614 auto indicator = indicators_[cell->active_cell_index()];
615 indicator = indicator * inv_denominator - bias;
616 if (indicator < coarsening_threshold_)
617 cell->set_coarsen_flag();
618 else if (indicator > refinement_threshold_)
619 cell->set_refine_flag();
624 AssertThrow(
false, dealii::ExcInternalError());
633 if (triangulation.n_levels() > max_refinement_level_)
634 for (
const auto &cell :
635 triangulation.active_cell_iterators_on_level(max_refinement_level_))
636 cell->clear_refine_flag();
638 for (
const auto &cell :
639 triangulation.active_cell_iterators_on_level(min_refinement_level_))
640 cell->clear_coarsen_flag();
void compute_smoothness_indicators(const StateVector &state_vector) const
typename View::StateVector StateVector
Vectors::ScalarVector< Number > ScalarVector
MeshAdaptor(const MPIEnsemble &mpi_ensemble, const OfflineData< dim, Number > &offline_data, const HyperbolicSystem &hyperbolic_system, const ParabolicSystem ¶bolic_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
typename Description::ParabolicSystem ParabolicSystem
typename Description::HyperbolicSystem HyperbolicSystem
void mark_cells_for_coarsening_and_refinement(dealii::Triangulation< dim > &triangulation) const
void prepare(const Number t)
#define RYUJIN_PARALLEL_REGION_BEGIN
#define RYUJIN_PARALLEL_REGION_END