10#include "cell_types.h" 
   34template <std::
floating_po
int T>
 
   35Mesh<T> build_tri(MPI_Comm comm, 
const std::array<std::array<double, 2>, 2>& p,
 
   36                  std::array<std::size_t, 2> n,
 
   40template <std::
floating_po
int T>
 
   41Mesh<T> build_quad(MPI_Comm comm, 
const std::array<std::array<double, 2>, 2> p,
 
   42                   std::array<std::size_t, 2> n,
 
   45template <std::
floating_po
int T>
 
   46std::vector<T> create_geom(MPI_Comm comm,
 
   47                           const std::array<std::array<double, 3>, 2>& p,
 
   48                           std::array<std::size_t, 3> n);
 
   50template <std::
floating_po
int T>
 
   51Mesh<T> build_tet(MPI_Comm comm, 
const std::array<std::array<double, 3>, 2>& p,
 
   52                  std::array<std::size_t, 3> n,
 
   55template <std::
floating_po
int T>
 
   56Mesh<T> build_hex(MPI_Comm comm, 
const std::array<std::array<double, 3>, 2>& p,
 
   57                  std::array<std::size_t, 3> n,
 
   60template <std::
floating_po
int T>
 
   61Mesh<T> build_prism(MPI_Comm comm,
 
   62                    const std::array<std::array<double, 3>, 2>& p,
 
   63                    std::array<std::size_t, 3> n,
 
   84template <std::
floating_po
int T = 
double>
 
   86                   std::array<std::size_t, 3> n, 
CellType celltype,
 
   94  case CellType::tetrahedron:
 
   95    return impl::build_tet<T>(comm, p, n, partitioner);
 
   96  case CellType::hexahedron:
 
   97    return impl::build_hex<T>(comm, p, n, partitioner);
 
   99    return impl::build_prism<T>(comm, p, n, partitioner);
 
  101    throw std::runtime_error(
"Generate box mesh. Wrong cell type");
 
 
  121template <std::
floating_po
int T = 
double>
 
  123                         const std::array<std::array<double, 2>, 2>& p,
 
  124                         std::array<std::size_t, 2> n, 
CellType celltype,
 
  130  case CellType::triangle:
 
  131    return impl::build_tri<T>(comm, p, n, partitioner, diagonal);
 
  132  case CellType::quadrilateral:
 
  133    return impl::build_quad<T>(comm, p, n, partitioner);
 
  135    throw std::runtime_error(
"Generate rectangle mesh. Wrong cell type");
 
 
  153template <std::
floating_po
int T = 
double>
 
  155                         const std::array<std::array<double, 2>, 2>& p,
 
  156                         std::array<std::size_t, 2> n, 
CellType celltype,
 
  159  return create_rectangle<T>(comm, p, n, celltype, 
nullptr, diagonal);
 
 
  174template <std::
floating_po
int T = 
double>
 
  187    const T ab = (b - a) / 
static_cast<T
>(nx);
 
  189    if (std::abs(a - b) < DBL_EPSILON)
 
  191      throw std::runtime_error(
 
  192          "Length of interval is zero. Check your dimensions.");
 
  197      throw std::runtime_error(
 
  198          "Interval length is negative. Check order of arguments.");
 
  202      throw std::runtime_error(
 
  203          "Number of points on interval must be at least 1");
 
  206    std::vector<T> geom(nx + 1);
 
  207    for (std::size_t ix = 0; ix <= nx; ix++)
 
  208      geom[ix] = a + ab * 
static_cast<T
>(ix);
 
  211    std::vector<std::int64_t> cells(nx * 2);
 
  212    for (std::size_t ix = 0; ix < nx; ++ix)
 
  213      for (std::size_t j = 0; j < 2; ++j)
 
  214        cells[2 * ix + j] = ix + j;
 
  217                       {element}, geom, {geom.size(), 1}, partitioner);
 
  223        {element}, std::vector<T>(), {0, 1}, partitioner);
 
 
  229template <std::
floating_po
int T>
 
  230std::vector<T> create_geom(MPI_Comm comm,
 
  231                           const std::array<std::array<double, 3>, 2>& p,
 
  232                           std::array<std::size_t, 3> n)
 
  235  const std::array<double, 3> p0 = p[0];
 
  236  const std::array<double, 3> p1 = p[1];
 
  237  std::int64_t nx = n[0];
 
  238  std::int64_t ny = n[1];
 
  239  std::int64_t nz = n[2];
 
  241  const std::int64_t n_points = (nx + 1) * (ny + 1) * (nz + 1);
 
  246  const double x0 = std::min(p0[0], p1[0]);
 
  247  const double x1 = std::max(p0[0], p1[0]);
 
  248  const double y0 = std::min(p0[1], p1[1]);
 
  249  const double y1 = std::max(p0[1], p1[1]);
 
  250  const double z0 = std::min(p0[2], p1[2]);
 
  251  const double z1 = std::max(p0[2], p1[2]);
 
  255  const T ab = (b - a) / 
static_cast<T
>(nx);
 
  258  const T cd = (d - c) / 
static_cast<T
>(ny);
 
  261  const T ef = (f - e) / 
static_cast<T
>(nz);
 
  263  if (std::abs(x0 - x1) < 2.0 * DBL_EPSILON
 
  264      or std::abs(y0 - y1) < 2.0 * DBL_EPSILON
 
  265      or std::abs(z0 - z1) < 2.0 * DBL_EPSILON)
 
  267    throw std::runtime_error(
 
  268        "Box seems to have zero width, height or depth. Check dimensions");
 
  271  if (nx < 1 || ny < 1 || nz < 1)
 
  273    throw std::runtime_error(
 
  274        "BoxMesh has non-positive number of vertices in some dimension");
 
  277  std::vector<T> geom((range_p[1] - range_p[0]) * 3);
 
  278  const std::int64_t sqxy = (nx + 1) * (ny + 1);
 
  279  std::array<T, 3> point;
 
  280  for (std::int64_t v = range_p[0]; v < range_p[1]; ++v)
 
  282    const std::int64_t iz = v / sqxy;
 
  283    const std::int64_t p = v % sqxy;
 
  284    const std::int64_t iy = p / (nx + 1);
 
  285    const std::int64_t ix = p % (nx + 1);
 
  286    const T z = e + ef * 
static_cast<T
>(iz);
 
  287    const T y = c + cd * 
static_cast<T
>(iy);
 
  288    const T x = a + ab * 
static_cast<T
>(ix);
 
  290    for (std::size_t i = 0; i < 3; i++)
 
  291      geom[3 * (v - range_p[0]) + i] = point[i];
 
  297template <std::
floating_po
int T>
 
  298Mesh<T> build_tet(MPI_Comm comm, 
const std::array<std::array<double, 3>, 2>& p,
 
  299                  std::array<std::size_t, 3> n,
 
  302  common::Timer timer(
"Build BoxMesh");
 
  304  std::vector geom = create_geom<T>(comm, p, n);
 
  306  const std::int64_t nx = n[0];
 
  307  const std::int64_t ny = n[1];
 
  308  const std::int64_t nz = n[2];
 
  309  const std::int64_t n_cells = nx * ny * nz;
 
  312  const std::size_t cell_range = range_c[1] - range_c[0];
 
  313  std::vector<std::int64_t> 
cells(6 * cell_range * 4);
 
  316  for (std::int64_t i = range_c[0]; i < range_c[1]; ++i)
 
  318    const int iz = i / (nx * ny);
 
  319    const int j = i % (nx * ny);
 
  320    const int iy = j / nx;
 
  321    const int ix = j % nx;
 
  323    const std::int64_t v0 = iz * (nx + 1) * (ny + 1) + iy * (nx + 1) + ix;
 
  324    const std::int64_t v1 = v0 + 1;
 
  325    const std::int64_t v2 = v0 + (nx + 1);
 
  326    const std::int64_t v3 = v1 + (nx + 1);
 
  327    const std::int64_t v4 = v0 + (nx + 1) * (ny + 1);
 
  328    const std::int64_t v5 = v1 + (nx + 1) * (ny + 1);
 
  329    const std::int64_t v6 = v2 + (nx + 1) * (ny + 1);
 
  330    const std::int64_t v7 = v3 + (nx + 1) * (ny + 1);
 
  333    std::array<std::int64_t, 24> c
 
  334        = {v0, v1, v3, v7, v0, v1, v7, v5, v0, v5, v7, v4,
 
  335           v0, v3, v2, v7, v0, v6, v4, v7, v0, v2, v6, v7};
 
  336    std::size_t offset = 6 * (i - range_c[0]);
 
  337    std::copy(c.begin(), c.end(), std::next(
cells.begin(), 4 * offset));
 
  340  fem::CoordinateElement<T> element(CellType::tetrahedron, 1);
 
  342                     {element}, geom, {geom.size() / 3, 3}, partitioner);
 
  345template <std::
floating_po
int T>
 
  346mesh::Mesh<T> build_hex(MPI_Comm comm,
 
  347                        const std::array<std::array<double, 3>, 2>& p,
 
  348                        std::array<std::size_t, 3> n,
 
  351  std::vector geom = create_geom<T>(comm, p, n);
 
  353  const std::int64_t nx = n[0];
 
  354  const std::int64_t ny = n[1];
 
  355  const std::int64_t nz = n[2];
 
  356  const std::int64_t n_cells = nx * ny * nz;
 
  359  const std::size_t cell_range = range_c[1] - range_c[0];
 
  360  std::vector<std::int64_t> 
cells(cell_range * 8);
 
  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;
 
  370    const std::int64_t v0 = (iz * (ny + 1) + iy) * (nx + 1) + ix;
 
  371    const std::int64_t v1 = v0 + 1;
 
  372    const std::int64_t v2 = v0 + (nx + 1);
 
  373    const std::int64_t v3 = v1 + (nx + 1);
 
  374    const std::int64_t v4 = v0 + (nx + 1) * (ny + 1);
 
  375    const std::int64_t v5 = v1 + (nx + 1) * (ny + 1);
 
  376    const std::int64_t v6 = v2 + (nx + 1) * (ny + 1);
 
  377    const std::int64_t v7 = v3 + (nx + 1) * (ny + 1);
 
  379    std::array<std::int64_t, 8> c = {v0, v1, v2, v3, v4, v5, v6, v7};
 
  380    std::copy(c.begin(), c.end(),
 
  381              std::next(
cells.begin(), (i - range_c[0]) * 8));
 
  384  fem::CoordinateElement<T> element(CellType::hexahedron, 1);
 
  386                     {element}, geom, {geom.size() / 3, 3}, partitioner);
 
  389template <std::
floating_po
int T>
 
  390Mesh<T> build_prism(MPI_Comm comm,
 
  391                    const std::array<std::array<double, 3>, 2>& p,
 
  392                    std::array<std::size_t, 3> n,
 
  395  std::vector geom = create_geom<T>(comm, p, n);
 
  397  const std::int64_t nx = n[0];
 
  398  const std::int64_t ny = n[1];
 
  399  const std::int64_t nz = n[2];
 
  400  const std::int64_t n_cells = nx * ny * nz;
 
  403  const std::size_t cell_range = range_c[1] - range_c[0];
 
  404  std::vector<std::int64_t> 
cells(2 * cell_range * 6);
 
  407  for (std::int64_t i = range_c[0]; i < range_c[1]; ++i)
 
  409    const std::int64_t iz = i / (nx * ny);
 
  410    const std::int64_t j = i % (nx * ny);
 
  411    const std::int64_t iy = j / nx;
 
  412    const std::int64_t ix = j % nx;
 
  414    const std::int64_t v0 = (iz * (ny + 1) + iy) * (nx + 1) + ix;
 
  415    const std::int64_t v1 = v0 + 1;
 
  416    const std::int64_t v2 = v0 + (nx + 1);
 
  417    const std::int64_t v3 = v1 + (nx + 1);
 
  418    const std::int64_t v4 = v0 + (nx + 1) * (ny + 1);
 
  419    const std::int64_t v5 = v1 + (nx + 1) * (ny + 1);
 
  420    const std::int64_t v6 = v2 + (nx + 1) * (ny + 1);
 
  421    const std::int64_t v7 = v3 + (nx + 1) * (ny + 1);
 
  423    std::array<std::int64_t, 6> c0 = {v0, v1, v2, v4, v5, v6};
 
  424    std::array<std::int64_t, 6> c1 = {v1, v2, v3, v5, v6, v7};
 
  426    std::copy(c0.begin(), c0.end(),
 
  427              std::next(
cells.begin(), 6 * ((i - range_c[0]) * 2)));
 
  428    std::copy(c1.begin(), c1.end(),
 
  429              std::next(
cells.begin(), 6 * ((i - range_c[0]) * 2 + 1)));
 
  432  fem::CoordinateElement<T> element(CellType::prism, 1);
 
  434                     {element}, geom, {geom.size() / 3, 3}, partitioner);
 
  437template <std::
floating_po
int T>
 
  438Mesh<T> build_tri(MPI_Comm comm, 
const std::array<std::array<double, 2>, 2>& p,
 
  439                  std::array<std::size_t, 2> n,
 
  443  fem::CoordinateElement<T> element(CellType::triangle, 1);
 
  450        {element}, std::vector<T>(), {0, 2}, partitioner);
 
  453  const std::array<double, 2> p0 = p[0];
 
  454  const std::array<double, 2> p1 = p[1];
 
  456  const std::size_t nx = n[0];
 
  457  const std::size_t ny = n[1];
 
  460  const T x0 = std::min(p0[0], p1[0]);
 
  461  const T x1 = std::max(p0[0], p1[0]);
 
  462  const T y0 = std::min(p0[1], p1[1]);
 
  463  const T y1 = std::max(p0[1], p1[1]);
 
  467  const T ab = (b - a) / 
static_cast<T
>(nx);
 
  470  const T cd = (d - c) / 
static_cast<T
>(ny);
 
  472  if (std::abs(x0 - x1) < DBL_EPSILON || std::abs(y0 - y1) < DBL_EPSILON)
 
  474    throw std::runtime_error(
"Rectangle seems to have zero width, height or " 
  475                             "depth. Check dimensions");
 
  478  if (nx < 1 or ny < 1)
 
  480    throw std::runtime_error(
 
  481        "Rectangle has non-positive number of vertices in some dimension: " 
  482        "number of vertices must be at least 1 in each dimension");
 
  489  case DiagonalType::crossed:
 
  490    nv = (nx + 1) * (ny + 1) + nx * ny;
 
  494    nv = (nx + 1) * (ny + 1);
 
  498  std::vector<T> geom(nv * 2);
 
  499  std::vector<std::int64_t> 
cells(nc * 3);
 
  503  for (std::size_t iy = 0; iy <= ny; iy++)
 
  505    const T x1 = c + cd * 
static_cast<T
>(iy);
 
  506    for (std::size_t ix = 0; ix <= nx; ix++)
 
  508      geom[2 * 
vertex + 0] = a + ab * 
static_cast<T
>(ix);
 
  509      geom[2 * 
vertex + 1] = x1;
 
  517  case DiagonalType::crossed:
 
  518    for (std::size_t iy = 0; iy < ny; iy++)
 
  520      const T x1 = c + cd * (
static_cast<T
>(iy) + 0.5);
 
  521      for (std::size_t ix = 0; ix < nx; ix++)
 
  523        geom[2 * 
vertex + 0] = a + ab * (
static_cast<T
>(ix) + 0.5);
 
  524        geom[2 * 
vertex + 1] = x1;
 
  536  case DiagonalType::crossed:
 
  538    for (std::size_t iy = 0; iy < ny; iy++)
 
  540      for (std::size_t ix = 0; ix < nx; ix++)
 
  542        const std::size_t v0 = iy * (nx + 1) + ix;
 
  543        const std::size_t v1 = v0 + 1;
 
  544        const std::size_t v2 = v0 + (nx + 1);
 
  545        const std::size_t v3 = v1 + (nx + 1);
 
  546        const std::size_t vmid = (nx + 1) * (ny + 1) + iy * nx + ix;
 
  549        std::array<std::size_t, 12> c
 
  550            = {v0, v1, vmid, v0, v2, vmid, v1, v3, vmid, v2, v3, vmid};
 
  551        std::size_t offset = iy * nx + ix;
 
  552        std::copy(c.begin(), c.end(), std::next(
cells.begin(), 4 * offset * 3));
 
  560    for (std::size_t iy = 0; iy < ny; iy++)
 
  565      case DiagonalType::right_left:
 
  567          local_diagonal = DiagonalType::right;
 
  569          local_diagonal = DiagonalType::left;
 
  571      case DiagonalType::left_right:
 
  573          local_diagonal = DiagonalType::left;
 
  575          local_diagonal = DiagonalType::right;
 
  580      for (std::size_t ix = 0; ix < nx; ix++)
 
  582        const std::size_t v0 = iy * (nx + 1) + ix;
 
  583        const std::size_t v1 = v0 + 1;
 
  584        const std::size_t v2 = v0 + (nx + 1);
 
  585        const std::size_t v3 = v1 + (nx + 1);
 
  587        std::size_t offset = iy * nx + ix;
 
  588        switch (local_diagonal)
 
  590        case DiagonalType::left:
 
  592          std::array<std::size_t, 6> c = {v0, v1, v2, v1, v2, v3};
 
  593          std::copy(c.begin(), c.end(),
 
  594                    std::next(
cells.begin(), 2 * offset * 3));
 
  595          if (diagonal == DiagonalType::right_left
 
  596              or diagonal == DiagonalType::left_right)
 
  598            local_diagonal = DiagonalType::right;
 
  604          std::array<std::size_t, 6> c = {v0, v1, v3, v0, v2, v3};
 
  605          std::copy(c.begin(), c.end(),
 
  606                    std::next(
cells.begin(), 2 * offset * 3));
 
  607          if (diagonal == DiagonalType::right_left
 
  608              or diagonal == DiagonalType::left_right)
 
  610            local_diagonal = DiagonalType::left;
 
  620                     {element}, geom, {geom.size() / 2, 2}, partitioner);
 
  623template <std::
floating_po
int T>
 
  624Mesh<T> build_quad(MPI_Comm comm, 
const std::array<std::array<double, 2>, 2> p,
 
  625                   std::array<std::size_t, 2> n,
 
  628  fem::CoordinateElement<T> element(CellType::quadrilateral, 1);
 
  635        {element}, std::vector<T>(), {0, 2}, partitioner);
 
  638  const std::size_t nx = n[0];
 
  639  const std::size_t ny = n[1];
 
  643  const T ab = (b - a) / 
static_cast<T
>(nx);
 
  647  const T cd = (d - c) / 
static_cast<T
>(ny);
 
  650  std::vector<T> geom((nx + 1) * (ny + 1) * 2);
 
  652  for (std::size_t ix = 0; ix <= nx; ix++)
 
  654    T x0 = a + ab * 
static_cast<T
>(ix);
 
  655    for (std::size_t iy = 0; iy <= ny; iy++)
 
  657      geom[2 * 
vertex + 0] = x0;
 
  658      geom[2 * 
vertex + 1] = c + cd * 
static_cast<T
>(iy);
 
  664  std::vector<std::int64_t> 
cells(nx * ny * 4);
 
  665  for (std::size_t ix = 0; ix < nx; ix++)
 
  667    for (std::size_t iy = 0; iy < ny; iy++)
 
  669      const std::size_t i0 = ix * (ny + 1);
 
  670      std::size_t 
cell = ix * ny + iy;
 
  671      std::array<std::size_t, 4> c
 
  672          = {i0 + iy, i0 + iy + 1, i0 + iy + ny + 1, i0 + iy + ny + 2};
 
  673      std::copy(c.begin(), c.end(), std::next(
cells.begin(), 4 * cell));
 
  678                     {element}, geom, {geom.size() / 2, 2}, partitioner);
 
A CoordinateElement manages coordinate mappings for isoparametric cells.
Definition CoordinateElement.h:39
 
A Mesh consists of a set of connected and numbered mesh topological entities, and geometry data.
Definition Mesh.h:23
 
int size(MPI_Comm comm)
Return size of the group (number of processes) associated with the communicator.
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::span< const std::int32_t > cells, std::array< std::reference_wrapper< const DofMap >, 2 > dofmaps)
Iterate over cells and insert entries into sparsity pattern.
Definition sparsitybuild.cpp:18
 
AdjacencyList< typename std::decay_t< U >::value_type > regular_adjacency_list(U &&data, int degree)
Construct a constant degree (valency) adjacency list.
Definition AdjacencyList.h:183
 
Mesh data structures and algorithms on meshes.
Definition DofMap.h:32
 
Mesh< T > create_box(MPI_Comm comm, const std::array< std::array< double, 3 >, 2 > &p, std::array< std::size_t, 3 > n, CellType celltype, mesh::CellPartitionFunction partitioner=nullptr)
Create a uniform mesh::Mesh over rectangular prism spanned by the two points p.
Definition generation.h:85
 
std::function< graph::AdjacencyList< std::int32_t >(MPI_Comm comm, int nparts, int tdim, const graph::AdjacencyList< std::int64_t > &cells)> CellPartitionFunction
Signature for the cell partitioning function. The function should compute the destination rank for ce...
Definition utils.h:195
 
DiagonalType
Enum for different diagonal types.
Definition generation.h:23
 
Mesh< T > create_rectangle(MPI_Comm comm, const std::array< std::array< double, 2 >, 2 > &p, std::array< std::size_t, 2 > n, CellType celltype, const CellPartitionFunction &partitioner, DiagonalType diagonal=DiagonalType::right)
Create a uniform mesh::Mesh over the rectangle spanned by the two points p.
Definition generation.h:122
 
Mesh< typename std::remove_reference_t< typename U::value_type > > create_mesh(MPI_Comm comm, const graph::AdjacencyList< std::int64_t > &cells, const std::vector< fem::CoordinateElement< typename std::remove_reference_t< typename U::value_type > > > &elements, const U &x, std::array< std::size_t, 2 > xshape, CellPartitionFunction partitioner)
Create a mesh using a provided mesh partitioning function.
Definition utils.h:780
 
Mesh< T > create_interval(MPI_Comm comm, std::size_t nx, std::array< double, 2 > x, CellPartitionFunction partitioner=nullptr)
Interval mesh of the 1D line [a, b].
Definition generation.h:175
 
CellType
Cell type identifier.
Definition cell_types.h:22
 
CellPartitionFunction create_cell_partitioner(mesh::GhostMode ghost_mode=mesh::GhostMode::none, const graph::partition_fn &partfn=&graph::partition_graph)
Create a function that computes destination rank for mesh cells in this rank by applying the default ...
Definition utils.cpp:84