DOLFINx 0.12.0.0
DOLFINx C++
Loading...
Searching...
No Matches
interval.h
1// Copyright (C) 2024 Paul T. Kühner
2// Copyright (C) 2026 Garth N. Wells
3//
4// This file is part of DOLFINX (https://www.fenicsproject.org)
5//
6// SPDX-License-Identifier: LGPL-3.0-or-later
7
8#pragma once
9
10#include "dolfinx/common/IndexMap.h"
11#include "dolfinx/mesh/Mesh.h"
12#include "dolfinx/mesh/cell_types.h"
13#include "dolfinx/mesh/utils.h"
14#include "dolfinx/refinement/plaza.h"
15#include <algorithm>
16#include <concepts>
17#include <cstddef>
18#include <cstdint>
19#include <mpi.h>
20#include <optional>
21#include <stdexcept>
22#include <vector>
23
24#include "dolfinx/refinement/option.h"
25#include "dolfinx/refinement/utils.h"
26
27namespace dolfinx::refinement::interval
28{
37template <std::floating_point T>
38std::tuple<graph::AdjacencyList<std::int64_t>, std::vector<T>,
39 std::array<std::size_t, 2>, std::optional<std::vector<std::int32_t>>,
40 std::optional<std::vector<std::int8_t>>>
41compute_refinement_data(const mesh::Mesh<T>& mesh,
42 std::optional<std::span<const std::int32_t>> cells,
43 Option option)
44{
45 bool compute_parent_facet = option_parent_facet(option);
46 bool compute_parent_cell = option_parent_cell(option);
47
48 if (compute_parent_facet)
49 throw std::invalid_argument("Parent facet computation not yet supported!");
50
51 auto topology = mesh.topology();
52 assert(topology);
53 assert(topology->dim() == 1);
54 auto map_c = topology->index_map(1);
55 assert(map_c);
56
57 // Ranks sharing an owned or ghost cell with this rank, and for each
58 // cell the sharing ranks as positions in ranks
59 auto [ranks, _data, _offsets] = common::compute_sharing_neighbourhood(*map_c);
60 graph::AdjacencyList<int> cell_ranks(std::move(_data), std::move(_offsets));
61
62 // Create refinement flag for cells
63 std::vector<std::int8_t> refinement_marker(
64 map_c->size_local() + map_c->num_ghosts(), !cells.has_value());
65
66 // Mark cells for refinement
67 std::vector<std::vector<std::int32_t>> marked_for_update(ranks.size());
68 if (cells)
69 {
70 std::ranges::for_each(
71 cells.value(),
72 [&refinement_marker, &cell_ranks, &marked_for_update](auto cell)
73 {
74 if (!refinement_marker[cell])
75 {
76 refinement_marker[cell] = true;
77 for (int rank : cell_ranks.links(cell))
78 marked_for_update[rank].push_back(cell);
79 }
80 });
81 }
82
83 // Create neighborhood communicator for vertex creation
84 MPI_Comm neighbor_comm;
85 MPI_Dist_graph_create_adjacent(
86 mesh.comm(), ranks.size(), ranks.data(), MPI_UNWEIGHTED, ranks.size(),
87 ranks.data(), MPI_UNWEIGHTED, MPI_INFO_NULL, false, &neighbor_comm);
88
89 // Communicate ghost cells that might have been marked. This is not
90 // necessary for a uniform refinement.
91 if (cells)
92 {
93 update_logical_edgefunction(neighbor_comm, marked_for_update,
94 refinement_marker, *map_c);
95 }
96
97 // Construct the new vertices
98 const auto [new_vertex_map, new_vertex_coords, xshape]
99 = create_new_vertices(neighbor_comm, cell_ranks, mesh, refinement_marker);
100 MPI_Comm_free(&neighbor_comm);
101
102 auto c_to_v = mesh.topology()->connectivity(1, 0);
103 assert(c_to_v);
104
105 // Get the count of cells to refine, note: we only consider non-ghost
106 // cells
107 const std::int32_t number_of_refined_cells
108 = std::count(refinement_marker.begin(),
109 std::next(refinement_marker.begin(),
110 mesh.topology()->index_map(1)->size_local()),
111 true);
112
113 // Produce local global indices, by padding out the previous index map
114 std::vector<std::int64_t> global_indices
115 = adjust_indices(*mesh.topology()->index_map(0), number_of_refined_cells);
116
117 // Build the topology on the new vertices
118 std::size_t refined_cell_count
119 = mesh.topology()->index_map(1)->size_local() + number_of_refined_cells;
120
121 std::vector<std::int64_t> cell_topology;
122 cell_topology.reserve(refined_cell_count * 2);
123
124 std::optional<std::vector<std::int32_t>> parent_cell(std::nullopt);
125 if (compute_parent_cell)
126 {
127 parent_cell.emplace();
128 parent_cell->reserve(refined_cell_count);
129 }
130
131 for (std::int32_t cell = 0; cell < map_c->size_local(); ++cell)
132 {
133 std::span vertices = c_to_v->links(cell);
134 assert(vertices.size() == 2);
135
136 // We consider a cell (defined by global vertices)
137 // a ----------- b
138 const std::int64_t a = global_indices[vertices[0]];
139 const std::int64_t b = global_indices[vertices[1]];
140 if (refinement_marker[cell])
141 {
142 // Find (global) index of new midpoint vertex:
143 // a --- c --- b
144 std::span nv = new_vertex_map.links(cell);
145 assert(nv.size() == 1);
146 const std::int64_t c = nv[0];
147
148 // Add new cells/edges to refined topology
149 cell_topology.insert(cell_topology.end(), {a, c, c, b});
150
151 if (compute_parent_cell)
152 parent_cell->insert(parent_cell->end(), {cell, cell});
153 }
154 else
155 {
156 // Copy the previous cell
157 cell_topology.insert(cell_topology.end(), {a, b});
158
159 if (compute_parent_cell)
160 parent_cell->push_back(cell);
161 }
162 }
163
164 assert(cell_topology.size() == 2 * refined_cell_count);
165 assert(!compute_parent_cell or parent_cell->size() == refined_cell_count);
166
167 std::vector<std::int32_t> offsets(refined_cell_count + 1);
168 std::ranges::generate(offsets, [i = 0]() mutable { return 2 * i++; });
169 graph::AdjacencyList cell_adj(std::move(cell_topology), std::move(offsets));
170
171 return {std::move(cell_adj), std::move(new_vertex_coords), xshape,
172 std::move(parent_cell), std::nullopt};
173}
174
175} // namespace dolfinx::refinement::interval
Functions supporting mesh operations.
std::tuple< std::vector< int >, std::vector< int >, std::vector< std::int32_t > > compute_sharing_neighbourhood(const IndexMap &imap)
Compute the symmetric neighbourhood of ranks that share an owned or ghost index with the caller.
Definition IndexMap.cpp:984
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:40
@ cell
Cell.
Definition Form.h:44
std::tuple< graph::AdjacencyList< std::int64_t >, std::vector< T >, std::array< std::size_t, 2 > > create_new_vertices(MPI_Comm comm, const graph::AdjacencyList< int > &shared_edges, const mesh::Mesh< T > &mesh, std::span< const std::int8_t > marked_edges)
Add new vertex for each marked edge, and create new_vertex_coordinates and global_edge->new_vertex ma...
Definition utils.h:148
constexpr bool option_parent_cell(Option a)
Check if parent_cell flag is set.
Definition option.h:45
Option
Options for data to compute during mesh refinement.
Definition option.h:16
@ parent_cell
Definition option.h:20
constexpr bool option_parent_facet(Option a)
Check if parent_facet flag is set.
Definition option.h:36
std::vector< std::int64_t > adjust_indices(const common::IndexMap &map, std::int32_t n)
Given an index map, add "n" extra indices at the end of local range.
Definition utils.cpp:105
void update_logical_edgefunction(MPI_Comm comm, const std::vector< std::vector< std::int32_t > > &marked_for_update, std::span< std::int8_t > marked_edges, const common::IndexMap &map)
Communicate edge markers between processes that share edges.
Definition utils.cpp:49