13#include "graphbuild.h"
15#include <basix/mdspan.hpp>
18#include <dolfinx/graph/AdjacencyList.h>
19#include <dolfinx/graph/ordering.h>
20#include <dolfinx/graph/partition.h>
57void reorder_list(std::span<T> list, std::span<const std::int32_t> nodemap)
62 assert(list.size() % nodemap.size() == 0);
63 std::size_t degree = list.size() / nodemap.size();
64 const std::vector<T> orig(list.begin(), list.end());
65 for (std::size_t n = 0; n < nodemap.size(); ++n)
67 std::span links_old(orig.data() + n * degree, degree);
68 auto links_new = list.subspan(nodemap[n] * degree, degree);
69 std::ranges::copy(links_old, links_new.begin());
86template <std::
floating_po
int T>
87std::tuple<std::vector<std::int32_t>, std::vector<T>, std::vector<std::int32_t>>
89 std::span<const std::int32_t> facets)
91 auto topology =
mesh.topology();
93 const int tdim = topology->dim();
96 throw std::runtime_error(
97 "Cannot use mesh::locate_entities_boundary (boundary) for cells.");
101 mesh.topology_mutable()->create_connectivity(tdim - 1, 0);
102 mesh.topology_mutable()->create_connectivity(tdim - 1, dim);
103 std::vector<std::int32_t> vertices, entities;
105 auto f_to_v = topology->connectivity(tdim - 1, 0);
107 auto f_to_e = topology->connectivity(tdim - 1, dim);
109 for (
auto f : facets)
111 auto v = f_to_v->links(f);
112 vertices.insert(vertices.end(), v.begin(), v.end());
113 auto e = f_to_e->links(f);
114 entities.insert(entities.end(), e.begin(), e.end());
119 std::ranges::sort(vertices);
120 auto [unique_end, range_end] = std::ranges::unique(vertices);
121 vertices.erase(unique_end, range_end);
125 std::ranges::sort(entities);
126 auto [unique_end, range_end] = std::ranges::unique(entities);
127 entities.erase(unique_end, range_end);
132 auto x_dofmap =
mesh.geometry().dofmap();
133 std::span<const T> x_nodes =
mesh.geometry().x();
136 mesh.topology_mutable()->create_connectivity(0, tdim);
137 mesh.topology_mutable()->create_connectivity(tdim, 0);
138 auto v_to_c = topology->connectivity(0, tdim);
140 auto c_to_v = topology->connectivity(tdim, 0);
142 std::vector<T> x_vertices(3 * vertices.size(), -1.0);
143 std::vector<std::int32_t> vertex_to_pos(v_to_c->num_nodes(), -1);
144 for (std::size_t i = 0; i < vertices.size(); ++i)
146 const std::int32_t v = vertices[i];
149 const std::int32_t c = v_to_c->links(v).front();
150 auto cell_vertices = c_to_v->links(c);
151 auto it = std::ranges::find(cell_vertices, v);
152 assert(it != cell_vertices.end());
153 const std::size_t local_pos = std::distance(cell_vertices.begin(), it);
155 auto dofs = md::submdspan(x_dofmap, c, md::full_extent);
156 for (std::size_t j = 0; j < 3; ++j)
157 x_vertices[j * vertices.size() + i] = x_nodes[3 * dofs[local_pos] + j];
158 vertex_to_pos[v] = i;
161 return {std::move(entities), std::move(x_vertices), std::move(vertex_to_pos)};
213 MPI_Comm comm,
int nparts,
const std::vector<CellType>& cell_types,
214 const std::vector<std::span<const std::int64_t>>& cells)>;
233 std::optional<std::int32_t> max_facet_to_cell_links)
250 return [&, max_facet_to_cell_links](
251 const std::vector<CellType>& celltypes,
252 const std::vector<fem::ElementDofLayout>& doflayouts,
253 const std::vector<std::vector<int>>& ghost_owners,
254 std::vector<std::vector<std::int64_t>>& cells,
255 std::vector<std::vector<std::int64_t>>& cells_v,
256 std::vector<std::vector<std::int64_t>>& original_idx)
257 -> std::vector<std::int64_t>
263 spdlog::info(
"Build local dual graphs, re-order cells, and compute process "
264 "boundary vertices.");
266 std::vector<std::pair<std::vector<std::int64_t>,
int>> facets;
269 std::vector<std::span<const std::int64_t>> cells1_v_local;
270 for (std::size_t i = 0; i < celltypes.size(); ++i)
273 std::size_t num_owned_cells
275 cells1_v_local.emplace_back(cells_v[i].data(),
279 auto [
graph, unmatched_facets, max_v, _facet_attached_cells]
281 std::vector{cells1_v_local.back()},
282 max_facet_to_cell_links);
285 facets.emplace_back(std::move(unmatched_facets), max_v);
288 const std::vector<std::int32_t> remap = reorder_fn(
graph);
291 const std::vector<std::int64_t>& orig_idx = original_idx[i];
292 std::vector<std::int64_t> _original_idx(orig_idx.size());
293 std::copy_n(orig_idx.rbegin(), ghost_owners[i].size(),
294 _original_idx.rbegin());
296 for (std::size_t j = 0; j < remap.size(); ++j)
297 _original_idx[remap[j]] = orig_idx[j];
299 original_idx[i] = _original_idx;
306 std::span(cells[i].data(), remap.size() * doflayouts[i].num_dofs()),
310 if (facets.size() == 1)
312 std::vector<std::int64_t>& vertices = facets.front().first;
315 std::ranges::sort(vertices);
316 auto [unique_end, range_end] = std::ranges::unique(vertices);
317 vertices.erase(unique_end, range_end);
322 if (!vertices.empty() and vertices.front() == -1)
323 vertices.erase(vertices.begin());
331 std::vector<std::int64_t> facets0;
332 facets0.reserve(std::accumulate(facets.begin(), facets.end(),
333 std::size_t(0), [](std::size_t x,
auto& y)
334 { return x + y.first.size(); }));
335 int max_v = std::ranges::max_element(facets, [](
auto& a,
auto& b)
336 {
return a.second < b.second; })
338 for (
const auto& [v_data, num_v] : facets)
340 for (
auto it = v_data.begin(); it != v_data.end(); it += num_v)
342 facets0.insert(facets0.end(), it, std::next(it, num_v));
343 facets0.insert(facets0.end(), max_v - num_v, -1);
349 std::span<const std::int64_t>(facets0), max_v);
353 std::vector<std::int64_t> vertices;
355 auto it = perm.begin();
356 while (it != perm.end())
360 std::span _f(facets0.data() + (*it) * max_v, max_v);
361 auto end = std::find_if(_f.rbegin(), _f.rend(),
362 [](
auto a) { return a >= 0; });
363 auto f = _f.first(std::distance(end, _f.rend()));
365 auto it1 = std::find_if_not(
367 [f, max_v, it0 = facets0.begin()](
auto p) ->
bool
369 return std::equal(f.begin(), f.end(), std::next(it0, p * max_v));
373 if (std::distance(it, it1) == 1)
374 vertices.insert(vertices.end(), f.begin(), f.end());
375 else if (std::distance(it, it1) > 2)
376 throw std::runtime_error(
"More than two matching facets found.");
383 std::ranges::sort(vertices);
384 auto [unique_end, range_end] = std::ranges::unique(vertices);
385 vertices.erase(unique_end, range_end);
403 std::span<const std::int64_t> cells);
413template <std::
floating_po
int T>
414std::vector<T>
h(
const Mesh<T>&
mesh, std::span<const std::int32_t> entities,
417 if (entities.empty())
418 return std::vector<T>();
420 return std::vector<T>(entities.size(), 0);
423 const auto [vertex_xdofs, xdof_shape]
427 std::span<const T> x =
mesh.geometry().x();
430 auto delta_norm = [](
auto&& p0,
auto&& p1)
433 for (std::size_t i = 0; i < 3; ++i)
434 norm += (p0[i] - p1[i]) * (p0[i] - p1[i]);
435 return std::sqrt(norm);
440 std::vector<T>
h(entities.size(), 0);
441 for (std::size_t e = 0; e < entities.size(); ++e)
444 std::span<const std::int32_t> e_vertices(
445 vertex_xdofs.data() + e * xdof_shape[1], xdof_shape[1]);
448 for (std::size_t i = 0; i < e_vertices.size(); ++i)
450 std::span<const T, 3> p0(x.data() + 3 * e_vertices[i], 3);
451 for (std::size_t j = i + 1; j < e_vertices.size(); ++j)
453 std::span<const T, 3> p1(x.data() + 3 * e_vertices[j], 3);
454 h[e] = std::max(
h[e], delta_norm(p0, p1));
465template <std::
floating_po
int T>
467 std::span<const std::int32_t> entities)
469 if (entities.empty())
470 return std::vector<T>();
472 auto topology =
mesh.topology();
474 if (topology->cell_type() == CellType::prism and dim == 2)
476 throw std::runtime_error(
477 "Cell normal computation for prism cells not yet supported.");
480 const int gdim =
mesh.geometry().dim();
484 std::span<const T> x =
mesh.geometry().x();
485 const auto [geometry_entities, eshape]
488 std::vector<T> n(entities.size() * 3);
491 case CellType::interval:
494 throw std::invalid_argument(
"Interval cell normal undefined in 3D.");
495 for (std::size_t i = 0; i < entities.size(); ++i)
498 std::array vertices{geometry_entities[i * eshape[1]],
499 geometry_entities[i * eshape[1] + 1]};
500 std::array p = {std::span<const T, 3>(x.data() + 3 * vertices[0], 3),
501 std::span<const T, 3>(x.data() + 3 * vertices[1], 3)};
505 std::ranges::transform(p[1], p[0], t.begin(),
506 [](
auto x,
auto y) { return x - y; });
508 T norm = std::sqrt(t[0] * t[0] + t[1] * t[1]);
509 std::span<T, 3> ni(n.data() + 3 * i, 3);
510 ni[0] = -t[1] / norm;
516 case CellType::triangle:
518 for (std::size_t i = 0; i < entities.size(); ++i)
521 std::array vertices = {geometry_entities[i * eshape[1] + 0],
522 geometry_entities[i * eshape[1] + 1],
523 geometry_entities[i * eshape[1] + 2]};
524 std::array p = {std::span<const T, 3>(x.data() + 3 * vertices[0], 3),
525 std::span<const T, 3>(x.data() + 3 * vertices[1], 3),
526 std::span<const T, 3>(x.data() + 3 * vertices[2], 3)};
529 std::array<T, 3> dp1, dp2;
530 std::ranges::transform(p[1], p[0], dp1.begin(),
531 [](
auto x,
auto y) { return x - y; });
532 std::ranges::transform(p[2], p[0], dp2.begin(),
533 [](
auto x,
auto y) { return x - y; });
536 std::array<T, 3> ni = math::cross(dp1, dp2);
537 T norm = std::sqrt(ni[0] * ni[0] + ni[1] * ni[1] + ni[2] * ni[2]);
538 std::ranges::transform(ni, std::next(n.begin(), 3 * i),
539 [norm](
auto x) { return x / norm; });
544 case CellType::quadrilateral:
547 for (std::size_t i = 0; i < entities.size(); ++i)
550 std::array vertices = {geometry_entities[i * eshape[1] + 0],
551 geometry_entities[i * eshape[1] + 1],
552 geometry_entities[i * eshape[1] + 2]};
553 std::array p = {std::span<const T, 3>(x.data() + 3 * vertices[0], 3),
554 std::span<const T, 3>(x.data() + 3 * vertices[1], 3),
555 std::span<const T, 3>(x.data() + 3 * vertices[2], 3)};
558 std::array<T, 3> dp1, dp2;
559 std::ranges::transform(p[1], p[0], dp1.begin(),
560 [](
auto x,
auto y) { return x - y; });
561 std::ranges::transform(p[2], p[0], dp2.begin(),
562 [](
auto x,
auto y) { return x - y; });
565 std::array<T, 3> ni = math::cross(dp1, dp2);
566 T norm = std::sqrt(ni[0] * ni[0] + ni[1] * ni[1] + ni[2] * ni[2]);
567 std::ranges::transform(ni, std::next(n.begin(), 3 * i),
568 [norm](
auto x) { return x / norm; });
574 throw std::invalid_argument(
575 "cell_normal not supported for this cell type.");
582template <std::
floating_po
int T>
584 std::span<const std::int32_t> entities)
586 if (entities.empty())
587 return std::vector<T>();
589 std::span<const T> x =
mesh.geometry().x();
592 const auto [e_to_g, eshape]
595 std::vector<T> x_mid(entities.size() * 3, 0);
596 for (std::size_t e = 0; e < entities.size(); ++e)
598 std::span<T, 3> p(x_mid.data() + 3 * e, 3);
599 std::span<const std::int32_t> rows(e_to_g.data() + e * eshape[1],
601 for (
auto row : rows)
603 std::span<const T, 3> xg(x.data() + 3 * row, 3);
604 std::ranges::transform(p, xg, p.begin(),
605 [size = rows.size()](
auto x,
auto y)
606 { return x + y / size; });
619template <std::
floating_po
int T>
620std::pair<std::vector<T>, std::array<std::size_t, 2>>
623 auto topology =
mesh.topology();
625 const int tdim = topology->dim();
630 const std::int32_t num_vertices = topology->index_map(0)->size_local()
631 + topology->index_map(0)->num_ghosts();
633 std::vector<std::int32_t> vertex_to_node(num_vertices);
634 for (
int cell_type_idx = 0,
635 num_cell_types = topology->entity_types(tdim).size();
636 cell_type_idx < num_cell_types; ++cell_type_idx)
638 auto x_dofmap =
mesh.geometry().dofmap(cell_type_idx);
639 auto c_to_v = topology->connectivity({tdim, cell_type_idx}, {0, 0});
641 for (
int c = 0; c < c_to_v->num_nodes(); ++c)
643 auto x_dofs = md::submdspan(x_dofmap, c, md::full_extent);
644 auto vertices = c_to_v->links(c);
645 for (std::size_t i = 0; i < vertices.size(); ++i)
646 vertex_to_node[vertices[i]] = x_dofs[i];
651 std::span<const T> x_nodes =
mesh.geometry().x();
652 std::vector<T> x_vertices(3 * vertex_to_node.size(), 0.0);
653 for (std::size_t i = 0; i < vertex_to_node.size(); ++i)
655 std::int32_t pos = 3 * vertex_to_node[i];
656 for (std::size_t j = 0; j < 3; ++j)
657 x_vertices[j * vertex_to_node.size() + i] = x_nodes[pos + j];
660 return {std::move(x_vertices), {3, vertex_to_node.size()}};
666template <
typename Fn,
typename T>
668 std::vector<std::int8_t>, Fn,
670 md::extents<std::size_t, 3, md::dynamic_extent>>>::value;
687template <std::
floating_po
int T, MarkerFn<T> U>
689 U marker,
int entity_type_idx)
693 = md::mdspan<const T, md::extents<std::size_t, 3, md::dynamic_extent>>;
696 const auto [xdata, xshape] = impl::compute_vertex_coords(
mesh);
698 cmdspan3x_t x(xdata.data(), xshape);
699 const std::vector<std::int8_t> marked = marker(x);
700 if (marked.size() != x.extent(1))
701 throw std::runtime_error(
"Length of array of markers is wrong.");
703 auto topology =
mesh.topology();
705 const int tdim = topology->dim();
707 mesh.topology_mutable()->create_entities(dim);
709 mesh.topology_mutable()->create_connectivity(dim, 0);
713 auto e_to_v = topology->connectivity({dim, entity_type_idx}, {0, 0});
715 std::vector<std::int32_t> entities;
716 for (
int e = 0; e < e_to_v->num_nodes(); ++e)
719 bool all_vertices_marked =
true;
720 for (std::int32_t v : e_to_v->links(e))
724 all_vertices_marked =
false;
729 if (all_vertices_marked)
730 entities.push_back(e);
749template <std::
floating_po
int T, MarkerFn<T> U>
753 const int num_entity_types =
mesh.topology()->entity_types(dim).size();
754 if (num_entity_types > 1)
756 throw std::runtime_error(
757 "Multiple entity types of this dimension. Specify entity type index");
785template <std::
floating_po
int T, MarkerFn<T> U>
790 auto topology =
mesh.topology();
792 int tdim = topology->dim();
795 throw std::runtime_error(
796 "Cannot use mesh::locate_entities_boundary (boundary) for cells.");
800 mesh.topology_mutable()->create_entities(tdim - 1);
801 mesh.topology_mutable()->create_connectivity(tdim - 1, tdim);
805 = md::mdspan<const T, md::extents<std::size_t, 3, md::dynamic_extent>>;
808 auto [facet_entities, xdata, vertex_to_pos]
809 = impl::compute_vertex_coords_boundary(
mesh, dim, boundary_facets);
810 cmdspan3x_t x(xdata.data(), 3, xdata.size() / 3);
811 std::vector<std::int8_t> marked = marker(x);
812 if (marked.size() != x.extent(1))
813 throw std::runtime_error(
"Length of array of markers is wrong.");
816 mesh.topology_mutable()->create_entities(dim);
817 auto e_to_v = topology->connectivity(dim, 0);
819 std::vector<std::int32_t> entities;
820 for (
auto e : facet_entities)
823 bool all_vertices_marked =
true;
824 for (
auto v : e_to_v->links(e))
826 const std::int32_t pos = vertex_to_pos[v];
829 all_vertices_marked =
false;
835 if (all_vertices_marked)
836 entities.push_back(e);
860template <std::
floating_po
int T>
861std::pair<std::vector<std::int32_t>, std::array<std::size_t, 2>>
863 std::span<const std::int32_t> entities,
864 bool permute =
false)
866 auto topology =
mesh.topology();
868 CellType cell_type = topology->cell_type();
869 if ((cell_type == CellType::prism or cell_type == CellType::pyramid)
872 throw std::runtime_error(
"mesh::entities_to_geometry for prism/pyramid "
873 "cell facets not yet supported.");
876 const int tdim = topology->dim();
884 std::vector<std::int32_t> entity_xdofs;
885 entity_xdofs.reserve(entities.size() * num_entity_dofs);
886 std::array<std::size_t, 2> eshape{entities.size(), num_entity_dofs};
889 const std::vector<std::vector<std::vector<int>>>& closure_dofs_all
895 for (std::int32_t c : entities)
898 auto x_c = md::submdspan(xdofs, c, md::full_extent);
899 for (std::int32_t entity_dof : closure_dofs_all[tdim][0])
900 entity_xdofs.push_back(x_c[entity_dof]);
903 return {std::move(entity_xdofs), eshape};
908 auto e_to_c = topology->connectivity(dim, tdim);
911 throw std::runtime_error(
912 "Entity-to-cell connectivity has not been computed. Missing dims "
913 + std::to_string(dim) +
"->" + std::to_string(tdim));
916 auto c_to_e = topology->connectivity(tdim, dim);
919 throw std::runtime_error(
920 "Cell-to-entity connectivity has not been computed. Missing dims "
921 + std::to_string(tdim) +
"->" + std::to_string(dim));
925 std::span<const std::uint32_t> cell_info;
927 cell_info = std::span(
mesh.topology()->get_cell_permutation_info());
929 for (std::int32_t e : entities)
932 assert(!e_to_c->links(e).empty());
933 std::int32_t c = e_to_c->links(e).front();
936 std::span<const std::int32_t> cell_entities = c_to_e->links(c);
937 auto it = std::find(cell_entities.begin(), cell_entities.end(), e);
938 assert(it != cell_entities.end());
939 std::size_t local_entity = std::distance(cell_entities.begin(), it);
943 std::vector<std::int32_t> closure_dofs(closure_dofs_all[dim][local_entity]);
949 entity_type, local_entity);
953 auto x_c = md::submdspan(xdofs, c, md::full_extent);
954 for (std::int32_t entity_dof : closure_dofs)
955 entity_xdofs.push_back(x_c[entity_dof]);
958 return {std::move(entity_xdofs), eshape};
975 std::optional<std::int32_t> max_facet_to_cell_links);
988 std::optional<std::int32_t> max_facet_to_cell_links);
997std::vector<std::int32_t>
999 std::span<const std::int32_t> entities,
int d0,
1045template <
typename U>
1047 MPI_Comm comm, MPI_Comm commt,
1048 std::vector<std::span<const std::int64_t>> cells,
1050 typename std::remove_reference_t<typename U::value_type>>>& elements,
1051 MPI_Comm commg,
const U& x, std::array<std::size_t, 2> xshape,
1053 std::optional<std::int32_t> max_facet_to_cell_links,
1056 assert(cells.size() == elements.size());
1057 std::vector<CellType> celltypes;
1058 std::ranges::transform(elements, std::back_inserter(celltypes),
1059 [](
auto& e) {
return e.cell_shape(); });
1060 std::vector<fem::ElementDofLayout> doflayouts;
1061 std::ranges::transform(elements, std::back_inserter(doflayouts),
1062 [](
auto& e) {
return e.create_dof_layout(); });
1071 std::int32_t num_cell_types = cells.size();
1074 std::vector<std::vector<std::int64_t>> cells1(num_cell_types);
1075 std::vector<std::vector<std::int64_t>> original_idx1(num_cell_types);
1076 std::vector<std::vector<int>> ghost_owners(num_cell_types);
1079 spdlog::info(
"Using partitioner with cell data ({} cell types)",
1082 if (commt != MPI_COMM_NULL)
1085 std::vector<std::vector<std::int64_t>> t(num_cell_types);
1086 std::vector<std::span<const std::int64_t>> tspan(num_cell_types);
1087 for (std::int32_t i = 0; i < num_cell_types; ++i)
1090 tspan[i] = std::span(t[i]);
1092 dest = partitioner(commt, size, celltypes, tspan);
1095 std::int32_t cell_offset = 0;
1096 for (std::int32_t i = 0; i < num_cell_types; ++i)
1098 std::size_t num_cell_nodes = doflayouts[i].num_dofs();
1099 assert(cells[i].size() % num_cell_nodes == 0);
1100 std::size_t num_cells = cells[i].size() / num_cell_nodes;
1103 std::vector<std::int32_t> offsets_i(
1104 std::next(dest.
offsets().begin(), cell_offset),
1105 std::next(dest.
offsets().begin(), cell_offset + num_cells + 1));
1106 std::vector<std::int32_t> data_i(
1107 std::next(dest.
array().begin(), offsets_i.front()),
1108 std::next(dest.
array().begin(), offsets_i.back()));
1109 std::int32_t offset_0 = offsets_i.front();
1110 std::ranges::for_each(offsets_i,
1111 [&offset_0](std::int32_t& j) { j -= offset_0; });
1113 cell_offset += num_cells;
1117 std::vector<int> src_ranks;
1118 std::tie(cells1[i], src_ranks, original_idx1[i], ghost_owners[i])
1120 {num_cells, num_cell_nodes}, dest_i);
1121 spdlog::debug(
"Got {} cells from distribution", cells1[i].size());
1127 std::int64_t num_owned = 0;
1128 for (std::int32_t i = 0; i < num_cell_types; ++i)
1130 cells1[i] = std::vector<std::int64_t>(cells[i].begin(), cells[i].end());
1131 std::int32_t num_cell_nodes = doflayouts[i].num_dofs();
1132 assert(cells1[i].size() % num_cell_nodes == 0);
1133 original_idx1[i].resize(cells1[i].size() / num_cell_nodes);
1134 num_owned += original_idx1[i].size();
1138 std::int64_t global_offset = 0;
1139 MPI_Exscan(&num_owned, &global_offset, 1, MPI_INT64_T, MPI_SUM, comm);
1140 for (std::int32_t i = 0; i < num_cell_types; ++i)
1142 std::iota(original_idx1[i].begin(), original_idx1[i].end(),
1144 global_offset += original_idx1[i].size();
1150 std::vector<std::vector<std::int64_t>> cells1_v(num_cell_types);
1151 for (std::int32_t i = 0; i < num_cell_types; ++i)
1154 spdlog::info(
"Extract basic topology: {}->{}", cells1[i].size(),
1155 cells1_v[i].size());
1160 const std::vector<std::int64_t> boundary_v = boundary_v_fn(
1161 celltypes, doflayouts, ghost_owners, cells1, cells1_v, original_idx1);
1163 spdlog::debug(
"Got {} boundary vertices", boundary_v.size());
1166 std::vector<std::span<const std::int64_t>> cells1_v_span;
1167 std::ranges::transform(cells1_v, std::back_inserter(cells1_v_span),
1168 [](
auto& c) {
return std::span(c); });
1169 std::vector<std::span<const std::int64_t>> original_idx1_span;
1170 std::ranges::transform(original_idx1, std::back_inserter(original_idx1_span),
1171 [](
auto& c) {
return std::span(c); });
1172 std::vector<std::span<const int>> ghost_owners_span;
1173 std::ranges::transform(ghost_owners, std::back_inserter(ghost_owners_span),
1174 [](
auto& c) {
return std::span(c); });
1177 ghost_owners_span, boundary_v, 0);
1181 for (
int i = 0; i < num_cell_types; ++i)
1183 const auto& entity_dofs = doflayouts[i].entity_dofs_all();
1184 for (
int dim = 1; dim < topology.dim(); ++dim)
1188 = std::accumulate(entity_dofs[dim].begin(), entity_dofs[dim].end(), 0,
1189 [](
int c,
auto v) {
return c + v.size(); });
1191 spdlog::debug(
"Counting entity dofs, dim={}: {}", dim, dim_sum);
1193 topology.create_entities(dim);
1196 if (elements[i].needs_dof_permutations())
1197 topology.create_entity_permutations();
1202 std::vector<std::int64_t> nodes1, nodes2;
1203 for (std::vector<std::int64_t>& c : cells1)
1204 nodes1.insert(nodes1.end(), c.begin(), c.end());
1205 for (std::vector<std::int64_t>& c : cells1)
1206 nodes2.insert(nodes2.end(), c.begin(), c.end());
1209 auto [unique_end, range_end] = std::ranges::unique(nodes1);
1210 nodes1.erase(unique_end, range_end);
1217 =
create_geometry(topology, elements, nodes1, nodes2, coords, xshape[1]);
1219 return Mesh(comm, std::make_shared<Topology>(std::move(topology)),
1260template <
typename U>
1262 MPI_Comm comm, MPI_Comm commt, std::span<const std::int64_t> cells,
1264 typename std::remove_reference_t<typename U::value_type>>& element,
1265 MPI_Comm commg,
const U& x, std::array<std::size_t, 2> xshape,
1267 std::optional<std::int32_t> max_facet_to_cell_links,
1270 return create_mesh(comm, commt, std::vector{cells}, std::vector{element},
1271 commg, x, xshape, partitioner, max_facet_to_cell_links,
1295template <
typename U>
1296Mesh<typename std::remove_reference_t<typename U::value_type>>
1299 std::remove_reference_t<typename U::value_type>>& elements,
1300 const U& x, std::array<std::size_t, 2> xshape,
GhostMode ghost_mode,
1301 std::optional<std::int32_t> max_facet_to_cell_links = 2)
1305 return create_mesh(comm, comm, std::vector{cells}, std::vector{elements},
1306 comm, x, xshape,
nullptr, max_facet_to_cell_links);
1311 comm, comm, std::vector{cells}, std::vector{elements}, comm, x, xshape,
1313 max_facet_to_cell_links);
1330template <std::
floating_po
int T>
1331std::pair<Geometry<T>, std::vector<int32_t>>
1333 std::span<const std::int32_t> subentity_to_entity)
1341 const std::vector<std::int32_t> x_indices
1344 std::vector<std::int32_t> sub_x_dofs = x_indices;
1345 std::ranges::sort(sub_x_dofs);
1346 auto [unique_end, range_end] = std::ranges::unique(sub_x_dofs);
1347 sub_x_dofs.erase(unique_end, range_end);
1350 auto x_index_map =
geometry.index_map();
1351 assert(x_index_map);
1353 std::shared_ptr<common::IndexMap> sub_x_dof_index_map;
1354 std::vector<std::int32_t> subx_to_x_dofmap;
1358 sub_x_dof_index_map = std::make_shared<common::IndexMap>(std::move(map));
1359 subx_to_x_dofmap = std::move(new_to_old);
1363 std::span<const T> x =
geometry.x();
1364 std::int32_t sub_num_x_dofs = subx_to_x_dofmap.size();
1365 std::vector<T> sub_x(3 * sub_num_x_dofs);
1366 for (std::int32_t i = 0; i < sub_num_x_dofs; ++i)
1368 std::copy_n(std::next(x.begin(), 3 * subx_to_x_dofmap[i]), 3,
1369 std::next(sub_x.begin(), 3 * i));
1373 std::vector<std::int32_t> x_to_subx_dof_map(
1374 x_index_map->size_local() + x_index_map->num_ghosts(), -1);
1375 for (std::size_t i = 0; i < subx_to_x_dofmap.size(); ++i)
1376 x_to_subx_dof_map[subx_to_x_dofmap[i]] = i;
1379 std::vector<std::int32_t> sub_x_dofmap;
1380 sub_x_dofmap.reserve(x_indices.size());
1381 std::ranges::transform(x_indices, std::back_inserter(sub_x_dofmap),
1382 [&x_to_subx_dof_map](
auto x_dof)
1384 assert(x_to_subx_dof_map[x_dof] != -1);
1385 return x_to_subx_dof_map[x_dof];
1393 int degree = (sub_xcell == CellType::point) ? 0 :
geometry.cmap().degree();
1398 const std::vector<std::int64_t>& igi =
geometry.input_global_indices();
1399 std::vector<std::int64_t> sub_igi;
1400 sub_igi.reserve(subx_to_x_dofmap.size());
1401 std::ranges::transform(subx_to_x_dofmap, std::back_inserter(sub_igi),
1402 [&igi](
auto sub_x_dof) {
return igi[sub_x_dof]; });
1406 sub_x_dof_index_map,
1407 std::vector<std::vector<std::int32_t>>{std::move(sub_x_dofmap)},
1408 {sub_cmap}, std::move(sub_x),
geometry.dim(), std::move(sub_igi)),
1409 std::move(subx_to_x_dofmap)};
1421template <std::
floating_po
int T>
1422std::tuple<Mesh<T>, EntityMap, EntityMap, std::vector<std::int32_t>>
1424 std::span<const std::int32_t> entities)
1427 mesh.topology_mutable()->create_connectivity(dim, 0);
1428 auto [topology, subentity_to_entity, subvertex_to_vertex]
1432 const int tdim =
mesh.topology()->dim();
1433 mesh.topology_mutable()->create_entities(dim);
1434 mesh.topology_mutable()->create_connectivity(dim, tdim);
1435 mesh.topology_mutable()->create_connectivity(tdim, dim);
1436 mesh.topology_mutable()->create_entity_permutations();
1441 =
Mesh(
mesh.comm(), std::make_shared<Topology>(std::move(topology)),
1444 subentity_to_entity);
1446 subvertex_to_vertex);
1447 return {std::move(submesh), std::move(entity_map), std::move(vertex_map),
1448 std::move(subx_to_x_dofmap)};
1458template <
typename T>
1461 std::shared_ptr<const dolfinx::mesh::Topology> submesh_topology,
1464 int tag_dim = tags.
dim();
1465 int submesh_tdim = submesh_topology->dim();
1467 if (tag_dim > submesh_tdim)
1469 throw std::runtime_error(
"Tag dimension must be less than or equal to "
1470 "submesh dimension");
1472 std::shared_ptr<const dolfinx::common::IndexMap> sub_cell_imap
1473 = submesh_topology->index_map(submesh_tdim);
1476 throw std::runtime_error(
1477 std::format(
"Entities of dimension {} does not exist in mesh topology.",
1482 std::int32_t submesh_num_cells
1483 = sub_cell_imap->size_local() + sub_cell_imap->num_ghosts();
1484 auto sub_cells = std::ranges::views::iota(0, submesh_num_cells);
1485 std::vector<std::int32_t> sub_cell_to_parent_entity
1490 auto parent_entity_imap = topology->index_map(submesh_tdim);
1491 if (!parent_entity_imap)
1493 throw std::runtime_error(std::format(
1494 "Entities of dimension {} does not exist in parent mesh topology.",
1497 std::size_t num_parent_entities
1498 = parent_entity_imap->size_local() + parent_entity_imap->num_ghosts();
1499 std::vector<std::int32_t> parent_entity_to_sub_cell(num_parent_entities, -1);
1500 for (std::size_t i = 0; i < sub_cell_to_parent_entity.size(); ++i)
1501 parent_entity_to_sub_cell[sub_cell_to_parent_entity[i]]
1502 =
static_cast<std::int32_t
>(i);
1505 std::vector<std::int32_t> sub_to_parent_vertex;
1507 auto sub_vertex_map = submesh_topology->index_map(0);
1508 std::int32_t num_sub_vertices
1509 = sub_vertex_map->size_local() + sub_vertex_map->num_ghosts();
1510 auto sub_vertices = std::ranges::views::iota(0, num_sub_vertices);
1512 sub_to_parent_vertex
1516 auto sub_e_to_v = submesh_topology->connectivity(tag_dim, 0);
1517 auto sub_c_to_e = submesh_topology->connectivity(submesh_tdim, tag_dim);
1518 auto sub_entity_imap = submesh_topology->index_map(tag_dim);
1519 auto e_to_v = topology->connectivity(tag_dim, 0);
1520 std::shared_ptr<const dolfinx::graph::AdjacencyList<std::int32_t>>
1521 e_to_sub_cell =
nullptr;
1522 if (tag_dim != submesh_tdim)
1524 e_to_sub_cell = topology->connectivity(tag_dim, submesh_tdim);
1527 throw std::runtime_error(
1528 std::format(
"Missing connectivity between {} and {} in parent mesh",
1529 tag_dim, submesh_tdim));
1535 throw std::runtime_error(std::format(
1536 "Missing connectivity between {} and {} in submesh", tag_dim, 0));
1540 throw std::runtime_error(
1541 std::format(
"Missing connectivity between {} and {} in submesh",
1542 submesh_tdim, tag_dim));
1544 if (!sub_entity_imap)
1546 throw std::runtime_error(std::format(
1547 "Entities of dimension {} does not exist in submesh topology.",
1552 throw std::runtime_error(
1553 std::format(
"Missing connectivity between {} and 0", tag_dim));
1557 std::size_t num_sub_entities
1558 = sub_entity_imap->size_local() + sub_entity_imap->num_ghosts();
1559 constexpr T max_val = std::numeric_limits<T>::max();
1560 std::vector<T> submesh_values(num_sub_entities, max_val);
1561 std::vector<std::int32_t> submesh_indices(num_sub_entities);
1562 std::iota(submesh_indices.begin(), submesh_indices.end(), 0);
1564 std::span<const std::int32_t> tagged_entities = tags.
indices();
1565 std::span<const T> tagged_values = tags.
values();
1568 for (std::size_t i = 0; i < tagged_entities.size(); ++i)
1570 auto find_and_map_sub_entity
1571 = [tag_dim, submesh_tdim, &e_to_v, &parent_entity_to_sub_cell,
1572 &sub_to_parent_vertex, &sub_e_to_v, &sub_c_to_e,
1573 &e_to_sub_cell](std::int32_t entity)
1577 if (tag_dim == submesh_tdim)
1578 return parent_entity_to_sub_cell[entity];
1582 auto entity_vertices = e_to_v->links(entity);
1583 auto parent_sub_cells = e_to_sub_cell->links(entity);
1586 | std::views::transform([&parent_entity_to_sub_cell](
auto c)
1587 {
return parent_entity_to_sub_cell[c]; })
1588 | std::views::filter([](
auto sub_cell) {
return sub_cell != -1; });
1589 for (
auto sub_cell : submesh_cells)
1591 for (
auto sub_entity : sub_c_to_e->links(sub_cell))
1594 auto parent_vertices
1595 = sub_e_to_v->links(sub_entity)
1596 | std::views::transform([&sub_to_parent_vertex](
auto v)
1597 {
return sub_to_parent_vertex[v]; });
1601 bool entity_matches = std::ranges::all_of(
1606 return std::ranges::find(entity_vertices, p_v)
1607 != std::ranges::end(entity_vertices);
1619 std::int32_t sub_entity = find_and_map_sub_entity(tagged_entities[i]);
1620 if (sub_entity != -1)
1621 submesh_values[sub_entity] = tagged_values[i];
1625 std::vector<std::int32_t> filtered_indices;
1626 std::vector<T> filtered_values;
1627 filtered_indices.reserve(num_sub_entities);
1628 filtered_values.reserve(num_sub_entities);
1629 for (std::size_t i = 0; i < submesh_values.size(); ++i)
1631 if (submesh_values[i] != max_val)
1633 filtered_indices.push_back(submesh_indices[i]);
1634 filtered_values.push_back(submesh_values[i]);
1637 filtered_indices.shrink_to_fit();
1638 filtered_values.shrink_to_fit();
1639 MeshTags<T> new_meshtag(submesh_topology, tag_dim, filtered_indices,
Definition CoordinateElement.h:38
ElementDofLayout create_dof_layout() const
Compute and return the dof layout.
Definition CoordinateElement.cpp:75
void permute_subentity_closure(std::span< std::int32_t > d, std::uint32_t cell_info, mesh::CellType entity_type, int entity_index) const
Given the closure DOFs of a cell sub-entity in reference ordering, this function computes the permut...
Definition CoordinateElement.cpp:64
Definition ElementDofLayout.h:31
const std::vector< int > & entity_closure_dofs(int dim, int entity_index) const
Definition ElementDofLayout.cpp:65
const std::vector< std::vector< std::vector< int > > > & entity_closure_dofs_all() const
Definition ElementDofLayout.cpp:77
This class provides a static adjacency list data structure.
Definition AdjacencyList.h:38
const std::vector< LinkData > & array() const
Return contiguous array of links for all nodes (const version).
Definition AdjacencyList.h:174
const std::vector< std::int32_t > & offsets() const
Offset for each node in array() (const version).
Definition AdjacencyList.h:180
A bidirectional map relating entities in one topology to another.
Definition EntityMap.h:21
std::vector< std::int32_t > sub_topology_to_topology(CellRange auto &&entities, bool inverse) const
Map entities between the sub-topology and the parent topology.
Definition EntityMap.h:103
Geometry stores the geometry imposed on a mesh.
Definition Geometry.h:34
A Mesh consists of a set of connected and numbered mesh topological entities, and geometry data.
Definition Mesh.h:23
std::shared_ptr< Topology > topology()
Get mesh topology.
Definition Mesh.h:69
Topology stores the topology of a mesh, consisting of mesh entities and connectivity (incidence relat...
Definition Topology.h:49
Requirements on function for geometry marking.
Definition utils.h:667
void reorder_list(std::span< T > list, std::span< const std::int32_t > nodemap)
Re-order the nodes of a fixed-degree adjacency list.
Definition utils.h:57
std::tuple< std::vector< std::int32_t >, std::vector< T >, std::vector< std::int32_t > > compute_vertex_coords_boundary(const mesh::Mesh< T > &mesh, int dim, std::span< const std::int32_t > facets)
Compute the coordinates of 'vertices' for entities of a given dimension that are attached to specifie...
Definition utils.h:88
std::pair< std::vector< T >, std::array< std::size_t, 2 > > compute_vertex_coords(const mesh::Mesh< T > &mesh)
The coordinates for all 'vertices' in the mesh.
Definition utils.h:621
std::vector< typename std::remove_reference_t< typename U::value_type > > distribute_data(MPI_Comm comm0, std::span< const std::int64_t > indices, MPI_Comm comm1, const U &x, int shape1)
Distribute rows of a rectangular data array to ranks where they are required (scalable version).
Definition MPI.h:679
int size(MPI_Comm comm)
Definition MPI.cpp:72
std::pair< IndexMap, std::vector< std::int32_t > > create_sub_index_map(const IndexMap &imap, std::span< const std::int32_t > indices, IndexMapOrder order=IndexMapOrder::any, bool allow_owner_change=false)
Create a new index map from a subset of indices in an existing index map.
Definition IndexMap.cpp:816
@ any
Allow arbitrary ordering of ghost indices in sub-maps.
Definition IndexMap.h:29
Finite element method functionality.
Definition assemble_expression_impl.h:23
Geometry data structures and algorithms.
Definition BoundingBoxTree.h:22
std::tuple< graph::AdjacencyList< std::int64_t >, std::vector< int >, std::vector< std::int64_t >, std::vector< int > > distribute(MPI_Comm comm, const graph::AdjacencyList< std::int64_t > &list, const graph::AdjacencyList< std::int32_t > &destinations)
Distribute adjacency list nodes to destination ranks.
Definition partition.cpp:39
Graph data structures and algorithms.
Definition AdjacencyList.h:20
std::vector< std::int32_t > reorder_gps(const graph::AdjacencyList< std::int32_t > &graph)
Re-order a graph using the Gibbs-Poole-Stockmeyer algorithm.
Definition ordering.cpp:363
std::function< graph::AdjacencyList< std::int32_t >( MPI_Comm, int, const AdjacencyList< std::int64_t > &, bool)> partition_fn
Signature of functions for computing the parallel partitioning of a distributed graph.
Definition partition.h:31
Mesh data structures and algorithms on meshes.
Definition DofMap.h:32
CellPartitionFunction create_cell_partitioner(mesh::GhostMode ghost_mode, const graph::partition_fn &partfn, std::optional< std::int32_t > max_facet_to_cell_links)
Create a function that computes destination rank for mesh cells on this rank by applying the default ...
Definition utils.cpp:100
std::tuple< graph::AdjacencyList< std::int32_t >, std::vector< std::int64_t >, int, std::vector< std::int32_t > > build_local_dual_graph(std::span< const CellType > celltypes, const std::vector< std::span< const std::int64_t > > &cells, std::optional< std::int32_t > max_facet_to_cell_links)
Compute the local part of the dual graph (cell-cell connections via facets) and facets with only one ...
Definition graphbuild.cpp:530
std::function< std::vector< std::int32_t >( const graph::AdjacencyList< std::int32_t > &)> CellReorderFunction
Function that reorders (locally) cells that are owned by this process. It takes the local mesh dual g...
Definition utils.h:220
MeshTags< T > transfer_meshtags_to_submesh(const MeshTags< T > &tags, std::shared_ptr< const dolfinx::mesh::Topology > submesh_topology, const EntityMap &vertex_map, const EntityMap &cell_map)
Transfer a meshtags object from a parent to a submesh.
Definition utils.h:1459
std::function< graph::AdjacencyList< std::int32_t >( MPI_Comm comm, int nparts, const std::vector< CellType > &cell_types, const std::vector< std::span< const std::int64_t > > &cells)> CellPartitionFunction
Signature for the cell partitioning function. Function that implement this interface compute the dest...
Definition utils.h:212
std::vector< T > cell_normals(const Mesh< T > &mesh, int dim, std::span< const std::int32_t > entities)
Compute normal to given cell (viewed as embedded in 3D).
Definition utils.h:466
std::tuple< Topology, std::vector< int32_t >, std::vector< int32_t > > create_subtopology(const Topology &topology, int dim, std::span< const std::int32_t > entities)
Create a topology for a subset of entities of a given topological dimension.
Definition Topology.cpp:1369
std::tuple< Mesh< T >, EntityMap, EntityMap, std::vector< std::int32_t > > create_submesh(const Mesh< T > &mesh, int dim, std::span< const std::int32_t > entities)
Create a new mesh consisting of a subset of entities in a mesh.
Definition utils.h:1423
std::vector< std::int32_t > exterior_facet_indices(const Topology &topology, int facet_type_idx)
Compute the indices of all exterior facets that are owned by the caller.
Definition utils.cpp:59
std::vector< std::int32_t > locate_entities_boundary(const Mesh< T > &mesh, int dim, U marker)
Compute indices of all mesh entities that are attached to an owned boundary facet and evaluate to tru...
Definition utils.h:786
CellType
Cell type identifier.
Definition cell_types.h:21
int num_cell_vertices(CellType type)
Number vertices for a cell type.
Definition cell_types.cpp:98
std::vector< T > h(const Mesh< T > &mesh, std::span< const std::int32_t > entities, int dim)
Compute greatest distance between any two vertices of the mesh entities (h).
Definition utils.h:414
std::pair< Geometry< T >, std::vector< int32_t > > create_subgeometry(const Mesh< T > &mesh, int dim, std::span< const std::int32_t > subentity_to_entity)
Create a sub-geometry from a mesh and a subset of mesh entities to be included.
Definition utils.h:1332
auto create_boundary_vertices_fn(const CellReorderFunction &reorder_fn, std::optional< std::int32_t > max_facet_to_cell_links)
Creates the default boundary vertices routine for a given reorder function.
Definition utils.h:232
Mesh< typename std::remove_reference_t< typename U::value_type > > create_mesh(MPI_Comm comm, MPI_Comm commt, std::vector< std::span< const std::int64_t > > cells, const std::vector< fem::CoordinateElement< typename std::remove_reference_t< typename U::value_type > > > &elements, MPI_Comm commg, const U &x, std::array< std::size_t, 2 > xshape, const CellPartitionFunction &partitioner, std::optional< std::int32_t > max_facet_to_cell_links, const CellReorderFunction &reorder_fn=graph::reorder_gps)
Create a distributed mesh::Mesh from mesh data and using the provided graph partitioning function for...
Definition utils.h:1046
Geometry< typename std::remove_reference_t< typename U::value_type > > create_geometry(const Topology &topology, const std::vector< fem::CoordinateElement< std::remove_reference_t< typename U::value_type > > > &elements, std::span< const std::int64_t > nodes, std::span< const std::int64_t > xdofs, const U &x, int dim, const std::function< std::vector< int >(const graph::AdjacencyList< std::int32_t > &)> &reorder_fn=nullptr)
Build Geometry from input data.
Definition Geometry.h:238
std::pair< std::vector< std::int32_t >, std::array< std::size_t, 2 > > entities_to_geometry(const Mesh< T > &mesh, int dim, std::span< const std::int32_t > entities, bool permute=false)
Compute the geometry degrees of freedom associated with the closure of a given set of cell entities.
Definition utils.h:862
std::vector< std::int32_t > compute_incident_entities(const Topology &topology, std::span< const std::int32_t > entities, int d0, int d1)
Compute incident entities.
Definition utils.cpp:132
std::vector< std::int64_t > extract_topology(CellType cell_type, const fem::ElementDofLayout &layout, std::span< const std::int64_t > cells)
Extract topology from cell data, i.e. extract cell vertices.
Definition utils.cpp:30
std::vector< std::int32_t > locate_entities(const Mesh< T > &mesh, int dim, U marker, int entity_type_idx)
Compute indices of all mesh entities that evaluate to true for the provided geometric marking functio...
Definition utils.h:688
std::vector< T > compute_midpoints(const Mesh< T > &mesh, int dim, std::span< const std::int32_t > entities)
Compute the midpoints for mesh entities of a given dimension.
Definition utils.h:583
GhostMode
Enum for different partitioning ghost modes.
Definition utils.h:44
Topology create_topology(MPI_Comm comm, const std::vector< CellType > &cell_types, std::vector< std::span< const std::int64_t > > cells, std::vector< std::span< const std::int64_t > > original_cell_index, std::vector< std::span< const int > > ghost_owners, std::span< const std::int64_t > boundary_vertices, int num_threads)
Create a mesh topology.
Definition Topology.cpp:1051
CellType cell_entity_type(CellType type, int d, int index)
Return type of cell for entity of dimension d at given entity index.
Definition cell_types.h:110
constexpr void radix_sort(R &&range, P proj={})
Sort a range with radix sorting algorithm. The bucket size is determined by the number of bits to sor...
Definition sort.h:78
std::vector< std::int32_t > sort_by_perm(std::span< const T > x, std::size_t shape1)
Compute the permutation array that sorts a 2D array by row.
Definition sort.h:177