48std::vector<std::int8_t>
49compute_parent_facets(std::span<const std::int32_t> simplex_set)
52 assert(simplex_set.size() % (tdim + 1) == 0);
53 std::vector<std::int8_t>
parent_facet(simplex_set.size(), -1);
58 constexpr std::array<std::array<int, 3>, 3> facet_table_2d{
59 {{1, 2, 3}, {0, 2, 4}, {0, 1, 5}}};
61 constexpr std::array<std::array<int, 6>, 4> facet_table_3d{
67 const int ncells = simplex_set.size() / (tdim + 1);
68 for (
int fpi = 0; fpi < (tdim + 1); ++fpi)
71 for (
int cc = 0; cc < ncells; ++cc)
73 for (
int fci = 0; fci < (tdim + 1); ++fci)
76 std::array<int, tdim> cf, set_output;
78 int num_common_vertices;
79 if constexpr (tdim == 2)
81 for (
int j = 0; j < tdim; ++j)
82 cf[j] = simplex_set[cc * 3 + facet_table_2d[fci][j]];
83 std::sort(cf.begin(), cf.end());
84 auto it = std::set_intersection(
85 facet_table_2d[fpi].begin(), facet_table_2d[fpi].end(),
86 cf.begin(), cf.end(), set_output.begin());
87 num_common_vertices = std::distance(set_output.begin(), it);
91 for (
int j = 0; j < tdim; ++j)
92 cf[j] = simplex_set[cc * 4 + facet_table_3d[fci][j]];
93 std::sort(cf.begin(), cf.end());
94 auto it = std::set_intersection(
95 facet_table_3d[fpi].begin(), facet_table_3d[fpi].end(),
96 cf.begin(), cf.end(), set_output.begin());
97 num_common_vertices = std::distance(set_output.begin(), it);
100 if (num_common_vertices == tdim)
127std::vector<std::int32_t>
128get_simplices(std::span<const std::int64_t> indices,
129 std::span<const std::int32_t> longest_edge,
int tdim,
134void enforce_rules(MPI_Comm comm,
const graph::AdjacencyList<int>& shared_edges,
135 std::vector<std::int8_t>& marked_edges,
136 const mesh::Topology& topology,
137 std::span<const std::int32_t> long_edge);
140template <std::
floating_po
int T>
141std::pair<std::vector<std::int32_t>, std::vector<std::int8_t>>
142face_long_edge(
const mesh::Mesh<T>& mesh)
144 const int tdim = mesh.topology()->dim();
146 mesh.topology_mutable()->create_entities(1);
147 mesh.topology_mutable()->create_entities(2);
148 mesh.topology_mutable()->create_connectivity(2, 1);
149 mesh.topology_mutable()->create_connectivity(1, tdim);
150 mesh.topology_mutable()->create_connectivity(tdim, 2);
152 std::int64_t num_faces = mesh.topology()->index_map(2)->size_local()
153 + mesh.topology()->index_map(2)->num_ghosts();
156 std::vector<std::int32_t> long_edge(num_faces);
157 std::vector<std::int8_t> edge_ratio_ok;
161 const T min_ratio = sqrt(2.0) / 2.0;
163 edge_ratio_ok.resize(num_faces);
165 auto x_dofmap = mesh.geometry().dofmap();
167 auto c_to_v = mesh.topology()->connectivity(tdim, 0);
169 auto e_to_c = mesh.topology()->connectivity(1, tdim);
171 auto e_to_v = mesh.topology()->connectivity(1, 0);
175 auto map_e = mesh.topology()->index_map(1);
177 std::vector<T> edge_length(map_e->size_local() + map_e->num_ghosts());
178 for (std::size_t e = 0; e < edge_length.size(); ++e)
181 auto cells = e_to_c->links(e);
182 assert(!
cells.empty());
183 auto cell_vertices = c_to_v->links(
cells.front());
184 auto edge_vertices = e_to_v->links(e);
187 auto it0 = std::find(cell_vertices.begin(), cell_vertices.end(),
189 assert(it0 != cell_vertices.end());
190 const std::size_t local0 = std::distance(cell_vertices.begin(), it0);
191 auto it1 = std::find(cell_vertices.begin(), cell_vertices.end(),
193 assert(it1 != cell_vertices.end());
194 const std::size_t local1 = std::distance(cell_vertices.begin(), it1);
197 = MDSPAN_IMPL_STANDARD_NAMESPACE::MDSPAN_IMPL_PROPOSED_NAMESPACE::
198 submdspan(x_dofmap,
cells.front(),
199 MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
200 std::span<const T, 3> x0(mesh.geometry().x().data() + 3 * x_dofs[local0],
202 std::span<const T, 3> x1(mesh.geometry().x().data() + 3 * x_dofs[local1],
206 edge_length[e] = std::sqrt(std::transform_reduce(
207 x0.begin(), x0.end(), x1.begin(), 0.0, std::plus<>(),
208 [](
auto x0,
auto x1) { return (x0 - x1) * (x0 - x1); }));
212 auto f_to_v = mesh.topology()->connectivity(2, 0);
214 auto f_to_e = mesh.topology()->connectivity(2, 1);
216 const std::vector global_indices
217 = mesh.topology()->index_map(0)->global_indices();
218 for (
int f = 0; f < f_to_v->num_nodes(); ++f)
220 auto face_edges = f_to_e->links(f);
222 std::int32_t imax = 0;
224 T min_len = std::numeric_limits<T>::max();
226 for (
int i = 0; i < 3; ++i)
228 const T e_len = edge_length[face_edges[i]];
229 min_len = std::min(e_len, min_len);
235 else if (tdim == 3 and e_len == max_len)
240 auto vertices = f_to_v->links(f);
241 const int vmax = vertices[imax];
242 const int vi = vertices[i];
243 if (global_indices[vi] > global_indices[vmax])
250 edge_ratio_ok[f] = (min_len / max_len >= min_ratio);
252 long_edge[f] = face_edges[imax];
255 return std::pair(std::move(long_edge), std::move(edge_ratio_ok));
259template <std::
floating_po
int T>
260std::tuple<graph::AdjacencyList<std::int64_t>, std::vector<T>,
261 std::array<std::size_t, 2>, std::vector<std::int32_t>,
262 std::vector<std::int8_t>>
263compute_refinement(MPI_Comm neighbor_comm,
264 const std::vector<std::int8_t>& marked_edges,
265 const graph::AdjacencyList<int>& shared_edges,
266 const mesh::Mesh<T>& mesh,
267 const std::vector<std::int32_t>& long_edge,
268 const std::vector<std::int8_t>& edge_ratio_ok,
271 int tdim = mesh.topology()->dim();
272 int num_cell_edges = tdim * 3 - 3;
276 bool compute_parent_cell
281 const auto [new_vertex_map, new_vertex_coords, xshape]
286 std::vector<std::int64_t> indices(num_cell_vertices + num_cell_edges);
287 std::vector<std::int32_t> simplex_set;
289 auto map_c = mesh.topology()->index_map(tdim);
291 auto c_to_v = mesh.topology()->connectivity(tdim, 0);
293 auto c_to_e = mesh.topology()->connectivity(tdim, 1);
295 auto c_to_f = mesh.topology()->connectivity(tdim, 2);
298 std::int32_t num_new_vertices_local = std::count(
299 marked_edges.begin(),
300 marked_edges.begin() + mesh.topology()->index_map(1)->size_local(),
true);
302 std::vector<std::int64_t> global_indices
303 =
adjust_indices(*mesh.topology()->index_map(0), num_new_vertices_local);
305 const int num_cells = map_c->size_local();
308 std::vector<std::int64_t> cell_topology;
309 for (
int c = 0; c < num_cells; ++c)
315 auto vertices = c_to_v->links(c);
316 for (std::size_t v = 0; v < vertices.size(); ++v)
317 indices[v] = global_indices[vertices[v]];
320 auto edges = c_to_e->links(c);
321 bool no_edge_marked =
true;
322 for (std::size_t ei = 0; ei < edges.size(); ++ei)
324 if (marked_edges[edges[ei]])
326 no_edge_marked =
false;
327 auto it = new_vertex_map.find(edges[ei]);
328 assert(it != new_vertex_map.end());
338 for (
auto v : vertices)
339 cell_topology.push_back(global_indices[v]);
341 if (compute_parent_cell)
356 std::vector<std::int32_t> longest_edge;
357 for (
auto f : c_to_f->links(c))
358 longest_edge.push_back(long_edge[f]);
361 for (std::int32_t& p : longest_edge)
363 for (std::size_t ej = 0; ej < edges.size(); ++ej)
373 const bool uniform = (tdim == 2) ? edge_ratio_ok[c] : false;
376 simplex_set = get_simplices(indices, longest_edge, tdim, uniform);
381 if (compute_parent_cell)
383 for (std::int32_t i = 0; i < ncells; ++i)
389 std::vector<std::int8_t> npf;
391 npf = compute_parent_facets<3>(simplex_set);
393 npf = compute_parent_facets<2>(simplex_set);
398 for (std::int32_t v : simplex_set)
399 cell_topology.push_back(indices[v]);
403 assert(cell_topology.size() % num_cell_vertices == 0);
404 std::vector<std::int32_t> offsets(
405 cell_topology.size() / num_cell_vertices + 1, 0);
406 for (std::size_t i = 0; i < offsets.size() - 1; ++i)
407 offsets[i + 1] = offsets[i] + num_cell_vertices;
408 graph::AdjacencyList cell_adj(std::move(cell_topology), std::move(offsets));
410 return {std::move(cell_adj), std::move(new_vertex_coords), xshape,
425template <std::
floating_po
int T>
426std::tuple<mesh::Mesh<T>, std::vector<std::int32_t>, std::vector<std::int8_t>>
429 if (mesh.
geometry().cmaps().size() > 1)
431 throw std::runtime_error(
"Mixed topology not supported");
440 new_coords, xshape, mesh::GhostMode::none),
445 std::shared_ptr<const common::IndexMap> map_c
447 const int num_ghost_cells = map_c->num_ghosts();
450 int max_ghost_cells = 0;
451 MPI_Allreduce(&num_ghost_cells, &max_ghost_cells, 1, MPI_INT, MPI_MAX,
456 ? mesh::GhostMode::none
457 : mesh::GhostMode::shared_facet;
458 return {partition<T>(mesh, cell_adj, std::span(new_coords), xshape,
459 redistribute, ghost_mode),
475template <std::
floating_po
int T>
476std::tuple<mesh::Mesh<T>, std::vector<std::int32_t>, std::vector<std::int8_t>>
478 bool redistribute,
Option option)
480 if (mesh.
geometry().cmaps().size() > 1)
481 throw std::runtime_error(
"Mixed topology not supported");
489 new_vertex_coords, xshape, mesh::GhostMode::none),
494 std::shared_ptr<const common::IndexMap> map_c
496 const int num_ghost_cells = map_c->num_ghosts();
499 int max_ghost_cells = 0;
500 MPI_Allreduce(&num_ghost_cells, &max_ghost_cells, 1, MPI_INT, MPI_MAX,
505 ? mesh::GhostMode::none
506 : mesh::GhostMode::shared_facet;
508 return {partition<T>(mesh, cell_adj, new_vertex_coords, xshape,
509 redistribute, ghost_mode),
522template <std::
floating_po
int T>
523std::tuple<graph::AdjacencyList<std::int64_t>, std::vector<T>,
524 std::array<std::size_t, 2>, std::vector<std::int32_t>,
525 std::vector<std::int8_t>>
532 if (topology->cell_types().size() > 1)
533 throw std::runtime_error(
"Mixed topology not supported");
535 if (topology->cell_types()[0] != mesh::CellType::triangle
536 and topology->cell_types()[0] != mesh::CellType::tetrahedron)
538 throw std::runtime_error(
"Cell type not supported");
541 auto map_e = topology->index_map(1);
543 throw std::runtime_error(
"Edges must be initialised");
550 std::vector<int> ranks(edge_ranks.
array().begin(), edge_ranks.
array().end());
551 std::sort(ranks.begin(), ranks.end());
552 ranks.erase(std::unique(ranks.begin(), ranks.end()), ranks.end());
555 std::transform(edge_ranks.
array().begin(), edge_ranks.
array().end(),
556 edge_ranks.
array().begin(),
559 auto it = std::lower_bound(ranks.begin(), ranks.end(), r);
560 assert(it != ranks.end() and *it == r);
561 return std::distance(ranks.begin(), it);
565 MPI_Dist_graph_create_adjacent(mesh.
comm(), ranks.size(), ranks.data(),
566 MPI_UNWEIGHTED, ranks.size(), ranks.data(),
567 MPI_UNWEIGHTED, MPI_INFO_NULL,
false, &comm);
569 const auto [long_edge, edge_ratio_ok] = impl::face_long_edge(mesh);
571 = impl::compute_refinement(
573 std::vector<std::int8_t>(map_e->size_local() + map_e->num_ghosts(),
575 edge_ranks, mesh, long_edge, edge_ratio_ok, option);
576 MPI_Comm_free(&comm);
578 return {std::move(cell_adj), std::move(new_vertex_coords), xshape,
591template <std::
floating_po
int T>
592std::tuple<graph::AdjacencyList<std::int64_t>, std::vector<T>,
593 std::array<std::size_t, 2>, std::vector<std::int32_t>,
594 std::vector<std::int8_t>>
596 std::span<const std::int32_t> edges,
Option option)
602 if (topology->cell_types().size() > 1)
603 throw std::runtime_error(
"Mixed topology not supported");
605 if (topology->cell_types()[0] != mesh::CellType::triangle
606 and topology->cell_types()[0] != mesh::CellType::tetrahedron)
608 throw std::runtime_error(
"Cell type not supported");
611 auto map_e = topology->index_map(1);
613 throw std::runtime_error(
"Edges must be initialised");
620 std::vector<int> ranks(edge_ranks.
array().begin(), edge_ranks.
array().end());
621 std::sort(ranks.begin(), ranks.end());
622 ranks.erase(std::unique(ranks.begin(), ranks.end()), ranks.end());
625 std::transform(edge_ranks.
array().begin(), edge_ranks.
array().end(),
626 edge_ranks.
array().begin(),
629 auto it = std::lower_bound(ranks.begin(), ranks.end(), r);
630 assert(it != ranks.end() and *it == r);
631 return std::distance(ranks.begin(), it);
635 std::vector<std::int8_t> marked_edges(
636 map_e->size_local() + map_e->num_ghosts(),
false);
637 std::vector<std::vector<std::int32_t>> marked_for_update(ranks.size());
638 for (
auto edge : edges)
640 if (!marked_edges[edge])
642 marked_edges[edge] =
true;
645 for (
int rank : edge_ranks.
links(edge))
646 marked_for_update[rank].push_back(edge);
651 MPI_Dist_graph_create_adjacent(mesh.
comm(), ranks.size(), ranks.data(),
652 MPI_UNWEIGHTED, ranks.size(), ranks.data(),
653 MPI_UNWEIGHTED, MPI_INFO_NULL,
false, &comm);
660 const auto [long_edge, edge_ratio_ok] = impl::face_long_edge(mesh);
661 impl::enforce_rules(comm, edge_ranks, marked_edges, *topology, long_edge);
664 = impl::compute_refinement(comm, marked_edges, edge_ranks, mesh,
665 long_edge, edge_ratio_ok, option);
666 MPI_Comm_free(&comm);
668 return {std::move(cell_adj), std::move(new_vertex_coords), xshape,