12#include "graphbuild.h" 
   14#include <basix/mdspan.hpp> 
   17#include <dolfinx/graph/AdjacencyList.h> 
   18#include <dolfinx/graph/ordering.h> 
   19#include <dolfinx/graph/partition.h> 
   54void reorder_list(std::span<T> list, std::span<const std::int32_t> nodemap)
 
   59  assert(list.size() % nodemap.size() == 0);
 
   60  std::size_t degree = list.size() / nodemap.size();
 
   61  const std::vector<T> orig(list.begin(), list.end());
 
   62  for (std::size_t n = 0; n < nodemap.size(); ++n)
 
   64    std::span links_old(orig.data() + n * degree, degree);
 
   65    auto links_new = list.subspan(nodemap[n] * degree, degree);
 
   66    std::ranges::copy(links_old, links_new.begin());
 
 
   83template <std::
floating_po
int T>
 
   84std::tuple<std::vector<std::int32_t>, std::vector<T>, std::vector<std::int32_t>>
 
   86                               std::span<const std::int32_t> facets)
 
   88  auto topology = 
mesh.topology();
 
   90  const int tdim = topology->dim();
 
   93    throw std::runtime_error(
 
   94        "Cannot use mesh::locate_entities_boundary (boundary) for cells.");
 
   98  mesh.topology_mutable()->create_connectivity(tdim - 1, 0);
 
   99  mesh.topology_mutable()->create_connectivity(tdim - 1, dim);
 
  100  std::vector<std::int32_t> vertices, entities;
 
  102    auto f_to_v = topology->connectivity(tdim - 1, 0);
 
  104    auto f_to_e = topology->connectivity(tdim - 1, dim);
 
  106    for (
auto f : facets)
 
  108      auto v = f_to_v->links(f);
 
  109      vertices.insert(vertices.end(), v.begin(), v.end());
 
  110      auto e = f_to_e->links(f);
 
  111      entities.insert(entities.end(), e.begin(), e.end());
 
  116      std::ranges::sort(vertices);
 
  117      auto [unique_end, range_end] = std::ranges::unique(vertices);
 
  118      vertices.erase(unique_end, range_end);
 
  122      std::ranges::sort(entities);
 
  123      auto [unique_end, range_end] = std::ranges::unique(entities);
 
  124      entities.erase(unique_end, range_end);
 
  129  auto x_dofmap = 
mesh.geometry().dofmap();
 
  130  std::span<const T> x_nodes = 
mesh.geometry().x();
 
  133  mesh.topology_mutable()->create_connectivity(0, tdim);
 
  134  mesh.topology_mutable()->create_connectivity(tdim, 0);
 
  135  auto v_to_c = topology->connectivity(0, tdim);
 
  137  auto c_to_v = topology->connectivity(tdim, 0);
 
  139  std::vector<T> x_vertices(3 * vertices.size(), -1.0);
 
  140  std::vector<std::int32_t> vertex_to_pos(v_to_c->num_nodes(), -1);
 
  141  for (std::size_t i = 0; i < vertices.size(); ++i)
 
  143    const std::int32_t v = vertices[i];
 
  146    const std::int32_t c = v_to_c->links(v).front();
 
  147    auto cell_vertices = c_to_v->links(c);
 
  148    auto it = std::find(cell_vertices.begin(), cell_vertices.end(), v);
 
  149    assert(it != cell_vertices.end());
 
  150    const std::size_t local_pos = std::distance(cell_vertices.begin(), it);
 
  152    auto dofs = md::submdspan(x_dofmap, c, md::full_extent);
 
  153    for (std::size_t j = 0; j < 3; ++j)
 
  154      x_vertices[j * vertices.size() + i] = x_nodes[3 * dofs[local_pos] + j];
 
  155    vertex_to_pos[v] = i;
 
  158  return {std::move(entities), std::move(x_vertices), std::move(vertex_to_pos)};
 
 
  210    MPI_Comm comm, 
int nparts, 
const std::vector<CellType>& cell_types,
 
  211    const std::vector<std::span<const std::int64_t>>& cells)>;
 
  230                            std::optional<std::int32_t> max_facet_to_cell_links
 
  244  return [&, max_facet_to_cell_links](
 
  245             const std::vector<CellType>& celltypes,
 
  246             const std::vector<fem::ElementDofLayout>& doflayouts,
 
  247             const std::vector<std::vector<int>>& ghost_owners,
 
  248             std::vector<std::vector<std::int64_t>>& cells,
 
  249             std::vector<std::vector<std::int64_t>>& cells_v,
 
  250             std::vector<std::vector<std::int64_t>>& original_idx)
 
  251             -> std::vector<std::int64_t>
 
  257    spdlog::info(
"Build local dual graphs, re-order cells, and compute process " 
  258                 "boundary vertices.");
 
  260    std::vector<std::pair<std::vector<std::int64_t>, 
int>> facets;
 
  263    std::vector<std::span<const std::int64_t>> cells1_v_local;
 
  264    for (std::size_t i = 0; i < celltypes.size(); ++i)
 
  267      std::size_t num_owned_cells
 
  269      cells1_v_local.emplace_back(cells_v[i].data(),
 
  273      auto [
graph, unmatched_facets, max_v, _facet_attached_cells]
 
  275                                   std::vector{cells1_v_local.back()},
 
  276                                   max_facet_to_cell_links);
 
  279      facets.emplace_back(std::move(unmatched_facets), max_v);
 
  282      const std::vector<std::int32_t> remap = reorder_fn(
graph);
 
  285      const std::vector<std::int64_t>& orig_idx = original_idx[i];
 
  286      std::vector<std::int64_t> _original_idx(orig_idx.size());
 
  287      std::copy_n(orig_idx.rbegin(), ghost_owners[i].size(),
 
  288                  _original_idx.rbegin());
 
  290        for (std::size_t j = 0; j < remap.size(); ++j)
 
  291          _original_idx[remap[j]] = orig_idx[j];
 
  293      original_idx[i] = _original_idx;
 
  300          std::span(cells[i].data(), remap.size() * doflayouts[i].num_dofs()),
 
  304    if (facets.size() == 1) 
 
  306      std::vector<std::int64_t>& vertices = facets.front().first;
 
  309      std::ranges::sort(vertices);
 
  310      auto [unique_end, range_end] = std::ranges::unique(vertices);
 
  311      vertices.erase(unique_end, range_end);
 
  316      if (!vertices.empty() and vertices.front() == -1)
 
  317        vertices.erase(vertices.begin());
 
  325      std::vector<std::int64_t> facets0;
 
  326      facets0.reserve(std::accumulate(facets.begin(), facets.end(),
 
  327                                      std::size_t(0), [](std::size_t x, 
auto& y)
 
  328                                      { return x + y.first.size(); }));
 
  329      int max_v = std::ranges::max_element(facets, [](
auto& a, 
auto& b)
 
  330                                           { 
return a.second < b.second; })
 
  332      for (
const auto& [v_data, num_v] : facets)
 
  334        for (
auto it = v_data.begin(); it != v_data.end(); it += num_v)
 
  336          facets0.insert(facets0.end(), it, std::next(it, num_v));
 
  337          facets0.insert(facets0.end(), max_v - num_v, -1);
 
  343          std::span<const std::int64_t>(facets0), max_v);
 
  347      std::vector<std::int64_t> vertices;
 
  349      auto it = perm.begin();
 
  350      while (it != perm.end())
 
  354        std::span _f(facets0.data() + (*it) * max_v, max_v);
 
  355        auto end = std::find_if(_f.rbegin(), _f.rend(),
 
  356                                [](
auto a) { return a >= 0; });
 
  357        auto f = _f.first(std::distance(end, _f.rend()));
 
  359        auto it1 = std::find_if_not(
 
  361            [f, max_v, it0 = facets0.begin()](
auto p) -> 
bool 
  363              return std::equal(f.begin(), f.end(), std::next(it0, p * max_v));
 
  367        if (std::distance(it, it1) == 1)
 
  368          vertices.insert(vertices.end(), f.begin(), f.end());
 
  369        else if (std::distance(it, it1) > 2)
 
  370          throw std::runtime_error(
"More than two matching facets found.");
 
  377      std::ranges::sort(vertices);
 
  378      auto [unique_end, range_end] = std::ranges::unique(vertices);
 
  379      vertices.erase(unique_end, range_end);
 
 
  397                                           std::span<const std::int64_t> cells);
 
  407template <std::
floating_po
int T>
 
  408std::vector<T> 
h(
const Mesh<T>& 
mesh, std::span<const std::int32_t> entities,
 
  411  if (entities.empty())
 
  412    return std::vector<T>();
 
  414    return std::vector<T>(entities.size(), 0);
 
  417  const auto [vertex_xdofs, xdof_shape]
 
  421  std::span<const T> x = 
mesh.geometry().x();
 
  424  auto delta_norm = [](
auto&& p0, 
auto&& p1)
 
  427    for (std::size_t i = 0; i < 3; ++i)
 
  428      norm += (p0[i] - p1[i]) * (p0[i] - p1[i]);
 
  429    return std::sqrt(norm);
 
  434  std::vector<T> 
h(entities.size(), 0);
 
  435  for (std::size_t e = 0; e < entities.size(); ++e)
 
  438    std::span<const std::int32_t> e_vertices(
 
  439        vertex_xdofs.data() + e * xdof_shape[1], xdof_shape[1]);
 
  442    for (std::size_t i = 0; i < e_vertices.size(); ++i)
 
  444      std::span<const T, 3> p0(x.data() + 3 * e_vertices[i], 3);
 
  445      for (std::size_t j = i + 1; j < e_vertices.size(); ++j)
 
  447        std::span<const T, 3> p1(x.data() + 3 * e_vertices[j], 3);
 
  448        h[e] = std::max(
h[e], delta_norm(p0, p1));
 
 
  459template <std::
floating_po
int T>
 
  461                            std::span<const std::int32_t> entities)
 
  463  if (entities.empty())
 
  464    return std::vector<T>();
 
  466  auto topology = 
mesh.topology();
 
  468  if (topology->cell_type() == CellType::prism and dim == 2)
 
  470    throw std::runtime_error(
 
  471        "Cell normal computation for prism cells not yet supported.");
 
  474  const int gdim = 
mesh.geometry().dim();
 
  478  std::span<const T> x = 
mesh.geometry().x();
 
  479  const auto [geometry_entities, eshape]
 
  482  std::vector<T> n(entities.size() * 3);
 
  485  case CellType::interval:
 
  488      throw std::invalid_argument(
"Interval cell normal undefined in 3D.");
 
  489    for (std::size_t i = 0; i < entities.size(); ++i)
 
  492      std::array vertices{geometry_entities[i * eshape[1]],
 
  493                          geometry_entities[i * eshape[1] + 1]};
 
  494      std::array p = {std::span<const T, 3>(x.data() + 3 * vertices[0], 3),
 
  495                      std::span<const T, 3>(x.data() + 3 * vertices[1], 3)};
 
  499      std::ranges::transform(p[1], p[0], t.begin(),
 
  500                             [](
auto x, 
auto y) { return x - y; });
 
  502      T norm = std::sqrt(t[0] * t[0] + t[1] * t[1]);
 
  503      std::span<T, 3> ni(n.data() + 3 * i, 3);
 
  504      ni[0] = -t[1] / norm;
 
  510  case CellType::triangle:
 
  512    for (std::size_t i = 0; i < entities.size(); ++i)
 
  515      std::array vertices = {geometry_entities[i * eshape[1] + 0],
 
  516                             geometry_entities[i * eshape[1] + 1],
 
  517                             geometry_entities[i * eshape[1] + 2]};
 
  518      std::array p = {std::span<const T, 3>(x.data() + 3 * vertices[0], 3),
 
  519                      std::span<const T, 3>(x.data() + 3 * vertices[1], 3),
 
  520                      std::span<const T, 3>(x.data() + 3 * vertices[2], 3)};
 
  523      std::array<T, 3> dp1, dp2;
 
  524      std::ranges::transform(p[1], p[0], dp1.begin(),
 
  525                             [](
auto x, 
auto y) { return x - y; });
 
  526      std::ranges::transform(p[2], p[0], dp2.begin(),
 
  527                             [](
auto x, 
auto y) { return x - y; });
 
  530      std::array<T, 3> ni = math::cross(dp1, dp2);
 
  531      T norm = std::sqrt(ni[0] * ni[0] + ni[1] * ni[1] + ni[2] * ni[2]);
 
  532      std::ranges::transform(ni, std::next(n.begin(), 3 * i),
 
  533                             [norm](
auto x) { return x / norm; });
 
  538  case CellType::quadrilateral:
 
  541    for (std::size_t i = 0; i < entities.size(); ++i)
 
  544      std::array vertices = {geometry_entities[i * eshape[1] + 0],
 
  545                             geometry_entities[i * eshape[1] + 1],
 
  546                             geometry_entities[i * eshape[1] + 2]};
 
  547      std::array p = {std::span<const T, 3>(x.data() + 3 * vertices[0], 3),
 
  548                      std::span<const T, 3>(x.data() + 3 * vertices[1], 3),
 
  549                      std::span<const T, 3>(x.data() + 3 * vertices[2], 3)};
 
  552      std::array<T, 3> dp1, dp2;
 
  553      std::ranges::transform(p[1], p[0], dp1.begin(),
 
  554                             [](
auto x, 
auto y) { return x - y; });
 
  555      std::ranges::transform(p[2], p[0], dp2.begin(),
 
  556                             [](
auto x, 
auto y) { return x - y; });
 
  559      std::array<T, 3> ni = math::cross(dp1, dp2);
 
  560      T norm = std::sqrt(ni[0] * ni[0] + ni[1] * ni[1] + ni[2] * ni[2]);
 
  561      std::ranges::transform(ni, std::next(n.begin(), 3 * i),
 
  562                             [norm](
auto x) { return x / norm; });
 
  568    throw std::invalid_argument(
 
  569        "cell_normal not supported for this cell type.");
 
 
  576template <std::
floating_po
int T>
 
  578                                 std::span<const std::int32_t> entities)
 
  580  if (entities.empty())
 
  581    return std::vector<T>();
 
  583  std::span<const T> x = 
mesh.geometry().x();
 
  586  const auto [e_to_g, eshape]
 
  589  std::vector<T> x_mid(entities.size() * 3, 0);
 
  590  for (std::size_t e = 0; e < entities.size(); ++e)
 
  592    std::span<T, 3> p(x_mid.data() + 3 * e, 3);
 
  593    std::span<const std::int32_t> rows(e_to_g.data() + e * eshape[1],
 
  595    for (
auto row : rows)
 
  597      std::span<const T, 3> xg(x.data() + 3 * row, 3);
 
  598      std::ranges::transform(p, xg, p.begin(),
 
  599                             [size = rows.size()](
auto x, 
auto y)
 
  600                             { return x + y / size; });
 
 
  613template <std::
floating_po
int T>
 
  614std::pair<std::vector<T>, std::array<std::size_t, 2>>
 
  617  auto topology = 
mesh.topology();
 
  619  const int tdim = topology->dim();
 
  624  const std::int32_t num_vertices = topology->index_map(0)->size_local()
 
  625                                    + topology->index_map(0)->num_ghosts();
 
  627  std::vector<std::int32_t> vertex_to_node(num_vertices);
 
  628  for (
int cell_type_idx = 0,
 
  629           num_cell_types = topology->entity_types(tdim).size();
 
  630       cell_type_idx < num_cell_types; ++cell_type_idx)
 
  632    auto x_dofmap = 
mesh.geometry().dofmap(cell_type_idx);
 
  633    auto c_to_v = topology->connectivity({tdim, cell_type_idx}, {0, 0});
 
  635    for (
int c = 0; c < c_to_v->num_nodes(); ++c)
 
  637      auto x_dofs = md::submdspan(x_dofmap, c, md::full_extent);
 
  638      auto vertices = c_to_v->links(c);
 
  639      for (std::size_t i = 0; i < vertices.size(); ++i)
 
  640        vertex_to_node[vertices[i]] = x_dofs[i];
 
  645  std::span<const T> x_nodes = 
mesh.geometry().x();
 
  646  std::vector<T> x_vertices(3 * vertex_to_node.size(), 0.0);
 
  647  for (std::size_t i = 0; i < vertex_to_node.size(); ++i)
 
  649    std::int32_t pos = 3 * vertex_to_node[i];
 
  650    for (std::size_t j = 0; j < 3; ++j)
 
  651      x_vertices[j * vertex_to_node.size() + i] = x_nodes[pos + j];
 
  654  return {std::move(x_vertices), {3, vertex_to_node.size()}};
 
 
  660template <
typename Fn, 
typename T>
 
  662    std::vector<std::int8_t>, Fn,
 
  664               md::extents<std::size_t, 3, md::dynamic_extent>>>::value;
 
  681template <std::
floating_po
int T, MarkerFn<T> U>
 
  683                                          U marker, 
int entity_type_idx)
 
  687      = md::mdspan<const T, md::extents<std::size_t, 3, md::dynamic_extent>>;
 
  690  const auto [xdata, xshape] = impl::compute_vertex_coords(
mesh);
 
  692  cmdspan3x_t x(xdata.data(), xshape);
 
  693  const std::vector<std::int8_t> marked = marker(x);
 
  694  if (marked.size() != x.extent(1))
 
  695    throw std::runtime_error(
"Length of array of markers is wrong.");
 
  697  auto topology = 
mesh.topology();
 
  699  const int tdim = topology->dim();
 
  701  mesh.topology_mutable()->create_entities(dim);
 
  703    mesh.topology_mutable()->create_connectivity(dim, 0);
 
  707  auto e_to_v = topology->connectivity({dim, entity_type_idx}, {0, 0});
 
  709  std::vector<std::int32_t> entities;
 
  710  for (
int e = 0; e < e_to_v->num_nodes(); ++e)
 
  713    bool all_vertices_marked = 
true;
 
  714    for (std::int32_t v : e_to_v->links(e))
 
  718        all_vertices_marked = 
false;
 
  723    if (all_vertices_marked)
 
  724      entities.push_back(e);
 
 
  743template <std::
floating_po
int T, MarkerFn<T> U>
 
  747  const int num_entity_types = 
mesh.topology()->entity_types(dim).size();
 
  748  if (num_entity_types > 1)
 
  750    throw std::runtime_error(
 
  751        "Multiple entity types of this dimension. Specify entity type index");
 
 
  779template <std::
floating_po
int T, MarkerFn<T> U>
 
  784  auto topology = 
mesh.topology();
 
  786  int tdim = topology->dim();
 
  789    throw std::runtime_error(
 
  790        "Cannot use mesh::locate_entities_boundary (boundary) for cells.");
 
  794  mesh.topology_mutable()->create_entities(tdim - 1);
 
  795  mesh.topology_mutable()->create_connectivity(tdim - 1, tdim);
 
  799      = md::mdspan<const T, md::extents<std::size_t, 3, md::dynamic_extent>>;
 
  802  auto [facet_entities, xdata, vertex_to_pos]
 
  803      = impl::compute_vertex_coords_boundary(
mesh, dim, boundary_facets);
 
  804  cmdspan3x_t x(xdata.data(), 3, xdata.size() / 3);
 
  805  std::vector<std::int8_t> marked = marker(x);
 
  806  if (marked.size() != x.extent(1))
 
  807    throw std::runtime_error(
"Length of array of markers is wrong.");
 
  810  mesh.topology_mutable()->create_entities(dim);
 
  811  auto e_to_v = topology->connectivity(dim, 0);
 
  813  std::vector<std::int32_t> entities;
 
  814  for (
auto e : facet_entities)
 
  817    bool all_vertices_marked = 
true;
 
  818    for (
auto v : e_to_v->links(e))
 
  820      const std::int32_t pos = vertex_to_pos[v];
 
  823        all_vertices_marked = 
false;
 
  829    if (all_vertices_marked)
 
  830      entities.push_back(e);
 
 
  854template <std::
floating_po
int T>
 
  855std::pair<std::vector<std::int32_t>, std::array<std::size_t, 2>>
 
  857                     std::span<const std::int32_t> entities,
 
  858                     bool permute = 
false)
 
  860  auto topology = 
mesh.topology();
 
  862  CellType cell_type = topology->cell_type();
 
  863  if (cell_type == CellType::prism and dim == 2)
 
  865    throw std::runtime_error(
 
  866        "mesh::entities_to_geometry for prism cells not yet supported.");
 
  869  const int tdim = topology->dim();
 
  877  std::vector<std::int32_t> entity_xdofs;
 
  878  entity_xdofs.reserve(entities.size() * num_entity_dofs);
 
  879  std::array<std::size_t, 2> eshape{entities.size(), num_entity_dofs};
 
  882  const std::vector<std::vector<std::vector<int>>>& closure_dofs_all
 
  888    for (std::int32_t c : entities)
 
  891      auto x_c = md::submdspan(xdofs, c, md::full_extent);
 
  892      for (std::int32_t entity_dof : closure_dofs_all[tdim][0])
 
  893        entity_xdofs.push_back(x_c[entity_dof]);
 
  896    return {std::move(entity_xdofs), eshape};
 
  901  auto e_to_c = topology->connectivity(dim, tdim);
 
  904    throw std::runtime_error(
 
  905        "Entity-to-cell connectivity has not been computed. Missing dims " 
  906        + std::to_string(dim) + 
"->" + std::to_string(tdim));
 
  909  auto c_to_e = topology->connectivity(tdim, dim);
 
  912    throw std::runtime_error(
 
  913        "Cell-to-entity connectivity has not been computed. Missing dims " 
  914        + std::to_string(tdim) + 
"->" + std::to_string(dim));
 
  918  std::span<const std::uint32_t> cell_info;
 
  920    cell_info = std::span(
mesh.topology()->get_cell_permutation_info());
 
  922  for (std::int32_t e : entities)
 
  925    assert(!e_to_c->links(e).empty());
 
  926    std::int32_t c = e_to_c->links(e).front();
 
  929    std::span<const std::int32_t> cell_entities = c_to_e->links(c);
 
  930    auto it = std::find(cell_entities.begin(), cell_entities.end(), e);
 
  931    assert(it != cell_entities.end());
 
  932    std::size_t local_entity = std::distance(cell_entities.begin(), it);
 
  936    std::vector<std::int32_t> closure_dofs(closure_dofs_all[dim][local_entity]);
 
  942                                          entity_type, local_entity);
 
  946    auto x_c = md::submdspan(xdofs, c, md::full_extent);
 
  947    for (std::int32_t entity_dof : closure_dofs)
 
  948      entity_xdofs.push_back(x_c[entity_dof]);
 
  951  return {std::move(entity_xdofs), eshape};
 
 
  967    std::optional<std::int32_t> max_facet_to_cell_links = 2);
 
  976std::vector<std::int32_t>
 
  978                          std::span<const std::int32_t> entities, 
int d0,
 
 1024template <
typename U>
 
 1026    MPI_Comm comm, MPI_Comm commt,
 
 1027    std::vector<std::span<const std::int64_t>> cells,
 
 1029        typename std::remove_reference_t<typename U::value_type>>>& elements,
 
 1030    MPI_Comm commg, 
const U& x, std::array<std::size_t, 2> xshape,
 
 1032    std::optional<std::int32_t> max_facet_to_cell_links,
 
 1035  assert(cells.size() == elements.size());
 
 1036  std::vector<CellType> celltypes;
 
 1037  std::ranges::transform(elements, std::back_inserter(celltypes),
 
 1038                         [](
auto& e) { 
return e.cell_shape(); });
 
 1039  std::vector<fem::ElementDofLayout> doflayouts;
 
 1040  std::ranges::transform(elements, std::back_inserter(doflayouts),
 
 1041                         [](
auto& e) { 
return e.create_dof_layout(); });
 
 1050  std::int32_t num_cell_types = cells.size();
 
 1053  std::vector<std::vector<std::int64_t>> cells1(num_cell_types);
 
 1054  std::vector<std::vector<std::int64_t>> original_idx1(num_cell_types);
 
 1055  std::vector<std::vector<int>> ghost_owners(num_cell_types);
 
 1058    spdlog::info(
"Using partitioner with cell data ({} cell types)",
 
 1061    if (commt != MPI_COMM_NULL)
 
 1064      std::vector<std::vector<std::int64_t>> t(num_cell_types);
 
 1065      std::vector<std::span<const std::int64_t>> tspan(num_cell_types);
 
 1066      for (std::int32_t i = 0; i < num_cell_types; ++i)
 
 1069        tspan[i] = std::span(t[i]);
 
 1071      dest = partitioner(commt, size, celltypes, tspan);
 
 1074    std::int32_t cell_offset = 0;
 
 1075    for (std::int32_t i = 0; i < num_cell_types; ++i)
 
 1077      std::size_t num_cell_nodes = doflayouts[i].num_dofs();
 
 1078      assert(cells[i].size() % num_cell_nodes == 0);
 
 1079      std::size_t num_cells = cells[i].size() / num_cell_nodes;
 
 1082      std::vector<std::int32_t> offsets_i(
 
 1083          std::next(dest.
offsets().begin(), cell_offset),
 
 1084          std::next(dest.
offsets().begin(), cell_offset + num_cells + 1));
 
 1085      std::vector<std::int32_t> data_i(
 
 1086          std::next(dest.
array().begin(), offsets_i.front()),
 
 1087          std::next(dest.
array().begin(), offsets_i.back()));
 
 1088      std::int32_t offset_0 = offsets_i.front();
 
 1089      std::ranges::for_each(offsets_i,
 
 1090                            [&offset_0](std::int32_t& j) { j -= offset_0; });
 
 1092      cell_offset += num_cells;
 
 1096      std::vector<int> src_ranks;
 
 1097      std::tie(cells1[i], src_ranks, original_idx1[i], ghost_owners[i])
 
 1099                                     {num_cells, num_cell_nodes}, dest_i);
 
 1100      spdlog::debug(
"Got {} cells from distribution", cells1[i].size());
 
 1106    std::int64_t num_owned = 0;
 
 1107    for (std::int32_t i = 0; i < num_cell_types; ++i)
 
 1109      cells1[i] = std::vector<std::int64_t>(cells[i].begin(), cells[i].end());
 
 1110      std::int32_t num_cell_nodes = doflayouts[i].num_dofs();
 
 1111      assert(cells1[i].size() % num_cell_nodes == 0);
 
 1112      original_idx1[i].resize(cells1[i].size() / num_cell_nodes);
 
 1113      num_owned += original_idx1[i].size();
 
 1117    std::int64_t global_offset = 0;
 
 1118    MPI_Exscan(&num_owned, &global_offset, 1, MPI_INT64_T, MPI_SUM, comm);
 
 1119    for (std::int32_t i = 0; i < num_cell_types; ++i)
 
 1121      std::iota(original_idx1[i].begin(), original_idx1[i].end(),
 
 1123      global_offset += original_idx1[i].size();
 
 1129  std::vector<std::vector<std::int64_t>> cells1_v(num_cell_types);
 
 1130  for (std::int32_t i = 0; i < num_cell_types; ++i)
 
 1133    spdlog::info(
"Extract basic topology: {}->{}", cells1[i].size(),
 
 1134                 cells1_v[i].size());
 
 1139  const std::vector<std::int64_t> boundary_v = boundary_v_fn(
 
 1140      celltypes, doflayouts, ghost_owners, cells1, cells1_v, original_idx1);
 
 1142  spdlog::debug(
"Got {} boundary vertices", boundary_v.size());
 
 1145  std::vector<std::span<const std::int64_t>> cells1_v_span;
 
 1146  std::ranges::transform(cells1_v, std::back_inserter(cells1_v_span),
 
 1147                         [](
auto& c) { 
return std::span(c); });
 
 1148  std::vector<std::span<const std::int64_t>> original_idx1_span;
 
 1149  std::ranges::transform(original_idx1, std::back_inserter(original_idx1_span),
 
 1150                         [](
auto& c) { 
return std::span(c); });
 
 1151  std::vector<std::span<const int>> ghost_owners_span;
 
 1152  std::ranges::transform(ghost_owners, std::back_inserter(ghost_owners_span),
 
 1153                         [](
auto& c) { 
return std::span(c); });
 
 1156                        ghost_owners_span, boundary_v);
 
 1160  for (
int i = 0; i < num_cell_types; ++i)
 
 1162    for (
int e = 1; e < topology.dim(); ++e)
 
 1164      if (doflayouts[i].num_entity_dofs(e) > 0)
 
 1165        topology.create_entities(e);
 
 1168    if (elements[i].needs_dof_permutations())
 
 1169      topology.create_entity_permutations();
 
 1174  std::vector<std::int64_t> nodes1, nodes2;
 
 1175  for (std::vector<std::int64_t>& c : cells1)
 
 1176    nodes1.insert(nodes1.end(), c.begin(), c.end());
 
 1177  for (std::vector<std::int64_t>& c : cells1)
 
 1178    nodes2.insert(nodes2.end(), c.begin(), c.end());
 
 1181  auto [unique_end, range_end] = std::ranges::unique(nodes1);
 
 1182  nodes1.erase(unique_end, range_end);
 
 1189      = 
create_geometry(topology, elements, nodes1, nodes2, coords, xshape[1]);
 
 1191  return Mesh(comm, std::make_shared<Topology>(std::move(topology)),
 
 
 1232template <
typename U>
 
 1234    MPI_Comm comm, MPI_Comm commt, std::span<const std::int64_t> cells,
 
 1236        typename std::remove_reference_t<typename U::value_type>>& element,
 
 1237    MPI_Comm commg, 
const U& x, std::array<std::size_t, 2> xshape,
 
 1239    std::optional<std::int32_t> max_facet_to_cell_links = 2,
 
 1242  return create_mesh(comm, commt, std::vector{cells}, std::vector{element},
 
 1243                     commg, x, xshape, partitioner, max_facet_to_cell_links,
 
 
 1267template <
typename U>
 
 1268Mesh<typename std::remove_reference_t<typename U::value_type>>
 
 1271                std::remove_reference_t<typename U::value_type>>& elements,
 
 1272            const U& x, std::array<std::size_t, 2> xshape, 
GhostMode ghost_mode,
 
 1273            std::optional<std::int32_t> max_facet_to_cell_links = 2)
 
 1277    return create_mesh(comm, comm, std::vector{cells}, std::vector{elements},
 
 1278                       comm, x, xshape, 
nullptr, max_facet_to_cell_links);
 
 1282    return create_mesh(comm, comm, std::vector{cells}, std::vector{elements},
 
 1284                       max_facet_to_cell_links);
 
 
 1301template <std::
floating_po
int T>
 
 1302std::pair<Geometry<T>, std::vector<int32_t>>
 
 1304                   std::span<const std::int32_t> subentity_to_entity)
 
 1312  const std::vector<std::int32_t> x_indices
 
 1315  std::vector<std::int32_t> sub_x_dofs = x_indices;
 
 1316  std::ranges::sort(sub_x_dofs);
 
 1317  auto [unique_end, range_end] = std::ranges::unique(sub_x_dofs);
 
 1318  sub_x_dofs.erase(unique_end, range_end);
 
 1321  auto x_index_map = 
geometry.index_map();
 
 1322  assert(x_index_map);
 
 1324  std::shared_ptr<common::IndexMap> sub_x_dof_index_map;
 
 1325  std::vector<std::int32_t> subx_to_x_dofmap;
 
 1329    sub_x_dof_index_map = std::make_shared<common::IndexMap>(std::move(map));
 
 1330    subx_to_x_dofmap = std::move(new_to_old);
 
 1334  std::span<const T> x = 
geometry.x();
 
 1335  std::int32_t sub_num_x_dofs = subx_to_x_dofmap.size();
 
 1336  std::vector<T> sub_x(3 * sub_num_x_dofs);
 
 1337  for (std::int32_t i = 0; i < sub_num_x_dofs; ++i)
 
 1339    std::copy_n(std::next(x.begin(), 3 * subx_to_x_dofmap[i]), 3,
 
 1340                std::next(sub_x.begin(), 3 * i));
 
 1344  std::vector<std::int32_t> x_to_subx_dof_map(
 
 1345      x_index_map->size_local() + x_index_map->num_ghosts(), -1);
 
 1346  for (std::size_t i = 0; i < subx_to_x_dofmap.size(); ++i)
 
 1347    x_to_subx_dof_map[subx_to_x_dofmap[i]] = i;
 
 1350  std::vector<std::int32_t> sub_x_dofmap;
 
 1351  sub_x_dofmap.reserve(x_indices.size());
 
 1352  std::ranges::transform(x_indices, std::back_inserter(sub_x_dofmap),
 
 1353                         [&x_to_subx_dof_map](
auto x_dof)
 
 1355                           assert(x_to_subx_dof_map[x_dof] != -1);
 
 1356                           return x_to_subx_dof_map[x_dof];
 
 1364  int degree = (sub_xcell == CellType::point) ? 0 : 
geometry.cmap().degree();
 
 1369  const std::vector<std::int64_t>& igi = 
geometry.input_global_indices();
 
 1370  std::vector<std::int64_t> sub_igi;
 
 1371  sub_igi.reserve(subx_to_x_dofmap.size());
 
 1372  std::ranges::transform(subx_to_x_dofmap, std::back_inserter(sub_igi),
 
 1373                         [&igi](
auto sub_x_dof) { 
return igi[sub_x_dof]; });
 
 1377              sub_x_dof_index_map,
 
 1378              std::vector<std::vector<std::int32_t>>{std::move(sub_x_dofmap)},
 
 1379              {sub_cmap}, std::move(sub_x), 
geometry.dim(), std::move(sub_igi)),
 
 1380          std::move(subx_to_x_dofmap)};
 
 
 1392template <std::
floating_po
int T>
 
 1393std::tuple<Mesh<T>, EntityMap, EntityMap, std::vector<std::int32_t>>
 
 1395               std::span<const std::int32_t> entities)
 
 1398  mesh.topology_mutable()->create_connectivity(dim, 0);
 
 1399  auto [topology, subentity_to_entity, subvertex_to_vertex]
 
 1403  const int tdim = 
mesh.topology()->dim();
 
 1404  mesh.topology_mutable()->create_entities(dim);
 
 1405  mesh.topology_mutable()->create_connectivity(dim, tdim);
 
 1406  mesh.topology_mutable()->create_connectivity(tdim, dim);
 
 1407  mesh.topology_mutable()->create_entity_permutations();
 
 1412      = 
Mesh(
mesh.comm(), std::make_shared<Topology>(std::move(topology)),
 
 1414  EntityMap entity_map(
mesh.topology(), submesh.topology(), dim,
 
 1415                       subentity_to_entity);
 
 1416  EntityMap vertex_map(
mesh.topology(), submesh.topology(), 0,
 
 1417                       subvertex_to_vertex);
 
 1418  return {std::move(submesh), std::move(entity_map), std::move(vertex_map),
 
 1419          std::move(subx_to_x_dofmap)};
 
 
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< std::vector< std::vector< int > > > & entity_closure_dofs_all() const
Definition ElementDofLayout.cpp:92
 
int num_entity_closure_dofs(int dim) const
Definition ElementDofLayout.cpp:68
 
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:173
 
const std::vector< std::int32_t > & offsets() const
Offset for each node in array() (const version).
Definition AdjacencyList.h:179
 
A bidirectional map relating entities in one topology to another.
Definition EntityMap.h:20
 
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
 
Topology stores the topology of a mesh, consisting of mesh entities and connectivity (incidence relat...
Definition Topology.h:41
 
Requirements on function for geometry marking.
Definition utils.h:661
 
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:54
 
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:85
 
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:615
 
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:38
 
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:361
 
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
 
AdjacencyList< std::int32_t > partition_graph(MPI_Comm comm, int nparts, const AdjacencyList< std::int64_t > &local_graph, bool ghosting)
Partition graph across processes using the default graph partitioner.
Definition partition.cpp:21
 
Mesh data structures and algorithms on meshes.
Definition DofMap.h:32
 
CellPartitionFunction create_cell_partitioner(mesh::GhostMode ghost_mode=mesh::GhostMode::none, const graph::partition_fn &partfn=&graph::partition_graph, std::optional< std::int32_t > max_facet_to_cell_links=2)
Create a function that computes destination rank for mesh cells on this rank by applying the default ...
Definition utils.cpp:100
 
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)
Create a mesh topology.
Definition Topology.cpp:1025
 
auto create_boundary_vertices_fn(const CellReorderFunction &reorder_fn, std::optional< std::int32_t > max_facet_to_cell_links=2)
Creates the default boundary vertices routine for a given reorder function.
Definition utils.h:229
 
std::tuple< graph::AdjacencyList< std::int32_t >, std::vector< std::int64_t >, std::size_t, 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=2)
Compute the local part of the dual graph (cell-cell connections via facets) and facets with only one ...
Definition graphbuild.cpp:524
 
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:460
 
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.cpp:64
 
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:217
 
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:1313
 
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:1394
 
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:780
 
CellType
Cell type identifier.
Definition cell_types.h:22
 
int num_cell_vertices(CellType type)
Definition cell_types.cpp:147
 
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:408
 
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:1303
 
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:1025
 
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:237
 
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:856
 
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:124
 
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:682
 
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:209
 
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:577
 
GhostMode
Enum for different partitioning ghost modes.
Definition utils.h:41
 
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:183
 
constexpr __radix_sort radix_sort
Radix sort.
Definition sort.h:170