160 const Callable &height)
const
163 constexpr auto invalid = dealii::numbers::invalid_unsigned_int;
165 using Requests = std::map<unsigned int, dealii::Point<dim>>;
167 const auto distributed =
168 dynamic_cast<dealii::parallel::DistributedTriangulationBase<dim> *
>(
177 dealii::GridTools::get_locally_owned_vertices(triangulation);
178 const auto vertex_to_cells =
179 dealii::GridTools::vertex_to_cell_map(triangulation);
181 const unsigned int n_vertices = triangulation.n_vertices();
182 const unsigned int n_cells = triangulation.n_active_cells();
189 const auto compute_vertex_states = [&]() {
190 std::vector<int> result(n_vertices, 0);
191 for (
const auto &cell : triangulation.active_cell_iterators())
192 if (!cell->is_artificial())
193 for (
unsigned int i = 0; i < 4; ++i)
194 result[cell->vertex_index(i)] =
200 const auto move_vertex =
201 [&](
const unsigned int g,
const dealii::Point<dim> &p) {
202 const auto &cell = *vertex_to_cells[g].begin();
203 for (
unsigned int i = 0; i < 4; ++i)
204 if (cell->vertex_index(i) == g)
215 const auto admissible = [&](
const auto &cell,
216 const unsigned int i,
217 const dealii::Point<dim> &p,
218 const double floor) {
219 const auto g = cell->vertex_index(i);
222 if (p[0] != cell->vertex(i)[0])
223 for (
const auto &cell : vertex_to_cells[g])
224 for (
const unsigned int f : {0u, 1u})
225 if (cell->face(f)->at_boundary())
226 for (
unsigned int k = 0; k < 2; ++k)
227 if (cell->face(f)->vertex_index(k) == g)
231 const auto saved = cell->vertex(i);
233 double jacobian = std::numeric_limits<double>::max();
234 for (
const auto &cell : vertex_to_cells[g])
235 for (
unsigned int k = 0; k < 4; ++k) {
236 const auto e_x = cell->vertex(k ^ 1) - cell->vertex(k);
237 const auto e_y = cell->vertex(k ^ 2) - cell->vertex(k);
238 const double sign = (k == 1 || k == 2) ? -1. : 1.;
240 std::min(jacobian, sign * (e_x[0] * e_y[1] - e_x[1] * e_y[0]));
242 move_vertex(g, saved);
243 return jacobian > floor;
252 const auto propose = [&](Requests &requests,
254 const unsigned int i,
255 const dealii::Point<dim> &p) {
256 const auto g = cell->vertex_index(i);
257 const auto key = [&](
const dealii::Point<dim> &q) {
258 return std::make_tuple((q - cell->vertex(i)).norm(), q[0], q[1]);
260 const auto [it, inserted] = requests.try_emplace(g, p);
261 if (!inserted && key(p) < key(it->second))
266 const auto apply = [&](
const Requests &requests) {
267 for (
const auto &[g, p] : requests)
270 if (distributed !=
nullptr)
271 distributed->communicate_locally_moved_vertices(owned);
284 for (
const unsigned int direction : {y, 0u}) {
285 const auto vertex_states = compute_vertex_states();
288 for (
const auto &cell : triangulation.active_cell_iterators()) {
289 if (cell->is_artificial())
292 const double h0 = cell->diameter();
293 const unsigned int bit = 1u << direction;
294 for (
unsigned int i = 0; i < 4; ++i) {
295 const auto g_a = cell->vertex_index(i);
296 const auto g_b = cell->vertex_index(i | bit);
297 if ((i & bit) != 0 || vertex_states[g_a] * vertex_states[g_b] >= 0)
301 const auto a = cell->vertex(i);
302 const auto d = cell->vertex(i | bit) - a;
303 double t_a = 0., t_b = 1.;
304 for (
unsigned int k = 0; k < 60; ++k) {
305 const double t = 0.5 * (t_a + t_b);
306 const auto p = a + t * d;
307 (
vertex_state(height, p) == vertex_states[g_a] ? t_a : t_b) = t;
309 const double t = 0.5 * (t_a + t_b);
310 auto cut = a + t * d;
311 cut[y] = height(cut);
314 t <= 0.5 ? std::array{i, i | bit} : std::array{i | bit, i};
316 for (
const double floor :
317 {minimal_jacobian_fraction_ * h0 * h0, 0.})
318 for (
const auto j : order)
319 if (!done && admissible(cell, j, cut, floor)) {
320 propose(requests, cell, j, cut);
349 const auto priority = [&](
const dealii::Point<dim> &v) {
351 std::uint64_t hash = 0x9e3779b97f4a7c15ull;
352 for (
unsigned int d = 0; d < dim; ++d) {
353 const auto bits = std::bit_cast<std::uint64_t>(v[d]);
354 hash ^= bits + 0x9e3779b97f4a7c15ull + (hash << 6) + (hash >> 2);
355 hash *= 0xbf58476d1ce4e5b9ull;
361 constexpr std::array<std::pair<unsigned int, unsigned int>, 6> chords{
362 {{0, 1}, {2, 3}, {0, 2}, {1, 3}, {0, 3}, {1, 2}}};
364 const double nan = std::numeric_limits<double>::quiet_NaN();
366 std::vector<bool> pinned(n_vertices,
false);
368 for (
unsigned int sweep = 0; sweep < max_sweeps_; ++sweep) {
369 const auto vertex_states = compute_vertex_states();
372 std::vector<std::vector<double>> records(n_cells);
374 for (
const auto &cell : triangulation.active_cell_iterators()) {
375 if (!cell->is_locally_owned())
378 auto &record = records[cell->active_cell_index()];
379 const double h0 = cell->diameter();
381 for (
const auto &[i_a, i_b] : chords) {
382 const auto g_a = cell->vertex_index(i_a);
383 const auto g_b = cell->vertex_index(i_b);
384 if (vertex_states[g_a] != 0 || vertex_states[g_b] != 0)
391 if ((i_a ^ i_b) == 3 &&
392 vertex_states[cell->vertex_index(i_a ^ 1)] *
393 vertex_states[cell->vertex_index(i_a ^ 2)] >=
403 const auto a = cell->vertex(i_a);
404 const auto d = cell->vertex(i_b) - a;
405 double deviation = 0., t_best = 0., t_left = 0., t_right = 1.;
406 dealii::Point<dim> corner;
407 for (
unsigned int level = 0; level < 2; ++level) {
408 for (
unsigned int s = 1; s < 64; ++s) {
409 const double t = t_left + (t_right - t_left) * s / 64.;
411 const double h = height(p);
412 const double delta = (h - p[y]) * std::abs(d[0]) / d.norm();
413 if (std::abs(delta) > std::abs(deviation)) {
420 const double dt = (t_right - t_left) / 64.;
421 t_left = std::max(0., t_best - dt);
422 t_right = std::min(1., t_best + dt);
425 if (std::abs(deviation) < acceptable_deviation_ * h0)
434 const int side = deviation > 0. ? 1 : -1;
435 std::vector<std::tuple<double, double, double, unsigned int>>
437 for (
unsigned int i = 0; i < 4; ++i) {
438 const auto &v = cell->vertex(i);
439 if (i == i_a || i == i_b ||
440 vertex_states[cell->vertex_index(i)] == side)
441 candidates.emplace_back((corner - v).norm(), v[0], v[1], i);
443 std::sort(candidates.begin(), candidates.end());
445 for (
const auto &[displacement, x, z, i] : candidates) {
446 const auto g = cell->vertex_index(i);
449 cell, i, corner, minimal_jacobian_fraction_ * h0 * h0))
452 record.assign(4 * dim, nan);
453 const dealii::Point<dim> previous(record[2 * i],
455 if (std::isnan(previous[0]) ||
456 displacement < (previous - cell->vertex(i)).norm())
457 for (
unsigned int k = 0; k < dim; ++k)
458 record[2 * i + k] = corner[k];
467 for (
const auto &cell : triangulation.active_cell_iterators()) {
468 const auto &record = records[cell->active_cell_index()];
469 if (cell->is_artificial() || record.empty())
471 for (
unsigned int i = 0; i < 4; ++i)
472 if (!std::isnan(record[2 * i]))
476 dealii::Point<dim>(record[2 * i], record[2 * i + 1]));
480 std::vector<unsigned int> vetoes(n_cells, 0);
481 for (
const auto &cell : triangulation.active_cell_iterators()) {
482 if (!cell->is_locally_owned())
484 unsigned int i_best = invalid;
485 for (
unsigned int i = 0; i < 4; ++i)
486 if (requests.count(cell->vertex_index(i)) != 0 &&
487 (i_best == invalid ||
488 priority(cell->vertex(i)) > priority(cell->vertex(i_best))))
490 for (
unsigned int i = 0; i < 4; ++i)
491 if (i != i_best && requests.count(cell->vertex_index(i)) != 0)
492 vetoes[cell->active_cell_index()] |= 1u << i;
497 for (
const auto &cell : triangulation.active_cell_iterators())
498 if (!cell->is_artificial())
499 for (
unsigned int i = 0; i < 4; ++i)
500 if ((vetoes[cell->active_cell_index()] & (1u << i)) != 0)
501 requests.erase(cell->vertex_index(i));
505 unsigned int n_moved = 0;
506 for (
const auto &[g, p] : requests) {
510#if DEAL_II_VERSION_GTE(9, 7, 0)
511 const auto comm = triangulation.get_mpi_communicator();
513 const auto comm = triangulation.get_communicator();
515 n_moved = dealii::Utilities::MPI::max(n_moved, comm);