10#include "cell_types.h"
19#include <dolfinx/common/Timer.h>
20#include <dolfinx/common/local_range.h>
21#include <dolfinx/fem/CoordinateElement.h>
22#include <dolfinx/graph/ordering.h>
23#include <dolfinx/graph/partition.h>
48template <std::
floating_po
int T>
49std::tuple<std::vector<T>, std::vector<std::int64_t>>
50create_interval_cells(std::array<T, 2> p, std::int64_t n);
52template <std::
floating_po
int T>
53Mesh<T> build_tri(MPI_Comm comm, std::array<std::array<T, 2>, 2> p,
54 std::array<std::int64_t, 2> n,
59template <std::
floating_po
int T>
60Mesh<T> build_quad(MPI_Comm comm, std::array<std::array<T, 2>, 2> p,
61 std::array<std::int64_t, 2> n,
66template <std::
floating_po
int T>
67std::vector<T> create_geom(MPI_Comm comm, std::array<std::array<T, 3>, 2> p,
68 std::array<std::int64_t, 3> n);
70template <std::
floating_po
int T>
71Mesh<T> build_tet(MPI_Comm comm, MPI_Comm subcomm,
72 std::array<std::array<T, 3>, 2> p,
73 std::array<std::int64_t, 3> n,
77template <std::
floating_po
int T>
78Mesh<T> build_hex(MPI_Comm comm, MPI_Comm subcomm,
79 std::array<std::array<T, 3>, 2> p,
80 std::array<std::int64_t, 3> n,
84template <std::
floating_po
int T>
85Mesh<T> build_prism(MPI_Comm comm, MPI_Comm subcomm,
86 std::array<std::array<T, 3>, 2> p,
87 std::array<std::int64_t, 3> n,
97Mesh<typename std::remove_reference_t<typename U::value_type>> finalize_mesh(
98 MPI_Comm comm, MPI_Comm commx, std::span<const std::int64_t> cells,
100 typename std::remove_reference_t<typename U::value_type>>& element,
101 const U& x, std::array<std::size_t, 2> xshape,
105 return create_mesh(comm, commx, cells, element, commx, x, xshape,
137template <std::
floating_po
int T =
double>
139 std::array<std::array<T, 3>, 2> p,
140 std::array<std::int64_t, 3> n,
CellType celltype,
145 if (std::ranges::any_of(n, [](
auto e) {
return e < 1; }))
146 throw std::invalid_argument(
"At least one cell is required.");
148 for (int32_t i = 0; i < 3; i++)
150 if (p[0][i] >= p[1][i])
151 throw std::invalid_argument(
"It must hold p[0] < p[1].");
154 for (int32_t i = 0; i < 3; i++)
156 if (std::abs(p[1][i] - p[0][i]) /
static_cast<T
>(n[i])
157 < 2.0 * std::numeric_limits<T>::epsilon())
159 throw std::invalid_argument(
160 "Box seems to have zero width, height or depth. Check dimensions");
169 case CellType::tetrahedron:
170 return impl::build_tet<T>(comm, subcomm, p, n, partitioner, ghost_mode,
172 case CellType::hexahedron:
173 return impl::build_hex<T>(comm, subcomm, p, n, partitioner, ghost_mode,
175 case CellType::prism:
176 return impl::build_prism<T>(comm, subcomm, p, n, partitioner, ghost_mode,
179 throw std::invalid_argument(
"Generate box mesh. Wrong cell type");
204template <std::
floating_po
int T =
double>
206 std::array<std::int64_t, 3> n,
CellType celltype,
211 return create_box<T>(comm, comm, p, n, celltype, partitioner, ghost_mode,
239template <std::
floating_po
int T =
double>
241 std::array<std::int64_t, 2> n,
CellType celltype,
244 int gdim = 2,
GhostMode ghost_mode = GhostMode::none,
247 if (gdim < 2 || gdim > 3)
248 throw std::invalid_argument(
"2 <= gdim <= 3 for rectangle mesh.");
249 if (std::ranges::any_of(n, [](
auto e) {
return e < 1; }))
250 throw std::invalid_argument(
"At least one cell per dimension is required.");
252 for (int32_t i = 0; i < 2; i++)
254 if (p[0][i] >= p[1][i])
255 throw std::invalid_argument(
"It must hold p[0] < p[1].");
258 if (std::abs(p[1][0] - p[0][0]) < std::numeric_limits<T>::epsilon()
259 or std::abs(p[1][1] - p[0][1]) < std::numeric_limits<T>::epsilon())
261 throw std::invalid_argument(
262 "Rectangle seems to have zero width, height or depth. Check "
271 case CellType::triangle:
272 return impl::build_tri<T>(comm, p, n, partitioner, diagonal, ghost_mode,
274 case CellType::quadrilateral:
275 return impl::build_quad<T>(comm, p, n, partitioner, ghost_mode, reorder_fn,
278 throw std::invalid_argument(
"Generate rectangle mesh. Wrong cell type.");
300template <std::
floating_po
int T =
double>
302 std::array<std::int64_t, 2> n,
CellType celltype,
328template <std::
floating_po
int T =
double>
335 if (gdim < 1 || gdim > 3)
336 throw std::invalid_argument(
"1 <= gdim <= 3 for interval mesh.");
338 throw std::invalid_argument(
"At least one cell per dimension is required.");
340 const auto [a, b] = p;
342 throw std::invalid_argument(
"It must hold p[0] < p[1].");
343 if (std::abs(a - b) < std::numeric_limits<T>::epsilon())
345 throw std::invalid_argument(
346 "Length of interval is zero. Check your dimensions.");
352 fem::CoordinateElement<T> element(CellType::interval, 1);
355 auto [x1d,
cells] = impl::create_interval_cells<T>(p, n);
356 std::size_t npts = x1d.size();
359 return impl::finalize_mesh(comm, MPI_COMM_SELF, cells, element, x1d,
360 {npts, 1}, partitioner, ghost_mode,
363 std::vector<T> x(npts * gdim, T(0));
364 for (std::size_t i = 0; i < npts; i++)
365 x[i * gdim] = x1d[i];
366 return impl::finalize_mesh(comm, MPI_COMM_SELF, cells, element, x,
367 {npts,
static_cast<std::size_t
>(gdim)},
368 partitioner, ghost_mode, reorder_fn);
372 return impl::finalize_mesh(comm, MPI_COMM_NULL, {}, element,
374 {0,
static_cast<std::size_t
>(gdim)}, partitioner,
375 ghost_mode, reorder_fn);
382template <std::
floating_po
int T>
383std::tuple<std::vector<T>, std::vector<std::int64_t>>
384create_interval_cells(std::array<T, 2> p, std::int64_t n)
386 const auto [a, b] = p;
388 const T
h = (b - a) /
static_cast<T
>(n);
391 std::vector<T> x(n + 1);
392 std::ranges::generate(x, [i = std::int64_t(0), a,
h]()
mutable
393 {
return a +
h *
static_cast<T
>(i++); });
396 std::vector<std::int64_t>
cells(2 * n);
397 for (std::size_t ix = 0; ix <
cells.size() / 2; ++ix)
400 cells[2 * ix + 1] = ix + 1;
403 return {std::move(x), std::move(cells)};
406template <std::
floating_po
int T>
407std::vector<T> create_geom(MPI_Comm comm, std::array<std::array<T, 3>, 2> p,
408 std::array<std::int64_t, 3> n)
412 const auto [nx, ny, nz] = n;
414 assert(std::ranges::all_of(n, [](
auto e) {
return e >= 1; }));
418 const std::array<T, 3> extents = {
419 (p1[0] - p0[0]) /
static_cast<T
>(nx),
420 (p1[1] - p0[1]) /
static_cast<T
>(ny),
421 (p1[2] - p0[2]) /
static_cast<T
>(nz),
424 const std::int64_t n_points = (nx + 1) * (ny + 1) * (nz + 1);
429 geom.reserve((range_end - range_begin) * 3);
430 const std::int64_t sqxy = (nx + 1) * (ny + 1);
431 for (std::int64_t v = range_begin; v < range_end; ++v)
434 const std::int64_t xy_idx = v % sqxy;
435 std::array<std::int64_t, 3> idx
436 = {xy_idx % (nx + 1), xy_idx / (nx + 1), v / sqxy};
439 for (std::size_t i = 0; i < idx.size(); i++)
440 geom.push_back(p0[i] +
static_cast<T
>(idx[i]) * extents[i]);
446template <std::
floating_po
int T>
447Mesh<T> build_tet(MPI_Comm comm, MPI_Comm subcomm,
448 std::array<std::array<T, 3>, 2> p,
449 std::array<std::int64_t, 3> n,
453 common::Timer timer(
"Build BoxMesh (tetrahedra)");
455 std::vector<std::int64_t>
cells;
456 fem::CoordinateElement<T> element(CellType::tetrahedron, 1);
457 if (subcomm != MPI_COMM_NULL)
459 x = create_geom<T>(subcomm, p, n);
461 const auto [nx, ny, nz] = n;
462 const std::int64_t n_cells = nx * ny * nz;
466 cells.reserve(6 * (range_c[1] - range_c[0]) * 4);
469 for (std::int64_t i = range_c[0]; i < range_c[1]; ++i)
471 const std::int64_t iz = i / (nx * ny);
472 const std::int64_t j = i % (nx * ny);
473 const std::int64_t iy = j / nx;
474 const std::int64_t ix = j % nx;
475 const std::int64_t v0 = iz * (nx + 1) * (ny + 1) + iy * (nx + 1) + ix;
476 const std::int64_t v1 = v0 + 1;
477 const std::int64_t v2 = v0 + (nx + 1);
478 const std::int64_t v3 = v1 + (nx + 1);
479 const std::int64_t v4 = v0 + (nx + 1) * (ny + 1);
480 const std::int64_t v5 = v1 + (nx + 1) * (ny + 1);
481 const std::int64_t v6 = v2 + (nx + 1) * (ny + 1);
482 const std::int64_t v7 = v3 + (nx + 1) * (ny + 1);
487 {v0, v1, v3, v7, v0, v1, v7, v5, v0, v5, v7, v4,
488 v0, v3, v2, v7, v0, v6, v4, v7, v0, v2, v6, v7});
492 return finalize_mesh(comm, subcomm, cells, element, x, {x.size() / 3, 3},
493 partitioner, ghost_mode, reorder_fn);
496template <std::
floating_po
int T>
497mesh::Mesh<T> build_hex(MPI_Comm comm, MPI_Comm subcomm,
498 std::array<std::array<T, 3>, 2> p,
499 std::array<std::int64_t, 3> n,
503 common::Timer timer(
"Build BoxMesh (hexahedra)");
505 std::vector<std::int64_t>
cells;
506 fem::CoordinateElement<T> element(CellType::hexahedron, 1);
507 if (subcomm != MPI_COMM_NULL)
509 x = create_geom<T>(subcomm, p, n);
512 const auto [nx, ny, nz] = n;
513 const std::int64_t n_cells = nx * ny * nz;
516 cells.reserve((range_c[1] - range_c[0]) * 8);
517 for (std::int64_t i = range_c[0]; i < range_c[1]; ++i)
519 const std::int64_t iz = i / (nx * ny);
520 const std::int64_t j = i % (nx * ny);
521 const std::int64_t iy = j / nx;
522 const std::int64_t ix = j % nx;
524 const std::int64_t v0 = (iz * (ny + 1) + iy) * (nx + 1) + ix;
525 const std::int64_t v1 = v0 + 1;
526 const std::int64_t v2 = v0 + (nx + 1);
527 const std::int64_t v3 = v1 + (nx + 1);
528 const std::int64_t v4 = v0 + (nx + 1) * (ny + 1);
529 const std::int64_t v5 = v1 + (nx + 1) * (ny + 1);
530 const std::int64_t v6 = v2 + (nx + 1) * (ny + 1);
531 const std::int64_t v7 = v3 + (nx + 1) * (ny + 1);
532 cells.insert(
cells.end(), {v0, v1, v2, v3, v4, v5, v6, v7});
536 return finalize_mesh(comm, subcomm, cells, element, x, {x.size() / 3, 3},
537 partitioner, ghost_mode, reorder_fn);
540template <std::
floating_po
int T>
541Mesh<T> build_prism(MPI_Comm comm, MPI_Comm subcomm,
542 std::array<std::array<T, 3>, 2> p,
543 std::array<std::int64_t, 3> n,
548 std::vector<std::int64_t>
cells;
549 fem::CoordinateElement<T> element(CellType::prism, 1);
550 if (subcomm != MPI_COMM_NULL)
552 x = create_geom<T>(subcomm, p, n);
554 const std::int64_t nx = n[0];
555 const std::int64_t ny = n[1];
556 const std::int64_t nz = n[2];
557 const std::int64_t n_cells = nx * ny * nz;
560 const std::int64_t cell_range = range_c[1] - range_c[0];
563 cells.reserve(2 * cell_range * 6);
564 for (std::int64_t i = range_c[0]; i < range_c[1]; ++i)
566 const std::int64_t iz = i / (nx * ny);
567 const std::int64_t j = i % (nx * ny);
568 const std::int64_t iy = j / nx;
569 const std::int64_t ix = j % nx;
571 const std::int64_t v0 = (iz * (ny + 1) + iy) * (nx + 1) + ix;
572 const std::int64_t v1 = v0 + 1;
573 const std::int64_t v2 = v0 + (nx + 1);
574 const std::int64_t v3 = v1 + (nx + 1);
575 const std::int64_t v4 = v0 + (nx + 1) * (ny + 1);
576 const std::int64_t v5 = v1 + (nx + 1) * (ny + 1);
577 const std::int64_t v6 = v2 + (nx + 1) * (ny + 1);
578 const std::int64_t v7 = v3 + (nx + 1) * (ny + 1);
579 cells.insert(
cells.end(), {v0, v1, v2, v4, v5, v6});
580 cells.insert(
cells.end(), {v1, v2, v3, v5, v6, v7});
584 return finalize_mesh(comm, subcomm, cells, element, x, {x.size() / 3, 3},
585 partitioner, ghost_mode, reorder_fn);
588template <std::
floating_po
int T>
589Mesh<T> build_tri(MPI_Comm comm, std::array<std::array<T, 2>, 2> p,
590 std::array<std::int64_t, 2> n,
595 fem::CoordinateElement<T> element(CellType::triangle, 1);
596 if (gdim < 2 || gdim > 3)
597 throw std::invalid_argument(
"2 <= gdim <= 3 for tri mesh.");
601 const auto [p0, p1] = p;
602 const auto [nx, ny] = n;
604 const auto [a, c] = p0;
605 const auto [b, d] = p1;
607 const T ab = (b - a) /
static_cast<T
>(nx);
608 const T cd = (d - c) /
static_cast<T
>(ny);
614 case DiagonalType::crossed:
615 nv = (nx + 1) * (ny + 1) + nx * ny;
619 nv = (nx + 1) * (ny + 1);
625 std::vector<std::int64_t>
cells;
626 cells.reserve(nc * 3);
629 for (std::int64_t iy = 0; iy <= ny; iy++)
631 T x1 = c + cd *
static_cast<T
>(iy);
632 for (std::int64_t ix = 0; ix <= nx; ix++)
633 x.insert(x.end(), {a + ab * static_cast<T>(ix), x1});
639 case DiagonalType::crossed:
640 for (std::int64_t iy = 0; iy < ny; iy++)
642 T x1 = c + cd * (
static_cast<T
>(iy) + 0.5);
643 for (std::int64_t ix = 0; ix < nx; ix++)
645 T x0 = a + ab * (
static_cast<T
>(ix) + 0.5);
646 x.insert(x.end(), {x0, x1});
657 case DiagonalType::crossed:
659 for (std::int64_t iy = 0; iy < ny; iy++)
661 for (std::int64_t ix = 0; ix < nx; ix++)
663 std::int64_t v0 = iy * (nx + 1) + ix;
664 std::int64_t v1 = v0 + 1;
665 std::int64_t v2 = v0 + (nx + 1);
666 std::int64_t v3 = v1 + (nx + 1);
667 std::int64_t vmid = (nx + 1) * (ny + 1) + iy * nx + ix;
670 cells.insert(
cells.end(), {v0, v1, vmid, v0, v2, vmid, v1, v3, vmid,
679 for (std::int64_t iy = 0; iy < ny; iy++)
684 case DiagonalType::right_left:
686 local_diagonal = DiagonalType::right;
688 local_diagonal = DiagonalType::left;
690 case DiagonalType::left_right:
692 local_diagonal = DiagonalType::left;
694 local_diagonal = DiagonalType::right;
699 for (std::int64_t ix = 0; ix < nx; ix++)
701 std::int64_t v0 = iy * (nx + 1) + ix;
702 std::int64_t v1 = v0 + 1;
703 std::int64_t v2 = v0 + (nx + 1);
704 std::int64_t v3 = v1 + (nx + 1);
705 switch (local_diagonal)
707 case DiagonalType::left:
709 cells.insert(
cells.end(), {v0, v1, v2, v1, v2, v3});
710 if (diagonal == DiagonalType::right_left
711 or diagonal == DiagonalType::left_right)
713 local_diagonal = DiagonalType::right;
719 cells.insert(
cells.end(), {v0, v1, v3, v0, v2, v3});
720 if (diagonal == DiagonalType::right_left
721 or diagonal == DiagonalType::left_right)
723 local_diagonal = DiagonalType::left;
732 std::size_t npts = x.size() / 2;
735 return finalize_mesh(comm, MPI_COMM_SELF, cells, element, x, {npts, 2},
736 partitioner, ghost_mode, reorder_fn);
738 std::vector<T> xg(npts * gdim, T(0));
739 for (std::size_t i = 0; i < npts; i++)
741 xg[i * gdim] = x[2 * i];
742 xg[i * gdim + 1] = x[2 * i + 1];
744 return finalize_mesh(comm, MPI_COMM_SELF, cells, element, xg,
745 {npts,
static_cast<std::size_t
>(gdim)}, partitioner,
746 ghost_mode, reorder_fn);
750 return finalize_mesh(comm, MPI_COMM_NULL, {}, element, std::vector<T>{},
751 {0,
static_cast<std::size_t
>(gdim)}, partitioner,
752 ghost_mode, reorder_fn);
756template <std::
floating_po
int T>
757Mesh<T> build_quad(MPI_Comm comm, std::array<std::array<T, 2>, 2> p,
758 std::array<std::int64_t, 2> n,
763 if (gdim < 2 || gdim > 3)
764 throw std::invalid_argument(
"2 <= gdim <= 3 for quad mesh.");
766 fem::CoordinateElement<T> element(CellType::quadrilateral, 1);
769 const auto [nx, ny] = n;
770 const auto [a, c] = p[0];
771 const auto [b, d] = p[1];
773 const T ab = (b - a) /
static_cast<T
>(nx);
774 const T cd = (d - c) /
static_cast<T
>(ny);
778 x.reserve((nx + 1) * (ny + 1) * 2);
779 for (std::int64_t ix = 0; ix <= nx; ix++)
781 T x0 = a + ab *
static_cast<T
>(ix);
782 for (std::int64_t iy = 0; iy <= ny; iy++)
783 x.insert(x.end(), {x0, c + cd * static_cast<T>(iy)});
787 std::vector<std::int64_t>
cells;
788 cells.reserve(nx * ny * 4);
789 for (std::int64_t ix = 0; ix < nx; ix++)
791 for (std::int64_t iy = 0; iy < ny; iy++)
793 std::int64_t i0 = ix * (ny + 1);
794 cells.insert(
cells.end(), {i0 + iy, i0 + iy + 1, i0 + iy + ny + 1,
799 std::size_t npts = x.size() / 2;
802 return finalize_mesh(comm, MPI_COMM_SELF, cells, element, x, {npts, 2},
803 partitioner, ghost_mode, reorder_fn);
805 std::vector<T> xg(npts * gdim, T(0));
806 for (std::size_t i = 0; i < npts; i++)
808 xg[i * gdim] = x[2 * i];
809 xg[i * gdim + 1] = x[2 * i + 1];
811 return finalize_mesh(comm, MPI_COMM_SELF, cells, element, xg,
812 {npts,
static_cast<std::size_t
>(gdim)}, partitioner,
813 ghost_mode, reorder_fn);
817 return finalize_mesh(comm, MPI_COMM_NULL, {}, element, std::vector<T>{},
818 {0,
static_cast<std::size_t
>(gdim)}, partitioner,
819 ghost_mode, reorder_fn);
Definition CoordinateElement.h:39
A Mesh consists of a set of connected and numbered mesh topological entities, and geometry data.
Definition Mesh.h:25
Small, foundational mesh types (enums, etc.) with minimal dependencies.
Functions supporting mesh operations.
int size(MPI_Comm comm)
Definition MPI.cpp:81
int rank(MPI_Comm comm)
Return process rank for the communicator.
Definition MPI.cpp:73
constexpr std::array< std::int64_t, 2 > local_range(int index, std::int64_t N, int size)
Partition a global range [0, N - 1] across callers into non-overlapping sub-partitions of almost equa...
Definition local_range.h:26
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
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< std::int32_t > partition_graph(MPI_Comm comm, int nparts, const AdjacencyList< std::int64_t > &local_graph, std::optional< std::span< const std::int32_t > > node_weights, std::optional< std::span< const std::int32_t > > edge_weights, bool ghosting)
Partition graph across processes using the default graph partitioner.
Definition partition.cpp:137
std::variant< partition_fn, geom_partition_fn, hybrid_partition_fn > AnyPartitionFunction
Any of the three partitioning function shapes that mesh::create_mesh accepts: partition_fn,...
Definition partition.h:118
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
DiagonalType
Enum for different diagonal types.
Definition generation.h:37
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, graph::AnyPartitionFunction partitioner={}, GhostMode ghost_mode=GhostMode::none, const graph::Reorder &reorder_fn=graph::Reorder{})
Create a uniform mesh::Mesh over rectangular prism spanned by the two points p.
Definition generation.h:138
CellType
Cell type identifier.
Definition cell_types.h:24
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
Mesh< T > create_interval(MPI_Comm comm, std::int64_t n, std::array< T, 2 > p, mesh::GhostMode ghost_mode=mesh::GhostMode::none, graph::AnyPartitionFunction partitioner={}, int gdim=1, const graph::Reorder &reorder_fn=graph::Reorder{})
Interval mesh of the 1D line [a, b].
Definition generation.h:329
Mesh< T > create_rectangle(MPI_Comm comm, std::array< std::array< T, 2 >, 2 > p, std::array< std::int64_t, 2 > n, CellType celltype, graph::AnyPartitionFunction partitioner, DiagonalType diagonal=DiagonalType::right, int gdim=2, GhostMode ghost_mode=GhostMode::none, const graph::Reorder &reorder_fn=graph::Reorder{})
Create a uniform mesh::Mesh over the rectangle spanned by the two points p.
Definition generation.h:240
GhostMode
Enum for different partitioning ghost modes.
Definition types.h:19
An AnyPartitionFunction together with the node weights it should be called with, if any.
Definition partition.h:156