File: Geometry.h

package info (click to toggle)
fenics-dolfinx 1%3A0.10.0.post4-1exp1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 6,028 kB
  • sloc: cpp: 36,535; python: 25,391; makefile: 226; sh: 171; xml: 55
file content (330 lines) | stat: -rw-r--r-- 12,071 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
// Copyright (C) 2006-2022 Anders Logg and Garth N. Wells
//
// This file is part of DOLFINx (https://www.fenicsproject.org)
//
// SPDX-License-Identifier:    LGPL-3.0-or-later

#pragma once

#include "Topology.h"
#include <algorithm>
#include <basix/mdspan.hpp>
#include <concepts>
#include <cstdint>
#include <dolfinx/common/IndexMap.h>
#include <dolfinx/common/MPI.h>
#include <dolfinx/common/sort.h>
#include <dolfinx/fem/CoordinateElement.h>
#include <dolfinx/fem/ElementDofLayout.h>
#include <dolfinx/fem/dofmapbuilder.h>
#include <dolfinx/graph/AdjacencyList.h>
#include <dolfinx/graph/partition.h>
#include <functional>
#include <memory>
#include <span>
#include <utility>
#include <vector>

namespace dolfinx::mesh
{

/// @brief Geometry stores the geometry imposed on a mesh.
template <std::floating_point T>
class Geometry
{
public:
  /// @brief Value type
  using value_type = T;

  /// @brief Constructor of object that holds mesh geometry data.
  ///
  /// The geometry 'degree-of-freedom map' is a logically rectangular
  /// array (row-major) where each row corresponds to a cell, and the
  /// columns are the indices in the coordinate array of the cell
  /// coordinate degree-of-freedom. For each cell type there is a
  /// geometry degree-of-freedom map.
  ///
  /// @param[in] index_map Index map associated with the geometry
  /// degrees-of-freedom.
  /// @param[in] dofmaps The geometry (point) dofmaps for each cell type
  /// in the mesh. For a cell of a given type, the dofmap  gives the
  /// position in the point array of each local geometry node of the
  /// cell. Each cell type has its own dofmap. Each dofmap uses
  /// row-major storage.
  /// @param[in] elements Elements that describe cell geometry maps.
  /// `element[i]` is the coordinate element associated with
  /// `dofmaps[i]`.
  /// @param[in] x Point coordinates. The shape is `(num_points, 3)` and
  /// the storage is row-major.
  /// @param[in] dim The geometric dimension (`0 < dim <= 3`).
  /// @param[in] input_global_indices 'Global' input index of each
  /// point, commonly from a mesh input file.
  template <typename U, typename V, typename W>
    requires std::is_convertible_v<std::remove_cvref_t<U>,
                                   std::vector<std::vector<std::int32_t>>>
                 and std::is_convertible_v<std::remove_cvref_t<V>,
                                           std::vector<T>>
                 and std::is_convertible_v<std::remove_cvref_t<W>,
                                           std::vector<std::int64_t>>
  Geometry(
      std::shared_ptr<const common::IndexMap> index_map, U&& dofmaps,
      const std::vector<fem::CoordinateElement<
          typename std::remove_reference_t<typename V::value_type>>>& elements,
      V&& x, int dim, W&& input_global_indices)
      : _dim(dim), _dofmaps(std::forward<U>(dofmaps)),
        _index_map(std::move(index_map)), _cmaps(elements),
        _x(std::forward<V>(x)),
        _input_global_indices(std::forward<W>(input_global_indices))
  {
    assert(_x.size() % 3 == 0);
    if (_x.size() / 3 != _input_global_indices.size())
      throw std::runtime_error("Geometry size mismatch.");

    if (_dofmaps.size() != _cmaps.size())
    {
      throw std::runtime_error("Geometry number of dofmaps not equal to the "
                               "number of coordinate elements.");
    }

    // TODO: check that elements dim == number of dofmap columns
  }

  /// Copy constructor
  Geometry(const Geometry&) = default;

  /// Move constructor
  Geometry(Geometry&&) = default;

  /// Destructor
  ~Geometry() = default;

  /// Copy assignment
  Geometry& operator=(const Geometry&) = delete;

  /// Move assignment
  Geometry& operator=(Geometry&&) = default;

  /// @brief Return dimension of the Euclidean coordinate system.
  int dim() const { return _dim; }

  /// @brief DofMap for the geometry.
  /// @return A 2D array with shape `(num_cells, dofs_per_cell)`.
  md::mdspan<const std::int32_t, md::dextents<std::size_t, 2>> dofmap() const
  {
    if (_dofmaps.size() != 1)
      throw std::runtime_error("Multiple dofmaps");
    return this->dofmap(0);
  }

  /// @brief Degree-of-freedom map associated with the `i`th coordinate
  /// map element in the geometry.
  /// @param[in] i Index of the requested degree-of-freedom map. The
  /// degree-of-freedom map corresponds to the geometry element
  /// `cmaps()[i]`.
  /// @return A dofmap array, with shape `(num_cells, dofs_per_cell)`.
  md::mdspan<const std::int32_t, md::dextents<std::size_t, 2>>
  dofmap(std::size_t i) const
  {
    std::size_t ndofs = _cmaps.at(i).dim();
    return md::mdspan<const std::int32_t, md::dextents<std::size_t, 2>>(
        _dofmaps.at(i).data(), _dofmaps.at(i).size() / ndofs, ndofs);
  }

  /// @brief Index map for the geometry 'degrees-of-freedom'.
  /// @return Index map for the geometry dofs.
  std::shared_ptr<const common::IndexMap> index_map() const
  {
    return _index_map;
  }

  /// @brief Access geometry degrees-of-freedom data (const version).
  ///
  /// @return The flattened row-major geometry data, where the shape is
  /// `(num_points, 3)`.
  std::span<const value_type> x() const { return _x; }

  /// @brief Access geometry degrees-of-freedom data (non-const
  /// version).
  ///
  /// @return The flattened row-major geometry data, where the shape is
  /// `(num_points, 3)`.
  std::span<value_type> x() { return _x; }

  /// @brief The elements that describes the geometry map.
  ///
  /// The coordinate element `cmaps()[i]` corresponds to the
  /// degree-of-freedom map `dofmap(i)`.
  ///
  /// @return The coordinate/geometry elements.
  const std::vector<fem::CoordinateElement<value_type>>& cmaps() const
  {
    return _cmaps;
  }

  /// @brief The element that describes the geometry map.
  ///
  /// @return The coordinate/geometry element
  const fem::CoordinateElement<value_type>& cmap() const
  {
    if (_cmaps.size() > 1)
      throw std::runtime_error("Multiple cmaps.");
    return _cmaps.front();
  }

  /// @brief Global user indices.
  const std::vector<std::int64_t>& input_global_indices() const
  {
    return _input_global_indices;
  }

private:
  // Geometric dimension
  int _dim;

  // Map per cell for extracting coordinate data for each cmap
  std::vector<std::vector<std::int32_t>> _dofmaps;

  // IndexMap for geometry 'dofmap'
  std::shared_ptr<const common::IndexMap> _index_map;

  // The coordinate elements
  std::vector<fem::CoordinateElement<value_type>> _cmaps;

  // Coordinates for all points stored as a contiguous array (row-major,
  // column size = 3)
  std::vector<value_type> _x;

  // Global indices as provided on Geometry creation
  std::vector<std::int64_t> _input_global_indices;
};

/// @cond
/// Template type deduction
template <typename U, typename V, typename W>
Geometry(std::shared_ptr<const common::IndexMap>, U&&,
         const std::vector<fem::CoordinateElement<
             typename std::remove_reference_t<typename V::value_type>>>&,
         V&&, int, W&&)
    -> Geometry<typename std::remove_cvref_t<typename V::value_type>>;
/// @endcond

/// @brief Build Geometry from input data.
///
/// This function should be called after the mesh topology is built and
/// 'node' coordinate data has been distributed to the processes where
/// it is required.
///
/// @param[in] topology Mesh topology.
/// @param[in] elements List of elements that defines the geometry map for
/// each cell type.
/// @param[in] nodes Geometry node global indices for cells on this
/// process. @pre Must be sorted.
/// @param[in] xdofs Geometry degree-of-freedom map (using global
/// indices) for cells on this process. `nodes` is a sorted and unique
/// list of the indices in `xdofs`.
/// @param[in] x The node coordinates (row-major, with shape
/// `(num_nodes, dim)`. The global index of each node is `i +
/// rank_offset`, where `i` is the local row index in `x` and
/// `rank_offset` is the sum of `x` rows on all processed with a lower
/// rank than the caller.
/// @param[in] dim Geometric dimension (1, 2, or 3).
/// @param[in] reorder_fn Function for re-ordering the degree-of-freedom
/// map associated with the geometry data.
/// @note Experimental new interface for multiple cmap/dofmap
/// @return A mesh geometry.
template <typename U>
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,
                const std::function<std::vector<int>(
                    const graph::AdjacencyList<std::int32_t>&)>& reorder_fn
                = nullptr)
{
  spdlog::info("Create Geometry (multiple)");

  assert(std::ranges::is_sorted(nodes));
  using T = typename std::remove_reference_t<typename U::value_type>;

  // Check elements match cell types in topology
  const int tdim = topology.dim();
  const std::size_t num_cell_types = topology.entity_types(tdim).size();
  if (elements.size() != num_cell_types)
    throw std::runtime_error("Mismatch between topology and geometry.");

  std::vector<fem::ElementDofLayout> dof_layouts;
  dof_layouts.reserve(elements.size());
  for (auto& el : elements)
    dof_layouts.push_back(el.create_dof_layout());

  spdlog::info("Got {} dof layouts", dof_layouts.size());

  //  Build 'geometry' dofmap on the topology
  auto [_dof_index_map, bs, dofmaps]
      = fem::build_dofmap_data(topology.index_maps(topology.dim())[0]->comm(),
                               topology, dof_layouts, reorder_fn);
  auto dof_index_map
      = std::make_shared<common::IndexMap>(std::move(_dof_index_map));

  // If the mesh has higher order geometry, permute the dofmap
  if (elements.front().needs_dof_permutations())
  {
    const std::int32_t num_cells
        = topology.connectivity(topology.dim(), 0)->num_nodes();
    const std::vector<std::uint32_t>& cell_info
        = topology.get_cell_permutation_info();
    int d = elements.front().dim();
    for (std::int32_t cell = 0; cell < num_cells; ++cell)
    {
      std::span dofs(dofmaps.front().data() + cell * d, d);
      elements.front().permute_inv(dofs, cell_info[cell]);
    }
  }

  spdlog::info("Calling compute_local_to_global");
  // Compute local-to-global map from local indices in dofmap to the
  // corresponding global indices in cells, and pass to function to
  // compute local (dof) to local (position in coords) map from (i)
  // local-to-global for dofs and (ii) local-to-global for entries in
  // coords

  spdlog::info("xdofs.size = {}", xdofs.size());
  std::vector<std::int32_t> all_dofmaps;
  std::stringstream s;
  for (auto q : dofmaps)
  {
    s << q.size() << " ";
    all_dofmaps.insert(all_dofmaps.end(), q.begin(), q.end());
  }
  spdlog::info("dofmap sizes = {}", s.str());
  spdlog::info("all_dofmaps.size = {}", all_dofmaps.size());
  spdlog::info("nodes.size = {}", nodes.size());

  const std::vector<std::int32_t> l2l = graph::build::compute_local_to_local(
      graph::build::compute_local_to_global(xdofs, all_dofmaps), nodes);

  // Allocate space for input global indices and copy data
  std::vector<std::int64_t> igi(nodes.size());
  std::ranges::transform(l2l, igi.begin(),
                         [&nodes](auto index) { return nodes[index]; });

  // Build coordinate dof array, copying coordinates to correct position
  assert(x.size() % dim == 0);
  const std::size_t shape0 = x.size() / dim;
  const std::size_t shape1 = dim;
  std::vector<T> xg(3 * shape0, 0);
  for (std::size_t i = 0; i < shape0; ++i)
  {
    std::copy_n(std::next(x.begin(), shape1 * l2l[i]), shape1,
                std::next(xg.begin(), 3 * i));
  }

  spdlog::info("Creating geometry with {} dofmaps", dof_layouts.size());

  return Geometry(dof_index_map, std::move(dofmaps), elements, std::move(xg),
                  dim, std::move(igi));
}

} // namespace dolfinx::mesh