10#include "cell_types.h" 
   39template <std::
floating_po
int T>
 
   40std::tuple<std::vector<T>, std::vector<std::int64_t>>
 
   41create_interval_cells(std::array<T, 2> p, std::int64_t n);
 
   43template <std::
floating_po
int T>
 
   44Mesh<T> build_tri(MPI_Comm comm, std::array<std::array<T, 2>, 2> p,
 
   45                  std::array<std::int64_t, 2> n,
 
   49template <std::
floating_po
int T>
 
   50Mesh<T> build_quad(MPI_Comm comm, 
const std::array<std::array<T, 2>, 2> p,
 
   51                   std::array<std::int64_t, 2> n,
 
   54template <std::
floating_po
int T>
 
   55std::vector<T> create_geom(MPI_Comm comm, std::array<std::array<T, 3>, 2> p,
 
   56                           std::array<std::int64_t, 3> n);
 
   58template <std::
floating_po
int T>
 
   59Mesh<T> build_tet(MPI_Comm comm, MPI_Comm subcomm,
 
   60                  std::array<std::array<T, 3>, 2> p,
 
   61                  std::array<std::int64_t, 3> n,
 
   64template <std::
floating_po
int T>
 
   65Mesh<T> build_hex(MPI_Comm comm, MPI_Comm subcomm,
 
   66                  std::array<std::array<T, 3>, 2> p,
 
   67                  std::array<std::int64_t, 3> n,
 
   70template <std::
floating_po
int T>
 
   71Mesh<T> build_prism(MPI_Comm comm, MPI_Comm subcomm,
 
   72                    std::array<std::array<T, 3>, 2> p,
 
   73                    std::array<std::int64_t, 3> n,
 
   97template <std::
floating_po
int T = 
double>
 
   99                   std::array<std::array<T, 3>, 2> p,
 
  100                   std::array<std::int64_t, 3> n, 
CellType celltype,
 
  103  if (std::ranges::any_of(n, [](
auto e) { 
return e < 1; }))
 
  104    throw std::runtime_error(
"At least one cell per dimension is required");
 
  106  for (int32_t i = 0; i < 3; i++)
 
  108    if (p[0][i] >= p[1][i])
 
  109      throw std::runtime_error(
"It must hold p[0] < p[1].");
 
  117  case CellType::tetrahedron:
 
  118    return impl::build_tet<T>(comm, subcomm, p, n, partitioner);
 
  119  case CellType::hexahedron:
 
  120    return impl::build_hex<T>(comm, subcomm, p, n, partitioner);
 
  121  case CellType::prism:
 
  122    return impl::build_prism<T>(comm, subcomm, p, n, partitioner);
 
  124    throw std::runtime_error(
"Generate box mesh. Wrong cell type");
 
 
  144template <std::
floating_po
int T = 
double>
 
  146                   std::array<std::int64_t, 3> n, 
CellType celltype,
 
  149  return create_box<T>(comm, comm, p, n, celltype, partitioner);
 
 
  168template <std::
floating_po
int T = 
double>
 
  170                         std::array<std::int64_t, 2> n, 
CellType celltype,
 
  174  if (std::ranges::any_of(n, [](
auto e) { 
return e < 1; }))
 
  175    throw std::runtime_error(
"At least one cell per dimension is required");
 
  177  for (int32_t i = 0; i < 2; i++)
 
  179    if (p[0][i] >= p[1][i])
 
  180      throw std::runtime_error(
"It must hold p[0] < p[1].");
 
  188  case CellType::triangle:
 
  189    return impl::build_tri<T>(comm, p, n, partitioner, diagonal);
 
  190  case CellType::quadrilateral:
 
  191    return impl::build_quad<T>(comm, p, n, partitioner);
 
  193    throw std::runtime_error(
"Generate rectangle mesh. Wrong cell type");
 
 
  211template <std::
floating_po
int T = 
double>
 
  213                         std::array<std::int64_t, 2> n, 
CellType celltype,
 
 
  232template <std::
floating_po
int T = 
double>
 
  238    throw std::runtime_error(
"At least one cell is required.");
 
  240  const auto [a, b] = p;
 
  242    throw std::runtime_error(
"It must hold p[0] < p[1].");
 
  243  if (std::abs(a - b) < std::numeric_limits<T>::epsilon())
 
  245    throw std::runtime_error(
 
  246        "Length of interval is zero. Check your dimensions.");
 
  255    auto [x, cells] = impl::create_interval_cells<T>(p, n);
 
  256    return create_mesh(comm, MPI_COMM_SELF, cells, element, MPI_COMM_SELF, x,
 
  257                       {x.size(), 1}, partitioner);
 
  261    return create_mesh(comm, MPI_COMM_NULL, {}, element, MPI_COMM_NULL,
 
  262                       std::vector<T>{}, {0, 1}, partitioner);
 
 
  269template <std::
floating_po
int T>
 
  270std::tuple<std::vector<T>, std::vector<std::int64_t>>
 
  271create_interval_cells(std::array<T, 2> p, std::int64_t n)
 
  273  const auto [a, b] = p;
 
  275  const T 
h = (b - a) / 
static_cast<T
>(n);
 
  278  std::vector<T> x(n + 1);
 
  279  std::ranges::generate(x, [i = std::int64_t(0), a, 
h]() 
mutable 
  280                        { 
return a + 
h * 
static_cast<T
>(i++); });
 
  283  std::vector<std::int64_t> cells(2 * n);
 
  284  for (std::size_t ix = 0; ix < cells.size() / 2; ++ix)
 
  287    cells[2 * ix + 1] = ix + 1;
 
  290  return {std::move(x), std::move(cells)};
 
  293template <std::
floating_po
int T>
 
  294std::vector<T> create_geom(MPI_Comm comm, std::array<std::array<T, 3>, 2> p,
 
  295                           std::array<std::int64_t, 3> n)
 
  299  const auto [nx, ny, nz] = n;
 
  301  assert(std::ranges::all_of(n, [](
auto e) { 
return e >= 1; }));
 
  302  for (std::int64_t i = 0; i < 3; i++)
 
  303    assert(p0[i] < p1[i]);
 
  306  const std::array<T, 3> extents = {
 
  307      (p1[0] - p0[0]) / 
static_cast<T
>(nx),
 
  308      (p1[1] - p0[1]) / 
static_cast<T
>(ny),
 
  309      (p1[2] - p0[2]) / 
static_cast<T
>(nz),
 
  312  if (std::ranges::any_of(
 
  314          { 
return std::abs(e) < 2.0 * std::numeric_limits<T>::epsilon(); }))
 
  316    throw std::runtime_error(
 
  317        "Box seems to have zero width, height or depth. Check dimensions");
 
  320  const std::int64_t n_points = (nx + 1) * (ny + 1) * (nz + 1);
 
  325  geom.reserve((range_end - range_begin) * 3);
 
  326  const std::int64_t sqxy = (nx + 1) * (ny + 1);
 
  327  for (std::int64_t v = range_begin; v < range_end; ++v)
 
  330    const std::int64_t p = v % sqxy;
 
  331    std::array<std::int64_t, 3> idx = {p % (nx + 1), p / (nx + 1), v / sqxy};
 
  334    for (std::size_t i = 0; i < idx.size(); i++)
 
  335      geom.push_back(p0[i] + 
static_cast<T
>(idx[i]) * extents[i]);
 
  341template <std::
floating_po
int T>
 
  342Mesh<T> build_tet(MPI_Comm comm, MPI_Comm subcomm,
 
  343                  std::array<std::array<T, 3>, 2> p,
 
  344                  std::array<std::int64_t, 3> n,
 
  347  common::Timer timer(
"Build BoxMesh (tetrahedra)");
 
  349  std::vector<std::int64_t> 
cells;
 
  350  fem::CoordinateElement<T> element(CellType::tetrahedron, 1);
 
  351  if (subcomm != MPI_COMM_NULL)
 
  353    x = create_geom<T>(subcomm, p, n);
 
  355    const auto [nx, ny, nz] = n;
 
  356    const std::int64_t n_cells = nx * ny * nz;
 
  360    cells.reserve(6 * (range_c[1] - range_c[0]) * 4);
 
  363    for (std::int64_t i = range_c[0]; i < range_c[1]; ++i)
 
  365      const std::int64_t iz = i / (nx * ny);
 
  366      const std::int64_t j = i % (nx * ny);
 
  367      const std::int64_t iy = j / nx;
 
  368      const std::int64_t ix = j % nx;
 
  369      const std::int64_t v0 = iz * (nx + 1) * (ny + 1) + iy * (nx + 1) + ix;
 
  370      const std::int64_t v1 = v0 + 1;
 
  371      const std::int64_t v2 = v0 + (nx + 1);
 
  372      const std::int64_t v3 = v1 + (nx + 1);
 
  373      const std::int64_t v4 = v0 + (nx + 1) * (ny + 1);
 
  374      const std::int64_t v5 = v1 + (nx + 1) * (ny + 1);
 
  375      const std::int64_t v6 = v2 + (nx + 1) * (ny + 1);
 
  376      const std::int64_t v7 = v3 + (nx + 1) * (ny + 1);
 
  380                   {v0, v1, v3, v7, v0, v1, v7, v5, v0, v5, v7, v4,
 
  381                    v0, v3, v2, v7, v0, v6, v4, v7, v0, v2, v6, v7});
 
  385  return create_mesh(comm, subcomm, cells, element, subcomm, x,
 
  386                     {x.size() / 3, 3}, partitioner);
 
  389template <std::
floating_po
int T>
 
  390mesh::Mesh<T> build_hex(MPI_Comm comm, MPI_Comm subcomm,
 
  391                        std::array<std::array<T, 3>, 2> p,
 
  392                        std::array<std::int64_t, 3> n,
 
  395  common::Timer timer(
"Build BoxMesh (hexahedra)");
 
  397  std::vector<std::int64_t> 
cells;
 
  398  fem::CoordinateElement<T> element(CellType::hexahedron, 1);
 
  399  if (subcomm != MPI_COMM_NULL)
 
  401    x = create_geom<T>(subcomm, p, n);
 
  404    const auto [nx, ny, nz] = n;
 
  405    const std::int64_t n_cells = nx * ny * nz;
 
  408    cells.reserve((range_c[1] - range_c[0]) * 8);
 
  409    for (std::int64_t i = range_c[0]; i < range_c[1]; ++i)
 
  411      const std::int64_t iz = i / (nx * ny);
 
  412      const std::int64_t j = i % (nx * ny);
 
  413      const std::int64_t iy = j / nx;
 
  414      const std::int64_t ix = j % nx;
 
  416      const std::int64_t v0 = (iz * (ny + 1) + iy) * (nx + 1) + ix;
 
  417      const std::int64_t v1 = v0 + 1;
 
  418      const std::int64_t v2 = v0 + (nx + 1);
 
  419      const std::int64_t v3 = v1 + (nx + 1);
 
  420      const std::int64_t v4 = v0 + (nx + 1) * (ny + 1);
 
  421      const std::int64_t v5 = v1 + (nx + 1) * (ny + 1);
 
  422      const std::int64_t v6 = v2 + (nx + 1) * (ny + 1);
 
  423      const std::int64_t v7 = v3 + (nx + 1) * (ny + 1);
 
  424      cells.insert(
cells.end(), {v0, v1, v2, v3, v4, v5, v6, v7});
 
  428  return create_mesh(comm, subcomm, cells, element, subcomm, x,
 
  429                     {x.size() / 3, 3}, partitioner);
 
  432template <std::
floating_po
int T>
 
  433Mesh<T> build_prism(MPI_Comm comm, MPI_Comm subcomm,
 
  434                    std::array<std::array<T, 3>, 2> p,
 
  435                    std::array<std::int64_t, 3> n,
 
  439  std::vector<std::int64_t> 
cells;
 
  440  fem::CoordinateElement<T> element(CellType::prism, 1);
 
  441  if (subcomm != MPI_COMM_NULL)
 
  443    x = create_geom<T>(subcomm, p, n);
 
  445    const std::int64_t nx = n[0];
 
  446    const std::int64_t ny = n[1];
 
  447    const std::int64_t nz = n[2];
 
  448    const std::int64_t n_cells = nx * ny * nz;
 
  451    const std::int64_t cell_range = range_c[1] - range_c[0];
 
  454    cells.reserve(2 * cell_range * 6);
 
  455    for (std::int64_t i = range_c[0]; i < range_c[1]; ++i)
 
  457      const std::int64_t iz = i / (nx * ny);
 
  458      const std::int64_t j = i % (nx * ny);
 
  459      const std::int64_t iy = j / nx;
 
  460      const std::int64_t ix = j % nx;
 
  462      const std::int64_t v0 = (iz * (ny + 1) + iy) * (nx + 1) + ix;
 
  463      const std::int64_t v1 = v0 + 1;
 
  464      const std::int64_t v2 = v0 + (nx + 1);
 
  465      const std::int64_t v3 = v1 + (nx + 1);
 
  466      const std::int64_t v4 = v0 + (nx + 1) * (ny + 1);
 
  467      const std::int64_t v5 = v1 + (nx + 1) * (ny + 1);
 
  468      const std::int64_t v6 = v2 + (nx + 1) * (ny + 1);
 
  469      const std::int64_t v7 = v3 + (nx + 1) * (ny + 1);
 
  470      cells.insert(
cells.end(), {v0, v1, v2, v4, v5, v6});
 
  471      cells.insert(
cells.end(), {v1, v2, v3, v5, v6, v7});
 
  475  return create_mesh(comm, subcomm, cells, element, subcomm, x,
 
  476                     {x.size() / 3, 3}, partitioner);
 
  479template <std::
floating_po
int T>
 
  480Mesh<T> build_tri(MPI_Comm comm, std::array<std::array<T, 2>, 2> p,
 
  481                  std::array<std::int64_t, 2> n,
 
  485  fem::CoordinateElement<T> element(CellType::triangle, 1);
 
  488    const auto [p0, p1] = p;
 
  489    const auto [nx, ny] = n;
 
  491    const auto [a, c] = p0;
 
  492    const auto [b, d] = p1;
 
  494    const T ab = (b - a) / 
static_cast<T
>(nx);
 
  495    const T cd = (d - c) / 
static_cast<T
>(ny);
 
  496    if (std::abs(b - a) < std::numeric_limits<T>::epsilon()
 
  497        or std::abs(d - c) < std::numeric_limits<T>::epsilon())
 
  499      throw std::runtime_error(
"Rectangle seems to have zero width, height or " 
  500                               "depth. Check dimensions");
 
  507    case DiagonalType::crossed:
 
  508      nv = (nx + 1) * (ny + 1) + nx * ny;
 
  512      nv = (nx + 1) * (ny + 1);
 
  518    std::vector<std::int64_t> 
cells;
 
  519    cells.reserve(nc * 3);
 
  523    for (std::int64_t iy = 0; iy <= ny; iy++)
 
  525      T x1 = c + cd * 
static_cast<T
>(iy);
 
  526      for (std::int64_t ix = 0; ix <= nx; ix++)
 
  527        x.insert(x.end(), {a + ab * static_cast<T>(ix), x1});
 
  533    case DiagonalType::crossed:
 
  534      for (std::int64_t iy = 0; iy < ny; iy++)
 
  536        T x1 = c + cd * (
static_cast<T
>(iy) + 0.5);
 
  537        for (std::int64_t ix = 0; ix < nx; ix++)
 
  539          T x0 = a + ab * (
static_cast<T
>(ix) + 0.5);
 
  540          x.insert(x.end(), {x0, x1});
 
  551    case DiagonalType::crossed:
 
  553      for (std::int64_t iy = 0; iy < ny; iy++)
 
  555        for (std::int64_t ix = 0; ix < nx; ix++)
 
  557          std::int64_t v0 = iy * (nx + 1) + ix;
 
  558          std::int64_t v1 = v0 + 1;
 
  559          std::int64_t v2 = v0 + (nx + 1);
 
  560          std::int64_t v3 = v1 + (nx + 1);
 
  561          std::int64_t vmid = (nx + 1) * (ny + 1) + iy * nx + ix;
 
  564          cells.insert(
cells.end(), {v0, v1, vmid, v0, v2, vmid, v1, v3, vmid,
 
  573      for (std::int64_t iy = 0; iy < ny; iy++)
 
  578        case DiagonalType::right_left:
 
  580            local_diagonal = DiagonalType::right;
 
  582            local_diagonal = DiagonalType::left;
 
  584        case DiagonalType::left_right:
 
  586            local_diagonal = DiagonalType::left;
 
  588            local_diagonal = DiagonalType::right;
 
  593        for (std::int64_t ix = 0; ix < nx; ix++)
 
  595          std::int64_t v0 = iy * (nx + 1) + ix;
 
  596          std::int64_t v1 = v0 + 1;
 
  597          std::int64_t v2 = v0 + (nx + 1);
 
  598          std::int64_t v3 = v1 + (nx + 1);
 
  599          switch (local_diagonal)
 
  601          case DiagonalType::left:
 
  603            cells.insert(
cells.end(), {v0, v1, v2, v1, v2, v3});
 
  604            if (diagonal == DiagonalType::right_left
 
  605                or diagonal == DiagonalType::left_right)
 
  607              local_diagonal = DiagonalType::right;
 
  613            cells.insert(
cells.end(), {v0, v1, v3, v0, v2, v3});
 
  614            if (diagonal == DiagonalType::right_left
 
  615                or diagonal == DiagonalType::left_right)
 
  617              local_diagonal = DiagonalType::left;
 
  626    return create_mesh(comm, MPI_COMM_SELF, cells, element, MPI_COMM_SELF, x,
 
  627                       {x.size() / 2, 2}, partitioner);
 
  631    return create_mesh(comm, MPI_COMM_NULL, {}, element, MPI_COMM_NULL,
 
  632                       std::vector<T>{}, {0, 2}, partitioner);
 
  636template <std::
floating_po
int T>
 
  637Mesh<T> build_quad(MPI_Comm comm, 
const std::array<std::array<T, 2>, 2> p,
 
  638                   std::array<std::int64_t, 2> n,
 
  641  fem::CoordinateElement<T> element(CellType::quadrilateral, 1);
 
  644    const auto [nx, ny] = n;
 
  645    const auto [a, c] = p[0];
 
  646    const auto [b, d] = p[1];
 
  648    const T ab = (b - a) / 
static_cast<T
>(nx);
 
  649    const T cd = (d - c) / 
static_cast<T
>(ny);
 
  653    x.reserve((nx + 1) * (ny + 1) * 2);
 
  655    for (std::int64_t ix = 0; ix <= nx; ix++)
 
  657      T x0 = a + ab * 
static_cast<T
>(ix);
 
  658      for (std::int64_t iy = 0; iy <= ny; iy++)
 
  659        x.insert(x.end(), {x0, c + cd * static_cast<T>(iy)});
 
  663    std::vector<std::int64_t> 
cells;
 
  664    cells.reserve(nx * ny * 4);
 
  665    for (std::int64_t ix = 0; ix < nx; ix++)
 
  667      for (std::int64_t iy = 0; iy < ny; iy++)
 
  669        std::int64_t i0 = ix * (ny + 1);
 
  670        cells.insert(
cells.end(), {i0 + iy, i0 + iy + 1, i0 + iy + ny + 1,
 
  675    return create_mesh(comm, MPI_COMM_SELF, cells, element, MPI_COMM_SELF, x,
 
  676                       {x.size() / 2, 2}, partitioner);
 
  680    return create_mesh(comm, MPI_COMM_NULL, {}, element, MPI_COMM_NULL,
 
  681                       std::vector<T>{}, {0, 2}, partitioner);
 
A Mesh consists of a set of connected and numbered mesh topological entities, and geometry data.
Definition Mesh.h:23
Functions supporting mesh operations.
int size(MPI_Comm comm)
Definition MPI.cpp:72
int rank(MPI_Comm comm)
Return process rank for the communicator.
Definition MPI.cpp:64
constexpr std::array< std::int64_t, 2 > local_range(int rank, std::int64_t N, int size)
Return local range for the calling process, partitioning the global [0, N - 1] range across all ranks...
Definition MPI.h:91
void cells(la::SparsityPattern &pattern, std::array< std::span< const std::int32_t >, 2 > cells, std::array< std::reference_wrapper< const DofMap >, 2 > dofmaps)
Iterate over cells and insert entries into sparsity pattern.
Definition sparsitybuild.cpp:16
Mesh data structures and algorithms on meshes.
Definition DofMap.h:32
Mesh< T > create_box(MPI_Comm comm, MPI_Comm subcomm, std::array< std::array< T, 3 >, 2 > p, std::array< std::int64_t, 3 > n, CellType celltype, CellPartitionFunction partitioner=nullptr)
Create a uniform mesh::Mesh over rectangular prism spanned by the two points p.
Definition generation.h:98
GhostMode
Enum for different partitioning ghost modes.
Definition utils.h:36
DiagonalType
Enum for different diagonal types.
Definition generation.h:28
Mesh< typename std::remove_reference_t< typename U::value_type > > create_mesh(MPI_Comm comm, MPI_Comm commt, std::span< const std::int64_t > cells, const fem::CoordinateElement< typename std::remove_reference_t< typename U::value_type > > &element, MPI_Comm commg, const U &x, std::array< std::size_t, 2 > xshape, const CellPartitionFunction &partitioner)
Create a distributed mesh from mesh data using a provided graph partitioning function for determining...
Definition utils.h:783
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:211
Mesh< T > create_rectangle(MPI_Comm comm, std::array< std::array< T, 2 >, 2 > p, std::array< std::int64_t, 2 > n, CellType celltype, CellPartitionFunction partitioner, DiagonalType diagonal=DiagonalType::right)
Create a uniform mesh::Mesh over the rectangle spanned by the two points p.
Definition generation.h:169
Mesh< T > create_interval(MPI_Comm comm, std::int64_t n, std::array< T, 2 > p, mesh::GhostMode ghost_mode=mesh::GhostMode::none, CellPartitionFunction partitioner=nullptr)
Interval mesh of the 1D line [a, b].
Definition generation.h:233
CellType
Cell type identifier.
Definition cell_types.h:22
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. The function should compute the destination rank for ce...
Definition utils.h:185
CellPartitionFunction create_cell_partitioner(mesh::GhostMode ghost_mode=mesh::GhostMode::none, const graph::partition_fn &partfn=&graph::partition_graph)
Definition utils.cpp:85