13#include "graphbuild.h"
17#include <basix/mdspan.hpp>
18#include <boost/unordered/unordered_flat_map.hpp>
22#include <dolfinx/common/MPI.h>
23#include <dolfinx/common/Timer.h>
24#include <dolfinx/common/sort.h>
25#include <dolfinx/graph/AdjacencyList.h>
26#include <dolfinx/graph/ordering.h>
27#include <dolfinx/graph/partition.h>
65void reorder_list(std::span<T> list, std::span<const std::int32_t> nodemap)
70 assert(list.size() % nodemap.size() == 0);
71 std::size_t degree = list.size() / nodemap.size();
72 const std::vector<T> orig(list.begin(), list.end());
73 for (std::size_t n = 0; n < nodemap.size(); ++n)
75 std::span links_old(orig.data() + n * degree, degree);
76 auto links_new = list.subspan(nodemap[n] * degree, degree);
77 std::ranges::copy(links_old, links_new.begin());
94template <std::
floating_po
int T>
95std::tuple<std::vector<std::int32_t>, std::vector<T>, std::vector<std::int32_t>>
97 std::span<const std::int32_t> facets)
99 auto topology =
mesh.topology();
101 const int tdim = topology->dim();
104 throw std::invalid_argument(
105 "Cannot use mesh::locate_entities_boundary (boundary) for cells.");
109 mesh.topology_mutable()->create_connectivity(tdim - 1, 0);
110 mesh.topology_mutable()->create_connectivity(tdim - 1, dim);
111 std::vector<std::int32_t> vertices, entities;
113 auto f_to_v = topology->connectivity(tdim - 1, 0);
115 auto f_to_e = topology->connectivity(tdim - 1, dim);
117 for (
auto f : facets)
119 auto v = f_to_v->links(f);
120 vertices.insert(vertices.end(), v.begin(), v.end());
121 auto e = f_to_e->links(f);
122 entities.insert(entities.end(), e.begin(), e.end());
127 std::ranges::sort(vertices);
128 auto [unique_end, range_end] = std::ranges::unique(vertices);
129 vertices.erase(unique_end, range_end);
133 std::ranges::sort(entities);
134 auto [unique_end, range_end] = std::ranges::unique(entities);
135 entities.erase(unique_end, range_end);
140 auto x_dofmap =
mesh.geometry().dofmaps().front();
141 std::span<const T> x_nodes =
mesh.geometry().x();
144 mesh.topology_mutable()->create_connectivity(0, tdim);
145 mesh.topology_mutable()->create_connectivity(tdim, 0);
146 auto v_to_c = topology->connectivity(0, tdim);
148 auto c_to_v = topology->connectivity(tdim, 0);
150 std::vector<T> x_vertices(3 * vertices.size(), -1.0);
151 std::vector<std::int32_t> vertex_to_pos(v_to_c->num_nodes(), -1);
152 for (std::size_t i = 0; i < vertices.size(); ++i)
154 const std::int32_t v = vertices[i];
157 const std::int32_t c = v_to_c->links(v).front();
158 auto cell_vertices = c_to_v->links(c);
159 auto it = std::ranges::find(cell_vertices, v);
160 assert(it != cell_vertices.end());
161 const std::size_t local_pos
162 = std::ranges::distance(cell_vertices.begin(), it);
164 auto dofs = md::submdspan(x_dofmap, c, md::full_extent);
165 for (std::size_t j = 0; j < 3; ++j)
166 x_vertices[j * vertices.size() + i] = x_nodes[3 * dofs[local_pos] + j];
167 vertex_to_pos[v] = i;
170 return {std::move(entities), std::move(x_vertices), std::move(vertex_to_pos)};
247std::vector<std::int64_t> reorder_cells(
248 const graph::Reorder& reorder_fn, std::span<const double> cell_centroids,
249 int gdim, std::optional<std::int32_t> max_facet_to_cell_links,
250 const std::vector<CellType>& celltypes,
251 const std::vector<fem::ElementDofLayout>& doflayouts,
252 const std::vector<std::vector<int>>& ghost_owners,
253 std::vector<std::vector<std::int64_t>>& cells,
254 std::vector<std::span<std::int64_t>>& cells_v,
255 std::vector<std::vector<std::int64_t>>& original_idx,
int num_threads);
268 const fem::ElementDofLayout& layout,
269 std::span<const std::int64_t> cells);
283 const fem::ElementDofLayout& layout);
298template <std::
floating_po
int T>
299std::vector<T>
h(
const Mesh<T>&
mesh, std::span<const std::int32_t> entities,
302 if (entities.empty())
303 return std::vector<T>();
305 return std::vector<T>(entities.size(), 0);
308 const auto [vertex_xdofs, xdof_shape]
312 std::span<const T> x =
mesh.geometry().x();
315 auto delta_norm = [](
auto&& p0,
auto&& p1)
318 for (std::size_t i = 0; i < 3; ++i)
319 norm += (p0[i] - p1[i]) * (p0[i] - p1[i]);
320 return std::sqrt(norm);
325 std::vector<T>
h(entities.size(), 0);
326 for (std::size_t e = 0; e < entities.size(); ++e)
329 std::span<const std::int32_t> e_vertices(
330 vertex_xdofs.data() + e * xdof_shape[1], xdof_shape[1]);
333 for (std::size_t i = 0; i < e_vertices.size(); ++i)
335 std::span<const T, 3> p0(x.data() + 3 * e_vertices[i], 3);
336 for (std::size_t j = i + 1; j < e_vertices.size(); ++j)
338 std::span<const T, 3> p1(x.data() + 3 * e_vertices[j], 3);
339 h[e] = std::max(
h[e], delta_norm(p0, p1));
350template <std::
floating_po
int T>
352 std::span<const std::int32_t> entities)
354 if (entities.empty())
355 return std::vector<T>();
357 auto topology =
mesh.topology();
359 if (topology->cell_type() == CellType::prism and dim == 2)
361 throw std::invalid_argument(
362 "Cell normal computation for prism cells not yet supported.");
365 const int gdim =
mesh.geometry().dim();
369 std::span<const T> x =
mesh.geometry().x();
370 const auto [geometry_entities, eshape]
373 std::vector<T> n(entities.size() * 3);
376 case CellType::interval:
379 throw std::invalid_argument(
"Interval cell normal undefined in 3D.");
380 for (std::size_t i = 0; i < entities.size(); ++i)
383 std::array vertices{geometry_entities[i * eshape[1]],
384 geometry_entities[i * eshape[1] + 1]};
385 std::array p = {std::span<const T, 3>(x.data() + 3 * vertices[0], 3),
386 std::span<const T, 3>(x.data() + 3 * vertices[1], 3)};
390 std::ranges::transform(p[1], p[0], t.begin(),
391 [](
auto x,
auto y) { return x - y; });
393 T norm = std::sqrt(t[0] * t[0] + t[1] * t[1]);
394 std::span<T, 3> ni(n.data() + 3 * i, 3);
395 ni[0] = -t[1] / norm;
401 case CellType::triangle:
403 for (std::size_t i = 0; i < entities.size(); ++i)
406 std::array vertices = {geometry_entities[i * eshape[1] + 0],
407 geometry_entities[i * eshape[1] + 1],
408 geometry_entities[i * eshape[1] + 2]};
409 std::array p = {std::span<const T, 3>(x.data() + 3 * vertices[0], 3),
410 std::span<const T, 3>(x.data() + 3 * vertices[1], 3),
411 std::span<const T, 3>(x.data() + 3 * vertices[2], 3)};
414 std::array<T, 3> dp1, dp2;
415 std::ranges::transform(p[1], p[0], dp1.begin(),
416 [](
auto x,
auto y) { return x - y; });
417 std::ranges::transform(p[2], p[0], dp2.begin(),
418 [](
auto x,
auto y) { return x - y; });
421 std::array<T, 3> ni = math::cross(dp1, dp2);
422 T norm = std::sqrt(ni[0] * ni[0] + ni[1] * ni[1] + ni[2] * ni[2]);
423 std::ranges::transform(ni, std::next(n.begin(), 3 * i),
424 [norm](
auto x) { return x / norm; });
429 case CellType::quadrilateral:
432 for (std::size_t i = 0; i < entities.size(); ++i)
435 std::array vertices = {geometry_entities[i * eshape[1] + 0],
436 geometry_entities[i * eshape[1] + 1],
437 geometry_entities[i * eshape[1] + 2]};
438 std::array p = {std::span<const T, 3>(x.data() + 3 * vertices[0], 3),
439 std::span<const T, 3>(x.data() + 3 * vertices[1], 3),
440 std::span<const T, 3>(x.data() + 3 * vertices[2], 3)};
443 std::array<T, 3> dp1, dp2;
444 std::ranges::transform(p[1], p[0], dp1.begin(),
445 [](
auto x,
auto y) { return x - y; });
446 std::ranges::transform(p[2], p[0], dp2.begin(),
447 [](
auto x,
auto y) { return x - y; });
450 std::array<T, 3> ni = math::cross(dp1, dp2);
451 T norm = std::sqrt(ni[0] * ni[0] + ni[1] * ni[1] + ni[2] * ni[2]);
452 std::ranges::transform(ni, std::next(n.begin(), 3 * i),
453 [norm](
auto x) { return x / norm; });
459 throw std::invalid_argument(
460 "cell_normal not supported for this cell type.");
473template <std::
floating_po
int T>
475 std::span<const std::int32_t> entities)
477 if (entities.empty())
478 return std::vector<T>();
480 std::span<const T> x =
mesh.geometry().x();
483 const auto [e_to_g, eshape]
486 std::vector<T> x_mid(entities.size() * 3, 0);
487 for (std::size_t e = 0; e < entities.size(); ++e)
489 std::span<T, 3> p(x_mid.data() + 3 * e, 3);
490 std::span<const std::int32_t> rows(e_to_g.data() + e * eshape[1],
492 for (
auto row : rows)
494 std::span<const T, 3> xg(x.data() + 3 * row, 3);
495 std::ranges::transform(p, xg, p.begin(),
496 [size = rows.size()](
auto x,
auto y)
497 { return x + y / size; });
510template <std::
floating_po
int T>
511std::pair<std::vector<T>, std::array<std::size_t, 2>>
514 auto topology =
mesh.topology();
516 const int tdim = topology->dim();
521 const std::int32_t num_vertices = topology->index_map(0)->size_local()
522 + topology->index_map(0)->num_ghosts();
524 std::vector<std::int32_t> vertex_to_node(num_vertices);
525 for (
int cell_type_idx = 0,
526 num_cell_types = topology->entity_types(tdim).size();
527 cell_type_idx < num_cell_types; ++cell_type_idx)
529 auto x_dofmap =
mesh.geometry().dofmaps().at(cell_type_idx);
530 auto c_to_v = topology->connectivity({tdim, cell_type_idx}, {0, 0});
532 for (
int c = 0; c < c_to_v->num_nodes(); ++c)
534 auto x_dofs = md::submdspan(x_dofmap, c, md::full_extent);
535 auto vertices = c_to_v->links(c);
536 for (std::size_t i = 0; i < vertices.size(); ++i)
537 vertex_to_node[vertices[i]] = x_dofs[i];
542 std::span<const T> x_nodes =
mesh.geometry().x();
543 std::vector<T> x_vertices(3 * vertex_to_node.size(), 0.0);
544 for (std::size_t i = 0; i < vertex_to_node.size(); ++i)
546 std::int32_t pos = 3 * vertex_to_node[i];
547 for (std::size_t j = 0; j < 3; ++j)
548 x_vertices[j * vertex_to_node.size() + i] = x_nodes[pos + j];
551 return {std::move(x_vertices), {3, vertex_to_node.size()}};
557template <
typename Fn,
typename T>
559 std::vector<std::int8_t>, Fn,
561 md::extents<std::size_t, 3, md::dynamic_extent>>>::value;
580template <std::
floating_po
int T, MarkerFn<T> U>
582 U marker,
int entity_type_idx)
586 = md::mdspan<const T, md::extents<std::size_t, 3, md::dynamic_extent>>;
589 const auto [xdata, xshape] = impl::compute_vertex_coords(
mesh);
591 cmdspan3x_t x(xdata.data(), xshape);
592 const std::vector<std::int8_t> marked = marker(x);
593 if (marked.size() != x.extent(1))
594 throw std::invalid_argument(
"Length of array of markers is wrong.");
596 auto topology =
mesh.topology();
598 const int tdim = topology->dim();
600 if (entity_type_idx < 0
601 or
static_cast<std::size_t
>(entity_type_idx)
602 >= topology->entity_types(dim).size())
604 throw std::out_of_range(
605 "entity_type_idx out of range for Topology::entity_types(dim).");
608 mesh.topology_mutable()->create_entities(dim);
610 mesh.topology_mutable()->create_connectivity(dim, 0);
614 auto e_to_v = topology->connectivity({dim, entity_type_idx}, {0, 0});
616 std::vector<std::int32_t> entities;
617 for (
int e = 0; e < e_to_v->num_nodes(); ++e)
620 bool all_vertices_marked =
true;
621 for (std::int32_t v : e_to_v->links(e))
625 all_vertices_marked =
false;
630 if (all_vertices_marked)
631 entities.push_back(e);
652template <std::
floating_po
int T, MarkerFn<T> U>
656 const int num_entity_types =
mesh.topology()->entity_types(dim).size();
657 if (num_entity_types > 1)
659 throw std::runtime_error(
660 "Multiple entity types of this dimension. Specify entity type index");
691template <std::
floating_po
int T, MarkerFn<T> U>
696 auto topology =
mesh.topology();
698 int tdim = topology->dim();
701 throw std::invalid_argument(
702 "Cannot use mesh::locate_entities_boundary (boundary) for cells.");
706 mesh.topology_mutable()->create_entities(tdim - 1);
707 mesh.topology_mutable()->create_connectivity(tdim - 1, tdim);
709 mesh.topology_mutable()->create_entities(dim);
712 = md::mdspan<const T, md::extents<std::size_t, 3, md::dynamic_extent>>;
715 auto [facet_entities, xdata, vertex_to_pos]
716 = impl::compute_vertex_coords_boundary(
mesh, dim, boundary_facets);
717 cmdspan3x_t x(xdata.data(), 3, xdata.size() / 3);
718 std::vector<std::int8_t> marked = marker(x);
719 if (marked.size() != x.extent(1))
720 throw std::invalid_argument(
"Length of array of markers is wrong.");
723 auto e_to_v = topology->connectivity(dim, 0);
725 std::vector<std::int32_t> entities;
726 for (
auto e : facet_entities)
729 bool all_vertices_marked =
true;
730 for (
auto v : e_to_v->links(e))
732 const std::int32_t pos = vertex_to_pos[v];
735 all_vertices_marked =
false;
741 if (all_vertices_marked)
742 entities.push_back(e);
771template <std::
floating_po
int T>
772std::pair<std::vector<std::int32_t>, std::array<std::size_t, 2>>
774 std::span<const std::int32_t> entities,
775 bool permute =
false)
777 auto topology =
mesh.topology();
779 CellType cell_type = topology->cell_type();
780 if ((cell_type == CellType::prism or cell_type == CellType::pyramid)
783 throw std::invalid_argument(
"mesh::entities_to_geometry for prism/pyramid "
784 "cell facets not yet supported.");
787 const int tdim = topology->dim();
789 auto xdofs =
geometry.dofmaps().front();
795 throw std::invalid_argument(
796 "mesh::entities_to_geometry for sub-entities of a cell is not "
797 "supported for a discontinuous geometry, which has no coordinate "
798 "degrees-of-freedom associated with sub-entities.");
803 std::vector<std::int32_t> entity_xdofs;
804 entity_xdofs.reserve(entities.size() * num_entity_dofs);
805 std::array<std::size_t, 2> eshape{entities.size(), num_entity_dofs};
808 const std::vector<std::vector<std::vector<int>>>& closure_dofs_all
814 for (std::int32_t c : entities)
817 auto x_c = md::submdspan(xdofs, c, md::full_extent);
818 for (std::int32_t entity_dof : closure_dofs_all[tdim][0])
819 entity_xdofs.push_back(x_c[entity_dof]);
822 return {std::move(entity_xdofs), eshape};
827 auto e_to_c = topology->connectivity(dim, tdim);
830 throw std::runtime_error(std::format(
831 "Entity-to-cell connectivity has not been computed. Missing dims "
836 auto c_to_e = topology->connectivity(tdim, dim);
839 throw std::runtime_error(std::format(
840 "Cell-to-entity connectivity has not been computed. Missing dims "
846 std::span<const std::uint32_t> cell_info;
848 cell_info = std::span(
mesh.topology()->get_cell_permutation_info());
853 std::vector<std::int32_t> closure_dofs(num_entity_dofs);
854 for (std::int32_t e : entities)
857 if (e_to_c->links(e).empty())
858 throw std::runtime_error(
"No cell incident to entity.");
859 std::int32_t c = e_to_c->links(e).front();
862 std::span<const std::int32_t> cell_entities = c_to_e->links(c);
863 auto it = std::find(cell_entities.begin(), cell_entities.end(), e);
864 assert(it != cell_entities.end());
865 std::size_t local_entity = std::ranges::distance(cell_entities.begin(), it);
869 const std::vector<int>& e_closure_dofs
870 = closure_dofs_all[dim][local_entity];
871 assert(e_closure_dofs.size() == closure_dofs.size());
872 std::ranges::copy(e_closure_dofs, closure_dofs.begin());
878 entity_type, local_entity);
882 auto x_c = md::submdspan(xdofs, c, md::full_extent);
883 for (std::int32_t entity_dof : closure_dofs)
884 entity_xdofs.push_back(x_c[entity_dof]);
887 return {std::move(entity_xdofs), eshape};
898std::vector<std::int32_t>
900 std::span<const std::int32_t> entities,
int d0,
932 error = std::current_exception();
958inline void mpi_check(MPI_Comm comm, std::string_view op_name,
959 const std::exception_ptr& error)
961 int failed = error ? 1 : 0;
963 MPI_Allreduce(&failed, &any_failed, 1, MPI_INT, MPI_MAX, comm);
965 std::rethrow_exception(error);
968 throw std::runtime_error(
969 std::format(
"{} failed on another rank.", op_name));
996template <std::
floating_po
int T>
998 std::span<const int> num_vertices_per_cell,
999 const std::vector<std::span<const std::int64_t>>& cells,
1000 const boost::unordered_flat_map<std::int64_t, std::size_t>& node_to_pos,
1001 std::span<const T> coords,
int gdim)
1003 std::size_t num_cells = 0;
1004 for (std::size_t i = 0; i < cells.size(); ++i)
1005 num_cells += cells[i].size() / num_vertices_per_cell[i];
1006 std::vector<double> centroid(gdim * num_cells, 0);
1009 for (std::size_t i = 0; i < cells.size(); ++i)
1011 const int nv = num_vertices_per_cell[i];
1012 const double w = 1.0 / nv;
1013 for (std::size_t c = 0; c < cells[i].size() / nv; ++c)
1015 for (
int v = 0; v < nv; ++v)
1017 auto it = node_to_pos.find(cells[i][nv * c + v]);
1018 assert(it != node_to_pos.end());
1019 std::size_t pos = it->second;
1020 for (
int d = 0; d < gdim; ++d)
1021 centroid[gdim * (c0 + c) + d] += w * coords[gdim * pos + d];
1025 c0 += cells[i].size() / nv;
1054template <std::
floating_po
int T>
1057 std::span<const int> num_vertices_per_cell,
1058 const std::vector<std::span<const std::int64_t>>& cells,
1059 MPI_Comm commg, std::span<const T> x,
int gdim)
1063 std::vector<std::int64_t> nodes;
1065 std::size_t size = 0;
1066 for (std::span<const std::int64_t> c : cells)
1068 nodes.reserve(size);
1069 for (std::span<const std::int64_t> c : cells)
1070 nodes.insert(nodes.end(), c.begin(), c.end());
1072 auto [unique_end, range_end] = std::ranges::unique(nodes);
1073 nodes.erase(unique_end, range_end);
1075 const std::vector<T> coords
1083 boost::unordered_flat_map<std::int64_t, std::size_t> node_to_pos;
1084 node_to_pos.reserve(nodes.size());
1085 for (std::size_t i = 0; i < nodes.size(); ++i)
1086 node_to_pos.emplace(nodes[i], i);
1089 std::span<const T>(coords), gdim);
1140template <std::
floating_po
int T>
1141std::tuple<std::vector<std::vector<std::int64_t>>,
1142 std::vector<std::vector<std::int64_t>>,
1143 std::vector<std::vector<int>>>
1145 const std::vector<std::span<const std::int64_t>>& cells,
1146 const std::vector<CellType>& celltypes,
1147 const std::vector<fem::ElementDofLayout>& doflayouts,
1150 std::optional<std::int32_t> max_facet_to_cell_links,
1151 int num_threads, MPI_Comm commg, std::span<const T> x,
1152 std::array<std::size_t, 2> xshape)
1154 const std::int32_t num_cell_types = cells.size();
1155 std::vector<std::vector<std::int64_t>> cells1(num_cell_types);
1156 std::vector<std::vector<std::int64_t>> original_idx1(num_cell_types);
1157 std::vector<std::vector<int>> ghost_owners(num_cell_types);
1160 spdlog::info(
"Using partitioner with cell data ({} cell types)",
1163 std::exception_ptr error;
1168 std::vector<double> centroid;
1169 const bool needs_centroids
1170 = std::holds_alternative<graph::geom_partition_fn>(partitioner.fn)
1171 or std::holds_alternative<graph::hybrid_partition_fn>(partitioner.fn);
1172 std::vector<std::vector<std::int64_t>> topology(num_cell_types);
1173 std::vector<std::span<const std::int64_t>> topology_view(num_cell_types);
1174 if (needs_centroids or commt != MPI_COMM_NULL)
1176 for (std::int32_t i = 0; i < num_cell_types; ++i)
1179 topology_view[i] = cells[i];
1183 topology_view[i] = topology[i];
1188 if (needs_centroids)
1190 std::vector<int> num_vertices_per_cell;
1191 num_vertices_per_cell.reserve(celltypes.size());
1192 std::ranges::transform(celltypes,
1193 std::back_inserter(num_vertices_per_cell),
1196 topology_view, commg, x, xshape[1]);
1199 if (std::holds_alternative<graph::geom_partition_fn>(partitioner.fn))
1202 [&dest, &comm, ¢roid, &partitioner, &xshape]
1205 const auto& p = std::get<graph::geom_partition_fn>(partitioner.fn);
1207 p(comm, size, std::span<const double>(centroid), xshape[1],
1208 partitioner.node_weights),
1214 if (commt != MPI_COMM_NULL)
1224 [&dest, &comm, &commt, &celltypes, &topology_view,
1225 &max_facet_to_cell_links, &num_threads, &partitioner, ¢roid,
1233 = [&commt, &celltypes, &topology_view, &max_facet_to_cell_links,
1237 max_facet_to_cell_links, num_threads);
1243 if (!std::holds_alternative<graph::geom_partition_fn>(
1247 [&dual_graph, &commt, size, ¢roid, &partitioner,
1251 using P = std::decay_t<
decltype(p)>;
1252 if constexpr (std::is_same_v<P, graph::hybrid_partition_fn>)
1254 return p(commt, size, dual_graph(),
1255 std::span<const double>(centroid),
1256 partitioner.node_weights, std::nullopt,
1259 else if constexpr (std::is_same_v<P, graph::partition_fn>)
1261 return p(commt, size, dual_graph(),
1262 partitioner.node_weights, std::nullopt,
1270 std::is_same_v<P, graph::geom_partition_fn>);
1271 throw std::logic_error(
"Unreachable.");
1280 mpi_check(comm,
"Cell partitioning", error);
1282 std::int32_t cell_offset = 0;
1283 for (std::int32_t i = 0; i < num_cell_types; ++i)
1285 std::size_t num_cell_nodes = doflayouts[i].num_dofs();
1286 std::size_t num_cells = cells[i].size() / num_cell_nodes;
1289 std::vector<std::int32_t> offsets_i(
1290 std::next(dest.
offsets().begin(), cell_offset),
1291 std::next(dest.
offsets().begin(), cell_offset + num_cells + 1));
1292 std::vector<std::int32_t> data_i(
1293 std::next(dest.
array().begin(), offsets_i.front()),
1294 std::next(dest.
array().begin(), offsets_i.back()));
1295 const std::int32_t offset_0 = offsets_i.front();
1296 std::ranges::transform(offsets_i, offsets_i.begin(),
1297 [offset_0](std::int32_t j)
1298 { return j - offset_0; });
1300 cell_offset += num_cells;
1304 std::vector<int> src_ranks;
1305 std::tie(cells1[i], src_ranks, original_idx1[i], ghost_owners[i])
1307 {num_cells, num_cell_nodes}, dest_i);
1308 spdlog::debug(
"Got {} cells from distribution", cells1[i].size());
1318 std::int64_t num_owned = 0;
1319 for (std::int32_t i = 0; i < num_cell_types; ++i)
1321 cells1[i] = std::vector<std::int64_t>(cells[i].begin(), cells[i].end());
1322 std::int32_t num_cell_nodes = doflayouts[i].num_dofs();
1323 original_idx1[i].resize(cells1[i].size() / num_cell_nodes);
1324 num_owned += original_idx1[i].size();
1332 std::int64_t global_offset = 0;
1333 MPI_Exscan(&num_owned, &global_offset, 1, MPI_INT64_T, MPI_SUM, comm);
1334 for (std::int32_t i = 0; i < num_cell_types; ++i)
1336 std::iota(original_idx1[i].begin(), original_idx1[i].end(),
1338 global_offset += original_idx1[i].size();
1342 return {std::move(cells1), std::move(original_idx1), std::move(ghost_owners)};
1400template <
typename U>
1402 MPI_Comm comm, MPI_Comm commt,
1403 std::vector<std::span<const std::int64_t>> cells,
1405 typename std::remove_reference_t<typename U::value_type>>>& elements,
1406 MPI_Comm commg,
const U& x, std::array<std::size_t, 2> xshape,
1408 std::optional<std::int32_t> max_facet_to_cell_links,
int num_threads,
1411 using T =
typename std::remove_reference_t<typename U::value_type>;
1413 if (cells.size() != elements.size())
1415 throw std::invalid_argument(
1416 "Number of cell arrays and elements must match.");
1418 std::vector<CellType> celltypes;
1419 std::ranges::transform(elements, std::back_inserter(celltypes),
1420 [](
auto& e) {
return e.cell_shape(); });
1421 std::vector<fem::ElementDofLayout> doflayouts;
1422 std::ranges::transform(elements, std::back_inserter(doflayouts),
1423 [](
auto& e) {
return e.create_dof_layout(); });
1424 for (std::size_t i = 0; i <
cells.size(); ++i)
1426 if (cells[i].
size() % doflayouts[i].num_dofs() != 0)
1428 throw std::invalid_argument(
"Cell array size is not a multiple of the "
1429 "number of nodes per cell.");
1442 const bool p1_geometry = std::ranges::all_of(
1443 std::views::iota(std::size_t(0), elements.size()),
1444 [&celltypes, &doflayouts](std::size_t i)
1445 { return is_vertex_dof_layout(celltypes[i], doflayouts[i]); });
1447 const std::int32_t num_cell_types =
cells.size();
1452 const bool ghosting = (ghost_mode != GhostMode::none);
1454 comm, commt, cells, celltypes, doflayouts, p1_geometry, partitioner,
1455 ghosting, max_facet_to_cell_links, num_threads, commg,
1456 std::span<const T>(x), xshape);
1461 std::vector<std::vector<std::int64_t>> cells1_v_storage(num_cell_types);
1462 std::vector<std::span<std::int64_t>> cells1_v(num_cell_types);
1463 for (std::int32_t i = 0; i < num_cell_types; ++i)
1466 cells1_v[i] = cells1[i];
1471 cells1_v[i] = cells1_v_storage[i];
1474 spdlog::info(
"Extract basic topology: {}->{}", cells1[i].
size(),
1475 cells1_v[i].
size());
1486 std::vector<double> cell_centroids;
1488 = std::get_if<graph::reorder_geom_fn>(&reorder_fn);
1497 std::vector<std::span<const std::int64_t>> cells1_v_owned;
1498 cells1_v_owned.reserve(cells1_v.size());
1499 for (std::size_t i = 0; i < cells1_v.size(); ++i)
1502 const std::size_t num_owned_cells
1503 = cells1_v[i].size() / num_cell_vertices_i - ghost_owners[i].size();
1504 cells1_v_owned.emplace_back(cells1_v[i].data(),
1505 num_owned_cells * num_cell_vertices_i);
1510 commg, std::span<const T>(x), xshape[1]);
1513 std::vector<std::int64_t> boundary_v;
1514 std::exception_ptr
error;
1516 [&boundary_v, &reorder_fn, &cell_centroids, &xshape,
1517 &max_facet_to_cell_links, &celltypes, &doflayouts, &ghost_owners,
1518 &cells1, &cells1_v, &original_idx1, &num_threads]
1521 max_facet_to_cell_links, celltypes,
1522 doflayouts, ghost_owners, cells1,
1523 cells1_v, original_idx1, num_threads);
1528 spdlog::debug(
"Got {} boundary vertices", boundary_v.size());
1531 std::vector<std::span<const std::int64_t>> cells1_v_span(cells1_v.begin(),
1533 std::vector<std::span<const std::int64_t>> original_idx1_span;
1534 std::ranges::transform(original_idx1, std::back_inserter(original_idx1_span),
1535 [](
auto& c) {
return std::span(c); });
1536 std::vector<std::span<const int>> ghost_owners_span;
1537 std::ranges::transform(ghost_owners, std::back_inserter(ghost_owners_span),
1538 [](
auto& c) {
return std::span(c); });
1543 auto [topology, vertex_index] = mesh::impl::create_topology(
1544 comm, celltypes, cells1_v_span, original_idx1_span, ghost_owners_span,
1545 boundary_v, num_threads);
1549 for (
int i = 0; i < num_cell_types; ++i)
1551 const auto& entity_dofs = doflayouts[i].entity_dofs_all();
1552 for (
int dim = 1; dim < topology.dim(); ++dim)
1556 = std::accumulate(entity_dofs[dim].begin(), entity_dofs[dim].end(), 0,
1557 [](
int c,
auto v) {
return c + v.size(); });
1559 spdlog::debug(
"Counting entity dofs, dim={}: {}", dim, dim_sum);
1561 topology.create_entities(dim, num_threads);
1564 if (elements[i].needs_dof_permutations())
1565 topology.create_cell_permutations(num_threads);
1570 std::vector<std::int64_t> nodes2_storage;
1571 std::span<const std::int64_t> nodes2;
1572 if (num_cell_types == 1)
1573 nodes2 = cells1.front();
1576 std::size_t
size = 0;
1577 for (
const std::vector<std::int64_t>& c : cells1)
1579 nodes2_storage.reserve(size);
1580 for (
const std::vector<std::int64_t>& c : cells1)
1581 nodes2_storage.insert(nodes2_storage.end(), c.begin(), c.end());
1582 nodes2 = nodes2_storage;
1589 std::vector<std::int64_t> nodes1;
1591 nodes1 = std::move(vertex_index);
1594 nodes1.assign(nodes2.begin(), nodes2.end());
1596 auto [unique_end, range_end] = std::ranges::unique(nodes1);
1597 nodes1.erase(unique_end, range_end);
1605 =
create_geometry(topology, elements, nodes1, nodes2, coords, xshape[1]);
1610 std::int64_t num_nodes_local = xshape[0];
1611 std::int64_t num_nodes = 0;
1612 int err = MPI_Allreduce(&num_nodes_local, &num_nodes, 1,
1615 if (std::int64_t num_used = geometry.index_map()->size_global();
1618 spdlog::warn(
"{} of {} input geometry nodes are not referenced by any "
1619 "cell and have been dropped.",
1620 num_nodes - num_used, num_nodes);
1625 return Mesh(comm, std::make_shared<Topology>(std::move(topology)),
1626 std::move(geometry));
1677template <
typename U>
1679 MPI_Comm comm, MPI_Comm commt, std::span<const std::int64_t> cells,
1681 typename std::remove_reference_t<typename U::value_type>>& element,
1682 MPI_Comm commg,
const U& x, std::array<std::size_t, 2> xshape,
1684 std::optional<std::int32_t> max_facet_to_cell_links,
int num_threads,
1687 return create_mesh(comm, commt, std::vector{cells}, std::vector{element},
1688 commg, x, xshape, partitioner, ghost_mode,
1689 max_facet_to_cell_links, num_threads, reorder_fn);
1714template <
typename U>
1718 std::remove_reference_t<typename U::value_type>>& element,
1719 const U& x, std::array<std::size_t, 2> xshape,
GhostMode ghost_mode,
1720 std::optional<std::int32_t> max_facet_to_cell_links = 2)
1728 return create_mesh(comm, comm, std::vector{cells}, std::vector{element}, comm,
1729 x, xshape, partitioner, ghost_mode,
1730 max_facet_to_cell_links, 1);
1748template <std::
floating_po
int T>
1749std::pair<Geometry<T>, std::vector<int32_t>>
1751 std::span<const std::int32_t> subentity_to_entity)
1757 const std::vector<std::int32_t> x_indices
1760 std::vector<std::int32_t> sub_x_dofs = x_indices;
1761 std::ranges::sort(sub_x_dofs);
1762 auto [unique_end, range_end] = std::ranges::unique(sub_x_dofs);
1763 sub_x_dofs.erase(unique_end, range_end);
1766 auto x_index_map =
geometry.index_map();
1767 assert(x_index_map);
1769 std::shared_ptr<common::IndexMap> sub_x_dof_index_map;
1770 std::vector<std::int32_t> subx_to_x_dofmap;
1776 sub_x_dof_index_map = std::make_shared<common::IndexMap>(std::move(map));
1777 subx_to_x_dofmap = std::move(new_to_old);
1781 std::span<const T> x =
geometry.x();
1782 std::int32_t sub_num_x_dofs = subx_to_x_dofmap.size();
1783 std::vector<T> sub_x(3 * sub_num_x_dofs);
1784 for (std::int32_t i = 0; i < sub_num_x_dofs; ++i)
1786 std::copy_n(std::next(x.begin(), 3 * subx_to_x_dofmap[i]), 3,
1787 std::next(sub_x.begin(), 3 * i));
1791 std::vector<std::int32_t> x_to_subx_dof_map(
1792 x_index_map->size_local() + x_index_map->num_ghosts(), -1);
1793 for (std::size_t i = 0; i < subx_to_x_dofmap.size(); ++i)
1794 x_to_subx_dof_map[subx_to_x_dofmap[i]] = i;
1797 std::vector<std::int32_t> sub_x_dofmap;
1798 sub_x_dofmap.reserve(x_indices.size());
1799 std::ranges::transform(x_indices, std::back_inserter(sub_x_dofmap),
1800 [&x_to_subx_dof_map](
auto x_dof)
1802 assert(x_to_subx_dof_map[x_dof] != -1);
1803 return x_to_subx_dof_map[x_dof];
1813 = (sub_xcell == CellType::point) ? 0 :
geometry.cmaps().front().degree();
1815 geometry.cmaps().front().variant());
1818 const std::vector<std::int64_t>& igi =
geometry.input_global_indices();
1819 std::vector<std::int64_t> sub_igi;
1820 sub_igi.reserve(subx_to_x_dofmap.size());
1821 std::ranges::transform(subx_to_x_dofmap, std::back_inserter(sub_igi),
1822 [&igi](
auto sub_x_dof) {
return igi[sub_x_dof]; });
1826 sub_x_dof_index_map,
1827 std::vector<std::vector<std::int32_t>>{std::move(sub_x_dofmap)},
1828 {sub_cmap}, std::move(sub_x),
geometry.dim(), std::move(sub_igi)),
1829 std::move(subx_to_x_dofmap)};
1841template <std::
floating_po
int T>
1842std::tuple<Mesh<T>, EntityMap, EntityMap, std::vector<std::int32_t>>
1844 std::span<const std::int32_t> entities)
1846 if (dim < 0 or dim >
mesh.topology()->dim())
1847 throw std::invalid_argument(
"dim out of range for mesh topology.");
1850 mesh.topology_mutable()->create_connectivity(dim, 0);
1851 auto [topology, subentity_to_entity, subvertex_to_vertex]
1855 const int tdim =
mesh.topology()->dim();
1856 mesh.topology_mutable()->create_entities(dim);
1857 mesh.topology_mutable()->create_connectivity(dim, tdim);
1858 mesh.topology_mutable()->create_connectivity(tdim, dim);
1859 mesh.topology_mutable()->create_cell_permutations();
1864 =
Mesh(
mesh.comm(), std::make_shared<Topology>(std::move(topology)),
1867 subentity_to_entity);
1869 subvertex_to_vertex);
1870 return {std::move(submesh), std::move(entity_map), std::move(vertex_map),
1871 std::move(subx_to_x_dofmap)};
1885template <
typename T>
1888 std::shared_ptr<const dolfinx::mesh::Topology> submesh_topology,
1891 int tag_dim = tags.
dim();
1892 int submesh_tdim = submesh_topology->dim();
1894 if (tag_dim > submesh_tdim)
1896 throw std::invalid_argument(
"Tag dimension must be less than or equal to "
1897 "submesh dimension");
1903 if (cell_map.
dim() != submesh_tdim)
1905 throw std::invalid_argument(
1906 "cell_map dimension must equal the submesh topology dimension.");
1908 if (cell_map.
topology() != topology)
1910 throw std::invalid_argument(
1911 "cell_map topology must match tags.topology().");
1915 throw std::invalid_argument(
1916 "cell_map sub_topology must match submesh_topology.");
1918 if (vertex_map.
dim() != 0)
1919 throw std::invalid_argument(
"vertex_map dimension must be 0.");
1920 if (vertex_map.
topology() != topology)
1922 throw std::invalid_argument(
1923 "vertex_map topology must match tags.topology().");
1927 throw std::invalid_argument(
1928 "vertex_map sub_topology must match submesh_topology.");
1930 std::shared_ptr<const dolfinx::common::IndexMap> sub_cell_imap
1931 = submesh_topology->index_map(submesh_tdim);
1934 throw std::runtime_error(
1935 std::format(
"Entities of dimension {} does not exist in mesh topology.",
1940 std::int32_t submesh_num_cells
1941 = sub_cell_imap->size_local() + sub_cell_imap->num_ghosts();
1942 auto sub_cells = std::ranges::views::iota(0, submesh_num_cells);
1943 std::vector<std::int32_t> sub_cell_to_parent_entity
1948 auto parent_entity_imap = topology->index_map(submesh_tdim);
1949 if (!parent_entity_imap)
1951 throw std::runtime_error(std::format(
1952 "Entities of dimension {} does not exist in parent mesh topology.",
1955 std::size_t num_parent_entities
1956 = parent_entity_imap->size_local() + parent_entity_imap->num_ghosts();
1957 std::vector<std::int32_t> parent_entity_to_sub_cell(num_parent_entities, -1);
1958 for (std::size_t i = 0; i < sub_cell_to_parent_entity.size(); ++i)
1959 parent_entity_to_sub_cell[sub_cell_to_parent_entity[i]]
1960 =
static_cast<std::int32_t
>(i);
1963 std::vector<std::int32_t> sub_to_parent_vertex;
1965 auto sub_vertex_map = submesh_topology->index_map(0);
1966 std::int32_t num_sub_vertices
1967 = sub_vertex_map->size_local() + sub_vertex_map->num_ghosts();
1968 auto sub_vertices = std::ranges::views::iota(0, num_sub_vertices);
1970 sub_to_parent_vertex
1974 auto sub_e_to_v = submesh_topology->connectivity(tag_dim, 0);
1975 auto sub_c_to_e = submesh_topology->connectivity(submesh_tdim, tag_dim);
1976 auto sub_entity_imap = submesh_topology->index_map(tag_dim);
1977 auto e_to_v = topology->connectivity(tag_dim, 0);
1978 std::shared_ptr<const dolfinx::graph::AdjacencyList<std::int32_t>>
1979 e_to_sub_cell =
nullptr;
1980 if (tag_dim != submesh_tdim)
1982 e_to_sub_cell = topology->connectivity(tag_dim, submesh_tdim);
1985 throw std::runtime_error(
1986 std::format(
"Missing connectivity between {} and {} in parent mesh",
1987 tag_dim, submesh_tdim));
1993 throw std::runtime_error(std::format(
1994 "Missing connectivity between {} and {} in submesh", tag_dim, 0));
1998 throw std::runtime_error(
1999 std::format(
"Missing connectivity between {} and {} in submesh",
2000 submesh_tdim, tag_dim));
2002 if (!sub_entity_imap)
2004 throw std::runtime_error(std::format(
2005 "Entities of dimension {} does not exist in submesh topology.",
2010 throw std::runtime_error(
2011 std::format(
"Missing connectivity between {} and 0", tag_dim));
2015 std::size_t num_sub_entities
2016 = sub_entity_imap->size_local() + sub_entity_imap->num_ghosts();
2017 std::vector<T> submesh_values(num_sub_entities);
2018 std::vector<std::int8_t> submesh_value_found(num_sub_entities, 0);
2019 std::vector<std::int32_t> submesh_indices(num_sub_entities);
2020 std::iota(submesh_indices.begin(), submesh_indices.end(), 0);
2022 std::span<const std::int32_t> tagged_entities = tags.
indices();
2023 std::span<const T> tagged_values = tags.
values();
2026 for (std::size_t i = 0; i < tagged_entities.size(); ++i)
2028 auto find_and_map_sub_entity
2029 = [tag_dim, submesh_tdim, &e_to_v, &parent_entity_to_sub_cell,
2030 &sub_to_parent_vertex, &sub_e_to_v, &sub_c_to_e,
2031 &e_to_sub_cell](std::int32_t entity)
2035 if (tag_dim == submesh_tdim)
2036 return parent_entity_to_sub_cell[entity];
2040 auto entity_vertices = e_to_v->links(entity);
2041 auto parent_sub_cells = e_to_sub_cell->links(entity);
2044 | std::views::transform([&parent_entity_to_sub_cell](
auto c)
2045 {
return parent_entity_to_sub_cell[c]; })
2046 | std::views::filter([](
auto sub_cell) {
return sub_cell != -1; });
2047 for (
auto sub_cell : submesh_cells)
2049 for (
auto sub_entity : sub_c_to_e->links(sub_cell))
2052 auto parent_vertices
2053 = sub_e_to_v->links(sub_entity)
2054 | std::views::transform([&sub_to_parent_vertex](
auto v)
2055 {
return sub_to_parent_vertex[v]; });
2059 bool entity_matches = std::ranges::all_of(
2061 [&entity_vertices](
auto p_v)
2064 return std::ranges::find(entity_vertices, p_v)
2065 != std::ranges::end(entity_vertices);
2077 std::int32_t sub_entity = find_and_map_sub_entity(tagged_entities[i]);
2078 if (sub_entity != -1)
2080 submesh_values[sub_entity] = tagged_values[i];
2081 submesh_value_found[sub_entity] = 1;
2088 std::vector<std::int32_t> filtered_indices;
2089 std::vector<T> filtered_values;
2090 filtered_indices.reserve(num_sub_entities);
2091 filtered_values.reserve(num_sub_entities);
2092 for (std::size_t i = 0; i < submesh_values.size(); ++i)
2094 if (submesh_value_found[i])
2096 filtered_indices.push_back(submesh_indices[i]);
2097 filtered_values.push_back(submesh_values[i]);
2100 filtered_indices.shrink_to_fit();
2101 filtered_values.shrink_to_fit();
2102 MeshTags<T> new_meshtag(submesh_topology, tag_dim, filtered_indices,
2103 filtered_values, tags.
name());
Definition CoordinateElement.h:39
ElementDofLayout create_dof_layout() const
Compute and return the dof layout.
Definition CoordinateElement.cpp:80
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:69
bool is_discontinuous() const
Check if the element is the discontinuous version of the coordinate element.
Definition CoordinateElement.cpp:244
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:41
const std::vector< LinkData > & array() const
Return contiguous array of links for all nodes (const version).
Definition AdjacencyList.h:188
const std::vector< std::int32_t > & offsets() const
Offset for each node in array() (const version).
Definition AdjacencyList.h:194
A bidirectional map relating entities in one topology to another.
Definition EntityMap.h:27
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:119
int dim() const
Get the topological dimension of the entities related by this EntityMap.
Definition EntityMap.cpp:13
std::shared_ptr< const Topology > sub_topology() const
Get the sub-topology.
Definition EntityMap.cpp:20
std::shared_ptr< const Topology > topology() const
Get the (parent) topology.
Definition EntityMap.cpp:15
Geometry stores the geometry imposed on a mesh.
Definition Geometry.h:39
A Mesh consists of a set of connected and numbered mesh topological entities, and geometry data.
Definition Mesh.h:25
std::shared_ptr< Topology > topology()
Get mesh topology.
Definition Mesh.h:74
Requirements on function for geometry marking.
Definition utils.h:558
Small, foundational mesh types (enums, etc.) with minimal dependencies.
void mpi_check(MPI_Comm comm, std::string_view op_name, const std::exception_ptr &error)
Collectively propagate a local failure captured by try_locally to every rank of comm,...
Definition utils.h:958
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:65
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:96
std::vector< std::int64_t > reorder_cells(const graph::Reorder &reorder_fn, std::span< const double > cell_centroids, int gdim, std::optional< std::int32_t > max_facet_to_cell_links, const std::vector< CellType > &celltypes, const std::vector< fem::ElementDofLayout > &doflayouts, const std::vector< std::vector< int > > &ghost_owners, std::vector< std::vector< std::int64_t > > &cells, std::vector< std::span< std::int64_t > > &cells_v, std::vector< std::vector< std::int64_t > > &original_idx, int num_threads)
Find a mesh's process boundary vertices, reordering cells for locality as a side effect.
Definition utils.cpp:35
std::vector< double > cell_centroids_local(std::span< const int > num_vertices_per_cell, const std::vector< std::span< const std::int64_t > > &cells, const boost::unordered_flat_map< std::int64_t, std::size_t > &node_to_pos, std::span< const T > coords, int gdim)
Compute the centroid of each cell from vertex coordinates already available locally.
Definition utils.h:997
std::tuple< std::vector< std::vector< std::int64_t > >, std::vector< std::vector< std::int64_t > >, std::vector< std::vector< int > > > partition_cells(MPI_Comm comm, MPI_Comm commt, const std::vector< std::span< const std::int64_t > > &cells, const std::vector< CellType > &celltypes, const std::vector< fem::ElementDofLayout > &doflayouts, bool p1_geometry, const graph::Partitioner &partitioner, bool ghosting, std::optional< std::int32_t > max_facet_to_cell_links, int num_threads, MPI_Comm commg, std::span< const T > x, std::array< std::size_t, 2 > xshape)
Partition cells across ranks of comm, or, if partitioner does not hold a callable function,...
Definition utils.h:1144
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:512
std::vector< double > compute_cell_centroids(MPI_Comm comm, std::span< const int > num_vertices_per_cell, const std::vector< std::span< const std::int64_t > > &cells, MPI_Comm commg, std::span< const T > x, int gdim)
Compute the centroid of each cell from its vertex positions.
Definition utils.h:1056
void try_locally(F &&fn, std::exception_ptr &error)
Run fn locally, capturing any exception it throws instead of letting it propagate.
Definition utils.h:921
MPI_Datatype mpi_t
Retrieves the MPI data type associated to the provided type.
Definition MPI.h:326
void check_error(MPI_Comm comm, int code) noexcept
Check MPI error code. If the error code is not equal to MPI_SUCCESS, then std::abort is called.
Definition MPI.cpp:89
int size(MPI_Comm comm)
Definition MPI.cpp:81
std::vector< std::ranges::range_value_t< U > > distribute_data(MPI_Comm comm0, std::span< const std::int64_t > indices, MPI_Comm comm1, const U &x, int shape1)
Distribute rows of a row-major array to the ranks that require them, via the post office pattern.
Definition MPI.h:817
int rank(MPI_Comm comm)
Return process rank for the communicator.
Definition MPI.cpp:73
void error(PetscErrorCode error_code, std::string_view petsc_function, std::source_location loc=std::source_location::current())
Print error message for a PETSc call that returned an error and throw a std::runtime_error.
Definition petsc.cpp:21
@ any
Allow arbitrary ghost-index ordering.
Definition IndexMap.h:28
std::tuple< IndexMap, std::vector< std::int32_t >, bool > create_sub_index_map(const IndexMap &imap, std::span< const std::int32_t > indices, IndexMapOrder order=IndexMapOrder::any)
Create an index map from a subset of an existing map.
Definition IndexMap.cpp:931
void cells(la::SparsityPattern &pattern, const std::pair< R0, R1 > &cells, std::array< std::reference_wrapper< const DofMap >, 2 > dofmaps)
Iterate over cells and insert entries into sparsity pattern.
Definition sparsitybuild.h:37
Finite element method functionality.
Definition assemble_expression_impl.h:22
Geometry data structures and algorithms.
Definition BoundingBoxTree.h:24
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:158
std::variant< reorder_graph_fn, reorder_geom_fn > Reorder
A graph or geometric reordering function for mesh cells.
Definition ordering.h:59
bool has_partitioner(const AnyPartitionFunction &partitioner)
Whether an AnyPartitionFunction holds a callable partitioner.
Definition partition.cpp:131
AdjacencyList< typename std::decay_t< U >::value_type, V > regular_adjacency_list(U &&data, int degree)
Construct a constant degree (valency) adjacency list.
Definition AdjacencyList.h:262
std::function< graph::AdjacencyList< std::int32_t >( MPI_Comm, int, const AdjacencyList< std::int64_t > &, std::optional< std::span< const std::int32_t > >, std::optional< std::span< const std::int32_t > >, bool)> partition_fn
Signature of functions for computing the parallel partitioning of a distributed graph,...
Definition partition.h:38
std::function< std::vector< std::int32_t >( std::span< const double > x, int gdim)> reorder_geom_fn
Signature of functions that reorder points from their positions.
Definition ordering.h:52
Mesh data structures and algorithms on meshes.
Definition DofMap.h:32
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 graph::Partitioner &partitioner, GhostMode ghost_mode, std::optional< std::int32_t > max_facet_to_cell_links, int num_threads, const graph::Reorder &reorder_fn=graph::Reorder{})
Create a distributed mesh::Mesh from mesh data and using the provided graph partitioning function for...
Definition utils.h:1401
graph::AdjacencyList< std::int64_t > build_dual_graph(MPI_Comm comm, 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, int num_threads=1)
Build distributed mesh dual graph (cell-cell connections via facets) from minimal mesh data.
Definition graphbuild.cpp:913
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:351
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:1599
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:1843
bool is_vertex_dof_layout(CellType cell_type, const fem::ElementDofLayout &layout)
Check if extract_topology is the identity operation for a dof layout, i.e. the cell 'nodes' are exact...
Definition utils.cpp:285
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:302
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:692
CellType
Cell type identifier.
Definition cell_types.h:24
int num_cell_vertices(CellType type)
Number vertices for a cell type.
Definition cell_types.cpp:106
std::vector< T > h(const Mesh< T > &mesh, std::span< const std::int32_t > entities, int dim)
Compute greatest distance between any two geometry nodes of the mesh entities (h).
Definition utils.h:299
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:1750
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:242
MeshTags< T > transfer_meshtags_to_submesh(const MeshTags< T > &tags, std::shared_ptr< const dolfinx::mesh::Topology > submesh_topology, const EntityMap &cell_map, const EntityMap &vertex_map)
Transfer a meshtags object from a parent to a submesh.
Definition utils.h:1886
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:773
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:344
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:251
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:581
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:474
GhostMode
Enum for different partitioning ghost modes.
Definition types.h:19
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:113
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:81
An AnyPartitionFunction together with the node weights it should be called with, if any.
Definition partition.h:156