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
226void check_entity_cell_mapping(const Topology& topology_c,
227 const Topology& topology, int dim);
228
248template <typename E>
249 requires(std::remove_cvref_t<E>::rank() == 1
250 or std::remove_cvref_t<E>::rank() == 2)
251 and std::same_as<typename std::remove_cvref_t<E>::value_type,
252 std::int32_t>
253std::vector<std::int32_t> extract_cells_from_entities(
254 const Topology& topology_c, const Topology& topology, E entities,
255 std::optional<std::reference_wrapper<const EntityMap>> entity_map)
256{
257 auto span_to_vector = [](auto entities)
258 {
259 assert(entities.rank() == 1);
260
261 std::vector<std::int32_t> vec;
262 vec.reserve(entities.extent(0));
263 for (std::size_t i = 0; i < entities.extent(0); ++i)
264 vec.push_back(entities[i]);
265 return vec;
266 };
267
268 if (&topology_c == &topology)
269 {
270 // If same topology no mapping is needed
271 if constexpr (entities.rank() == 1)
272 return span_to_vector(entities);
273 else
274 // If (cell, local_index) pairs are given, extract the cells
275 return span_to_vector(md::submdspan(entities, md::full_extent, 0));
276 }
277
278 if (!entity_map)
279 {
280 throw std::invalid_argument(
281 "An entity map is required when topology_c is not topology.");
282 }
283 const EntityMap& emap = entity_map->get();
284 const int tdim = topology.dim();
285 const int codim = tdim - topology_c.dim();
286 const bool inverse = emap.sub_topology().get() == &topology_c;
287 if constexpr (entities.rank() == 1)
288 {
289 // Cells map directly to cells only between equal dimensions
290 if (codim != 0)
291 {
292 throw std::invalid_argument(
293 std::format("Cannot map cells of a topology of dimension {} to "
294 "cells of a topology of dimension {}.",
295 tdim, topology_c.dim()));
296 }
297 return emap.sub_topology_to_topology(span_to_vector(entities), inverse);
298 }
299 else
300 {
301 if (codim == 0)
302 {
303 // If codim is zero we extract the cells and map them
304 auto cells = md::submdspan(entities, md::full_extent, 0);
305 return emap.sub_topology_to_topology(span_to_vector(cells), inverse);
306 }
307 else
308 {
309 // Any other codim needs to map (cell, local index) to entities and
310 // then to cells of `topology_c`
311 if (!inverse)
312 {
313 throw std::invalid_argument(
314 "Unsupported mapping. Can only map from submesh to parent mesh.");
315 }
316 assert(codim > 0);
317 std::shared_ptr<const graph::AdjacencyList<std::int32_t>> c_to_e
318 = topology.connectivity(tdim, tdim - codim);
319 if (!c_to_e)
320 {
321 throw std::runtime_error(
322 std::format("Topology connectivity from dimension {} to {} not "
323 "found.",
324 tdim, tdim - codim));
325 }
326 // Map (cell, local_index) to entity of `topology`
327 std::vector<std::int32_t> sub_entities;
328 sub_entities.reserve(entities.extent(0));
329 for (std::size_t e = 0; e < entities.extent(0); ++e)
330 sub_entities.push_back(c_to_e->links(entities(e, 0))[entities(e, 1)]);
331
332 // Map entity of `topology` to cell of `topology_c`
333 return emap.sub_topology_to_topology(sub_entities, inverse);
334 }
335 }
336}
337} // 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:52
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:959
int dim() const noexcept
Topological dimension of the mesh.
Definition Topology.cpp:898
Requirement on range of cell indices.
Definition Topology.h:35
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 entities of a topology to the cells of a related topology, e.g. the integration entities of a for...
Definition EntityMap.h:253
void check_entity_cell_mapping(const Topology &topology_c, const Topology &topology, int dim)
Check that entities of a topology can be mapped to cells of a related topology.
Definition EntityMap.cpp:54