37auto compute_parent_facets(std::span<const std::int32_t> simplex_set)
39 static_assert(tdim == 2 or tdim == 3);
40 assert(simplex_set.size() % (tdim + 1) == 0);
42 = std::conditional_t<tdim == 2, std::array<std::int8_t, 12>,
43 std::array<std::int8_t, 32>>;
51 constexpr std::array<std::array<int, 3>, 3> facet_table_2d{
52 {{1, 2, 3}, {0, 2, 4}, {0, 1, 5}}};
54 constexpr std::array<std::array<int, 6>, 4> facet_table_3d{
60 const int ncells = simplex_set.size() / (tdim + 1);
61 for (
int fpi = 0; fpi < (tdim + 1); ++fpi)
64 for (
int cc = 0; cc < ncells; ++cc)
66 for (
int fci = 0; fci < (tdim + 1); ++fci)
69 std::array<int, tdim> cf, set_output;
71 int num_common_vertices;
72 if constexpr (tdim == 2)
74 for (
int j = 0; j < tdim; ++j)
75 cf[j] = simplex_set[cc * 3 + facet_table_2d[fci][j]];
77 std::ranges::sort(cf);
78 auto [last1, last2, it_last] = std::ranges::set_intersection(
79 facet_table_2d[fpi], cf, set_output.begin());
81 = std::ranges::distance(set_output.begin(), it_last);
85 for (
int j = 0; j < tdim; ++j)
86 cf[j] = simplex_set[cc * 4 + facet_table_3d[fci][j]];
88 std::ranges::sort(cf);
89 auto [last1, last2, it_last] = std::ranges::set_intersection(
90 facet_table_3d[fpi], cf, set_output.begin());
92 = std::ranges::distance(set_output.begin(), it_last);
95 if (num_common_vertices == tdim)
126std::pair<std::array<std::int32_t, 32>, std::size_t>
127get_simplices(std::span<const std::int64_t> indices,
128 std::span<const std::int32_t> longest_edge,
int tdim,
134 std::span<std::int8_t> marked_edges,
136 std::span<const std::int32_t> long_edge);
147template <std::
floating_po
int T>
148std::pair<std::vector<std::int32_t>, std::vector<std::int8_t>>
151 const int tdim =
mesh.topology()->dim();
153 mesh.topology_mutable()->create_entities(1);
154 mesh.topology_mutable()->create_entities(2);
155 mesh.topology_mutable()->create_connectivity(2, 1);
156 mesh.topology_mutable()->create_connectivity(1, tdim);
157 mesh.topology_mutable()->create_connectivity(tdim, 2);
159 std::int64_t num_faces =
mesh.topology()->index_map(2)->size_local()
160 +
mesh.topology()->index_map(2)->num_ghosts();
163 std::vector<std::int32_t> long_edge(num_faces);
164 std::vector<std::int8_t> edge_ratio_ok;
168 const T min_ratio = std::sqrt(2.0) / 2.0;
170 edge_ratio_ok.resize(num_faces);
172 auto x_dofmap =
mesh.geometry().dofmaps().front();
174 auto c_to_v =
mesh.topology()->connectivity(tdim, 0);
176 auto e_to_c =
mesh.topology()->connectivity(1, tdim);
178 auto e_to_v =
mesh.topology()->connectivity(1, 0);
182 auto map_e =
mesh.topology()->index_map(1);
184 std::vector<T> edge_length(map_e->size_local() + map_e->num_ghosts());
185 for (std::size_t e = 0; e < edge_length.size(); ++e)
188 auto cells = e_to_c->links(e);
189 assert(!cells.empty());
190 auto cell_vertices = c_to_v->links(cells.front());
191 auto edge_vertices = e_to_v->links(e);
194 auto it0 = std::find(cell_vertices.begin(), cell_vertices.end(),
196 assert(it0 != cell_vertices.end());
197 const std::size_t local0
198 = std::ranges::distance(cell_vertices.begin(), it0);
199 auto it1 = std::find(cell_vertices.begin(), cell_vertices.end(),
201 assert(it1 != cell_vertices.end());
202 const std::size_t local1
203 = std::ranges::distance(cell_vertices.begin(), it1);
205 auto x_dofs = md::submdspan(x_dofmap, cells.front(), md::full_extent);
206 std::span<const T, 3> x0(
mesh.geometry().x().data() + 3 * x_dofs[local0],
208 std::span<const T, 3> x1(
mesh.geometry().x().data() + 3 * x_dofs[local1],
212 edge_length[e] = std::sqrt(std::transform_reduce(
213 x0.begin(), x0.end(), x1.begin(), 0.0, std::plus<>(),
214 [](
auto x0,
auto x1) { return (x0 - x1) * (x0 - x1); }));
218 auto f_to_v =
mesh.topology()->connectivity(2, 0);
220 auto f_to_e =
mesh.topology()->connectivity(2, 1);
222 const std::vector global_indices
223 =
mesh.topology()->index_map(0)->global_indices();
224 for (
int f = 0; f < f_to_v->num_nodes(); ++f)
226 auto face_edges = f_to_e->links(f);
228 std::int32_t imax = 0;
230 T min_len = std::numeric_limits<T>::max();
232 for (
int i = 0; i < 3; ++i)
234 const T e_len = edge_length[face_edges[i]];
235 min_len = std::min(e_len, min_len);
241 else if (tdim == 3 and e_len == max_len)
246 auto vertices = f_to_v->links(f);
247 const int vmax = vertices[imax];
248 const int vi = vertices[i];
249 if (global_indices[vi] > global_indices[vmax])
256 edge_ratio_ok[f] = (min_len / max_len >= min_ratio);
258 long_edge[f] = face_edges[imax];
261 return std::pair(std::move(long_edge), std::move(edge_ratio_ok));
288template <std::
floating_po
int T>
289std::tuple<graph::AdjacencyList<std::int64_t>, std::vector<T>,
290 std::array<std::size_t, 2>, std::optional<std::vector<std::int32_t>>,
291 std::optional<std::vector<std::int8_t>>>
292compute_refinement(MPI_Comm neighbor_comm,
293 std::span<const std::int8_t> marked_edges,
296 std::span<const std::int32_t> long_edge,
297 std::span<const std::int8_t> edge_ratio_ok,
Option option)
299 int tdim =
mesh.topology()->dim();
300 int num_cell_edges = tdim * 3 - 3;
301 int num_cell_vertices = tdim + 1;
307 const auto [new_vertex_map, new_vertex_coords, xshape]
310 std::optional<std::vector<std::int32_t>>
parent_cell(std::nullopt);
311 if (compute_parent_cell)
314 std::optional<std::vector<std::int8_t>>
parent_facet(std::nullopt);
318 std::vector<std::int64_t> indices(num_cell_vertices + num_cell_edges);
319 std::vector<std::int32_t> simplex_set;
321 auto map_c =
mesh.topology()->index_map(tdim);
323 auto c_to_v =
mesh.topology()->connectivity(tdim, 0);
325 auto c_to_e =
mesh.topology()->connectivity(tdim, 1);
327 auto c_to_f =
mesh.topology()->connectivity(tdim, 2);
330 std::int32_t num_new_vertices_local = std::count(
331 marked_edges.begin(),
332 marked_edges.begin() +
mesh.topology()->index_map(1)->size_local(),
true);
334 std::vector<std::int64_t> global_indices
337 const std::int32_t num_cells = map_c->size_local();
340 std::vector<std::int64_t> cell_topology;
341 for (
int c = 0; c < num_cells; ++c)
347 auto vertices = c_to_v->links(c);
348 for (std::size_t v = 0; v < vertices.size(); ++v)
349 indices[v] = global_indices[vertices[v]];
352 auto edges = c_to_e->links(c);
353 bool no_edge_marked =
true;
354 for (std::size_t ei = 0; ei < edges.size(); ++ei)
356 if (marked_edges[edges[ei]])
358 no_edge_marked =
false;
359 auto nv = new_vertex_map.links(edges[ei]);
360 assert(nv.size() == 1);
361 indices[num_cell_vertices + ei] = nv[0];
364 indices[num_cell_vertices + ei] = -1;
370 for (
auto v : vertices)
371 cell_topology.push_back(global_indices[v]);
373 if (compute_parent_cell)
388 std::vector<std::int32_t> longest_edge;
389 for (
auto f : c_to_f->links(c))
390 longest_edge.push_back(long_edge[f]);
393 for (std::int32_t& p : longest_edge)
395 for (std::size_t ej = 0; ej < edges.size(); ++ej)
405 const bool uniform = (tdim == 2) ? edge_ratio_ok[c] :
false;
406 const auto [simplex_set_b, simplex_set_size]
407 = get_simplices(indices, longest_edge, tdim, uniform);
408 std::span<const std::int32_t> simplex_set(simplex_set_b.data(),
412 const std::int32_t ncells = simplex_set.size() / num_cell_vertices;
413 if (compute_parent_cell)
415 for (std::int32_t i = 0; i < ncells; ++i)
423 auto npf = compute_parent_facets<3>(simplex_set);
425 std::next(npf.begin(), simplex_set.size()));
429 auto npf = compute_parent_facets<2>(simplex_set);
431 std::next(npf.begin(), simplex_set.size()));
436 for (std::int32_t v : simplex_set)
437 cell_topology.push_back(indices[v]);
441 assert(cell_topology.size() % num_cell_vertices == 0);
442 std::vector<std::int32_t> offsets(
443 cell_topology.size() / num_cell_vertices + 1, 0);
444 for (std::size_t i = 0; i < offsets.size() - 1; ++i)
445 offsets[i + 1] = offsets[i] + num_cell_vertices;
448 return {std::move(cell_adj), std::move(new_vertex_coords), xshape,
462template <std::
floating_po
int T>
463std::tuple<graph::AdjacencyList<std::int64_t>, std::vector<T>,
464 std::array<std::size_t, 2>, std::optional<std::vector<std::int32_t>>,
465 std::optional<std::vector<std::int8_t>>>
467 std::optional<std::span<const std::int32_t>> edges,
471 auto topology =
mesh.topology();
474 if (topology->cell_type() != mesh::CellType::triangle
475 and topology->cell_type() != mesh::CellType::tetrahedron)
477 throw std::runtime_error(
"Cell type not supported");
480 auto map_e = topology->index_map(1);
482 throw std::runtime_error(
"Edges must be initialised");
485 auto [_data, _offsets] = map_e->index_to_dest_ranks();
490 std::vector<int> ranks(edge_ranks.
array().begin(), edge_ranks.
array().end());
491 std::ranges::sort(ranks);
492 auto [unique_end, range_end] = std::ranges::unique(ranks);
493 ranks.erase(unique_end, range_end);
496 std::ranges::transform(edge_ranks.
array(), edge_ranks.
array().begin(),
499 auto it = std::ranges::lower_bound(ranks, r);
500 assert(it != ranks.end() and *it == r);
501 return std::ranges::distance(ranks.begin(), it);
505 std::vector<std::int8_t> marked_edges(
506 map_e->size_local() + map_e->num_ghosts(), !edges.has_value());
507 std::vector<std::vector<std::int32_t>> marked_for_update(ranks.size());
511 for (
auto edge : edges.value())
513 if (!marked_edges[edge])
515 marked_edges[edge] =
true;
518 for (
int rank : edge_ranks.
links(edge))
519 marked_for_update[rank].push_back(edge);
525 MPI_Dist_graph_create_adjacent(
mesh.comm(), ranks.size(), ranks.data(),
526 MPI_UNWEIGHTED, ranks.size(), ranks.data(),
527 MPI_UNWEIGHTED, MPI_INFO_NULL,
false, &comm);
534 const auto [long_edge, edge_ratio_ok] = impl::face_long_edge(
mesh);
535 impl::enforce_rules(comm, edge_ranks, marked_edges, *topology, long_edge);
538 = impl::compute_refinement(comm, marked_edges, edge_ranks,
mesh,
539 long_edge, edge_ratio_ok, option);
540 MPI_Comm_free(&comm);
542 return {std::move(cell_adj), std::move(new_vertex_coords), xshape,