DOLFINx 0.11.0.0
DOLFINx C++
Loading...
Searching...
No Matches
generation.h
1// Copyright (C) 2005-2024 Anders Logg and Garth N. Wells
2//
3// This file is part of DOLFINx (https://www.fenicsproject.org)
4//
5// SPDX-License-Identifier: LGPL-3.0-or-later
6
7#pragma once
8
9#include "Mesh.h"
10#include "cell_types.h"
11#include "utils.h"
12#include <algorithm>
13#include <array>
14#include <cmath>
15#include <concepts>
16#include <cstddef>
17#include <cstdint>
18#include <dolfinx/graph/ordering.h>
19#include <limits>
20#include <mpi.h>
21#include <stdexcept>
22#include <utility>
23#include <vector>
24
25namespace dolfinx::mesh
26{
28enum class DiagonalType
29{
30 left,
31 right,
32 crossed,
33 shared_facet,
34 left_right,
35 right_left
36};
37
38namespace impl
39{
40template <std::floating_point T>
41std::tuple<std::vector<T>, std::vector<std::int64_t>>
42create_interval_cells(std::array<T, 2> p, std::int64_t n);
43
44template <std::floating_point T>
45Mesh<T> build_tri(MPI_Comm comm, std::array<std::array<T, 2>, 2> p,
46 std::array<std::int64_t, 2> n,
47 const CellPartitionFunction& partitioner,
48 DiagonalType diagonal, const CellReorderFunction& reorder_fn,
49 int gdim);
50
51template <std::floating_point T>
52Mesh<T> build_quad(MPI_Comm comm, std::array<std::array<T, 2>, 2> p,
53 std::array<std::int64_t, 2> n,
54 const CellPartitionFunction& partitioner,
55 const CellReorderFunction& reorder_fn, int gdim);
56
57template <std::floating_point T>
58std::vector<T> create_geom(MPI_Comm comm, std::array<std::array<T, 3>, 2> p,
59 std::array<std::int64_t, 3> n);
60
61template <std::floating_point T>
62Mesh<T> build_tet(MPI_Comm comm, MPI_Comm subcomm,
63 std::array<std::array<T, 3>, 2> p,
64 std::array<std::int64_t, 3> n,
65 const CellPartitionFunction& partitioner,
66 const CellReorderFunction& reorder_fn);
67
68template <std::floating_point T>
69Mesh<T> build_hex(MPI_Comm comm, MPI_Comm subcomm,
70 std::array<std::array<T, 3>, 2> p,
71 std::array<std::int64_t, 3> n,
72 const CellPartitionFunction& partitioner,
73 const CellReorderFunction& reorder_fn);
74
75template <std::floating_point T>
76Mesh<T> build_prism(MPI_Comm comm, MPI_Comm subcomm,
77 std::array<std::array<T, 3>, 2> p,
78 std::array<std::int64_t, 3> n,
79 const CellPartitionFunction& partitioner,
80 const CellReorderFunction& reorder_fn);
81} // namespace impl
82
104template <std::floating_point T = double>
105Mesh<T> create_box(MPI_Comm comm, MPI_Comm subcomm,
106 std::array<std::array<T, 3>, 2> p,
107 std::array<std::int64_t, 3> n, CellType celltype,
108 CellPartitionFunction partitioner = nullptr,
109 const CellReorderFunction& reorder_fn = graph::reorder_gps)
110{
111 if (std::ranges::any_of(n, [](auto e) { return e < 1; }))
112 throw std::runtime_error("At least one cell is required.");
113
114 for (int32_t i = 0; i < 3; i++)
115 {
116 if (p[0][i] >= p[1][i])
117 throw std::runtime_error("It must hold p[0] < p[1].");
118 }
119
120 if (!partitioner and dolfinx::MPI::size(comm) > 1)
121 partitioner = create_cell_partitioner(mesh::GhostMode::none, 2);
122
123 switch (celltype)
124 {
125 case CellType::tetrahedron:
126 return impl::build_tet<T>(comm, subcomm, p, n, partitioner, reorder_fn);
127 case CellType::hexahedron:
128 return impl::build_hex<T>(comm, subcomm, p, n, partitioner, reorder_fn);
129 case CellType::prism:
130 return impl::build_prism<T>(comm, subcomm, p, n, partitioner, reorder_fn);
131 default:
132 throw std::runtime_error("Generate box mesh. Wrong cell type");
133 }
134}
135
153template <std::floating_point T = double>
154Mesh<T> create_box(MPI_Comm comm, std::array<std::array<T, 3>, 2> p,
155 std::array<std::int64_t, 3> n, CellType celltype,
156 const CellPartitionFunction& partitioner = nullptr,
157 const CellReorderFunction& reorder_fn = graph::reorder_gps)
158{
159 return create_box<T>(comm, comm, p, n, celltype, partitioner, reorder_fn);
160}
161
181template <std::floating_point T = double>
182Mesh<T>
183create_rectangle(MPI_Comm comm, std::array<std::array<T, 2>, 2> p,
184 std::array<std::int64_t, 2> n, CellType celltype,
185 CellPartitionFunction partitioner,
186 DiagonalType diagonal = DiagonalType::right, int gdim = 2,
187 const CellReorderFunction& reorder_fn = graph::reorder_gps)
188{
189 if (gdim < 2 || gdim > 3)
190 throw std::runtime_error("2 <= gdim <= 3 for rectangle mesh.");
191 if (std::ranges::any_of(n, [](auto e) { return e < 1; }))
192 throw std::runtime_error("At least one cell per dimension is required.");
193
194 for (int32_t i = 0; i < 2; i++)
195 {
196 if (p[0][i] >= p[1][i])
197 throw std::runtime_error("It must hold p[0] < p[1].");
198 }
199
200 if (!partitioner and dolfinx::MPI::size(comm) > 1)
201 partitioner = create_cell_partitioner(mesh::GhostMode::none, 2);
202
203 switch (celltype)
204 {
205 case CellType::triangle:
206 return impl::build_tri<T>(comm, p, n, partitioner, diagonal, reorder_fn,
207 gdim);
208 case CellType::quadrilateral:
209 return impl::build_quad<T>(comm, p, n, partitioner, reorder_fn, gdim);
210 default:
211 throw std::runtime_error("Generate rectangle mesh. Wrong cell type.");
212 }
213}
214
231template <std::floating_point T = double>
232Mesh<T> create_rectangle(MPI_Comm comm, std::array<std::array<T, 2>, 2> p,
233 std::array<std::int64_t, 2> n, CellType celltype,
234 DiagonalType diagonal = DiagonalType::right,
235 int gdim = 2)
236{
237 return create_rectangle<T>(comm, p, n, celltype, nullptr, diagonal, gdim);
238}
239
256template <std::floating_point T = double>
257Mesh<T>
258create_interval(MPI_Comm comm, std::int64_t n, std::array<T, 2> p,
259 mesh::GhostMode ghost_mode = mesh::GhostMode::none,
260 CellPartitionFunction partitioner = nullptr, int gdim = 1,
261 const CellReorderFunction& reorder_fn = graph::reorder_gps)
262{
263 if (gdim < 1 || gdim > 3)
264 throw std::runtime_error("1 <= gdim <= 3 for interval mesh.");
265 if (n < 1)
266 throw std::runtime_error("At least one cell per dimension is required.");
267
268 const auto [a, b] = p;
269 if (a >= b)
270 throw std::runtime_error("It must hold p[0] < p[1].");
271 if (std::abs(a - b) < std::numeric_limits<T>::epsilon())
272 {
273 throw std::runtime_error(
274 "Length of interval is zero. Check your dimensions.");
275 }
276
277 if (!partitioner and dolfinx::MPI::size(comm) > 1)
278 partitioner = create_cell_partitioner(ghost_mode, 2);
279
280 fem::CoordinateElement<T> element(CellType::interval, 1);
281 if (dolfinx::MPI::rank(comm) == 0)
282 {
283 auto [x1d, cells] = impl::create_interval_cells<T>(p, n);
284 std::size_t npts = x1d.size();
285 if (gdim == 1)
286 {
287 return create_mesh(comm, MPI_COMM_SELF, cells, element, MPI_COMM_SELF,
288 x1d, {npts, 1}, partitioner, 2, reorder_fn);
289 }
290 std::vector<T> x(npts * gdim, T(0));
291 for (std::size_t i = 0; i < npts; i++)
292 x[i * gdim] = x1d[i];
293 return create_mesh(comm, MPI_COMM_SELF, cells, element, MPI_COMM_SELF, x,
294 {npts, static_cast<std::size_t>(gdim)}, partitioner, 2,
295 reorder_fn);
296 }
297 else
298 {
299 return create_mesh(comm, MPI_COMM_NULL, {}, element, MPI_COMM_NULL,
300 std::vector<T>{}, {0, static_cast<std::size_t>(gdim)},
301 partitioner, 2, reorder_fn);
302 }
303}
304
305namespace impl
306{
307
308template <std::floating_point T>
309std::tuple<std::vector<T>, std::vector<std::int64_t>>
310create_interval_cells(std::array<T, 2> p, std::int64_t n)
311{
312 const auto [a, b] = p;
313
314 const T h = (b - a) / static_cast<T>(n);
315
316 // Create vertices
317 std::vector<T> x(n + 1);
318 std::ranges::generate(x, [i = std::int64_t(0), a, h]() mutable
319 { return a + h * static_cast<T>(i++); });
320
321 // Create intervals -> cells=[0, 1, 1, ..., n-1, n-1, n]
322 std::vector<std::int64_t> cells(2 * n);
323 for (std::size_t ix = 0; ix < cells.size() / 2; ++ix)
324 {
325 cells[2 * ix] = ix;
326 cells[2 * ix + 1] = ix + 1;
327 }
328
329 return {std::move(x), std::move(cells)};
330}
331
332template <std::floating_point T>
333std::vector<T> create_geom(MPI_Comm comm, std::array<std::array<T, 3>, 2> p,
334 std::array<std::int64_t, 3> n)
335{
336 // Extract data
337 auto [p0, p1] = p;
338 const auto [nx, ny, nz] = n;
339
340 assert(std::ranges::all_of(n, [](auto e) { return e >= 1; }));
341 assert(p0 < p1);
342
343 // Structured grid cuboid extents
344 const std::array<T, 3> extents = {
345 (p1[0] - p0[0]) / static_cast<T>(nx),
346 (p1[1] - p0[1]) / static_cast<T>(ny),
347 (p1[2] - p0[2]) / static_cast<T>(nz),
348 };
349
350 if (std::ranges::any_of(
351 extents, [](auto e)
352 { return std::abs(e) < 2.0 * std::numeric_limits<T>::epsilon(); }))
353 {
354 throw std::runtime_error(
355 "Box seems to have zero width, height or depth. Check dimensions");
356 }
357
358 const std::int64_t n_points = (nx + 1) * (ny + 1) * (nz + 1);
359 const auto [range_begin, range_end] = dolfinx::MPI::local_range(
360 dolfinx::MPI::rank(comm), n_points, dolfinx::MPI::size(comm));
361
362 std::vector<T> geom;
363 geom.reserve((range_end - range_begin) * 3);
364 const std::int64_t sqxy = (nx + 1) * (ny + 1);
365 for (std::int64_t v = range_begin; v < range_end; ++v)
366 {
367 // lexiographic index to spatial index
368 const std::int64_t p = v % sqxy;
369 std::array<std::int64_t, 3> idx = {p % (nx + 1), p / (nx + 1), v / sqxy};
370
371 // vertex = p0 + idx * extents (elementwise)
372 for (std::size_t i = 0; i < idx.size(); i++)
373 geom.push_back(p0[i] + static_cast<T>(idx[i]) * extents[i]);
374 }
375
376 return geom;
377}
378
379template <std::floating_point T>
380Mesh<T> build_tet(MPI_Comm comm, MPI_Comm subcomm,
381 std::array<std::array<T, 3>, 2> p,
382 std::array<std::int64_t, 3> n,
383 const CellPartitionFunction& partitioner,
384 const CellReorderFunction& reorder_fn)
385{
386 common::Timer timer("Build BoxMesh (tetrahedra)");
387 std::vector<T> x;
388 std::vector<std::int64_t> cells;
389 fem::CoordinateElement<T> element(CellType::tetrahedron, 1);
390 if (subcomm != MPI_COMM_NULL)
391 {
392 x = create_geom<T>(subcomm, p, n);
393
394 const auto [nx, ny, nz] = n;
395 const std::int64_t n_cells = nx * ny * nz;
396
397 std::array range_c = dolfinx::MPI::local_range(
398 dolfinx::MPI::rank(subcomm), n_cells, dolfinx::MPI::size(subcomm));
399 cells.reserve(6 * (range_c[1] - range_c[0]) * 4);
400
401 // Create tetrahedra
402 for (std::int64_t i = range_c[0]; i < range_c[1]; ++i)
403 {
404 const std::int64_t iz = i / (nx * ny);
405 const std::int64_t j = i % (nx * ny);
406 const std::int64_t iy = j / nx;
407 const std::int64_t ix = j % nx;
408 const std::int64_t v0 = iz * (nx + 1) * (ny + 1) + iy * (nx + 1) + ix;
409 const std::int64_t v1 = v0 + 1;
410 const std::int64_t v2 = v0 + (nx + 1);
411 const std::int64_t v3 = v1 + (nx + 1);
412 const std::int64_t v4 = v0 + (nx + 1) * (ny + 1);
413 const std::int64_t v5 = v1 + (nx + 1) * (ny + 1);
414 const std::int64_t v6 = v2 + (nx + 1) * (ny + 1);
415 const std::int64_t v7 = v3 + (nx + 1) * (ny + 1);
416
417 // Note that v0 < v1 < v2 < v3 < vmid
418 cells.insert(cells.end(),
419 {v0, v1, v3, v7, v0, v1, v7, v5, v0, v5, v7, v4,
420 v0, v3, v2, v7, v0, v6, v4, v7, v0, v2, v6, v7});
421 }
422 }
423
424 return create_mesh(comm, subcomm, cells, element, subcomm, x,
425 {x.size() / 3, 3}, partitioner, 2, reorder_fn);
426}
427
428template <std::floating_point T>
429mesh::Mesh<T>
430build_hex(MPI_Comm comm, MPI_Comm subcomm, std::array<std::array<T, 3>, 2> p,
431 std::array<std::int64_t, 3> n,
432 const CellPartitionFunction& partitioner,
433 const std::function<std::vector<std::int32_t>(
434 const graph::AdjacencyList<std::int32_t>&)>& reorder_fn)
435{
436 common::Timer timer("Build BoxMesh (hexahedra)");
437 std::vector<T> x;
438 std::vector<std::int64_t> cells;
439 fem::CoordinateElement<T> element(CellType::hexahedron, 1);
440 if (subcomm != MPI_COMM_NULL)
441 {
442 x = create_geom<T>(subcomm, p, n);
443
444 // Create cuboids
445 const auto [nx, ny, nz] = n;
446 const std::int64_t n_cells = nx * ny * nz;
447 std::array range_c = dolfinx::MPI::local_range(
448 dolfinx::MPI::rank(subcomm), n_cells, dolfinx::MPI::size(subcomm));
449 cells.reserve((range_c[1] - range_c[0]) * 8);
450 for (std::int64_t i = range_c[0]; i < range_c[1]; ++i)
451 {
452 const std::int64_t iz = i / (nx * ny);
453 const std::int64_t j = i % (nx * ny);
454 const std::int64_t iy = j / nx;
455 const std::int64_t ix = j % nx;
456
457 const std::int64_t v0 = (iz * (ny + 1) + iy) * (nx + 1) + ix;
458 const std::int64_t v1 = v0 + 1;
459 const std::int64_t v2 = v0 + (nx + 1);
460 const std::int64_t v3 = v1 + (nx + 1);
461 const std::int64_t v4 = v0 + (nx + 1) * (ny + 1);
462 const std::int64_t v5 = v1 + (nx + 1) * (ny + 1);
463 const std::int64_t v6 = v2 + (nx + 1) * (ny + 1);
464 const std::int64_t v7 = v3 + (nx + 1) * (ny + 1);
465 cells.insert(cells.end(), {v0, v1, v2, v3, v4, v5, v6, v7});
466 }
467 }
468
469 return create_mesh(comm, subcomm, cells, element, subcomm, x,
470 {x.size() / 3, 3}, partitioner, 2, reorder_fn);
471}
472
473template <std::floating_point T>
474Mesh<T> build_prism(MPI_Comm comm, MPI_Comm subcomm,
475 std::array<std::array<T, 3>, 2> p,
476 std::array<std::int64_t, 3> n,
477 const CellPartitionFunction& partitioner,
478 const CellReorderFunction& reorder_fn)
479{
480 std::vector<T> x;
481 std::vector<std::int64_t> cells;
482 fem::CoordinateElement<T> element(CellType::prism, 1);
483 if (subcomm != MPI_COMM_NULL)
484 {
485 x = create_geom<T>(subcomm, p, n);
486
487 const std::int64_t nx = n[0];
488 const std::int64_t ny = n[1];
489 const std::int64_t nz = n[2];
490 const std::int64_t n_cells = nx * ny * nz;
491 std::array range_c = dolfinx::MPI::local_range(
492 dolfinx::MPI::rank(comm), n_cells, dolfinx::MPI::size(comm));
493 const std::int64_t cell_range = range_c[1] - range_c[0];
494
495 // Create cuboids
496 cells.reserve(2 * cell_range * 6);
497 for (std::int64_t i = range_c[0]; i < range_c[1]; ++i)
498 {
499 const std::int64_t iz = i / (nx * ny);
500 const std::int64_t j = i % (nx * ny);
501 const std::int64_t iy = j / nx;
502 const std::int64_t ix = j % nx;
503
504 const std::int64_t v0 = (iz * (ny + 1) + iy) * (nx + 1) + ix;
505 const std::int64_t v1 = v0 + 1;
506 const std::int64_t v2 = v0 + (nx + 1);
507 const std::int64_t v3 = v1 + (nx + 1);
508 const std::int64_t v4 = v0 + (nx + 1) * (ny + 1);
509 const std::int64_t v5 = v1 + (nx + 1) * (ny + 1);
510 const std::int64_t v6 = v2 + (nx + 1) * (ny + 1);
511 const std::int64_t v7 = v3 + (nx + 1) * (ny + 1);
512 cells.insert(cells.end(), {v0, v1, v2, v4, v5, v6});
513 cells.insert(cells.end(), {v1, v2, v3, v5, v6, v7});
514 }
515 }
516
517 return create_mesh(comm, subcomm, cells, element, subcomm, x,
518 {x.size() / 3, 3}, partitioner, 2, reorder_fn);
519}
520
521template <std::floating_point T>
522Mesh<T> build_tri(MPI_Comm comm, std::array<std::array<T, 2>, 2> p,
523 std::array<std::int64_t, 2> n,
524 const CellPartitionFunction& partitioner,
525 DiagonalType diagonal, const CellReorderFunction& reorder_fn,
526 int gdim)
527{
528 fem::CoordinateElement<T> element(CellType::triangle, 1);
529 if (gdim < 2 || gdim > 3)
530 throw std::runtime_error("2 <= gdim <= 3 for tri mesh.");
531
532 if (dolfinx::MPI::rank(comm) == 0)
533 {
534 const auto [p0, p1] = p;
535 const auto [nx, ny] = n;
536
537 const auto [a, c] = p0;
538 const auto [b, d] = p1;
539
540 const T ab = (b - a) / static_cast<T>(nx);
541 const T cd = (d - c) / static_cast<T>(ny);
542 if (std::abs(b - a) < std::numeric_limits<T>::epsilon()
543 or std::abs(d - c) < std::numeric_limits<T>::epsilon())
544 {
545 throw std::runtime_error("Rectangle seems to have zero width, height or "
546 "depth. Check dimensions");
547 }
548
549 // Create vertices and cells
550 std::int64_t nv, nc;
551 switch (diagonal)
552 {
553 case DiagonalType::crossed:
554 nv = (nx + 1) * (ny + 1) + nx * ny;
555 nc = 4 * nx * ny;
556 break;
557 default:
558 nv = (nx + 1) * (ny + 1);
559 nc = 2 * nx * ny;
560 }
561
562 std::vector<T> x;
563 x.reserve(nv * 2);
564 std::vector<std::int64_t> cells;
565 cells.reserve(nc * 3);
566
567 // Create main vertices
568 for (std::int64_t iy = 0; iy <= ny; iy++)
569 {
570 T x1 = c + cd * static_cast<T>(iy);
571 for (std::int64_t ix = 0; ix <= nx; ix++)
572 x.insert(x.end(), {a + ab * static_cast<T>(ix), x1});
573 }
574
575 // Create midpoint vertices if the mesh type is crossed
576 switch (diagonal)
577 {
578 case DiagonalType::crossed:
579 for (std::int64_t iy = 0; iy < ny; iy++)
580 {
581 T x1 = c + cd * (static_cast<T>(iy) + 0.5);
582 for (std::int64_t ix = 0; ix < nx; ix++)
583 {
584 T x0 = a + ab * (static_cast<T>(ix) + 0.5);
585 x.insert(x.end(), {x0, x1});
586 }
587 }
588 break;
589 default:
590 break;
591 }
592
593 // Create triangles
594 switch (diagonal)
595 {
596 case DiagonalType::crossed:
597 {
598 for (std::int64_t iy = 0; iy < ny; iy++)
599 {
600 for (std::int64_t ix = 0; ix < nx; ix++)
601 {
602 std::int64_t v0 = iy * (nx + 1) + ix;
603 std::int64_t v1 = v0 + 1;
604 std::int64_t v2 = v0 + (nx + 1);
605 std::int64_t v3 = v1 + (nx + 1);
606 std::int64_t vmid = (nx + 1) * (ny + 1) + iy * nx + ix;
607
608 // Note that v0 < v1 < v2 < v3 < vmid
609 cells.insert(cells.end(), {v0, v1, vmid, v0, v2, vmid, v1, v3, vmid,
610 v2, v3, vmid});
611 }
612 }
613 break;
614 }
615 default:
616 {
617 DiagonalType local_diagonal = diagonal;
618 for (std::int64_t iy = 0; iy < ny; iy++)
619 {
620 // Set up alternating diagonal
621 switch (diagonal)
622 {
623 case DiagonalType::right_left:
624 if (iy % 2)
625 local_diagonal = DiagonalType::right;
626 else
627 local_diagonal = DiagonalType::left;
628 break;
629 case DiagonalType::left_right:
630 if (iy % 2)
631 local_diagonal = DiagonalType::left;
632 else
633 local_diagonal = DiagonalType::right;
634 break;
635 default:
636 break;
637 }
638 for (std::int64_t ix = 0; ix < nx; ix++)
639 {
640 std::int64_t v0 = iy * (nx + 1) + ix;
641 std::int64_t v1 = v0 + 1;
642 std::int64_t v2 = v0 + (nx + 1);
643 std::int64_t v3 = v1 + (nx + 1);
644 switch (local_diagonal)
645 {
646 case DiagonalType::left:
647 {
648 cells.insert(cells.end(), {v0, v1, v2, v1, v2, v3});
649 if (diagonal == DiagonalType::right_left
650 or diagonal == DiagonalType::left_right)
651 {
652 local_diagonal = DiagonalType::right;
653 }
654 break;
655 }
656 default:
657 {
658 cells.insert(cells.end(), {v0, v1, v3, v0, v2, v3});
659 if (diagonal == DiagonalType::right_left
660 or diagonal == DiagonalType::left_right)
661 {
662 local_diagonal = DiagonalType::left;
663 }
664 }
665 }
666 }
667 }
668 }
669 }
670
671 std::size_t npts = x.size() / 2;
672 if (gdim == 2)
673 {
674 return create_mesh(comm, MPI_COMM_SELF, cells, element, MPI_COMM_SELF, x,
675 {npts, 2}, partitioner, 2, reorder_fn);
676 }
677 std::vector<T> xg(npts * gdim, T(0));
678 for (std::size_t i = 0; i < npts; i++)
679 {
680 xg[i * gdim] = x[2 * i];
681 xg[i * gdim + 1] = x[2 * i + 1];
682 }
683 return create_mesh(comm, MPI_COMM_SELF, cells, element, MPI_COMM_SELF, xg,
684 {npts, static_cast<std::size_t>(gdim)}, partitioner, 2,
685 reorder_fn);
686 }
687 else
688 {
689 return create_mesh(comm, MPI_COMM_NULL, {}, element, MPI_COMM_NULL,
690 std::vector<T>{}, {0, static_cast<std::size_t>(gdim)},
691 partitioner, 2, reorder_fn);
692 }
693}
694
695template <std::floating_point T>
696Mesh<T> build_quad(MPI_Comm comm, std::array<std::array<T, 2>, 2> p,
697 std::array<std::int64_t, 2> n,
698 const CellPartitionFunction& partitioner,
699 const CellReorderFunction& reorder_fn, int gdim)
700{
701 if (gdim < 2 || gdim > 3)
702 throw std::runtime_error("2 <= gdim <= 3 for quad mesh.");
703
704 fem::CoordinateElement<T> element(CellType::quadrilateral, 1);
705 if (dolfinx::MPI::rank(comm) == 0)
706 {
707 const auto [nx, ny] = n;
708 const auto [a, c] = p[0];
709 const auto [b, d] = p[1];
710
711 const T ab = (b - a) / static_cast<T>(nx);
712 const T cd = (d - c) / static_cast<T>(ny);
713
714 // Create vertices
715 std::vector<T> x;
716 x.reserve((nx + 1) * (ny + 1) * 2);
717 for (std::int64_t ix = 0; ix <= nx; ix++)
718 {
719 T x0 = a + ab * static_cast<T>(ix);
720 for (std::int64_t iy = 0; iy <= ny; iy++)
721 x.insert(x.end(), {x0, c + cd * static_cast<T>(iy)});
722 }
723
724 // Create rectangles
725 std::vector<std::int64_t> cells;
726 cells.reserve(nx * ny * 4);
727 for (std::int64_t ix = 0; ix < nx; ix++)
728 {
729 for (std::int64_t iy = 0; iy < ny; iy++)
730 {
731 std::int64_t i0 = ix * (ny + 1);
732 cells.insert(cells.end(), {i0 + iy, i0 + iy + 1, i0 + iy + ny + 1,
733 i0 + iy + ny + 2});
734 }
735 }
736
737 std::size_t npts = x.size() / 2;
738 if (gdim == 2)
739 {
740 return create_mesh(comm, MPI_COMM_SELF, cells, element, MPI_COMM_SELF, x,
741 {npts, 2}, partitioner, 2, reorder_fn);
742 }
743 std::vector<T> xg(npts * gdim, T(0));
744 for (std::size_t i = 0; i < npts; i++)
745 {
746 xg[i * gdim] = x[2 * i];
747 xg[i * gdim + 1] = x[2 * i + 1];
748 }
749 return create_mesh(comm, MPI_COMM_SELF, cells, element, MPI_COMM_SELF, xg,
750 {npts, static_cast<std::size_t>(gdim)}, partitioner, 2,
751 reorder_fn);
752 }
753 else
754 {
755 return create_mesh(comm, MPI_COMM_NULL, {}, element, MPI_COMM_NULL,
756 std::vector<T>{}, {0, static_cast<std::size_t>(gdim)},
757 partitioner, 2, reorder_fn);
758 }
759}
760} // namespace impl
761} // namespace dolfinx::mesh
Definition CoordinateElement.h:38
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:89
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::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:363
Mesh data structures and algorithms on meshes.
Definition DofMap.h:32
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, int gdim=2, const CellReorderFunction &reorder_fn=graph::reorder_gps)
Create a uniform mesh::Mesh over the rectangle spanned by the two points p.
Definition generation.h:183
CellPartitionFunction create_cell_partitioner(mesh::GhostMode ghost_mode, const graph::partition_fn &partfn, std::optional< std::int32_t > max_facet_to_cell_links)
Create a function that computes destination rank for mesh cells on this rank by applying the default ...
Definition utils.cpp:100
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:220
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:212
DiagonalType
Enum for different diagonal types.
Definition generation.h:29
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, const CellReorderFunction &reorder_fn=graph::reorder_gps)
Create a uniform mesh::Mesh over rectangular prism spanned by the two points p.
Definition generation.h:105
CellType
Cell type identifier.
Definition cell_types.h:21
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:414
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:1046
GhostMode
Enum for different partitioning ghost modes.
Definition utils.h:44
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, int gdim=1, const CellReorderFunction &reorder_fn=graph::reorder_gps)
Interval mesh of the 1D line [a, b].
Definition generation.h:258