DOLFINx 0.8.0
DOLFINx C++ interface
Loading...
Searching...
No Matches
Geometry.h
1// Copyright (C) 2006-2022 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 "Topology.h"
10#include <basix/mdspan.hpp>
11#include <concepts>
12#include <cstdint>
13#include <dolfinx/common/IndexMap.h>
14#include <dolfinx/common/MPI.h>
15#include <dolfinx/common/sort.h>
16#include <dolfinx/fem/CoordinateElement.h>
17#include <dolfinx/fem/ElementDofLayout.h>
18#include <dolfinx/fem/dofmapbuilder.h>
19#include <dolfinx/graph/AdjacencyList.h>
20#include <dolfinx/graph/partition.h>
21#include <functional>
22#include <memory>
23#include <span>
24#include <utility>
25#include <vector>
26
27namespace dolfinx::mesh
28{
29
31template <std::floating_point T>
33{
34public:
36 using value_type = T;
37
49 template <typename U, typename V, typename W>
50 requires std::is_convertible_v<std::remove_cvref_t<U>,
51 std::vector<std::int32_t>>
52 and std::is_convertible_v<std::remove_cvref_t<V>,
53 std::vector<T>>
54 and std::is_convertible_v<std::remove_cvref_t<W>,
55 std::vector<std::int64_t>>
57 std::shared_ptr<const common::IndexMap> index_map, U&& dofmap,
59 typename std::remove_reference_t<typename V::value_type>>& element,
60 V&& x, int dim, W&& input_global_indices)
61 : _dim(dim), _dofmaps({dofmap}), _index_map(index_map), _cmaps({element}),
62 _x(std::forward<V>(x)),
63 _input_global_indices(std::forward<W>(input_global_indices))
64 {
65 assert(_x.size() % 3 == 0);
66 if (_x.size() / 3 != _input_global_indices.size())
67 throw std::runtime_error("Geometry size mis-match");
68 }
69
81 template <typename V, typename W>
82 requires std::is_convertible_v<std::remove_cvref_t<V>, std::vector<T>>
83 and std::is_convertible_v<std::remove_cvref_t<W>,
84 std::vector<std::int64_t>>
86 std::shared_ptr<const common::IndexMap> index_map,
87 const std::vector<std::vector<std::int32_t>>& dofmaps,
88 const std::vector<fem::CoordinateElement<
89 typename std::remove_reference_t<typename V::value_type>>>& elements,
90 V&& x, int dim, W&& input_global_indices)
91 : _dim(dim), _dofmaps(dofmaps), _index_map(index_map), _cmaps(elements),
92 _x(std::forward<V>(x)),
93 _input_global_indices(std::forward<W>(input_global_indices))
94 {
95 assert(_x.size() % 3 == 0);
96 if (_x.size() / 3 != _input_global_indices.size())
97 throw std::runtime_error("Geometry size mis-match");
98 }
99
101 Geometry(const Geometry&) = default;
102
104 Geometry(Geometry&&) = default;
105
107 ~Geometry() = default;
108
110 Geometry& operator=(const Geometry&) = delete;
111
114
116 int dim() const { return _dim; }
117
120 MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
121 const std::int32_t,
122 MDSPAN_IMPL_STANDARD_NAMESPACE::dextents<std::size_t, 2>>
123 dofmap() const
124 {
125 if (_dofmaps.size() != 1)
126 throw std::runtime_error("Multiple dofmaps");
127
128 int ndofs = _cmaps.front().dim();
129 return MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
130 const std::int32_t,
131 MDSPAN_IMPL_STANDARD_NAMESPACE::dextents<std::size_t, 2>>(
132 _dofmaps.front().data(), _dofmaps.front().size() / ndofs, ndofs);
133 }
134
139 MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
140 const std::int32_t,
141 MDSPAN_IMPL_STANDARD_NAMESPACE::dextents<std::size_t, 2>>
142 dofmap(std::int32_t i) const
143 {
144 if (i < 0 or i >= (int)_dofmaps.size())
145 {
146 throw std::out_of_range("Cannot get dofmap:" + std::to_string(i)
147 + " out of range");
148 }
149 int ndofs = _cmaps[i].dim();
150
151 return MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
152 const std::int32_t,
153 MDSPAN_IMPL_STANDARD_NAMESPACE::dextents<std::size_t, 2>>(
154 _dofmaps[i].data(), _dofmaps[i].size() / ndofs, ndofs);
155 }
156
159 std::shared_ptr<const common::IndexMap> index_map() const
160 {
161 return _index_map;
162 }
163
168 std::span<const value_type> x() const { return _x; }
169
175 std::span<value_type> x() { return _x; }
176
181 {
182 if (_cmaps.size() != 1)
183 throw std::runtime_error("Multiple cmaps.");
184 return _cmaps.front();
185 }
186
190 const fem::CoordinateElement<value_type>& cmap(std::int32_t i) const
191 {
192 if (i < 0 or i >= (int)_cmaps.size())
193 {
194 throw std::out_of_range("Cannot get cmap:" + std::to_string(i)
195 + " out of range");
196 }
197 return _cmaps[i];
198 }
199
201 const std::vector<std::int64_t>& input_global_indices() const
202 {
203 return _input_global_indices;
204 }
205
206private:
207 // Geometric dimension
208 int _dim;
209
210 // Map per cell for extracting coordinate data for each cmap
211 std::vector<std::vector<std::int32_t>> _dofmaps;
212
213 // IndexMap for geometry 'dofmap'
214 std::shared_ptr<const common::IndexMap> _index_map;
215
216 // The coordinate elements
217 std::vector<fem::CoordinateElement<value_type>> _cmaps;
218
219 // Coordinates for all points stored as a contiguous array (row-major,
220 // column size = 3)
221 std::vector<value_type> _x;
222
223 // Global indices as provided on Geometry creation
224 std::vector<std::int64_t> _input_global_indices;
225};
226
229template <typename U, typename V, typename W>
230Geometry(std::shared_ptr<const common::IndexMap>, U,
231 const std::vector<fem::CoordinateElement<
232 typename std::remove_reference_t<typename V::value_type>>>&,
233 V, int,
234 W) -> Geometry<typename std::remove_cvref_t<typename V::value_type>>;
236
261template <typename U>
262Geometry<typename std::remove_reference_t<typename U::value_type>>
264 const Topology& topology,
265 const std::vector<fem::CoordinateElement<
266 std::remove_reference_t<typename U::value_type>>>& elements,
267 std::span<const std::int64_t> nodes, std::span<const std::int64_t> xdofs,
268 const U& x, int dim,
269 std::function<std::vector<int>(const graph::AdjacencyList<std::int32_t>&)>
270 reorder_fn
271 = nullptr)
272{
273 LOG(INFO) << "Create Geometry (multiple)";
274
275 assert(std::is_sorted(nodes.begin(), nodes.end()));
276 using T = typename std::remove_reference_t<typename U::value_type>;
277
278 // Check elements match cell types in topology
279 const int tdim = topology.dim();
280 const std::size_t num_cell_types = topology.entity_types(tdim).size();
281 if (elements.size() != num_cell_types)
282 throw std::runtime_error("Mismatch between topology and geometry.");
283
284 std::vector<fem::ElementDofLayout> dof_layouts;
285 for (const auto& el : elements)
286 dof_layouts.push_back(el.create_dof_layout());
287
288 LOG(INFO) << "Got " << dof_layouts.size() << " dof layouts";
289
290 // Build 'geometry' dofmap on the topology
291 auto [_dof_index_map, bs, dofmaps]
292 = fem::build_dofmap_data(topology.index_map(topology.dim())->comm(),
293 topology, dof_layouts, reorder_fn);
294 auto dof_index_map
295 = std::make_shared<common::IndexMap>(std::move(_dof_index_map));
296
297 // If the mesh has higher order geometry, permute the dofmap
298 if (elements.front().needs_dof_permutations())
299 {
300 const std::int32_t num_cells
301 = topology.connectivity(topology.dim(), 0)->num_nodes();
302 const std::vector<std::uint32_t>& cell_info
303 = topology.get_cell_permutation_info();
304 int d = elements.front().dim();
305 for (std::int32_t cell = 0; cell < num_cells; ++cell)
306 {
307 std::span dofs(dofmaps.front().data() + cell * d, d);
308 elements.front().permute_inv(dofs, cell_info[cell]);
309 }
310 }
311
312 LOG(INFO) << "Calling compute_local_to_global";
313 // Compute local-to-global map from local indices in dofmap to the
314 // corresponding global indices in cells, and pass to function to
315 // compute local (dof) to local (position in coords) map from (i)
316 // local-to-global for dofs and (ii) local-to-global for entries in
317 // coords
318
319 LOG(INFO) << "xdofs.size = " << xdofs.size();
320 std::vector<std::int32_t> all_dofmaps;
321 std::stringstream s;
322 for (auto q : dofmaps)
323 {
324 s << q.size() << " ";
325 all_dofmaps.insert(all_dofmaps.end(), q.begin(), q.end());
326 }
327 LOG(INFO) << "dofmap sizes = " << s.str();
328 LOG(INFO) << "all_dofmaps.size = " << all_dofmaps.size();
329 LOG(INFO) << "nodes.size = " << nodes.size();
330
331 const std::vector<std::int32_t> l2l = graph::build::compute_local_to_local(
332 graph::build::compute_local_to_global(xdofs, all_dofmaps), nodes);
333
334 // Allocate space for input global indices and copy data
335 std::vector<std::int64_t> igi(nodes.size());
336 std::transform(l2l.cbegin(), l2l.cend(), igi.begin(),
337 [&nodes](auto index) { return nodes[index]; });
338
339 // Build coordinate dof array, copying coordinates to correct position
340 assert(x.size() % dim == 0);
341 const std::size_t shape0 = x.size() / dim;
342 const std::size_t shape1 = dim;
343 std::vector<T> xg(3 * shape0, 0);
344 for (std::size_t i = 0; i < shape0; ++i)
345 {
346 std::copy_n(std::next(x.begin(), shape1 * l2l[i]), shape1,
347 std::next(xg.begin(), 3 * i));
348 }
349
350 LOG(INFO) << "Creating geometry with " << dofmaps.size() << " dofmaps";
351
352 return Geometry(dof_index_map, std::move(dofmaps), elements, std::move(xg),
353 dim, std::move(igi));
354}
355
379template <typename U>
380Geometry<typename std::remove_reference_t<typename U::value_type>>
382 const Topology& topology,
384 std::remove_reference_t<typename U::value_type>>& element,
385 std::span<const std::int64_t> nodes, std::span<const std::int64_t> xdofs,
386 const U& x, int dim,
387 std::function<std::vector<int>(const graph::AdjacencyList<std::int32_t>&)>
388 reorder_fn
389 = nullptr)
390{
391 assert(std::is_sorted(nodes.begin(), nodes.end()));
392 using T = typename std::remove_reference_t<typename U::value_type>;
393
394 fem::ElementDofLayout dof_layout = element.create_dof_layout();
395
396 // Build 'geometry' dofmap on the topology
397 auto [_dof_index_map, bs, dofmaps]
398 = fem::build_dofmap_data(topology.index_map(topology.dim())->comm(),
399 topology, {dof_layout}, reorder_fn);
400 auto dof_index_map
401 = std::make_shared<common::IndexMap>(std::move(_dof_index_map));
402
403 // If the mesh has higher order geometry, permute the dofmap
404 if (element.needs_dof_permutations())
405 {
406 const std::int32_t num_cells
407 = topology.connectivity(topology.dim(), 0)->num_nodes();
408 const std::vector<std::uint32_t>& cell_info
409 = topology.get_cell_permutation_info();
410 int d = element.dim();
411 for (std::int32_t cell = 0; cell < num_cells; ++cell)
412 {
413 std::span dofs(dofmaps.front().data() + cell * d, d);
414 element.permute_inv(dofs, cell_info[cell]);
415 }
416 }
417
418 // Compute local-to-global map from local indices in dofmap to the
419 // corresponding global indices in cells, and pass to function to
420 // compute local (dof) to local (position in coords) map from (i)
421 // local-to-global for dofs and (ii) local-to-global for entries in
422 // coords
423 const std::vector<std::int32_t> l2l = graph::build::compute_local_to_local(
424 graph::build::compute_local_to_global(xdofs, dofmaps.front()), nodes);
425
426 // Allocate space for input global indices and copy data
427 std::vector<std::int64_t> igi(nodes.size());
428 std::transform(l2l.cbegin(), l2l.cend(), igi.begin(),
429 [&nodes](auto index) { return nodes[index]; });
430
431 // Build coordinate dof array, copying coordinates to correct position
432 assert(x.size() % dim == 0);
433 const std::size_t shape0 = x.size() / dim;
434 const std::size_t shape1 = dim;
435 std::vector<T> xg(3 * shape0, 0);
436 for (std::size_t i = 0; i < shape0; ++i)
437 {
438 std::copy_n(std::next(x.cbegin(), shape1 * l2l[i]), shape1,
439 std::next(xg.begin(), 3 * i));
440 }
441
442 return Geometry(dof_index_map, std::move(dofmaps.front()), {element},
443 std::move(xg), dim, std::move(igi));
444}
445
454template <std::floating_point T>
455std::pair<Geometry<T>, std::vector<int32_t>>
456create_subgeometry(const Topology& topology, const Geometry<T>& geometry,
457 int dim, std::span<const std::int32_t> subentity_to_entity)
458{
459 // Get the geometry dofs in the sub-geometry based on the entities in
460 // sub-geometry
461 const fem::ElementDofLayout layout = geometry.cmap().create_dof_layout();
462 // NOTE: Unclear what this return for prisms
463 const std::size_t num_entity_dofs = layout.num_entity_closure_dofs(dim);
464
465 std::vector<std::int32_t> x_indices;
466 x_indices.reserve(num_entity_dofs * subentity_to_entity.size());
467 {
468 auto xdofs = geometry.dofmap();
469 const int tdim = topology.dim();
470
471 // Fetch connectivities required to get entity dofs
472 const std::vector<std::vector<std::vector<int>>>& closure_dofs
473 = layout.entity_closure_dofs_all();
474 auto e_to_c = topology.connectivity(dim, tdim);
475 assert(e_to_c);
476 auto c_to_e = topology.connectivity(tdim, dim);
477 assert(c_to_e);
478 for (std::size_t i = 0; i < subentity_to_entity.size(); ++i)
479 {
480 const std::int32_t idx = subentity_to_entity[i];
481 assert(!e_to_c->links(idx).empty());
482 // Always pick the last cell to be consistent with the e_to_v connectivity
483 const std::int32_t cell = e_to_c->links(idx).back();
484 auto cell_entities = c_to_e->links(cell);
485 auto it = std::find(cell_entities.begin(), cell_entities.end(), idx);
486 assert(it != cell_entities.end());
487 std::size_t local_entity = std::distance(cell_entities.begin(), it);
488
489 auto xc = MDSPAN_IMPL_STANDARD_NAMESPACE::submdspan(
490 xdofs, cell, MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
491 for (std::int32_t entity_dof : closure_dofs[dim][local_entity])
492 x_indices.push_back(xc[entity_dof]);
493 }
494 }
495
496 std::vector<std::int32_t> sub_x_dofs = x_indices;
497 std::sort(sub_x_dofs.begin(), sub_x_dofs.end());
498 sub_x_dofs.erase(std::unique(sub_x_dofs.begin(), sub_x_dofs.end()),
499 sub_x_dofs.end());
500
501 // Get the sub-geometry dofs owned by this process
502 auto x_index_map = geometry.index_map();
503 assert(x_index_map);
504
505 std::shared_ptr<common::IndexMap> sub_x_dof_index_map;
506 std::vector<std::int32_t> subx_to_x_dofmap;
507 {
508 auto [map, new_to_old] = common::create_sub_index_map(
509 *x_index_map, sub_x_dofs, common::IndexMapOrder::any, true);
510 sub_x_dof_index_map = std::make_shared<common::IndexMap>(std::move(map));
511 subx_to_x_dofmap = std::move(new_to_old);
512 }
513
514 // Create sub-geometry coordinates
515 std::span<const T> x = geometry.x();
516 std::int32_t sub_num_x_dofs = subx_to_x_dofmap.size();
517 std::vector<T> sub_x(3 * sub_num_x_dofs);
518 for (int i = 0; i < sub_num_x_dofs; ++i)
519 {
520 std::copy_n(std::next(x.begin(), 3 * subx_to_x_dofmap[i]), 3,
521 std::next(sub_x.begin(), 3 * i));
522 }
523
524 // Create geometry to sub-geometry map
525 std::vector<std::int32_t> x_to_subx_dof_map(
526 x_index_map->size_local() + x_index_map->num_ghosts(), -1);
527 for (std::size_t i = 0; i < subx_to_x_dofmap.size(); ++i)
528 x_to_subx_dof_map[subx_to_x_dofmap[i]] = i;
529
530 // Create sub-geometry dofmap
531 std::vector<std::int32_t> sub_x_dofmap;
532 sub_x_dofmap.reserve(x_indices.size());
533 std::transform(x_indices.cbegin(), x_indices.cend(),
534 std::back_inserter(sub_x_dofmap),
535 [&x_to_subx_dof_map](auto x_dof)
536 {
537 assert(x_to_subx_dof_map[x_dof] != -1);
538 return x_to_subx_dof_map[x_dof];
539 });
540
541 // Create sub-geometry coordinate element
542 CellType sub_coord_cell
543 = cell_entity_type(geometry.cmap().cell_shape(), dim, 0);
544 fem::CoordinateElement<T> sub_cmap(sub_coord_cell, geometry.cmap().degree(),
545 geometry.cmap().variant());
546
547 // Sub-geometry input_global_indices
548 // TODO: Check this
549 const std::vector<std::int64_t>& igi = geometry.input_global_indices();
550 std::vector<std::int64_t> sub_igi;
551 sub_igi.reserve(subx_to_x_dofmap.size());
552 std::transform(subx_to_x_dofmap.begin(), subx_to_x_dofmap.end(),
553 std::back_inserter(sub_igi),
554 [&igi](std::int32_t sub_x_dof) { return igi[sub_x_dof]; });
555
556 // Create geometry
557 return {Geometry(sub_x_dof_index_map, std::move(sub_x_dofmap), {sub_cmap},
558 std::move(sub_x), geometry.dim(), std::move(sub_igi)),
559 std::move(subx_to_x_dofmap)};
560}
561
562} // namespace dolfinx::mesh
Definition CoordinateElement.h:38
Definition ElementDofLayout.h:30
const std::vector< std::vector< std::vector< int > > > & entity_closure_dofs_all() const
Definition ElementDofLayout.cpp:92
int num_entity_closure_dofs(int dim) const
Definition ElementDofLayout.cpp:68
Definition AdjacencyList.h:28
Geometry stores the geometry imposed on a mesh.
Definition Geometry.h:33
~Geometry()=default
Destructor.
std::span< value_type > x()
Access geometry degrees-of-freedom data (non-const version).
Definition Geometry.h:175
Geometry(std::shared_ptr< const common::IndexMap > index_map, const std::vector< std::vector< std::int32_t > > &dofmaps, const std::vector< fem::CoordinateElement< typename std::remove_reference_t< typename V::value_type > > > &elements, V &&x, int dim, W &&input_global_indices)
Constructor of object that holds mesh geometry data.
Definition Geometry.h:85
Geometry(std::shared_ptr< const common::IndexMap > index_map, U &&dofmap, const fem::CoordinateElement< typename std::remove_reference_t< typename V::value_type > > &element, V &&x, int dim, W &&input_global_indices)
Constructor of object that holds mesh geometry data.
Definition Geometry.h:56
MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan< const std::int32_t, MDSPAN_IMPL_STANDARD_NAMESPACE::dextents< std::size_t, 2 > > dofmap(std::int32_t i) const
The dofmap associated with the ith coordinate map in the geometry.
Definition Geometry.h:142
std::shared_ptr< const common::IndexMap > index_map() const
Index map.
Definition Geometry.h:159
Geometry(Geometry &&)=default
Move constructor.
Geometry(const Geometry &)=default
Copy constructor.
const fem::CoordinateElement< value_type > & cmap() const
The element that describes the geometry map.
Definition Geometry.h:180
int dim() const
Return Euclidean dimension of coordinate system.
Definition Geometry.h:116
Geometry & operator=(Geometry &&)=default
Move Assignment.
MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan< const std::int32_t, MDSPAN_IMPL_STANDARD_NAMESPACE::dextents< std::size_t, 2 > > dofmap() const
DofMap for the geometry.
Definition Geometry.h:123
const fem::CoordinateElement< value_type > & cmap(std::int32_t i) const
The element that describe the ith geometry map.
Definition Geometry.h:190
const std::vector< std::int64_t > & input_global_indices() const
Global user indices.
Definition Geometry.h:201
std::span< const value_type > x() const
Access geometry degrees-of-freedom data (const version).
Definition Geometry.h:168
Geometry & operator=(const Geometry &)=delete
Copy Assignment.
T value_type
Value type.
Definition Geometry.h:36
Topology stores the topology of a mesh, consisting of mesh entities and connectivity (incidence relat...
Definition Topology.h:44
std::shared_ptr< const common::IndexMap > index_map(int dim) const
Get the IndexMap that described the parallel distribution of the mesh entities.
Definition Topology.cpp:813
std::shared_ptr< const graph::AdjacencyList< std::int32_t > > connectivity(int d0, int d1) const
Return connectivity from entities of dimension d0 to entities of dimension d1. Assumes only one entit...
Definition Topology.cpp:929
const std::vector< std::uint32_t > & get_cell_permutation_info() const
Returns the permutation information.
Definition Topology.cpp:979
std::vector< CellType > entity_types(std::int8_t dim) const
Get the entity types in the topology for a given dimension.
Definition Topology.cpp:1021
int dim() const noexcept
Return the topological dimension of the mesh.
Definition Topology.cpp:792
std::pair< IndexMap, std::vector< std::int32_t > > create_sub_index_map(const IndexMap &imap, std::span< const std::int32_t > indices, IndexMapOrder order=IndexMapOrder::any, bool allow_owner_change=false)
Create a new index map from a subset of indices in an existing index map.
Definition IndexMap.cpp:751
@ any
Allow arbitrary ordering of ghost indices in sub-maps.
std::tuple< common::IndexMap, int, std::vector< std::vector< std::int32_t > > > build_dofmap_data(MPI_Comm comm, const mesh::Topology &topology, const std::vector< ElementDofLayout > &element_dof_layouts, const std::function< std::vector< int >(const graph::AdjacencyList< std::int32_t > &)> &reorder_fn)
Definition dofmapbuilder.cpp:621
std::vector< std::int64_t > compute_local_to_global(std::span< const std::int64_t > global, std::span< const std::int32_t > local)
Definition partition.cpp:377
std::vector< std::int32_t > compute_local_to_local(std::span< const std::int64_t > local0_to_global, std::span< const std::int64_t > local1_to_global)
Compute a local0-to-local1 map from two local-to-global maps with common global indices.
Definition partition.cpp:399
Mesh data structures and algorithms on meshes.
Definition DofMap.h:32
Geometry< typename std::remove_reference_t< typename U::value_type > > create_geometry(const Topology &topology, const std::vector< fem::CoordinateElement< std::remove_reference_t< typename U::value_type > > > &elements, std::span< const std::int64_t > nodes, std::span< const std::int64_t > xdofs, const U &x, int dim, std::function< std::vector< int >(const graph::AdjacencyList< std::int32_t > &)> reorder_fn=nullptr)
Build Geometry from input data.
Definition Geometry.h:263
CellType cell_entity_type(CellType type, int d, int index)
Return type of cell for entity of dimension d at given entity index.
Definition cell_types.cpp:64
std::pair< Geometry< T >, std::vector< int32_t > > create_subgeometry(const Topology &topology, const Geometry< T > &geometry, int dim, std::span< const std::int32_t > subentity_to_entity)
Create a sub-geometry for a subset of entities.
Definition Geometry.h:456
CellType
Cell type identifier.
Definition cell_types.h:22