DOLFINx 0.12.0.0
DOLFINx C++
Loading...
Searching...
No Matches
EntityMap.h
1// Copyright (C) 2025-2026 Jørgen S. Dokken and Joseph P. Dean
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 "Topology.h"
10#include <algorithm>
11#include <basix/mdspan.hpp>
12#include <cassert>
13#include <concepts>
14#include <cstdint>
15#include <dolfinx/common/IndexMap.h>
16#include <dolfinx/common/types.h>
17#include <dolfinx/graph/AdjacencyList.h>
18#include <format>
19#include <functional>
20#include <iterator>
21#include <memory>
22#include <optional>
23#include <ranges>
24#include <span>
25#include <stdexcept>
26#include <type_traits>
27#include <unordered_map>
28#include <utility>
29#include <vector>
30
31namespace dolfinx::mesh
32{
36{
37public:
51 template <typename U>
52 requires std::is_convertible_v<std::remove_cvref_t<U>,
53 std::vector<std::int32_t>>
54 EntityMap(std::shared_ptr<const Topology> topology,
55 std::shared_ptr<const Topology> sub_topology, int dim,
57 : _dim(dim), _topology(topology),
58 _sub_topology_to_topology(std::forward<U>(sub_topology_to_topology)),
59 _sub_topology(sub_topology)
60 {
61 if (!topology)
62 throw std::invalid_argument("topology must not be null.");
63 if (!sub_topology)
64 throw std::invalid_argument("sub_topology must not be null.");
65 if (dim < 0 or dim > topology->dim() or dim > sub_topology->dim())
66 {
67 throw std::invalid_argument(
68 "dim out of range for topology/sub_topology.");
69 }
70
71 auto e_imap = sub_topology->index_map(_dim);
72 std::size_t num_ents = e_imap->size_local() + e_imap->num_ghosts();
73 if (num_ents != _sub_topology_to_topology.size())
74 {
75 throw std::invalid_argument(
76 "Size mismatch between `sub_topology_to_topology` and index map.");
77 }
78 }
79
81 EntityMap(const EntityMap& map) = default;
82
84 EntityMap(EntityMap&& map) = default;
85
87 ~EntityMap() = default;
88
89 // Copy assignment (deleted)
90 EntityMap& operator=(const EntityMap& map) = delete;
91
93 EntityMap& operator=(EntityMap&& map) = default;
94
98 int dim() const;
99
102 std::shared_ptr<const Topology> topology() const;
103
106 std::shared_ptr<const Topology> sub_topology() const;
107
128 std::vector<std::int32_t> sub_topology_to_topology(CellRange auto&& entities,
129 bool inverse) const
130 {
131 std::size_t num_entities = std::ranges::size(entities);
132 if (!inverse)
133 {
134 // In this case, we want to map from entity indices in
135 // `_sub_topology` to corresponding entities in `_topology`. Hence,
136 // for each index in `entities`, we get the corresponding index in
137 // `_topology` using `_sub_topology_to_topology`
138 auto mapped
139 = std::forward<decltype(entities)>(entities)
140 | std::views::transform([this](std::int32_t i)
141 { return _sub_topology_to_topology[i]; });
142 std::vector<std::int32_t> mapped_v;
143 mapped_v.reserve(num_entities);
144 std::ranges::copy(mapped, std::back_inserter(mapped_v));
145 return mapped_v;
146 }
147 else
148 {
149 // In this case, we are mapping from entity indices in `_topology`
150 // to entity indices in `_sub_topology`. Hence, we first need to
151 // construct the "inverse" of `_sub_topology_to_topology`
152 std::unordered_map<std::int32_t, std::int32_t> topology_to_sub_topology;
153 topology_to_sub_topology.reserve(_sub_topology_to_topology.size());
154 for (std::size_t i = 0; i < _sub_topology_to_topology.size(); ++i)
155 {
156 topology_to_sub_topology.insert(
157 {_sub_topology_to_topology[i], static_cast<std::int32_t>(i)});
158 }
159
160 // For each entity index in `entities` (which are indices in
161 // `_topology`), get the corresponding entity in `_sub_topology`.
162 // Since `_sub_topology` consists of a subset of entities in
163 // `_topology`, there are entities in topology that may not exist in
164 // `_sub_topology`. If this is the case, mark those entities with
165 // -1.
166
167 auto mapped = std::forward<decltype(entities)>(entities)
168 | std::views::transform(
169 [&topology_to_sub_topology](std::int32_t i)
170 {
171 // Map the entity if it exists. If it doesn't, mark
172 // with -1.
173 auto it = topology_to_sub_topology.find(i);
174 return (it != topology_to_sub_topology.end())
175 ? it->second
176 : -1;
177 });
178 std::vector<std::int32_t> mapped_v;
179 mapped_v.reserve(num_entities);
180 std::ranges::copy(mapped, std::back_inserter(mapped_v));
181 return mapped_v;
182 }
183 }
184
185private:
186 // Dimension of the entities
187 int _dim;
188
189 // A topology
190 std::shared_ptr<const Topology> _topology;
191
192 // A list of `_dim`-dimensional entities in _topology, where
193 // `_sub_topology_to_topology[i]` is the index in `_topology` of the
194 // `i`th entity in `_sub_topology`
195 std::vector<std::int32_t> _sub_topology_to_topology;
196
197 // A second topology, consisting of a subset of entities in
198 // `_topology`
199 std::shared_ptr<const Topology> _sub_topology;
200};
201
208const EntityMap& find_entity_map(
209 std::span<const std::reference_wrapper<const EntityMap>> entity_maps,
210 const Topology& topology0, const Topology& topology1);
211
226template <typename E>
227 requires(std::remove_cvref_t<E>::rank() == 1
228 or std::remove_cvref_t<E>::rank() == 2)
229 and std::same_as<typename std::remove_cvref_t<E>::value_type,
230 std::int32_t>
231std::vector<std::int32_t> extract_cells_from_entities(
232 const Topology& topology_c, const Topology& topology, E entities,
233 std::optional<std::reference_wrapper<const EntityMap>> entity_map)
234{
235 auto span_to_vector = [](auto entities)
236 {
237 assert(entities.rank() == 1);
238
239 std::vector<std::int32_t> vec;
240 vec.reserve(entities.extent(0));
241 for (std::size_t i = 0; i < entities.extent(0); ++i)
242 vec.push_back(entities[i]);
243 return vec;
244 };
245
246 if (&topology_c == &topology)
247 {
248 // If same topology no mapping is needed
249 if constexpr (entities.rank() == 1)
250 return span_to_vector(entities);
251 else
252 // If (cell, local_index) pairs are given, extract the cells
253 return span_to_vector(md::submdspan(entities, md::full_extent, 0));
254 }
255
256 if (!entity_map)
257 {
258 throw std::invalid_argument(
259 "An entity map is required when topology_c is not topology.");
260 }
261 const EntityMap& emap = entity_map->get();
262 const int tdim = topology.dim();
263 const int codim = tdim - topology_c.dim();
264 const bool inverse = emap.sub_topology().get() == &topology_c;
265 if constexpr (entities.rank() == 1)
266 {
267 // Cells map directly to cells only between equal dimensions
268 if (codim != 0)
269 {
270 throw std::invalid_argument(
271 std::format("Cannot map cells of a topology of dimension {} to "
272 "cells of a topology of dimension {}.",
273 tdim, topology_c.dim()));
274 }
275 return emap.sub_topology_to_topology(span_to_vector(entities), inverse);
276 }
277 else
278 {
279 if (codim == 0)
280 {
281 // If codim is zero we extract the cells and map them
282 auto cells = md::submdspan(entities, md::full_extent, 0);
283 return emap.sub_topology_to_topology(span_to_vector(cells), inverse);
284 }
285 else
286 {
287 // Any other codim needs to map (cell, local index) to entities and
288 // then to cells of `topology_c`
289 if (!inverse)
290 {
291 throw std::invalid_argument(
292 "Unsupported mapping. Can only map from submesh to parent mesh.");
293 }
294 assert(codim > 0);
295 std::shared_ptr<const graph::AdjacencyList<std::int32_t>> c_to_e
296 = topology.connectivity(tdim, tdim - codim);
297 if (!c_to_e)
298 {
299 throw std::runtime_error(
300 std::format("Topology connectivity from dimension {} to {} not "
301 "found.",
302 tdim, tdim - codim));
303 }
304 // Map (cell, local_index) to entity of `topology`
305 std::vector<std::int32_t> sub_entities;
306 sub_entities.reserve(entities.extent(0));
307 for (std::size_t e = 0; e < entities.extent(0); ++e)
308 sub_entities.push_back(c_to_e->links(entities(e, 0))[entities(e, 1)]);
309
310 // Map entity of `topology` to cell of `topology_c`
311 return emap.sub_topology_to_topology(sub_entities, inverse);
312 }
313 }
314}
315} // namespace dolfinx::mesh
A bidirectional map relating entities in one topology to another.
Definition EntityMap.h:36
EntityMap(EntityMap &&map)=default
Move constructor.
std::vector< std::int32_t > sub_topology_to_topology(CellRange auto &&entities, bool inverse) const
Map entities between the sub-topology and the parent topology.
Definition EntityMap.h:128
~EntityMap()=default
Destructor.
EntityMap(std::shared_ptr< const Topology > topology, std::shared_ptr< const Topology > sub_topology, int dim, U &&sub_topology_to_topology)
Constructor of a bidirectional map relating entities of dimension dim in topology and sub_topology.
Definition EntityMap.h:54
EntityMap(const EntityMap &map)=default
Copy constructor.
int dim() const
Get the topological dimension of the entities related by this EntityMap.
Definition EntityMap.cpp:18
std::shared_ptr< const Topology > sub_topology() const
Get the sub-topology.
Definition EntityMap.cpp:25
std::shared_ptr< const Topology > topology() const
Get the (parent) topology.
Definition EntityMap.cpp:20
EntityMap & operator=(EntityMap &&map)=default
Move assignment.
Topology stores the topology of a mesh, consisting of mesh entities and connectivity (incidence relat...
Definition Topology.h:49
std::shared_ptr< const graph::AdjacencyList< std::int32_t > > connectivity(std::array< int, 2 > d0, std::array< int, 2 > d1) const
Get the connectivity from entities of topological dimension d0 to dimension d1.
Definition Topology.cpp:958
int dim() const noexcept
Topological dimension of the mesh.
Definition Topology.cpp:897
Requirement on range of cell indices.
Definition Topology.h:32
Mesh data structures and algorithms on meshes.
Definition DofMap.h:32
const EntityMap & find_entity_map(std::span< const std::reference_wrapper< const EntityMap > > entity_maps, const Topology &topology0, const Topology &topology1)
Find the entity map relating two topologies.
Definition EntityMap.cpp:31
std::vector< std::int32_t > extract_cells_from_entities(const Topology &topology_c, const Topology &topology, E entities, std::optional< std::reference_wrapper< const EntityMap > > entity_map)
Map integration entities of a topology to the cells of a related topology.
Definition EntityMap.h:231