161 const Callable &height)
const
164 constexpr auto invalid = dealii::numbers::invalid_unsigned_int;
166 using Requests = std::map<unsigned int, dealii::Point<dim>>;
168 const auto distributed =
169 dynamic_cast<dealii::parallel::DistributedTriangulationBase<dim> *
>(
178 dealii::GridTools::get_locally_owned_vertices(triangulation);
179 const auto vertex_to_cells =
180 dealii::GridTools::vertex_to_cell_map(triangulation);
182 const unsigned int n_vertices = triangulation.n_vertices();
183 const unsigned int n_cells = triangulation.n_active_cells();
190 const auto compute_vertex_states = [&]() {
191 std::vector<int> result(n_vertices, 0);
192 for (
const auto &cell : triangulation.active_cell_iterators())
193 if (!cell->is_artificial())
194 for (
unsigned int i = 0; i < 4; ++i)
195 result[cell->vertex_index(i)] =
201 const auto move_vertex =
202 [&](
const unsigned int g,
const dealii::Point<dim> &p) {
203 const auto &cell = *vertex_to_cells[g].begin();
204 for (
unsigned int i = 0; i < 4; ++i)
205 if (cell->vertex_index(i) == g)
216 const auto admissible = [&](
const auto &cell,
217 const unsigned int i,
218 const dealii::Point<dim> &p,
219 const double floor) {
220 const auto g = cell->vertex_index(i);
223 if (p[0] != cell->vertex(i)[0])
224 for (
const auto &cell : vertex_to_cells[g])
225 for (
const unsigned int f : {0u, 1u})
226 if (cell->face(f)->at_boundary())
227 for (
unsigned int k = 0; k < 2; ++k)
228 if (cell->face(f)->vertex_index(k) == g)
232 const auto saved = cell->vertex(i);
234 double jacobian = std::numeric_limits<double>::max();
235 for (
const auto &cell : vertex_to_cells[g])
236 for (
unsigned int k = 0; k < 4; ++k) {
237 const auto e_x = cell->vertex(k ^ 1) - cell->vertex(k);
238 const auto e_y = cell->vertex(k ^ 2) - cell->vertex(k);
239 const double sign = (k == 1 || k == 2) ? -1. : 1.;
241 std::min(jacobian, sign * (e_x[0] * e_y[1] - e_x[1] * e_y[0]));
243 move_vertex(g, saved);
244 return jacobian > floor;
253 const auto propose = [&](Requests &requests,
255 const unsigned int i,
256 const dealii::Point<dim> &p) {
257 const auto g = cell->vertex_index(i);
258 const auto key = [&](
const dealii::Point<dim> &q) {
259 return std::make_tuple((q - cell->vertex(i)).norm(), q[0], q[1]);
261 const auto [it, inserted] = requests.try_emplace(g, p);
262 if (!inserted && key(p) < key(it->second))
267 const auto apply = [&](
const Requests &requests) {
268 for (
const auto &[g, p] : requests)
271 if (distributed !=
nullptr)
272 distributed->communicate_locally_moved_vertices(owned);
285 for (
const unsigned int direction : {y, 0u}) {
286 const auto vertex_states = compute_vertex_states();
289 for (
const auto &cell : triangulation.active_cell_iterators()) {
290 if (cell->is_artificial())
293 const double h0 = cell->diameter();
294 const unsigned int bit = 1u << direction;
295 for (
unsigned int i = 0; i < 4; ++i) {
296 const auto g_a = cell->vertex_index(i);
297 const auto g_b = cell->vertex_index(i | bit);
298 if ((i & bit) != 0 || vertex_states[g_a] * vertex_states[g_b] >= 0)
302 const auto a = cell->vertex(i);
303 const auto d = cell->vertex(i | bit) - a;
304 double t_a = 0., t_b = 1.;
305 for (
unsigned int k = 0; k < 60; ++k) {
306 const double t = 0.5 * (t_a + t_b);
307 const auto p = a + t * d;
308 (
vertex_state(height, p) == vertex_states[g_a] ? t_a : t_b) = t;
310 const double t = 0.5 * (t_a + t_b);
311 auto cut = a + t * d;
312 cut[y] = height(cut);
315 t <= 0.5 ? std::array{i, i | bit} : std::array{i | bit, i};
317 for (
const double floor :
318 {minimal_jacobian_fraction_ * h0 * h0, 0.})
319 for (
const auto j : order)
320 if (!done && admissible(cell, j, cut, floor)) {
321 propose(requests, cell, j, cut);
350 const auto priority = [&](
const dealii::Point<dim> &v) {
352 std::uint64_t hash = 0x9e3779b97f4a7c15ull;
353 for (
unsigned int d = 0; d < dim; ++d) {
354 const auto bits = std::bit_cast<std::uint64_t>(v[d]);
355 hash ^= bits + 0x9e3779b97f4a7c15ull + (hash << 6) + (hash >> 2);
356 hash *= 0xbf58476d1ce4e5b9ull;
362 constexpr std::array<std::pair<unsigned int, unsigned int>, 6> chords{
363 {{0, 1}, {2, 3}, {0, 2}, {1, 3}, {0, 3}, {1, 2}}};
365 const double nan = std::numeric_limits<double>::quiet_NaN();
367 std::vector<bool> pinned(n_vertices,
false);
369 for (
unsigned int sweep = 0; sweep < max_sweeps_; ++sweep) {
370 const auto vertex_states = compute_vertex_states();
373 std::vector<std::vector<double>> records(n_cells);
375 for (
const auto &cell : triangulation.active_cell_iterators()) {
376 if (!cell->is_locally_owned())
379 auto &record = records[cell->active_cell_index()];
380 const double h0 = cell->diameter();
382 for (
const auto &[i_a, i_b] : chords) {
383 const auto g_a = cell->vertex_index(i_a);
384 const auto g_b = cell->vertex_index(i_b);
385 if (vertex_states[g_a] != 0 || vertex_states[g_b] != 0)
392 if ((i_a ^ i_b) == 3 &&
393 vertex_states[cell->vertex_index(i_a ^ 1)] *
394 vertex_states[cell->vertex_index(i_a ^ 2)] >=
404 const auto a = cell->vertex(i_a);
405 const auto d = cell->vertex(i_b) - a;
406 double deviation = 0., t_best = 0., t_left = 0., t_right = 1.;
407 dealii::Point<dim> corner;
408 for (
unsigned int level = 0; level < 2; ++level) {
409 for (
unsigned int s = 1; s < 64; ++s) {
410 const double t = t_left + (t_right - t_left) * s / 64.;
412 const double h = height(p);
413 const double delta = (h - p[y]) * std::abs(d[0]) / d.norm();
414 if (std::abs(delta) > std::abs(deviation)) {
421 const double dt = (t_right - t_left) / 64.;
422 t_left = std::max(0., t_best - dt);
423 t_right = std::min(1., t_best + dt);
426 if (std::abs(deviation) < acceptable_deviation_ * h0)
435 const int side = deviation > 0. ? 1 : -1;
436 std::vector<std::tuple<double, double, double, unsigned int>>
438 for (
unsigned int i = 0; i < 4; ++i) {
439 const auto &v = cell->vertex(i);
440 if (i == i_a || i == i_b ||
441 vertex_states[cell->vertex_index(i)] == side)
442 candidates.emplace_back((corner - v).norm(), v[0], v[1], i);
444 std::sort(candidates.begin(), candidates.end());
446 for (
const auto &[displacement, x, z, i] : candidates) {
447 const auto g = cell->vertex_index(i);
450 cell, i, corner, minimal_jacobian_fraction_ * h0 * h0))
453 record.assign(4 * dim, nan);
454 const dealii::Point<dim> previous(record[2 * i],
456 if (std::isnan(previous[0]) ||
457 displacement < (previous - cell->vertex(i)).norm())
458 for (
unsigned int k = 0; k < dim; ++k)
459 record[2 * i + k] = corner[k];
468 for (
const auto &cell : triangulation.active_cell_iterators()) {
469 const auto &record = records[cell->active_cell_index()];
470 if (cell->is_artificial() || record.empty())
472 for (
unsigned int i = 0; i < 4; ++i)
473 if (!std::isnan(record[2 * i]))
477 dealii::Point<dim>(record[2 * i], record[2 * i + 1]));
481 std::vector<unsigned int> vetoes(n_cells, 0);
482 for (
const auto &cell : triangulation.active_cell_iterators()) {
483 if (!cell->is_locally_owned())
485 unsigned int i_best = invalid;
486 for (
unsigned int i = 0; i < 4; ++i)
487 if (requests.count(cell->vertex_index(i)) != 0 &&
488 (i_best == invalid ||
489 priority(cell->vertex(i)) > priority(cell->vertex(i_best))))
491 for (
unsigned int i = 0; i < 4; ++i)
492 if (i != i_best && requests.count(cell->vertex_index(i)) != 0)
493 vetoes[cell->active_cell_index()] |= 1u << i;
498 for (
const auto &cell : triangulation.active_cell_iterators())
499 if (!cell->is_artificial())
500 for (
unsigned int i = 0; i < 4; ++i)
501 if ((vetoes[cell->active_cell_index()] & (1u << i)) != 0)
502 requests.erase(cell->vertex_index(i));
506 unsigned int n_moved = 0;
507 for (
const auto &[g, p] : requests) {
511#if DEAL_II_VERSION_GTE(9, 7, 0)
512 const auto comm = triangulation.get_mpi_communicator();
514 const auto comm = triangulation.get_communicator();
516 n_moved = dealii::Utilities::MPI::max(n_moved, comm);