DOLFINx 0.12.0.0
DOLFINx C++
Loading...
Searching...
No Matches
expression_evaluate.h
Go to the documentation of this file.
1// Copyright (C) 2018-2026 Garth N. Wells and Jørgen S. Dokken
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 "Expression.h"
10#include "FiniteElement.h"
11#include "Function.h"
12#include "FunctionSpace.h"
13#include "assemble_expression_impl.h"
14#include "interpolate.h"
15#include "pack.h"
16#include "traits.h"
17#include <algorithm>
18#include <basix/mdspan.hpp>
19#include <cassert>
20#include <cmath>
21#include <concepts>
22#include <cstddef>
23#include <cstdint>
24#include <dolfinx/common/types.h>
25#include <dolfinx/mesh/EntityMap.h>
26#include <dolfinx/mesh/Mesh.h>
27#include <dolfinx/mesh/Topology.h>
28#include <format>
29#include <functional>
30#include <iterator>
31#include <memory>
32#include <optional>
33#include <ranges>
34#include <span>
35#include <stdexcept>
36#include <utility>
37#include <vector>
38
46
47namespace dolfinx::fem
48{
49namespace impl
50{
62template <dolfinx::scalar T, std::floating_point U>
64 const mesh::Mesh<U>& mesh, std::size_t rank)
65{
66 // An Expression is compiled for one cell type, and cell indices are
67 // local to a cell type, so neither cells nor (cell, local index)
68 // pairs identify entities of a mesh with several cell types
69 if (mesh.topology()->cell_types().size() > 1)
70 {
71 throw std::invalid_argument("Evaluating an Expression on a mesh with "
72 "multiple cell types is not supported.");
73 }
74
75 if (e.coordinate_element_hash() != mesh.geometry().cmaps().front().hash())
76 {
77 throw std::invalid_argument(
78 "Expression was created on a different mesh. Cannot tabulate.");
79 }
80
81 const int tdim = mesh.topology()->dim();
82 if (e.entity_dim() > tdim)
83 {
84 throw std::invalid_argument(
85 std::format("Cannot evaluate an Expression on entities of dimension "
86 "{} on a mesh of dimension {}.",
87 e.entity_dim(), tdim));
88 }
89
90 if (rank == 1 and e.entity_dim() != tdim)
91 {
92 throw std::invalid_argument(
93 "An Expression on facets, ridges or peaks must be evaluated on "
94 "(cell, local entity index) pairs.");
95 }
96
97 // An argument on another mesh must live on the evaluated entities
98 if (std::shared_ptr<const FunctionSpace<U>> V = e.argument_space();
99 V and V->mesh()->topology() != mesh.topology())
100 {
101 mesh::check_entity_cell_mapping(*V->mesh()->topology(), *mesh.topology(),
102 e.entity_dim());
103 }
104}
105} // namespace impl
106
120template <dolfinx::scalar T, std::floating_point U>
121std::pair<std::vector<T>, int> pack_coefficients(const fem::Expression<T, U>& e,
122 const mesh::Mesh<U>& mesh,
123 fem::MDSpan2 auto entities)
124{
125 // Validate before packing
126 impl::check_expression_entities(e, mesh, entities.rank());
127
128 std::vector<int> coffsets = e.coefficient_offsets();
129 const int cstride = coffsets.back();
130 std::vector<T> coeffs(entities.extent(0) * cstride);
131 std::vector<std::reference_wrapper<const Function<T, U>>> c;
132 std::ranges::transform(e.coefficients(), std::back_inserter(c),
133 [](const std::shared_ptr<const Function<T, U>>& f)
134 -> const Function<T, U>& { return *f; });
135 fem::pack_coefficients(c, *mesh.topology(), entities, e.entity_dim(),
136 e.entity_maps(), coffsets, std::span(coeffs));
137 return {std::move(coeffs), cstride};
138}
139
168template <dolfinx::scalar T, std::floating_point U>
170 std::span<T> values, const fem::Expression<T, U>& e,
171 md::mdspan<const T, md::dextents<std::size_t, 2>> coeffs,
172 std::span<const T> constants, const mesh::Mesh<U>& mesh,
173 fem::MDSpan2 auto entities,
174 std::optional<
175 std::pair<std::reference_wrapper<const FiniteElement<U>>, std::size_t>>
176 element)
177{
178 impl::check_expression_entities(e, mesh, entities.rank());
179
180 std::shared_ptr<const FunctionSpace<U>> V = e.argument_space();
181
182 // Topology providing the argument's cell orientation data and, when
183 // the argument is on another mesh, its cell for each of `entities`.
184 // `topology_v` and `argument_cells` back the spans passed to
185 // impl::tabulate_expression.
186 std::shared_ptr<mesh::Topology> topology_v = mesh.topology_mutable();
187 std::vector<std::int32_t> argument_cells;
188 std::span<const std::uint32_t> cell_info;
189 if (element and element->first.get().needs_dof_transformations())
190 {
191 if (V and V->mesh()->topology() != mesh.topology())
192 topology_v = V->mesh()->topology_mutable();
193
194 topology_v->create_cell_permutations();
195 cell_info = topology_v->get_cell_permutation_info();
196
197 if (topology_v != mesh.topology_mutable())
198 {
199 const mesh::Topology& topology = *mesh.topology();
200 const mesh::EntityMap& emap
201 = mesh::find_entity_map(e.entity_maps(), topology, *topology_v);
202 argument_cells = mesh::extract_cells_from_entities(
203 *topology_v, topology, entities, std::cref(emap));
204#ifndef NDEBUG
205 if (std::ranges::find(argument_cells, -1) != argument_cells.end())
206 {
207 throw std::invalid_argument(
208 "An entity has no cell in the mesh of the argument.");
209 }
210#endif
211 }
212 }
213
214 impl::tabulate_expression(values, e.kernel(), e.X().second, e.value_size(),
215 coeffs, constants, mesh, entities, element,
216 cell_info, argument_cells);
217}
218
235template <dolfinx::scalar T, std::floating_point U>
236void tabulate_expression(std::span<T> values, const fem::Expression<T, U>& e,
237 const mesh::Mesh<U>& mesh, fem::MDSpan2 auto entities)
238{
239 // Packing validates `e` against `mesh` and `entities` first
240 auto [coeffs, cstride] = fem::pack_coefficients(e, mesh, entities);
241 std::vector<T> constants = fem::pack_constants(e);
242
243 std::optional<
244 std::pair<std::reference_wrapper<const FiniteElement<U>>, std::size_t>>
245 element = std::nullopt;
246 if (std::shared_ptr<const FunctionSpace<U>> V = e.argument_space(); V)
247 {
248 std::size_t num_argument_dofs
249 = V->dofmap()->element_dof_layout().num_dofs() * V->dofmap()->bs();
250 assert(V->element());
251 element = {std::cref(*V->element()), num_argument_dofs};
252 }
253
255 values, e,
256 md::mdspan(std::as_const(coeffs).data(), entities.extent(0), cstride),
257 std::span<const T>(constants), mesh, entities, element);
258}
259
283template <dolfinx::scalar T, std::floating_point U>
285 const Expression<T, U>& e0, mesh::CellRange auto&& cells0)
286{
287 // Extract mesh
288 const mesh::Mesh<U>* mesh0 = nullptr;
289 for (auto& c : e0.coefficients())
290 {
291 assert(c);
292 assert(c->function_space());
293 assert(c->function_space()->mesh());
294 if (auto mesh = c->function_space()->mesh().get(); !mesh0)
295 mesh0 = mesh;
296 else if (mesh != mesh0)
297 {
298 throw std::invalid_argument(
299 "Expression coefficient Functions have different meshes.");
300 }
301 }
302
303 // If Expression has no Function coefficients take mesh from `u1`.
304 auto V1 = u1.function_space();
305 assert(V1);
306 assert(V1->mesh());
307 if (!mesh0)
308 mesh0 = V1->mesh().get();
309
310 if (cells0.size() != cells1.size())
311 throw std::invalid_argument("Cell lists have different lengths.");
312
313 // Check that Function and Expression spaces are compatible
314 assert(V1->element());
315 std::size_t value_size = e0.value_size();
316 if (e0.argument_space())
317 throw std::invalid_argument("Cannot interpolate Expression with Argument.");
318
319 if (value_size != (std::size_t)V1->element()->value_size())
320 {
321 throw std::invalid_argument(
322 "Function value size not equal to Expression value size.");
323 }
324
325 // Compatibility check
326 {
327 const auto& [X0, shape0] = e0.X();
328 auto [X1, shape1] = V1->element()->interpolation_points();
329 if (shape0 != shape1)
330 {
331 throw std::invalid_argument(
332 "Function element interpolation points has different shape to "
333 "Expression interpolation points");
334 }
335
336 for (std::size_t i = 0; i < X0.size(); ++i)
337 {
338 if (std::abs(X0[i] - X1[i]) > 1.0e-10)
339 {
340 throw std::invalid_argument("Function element interpolation points not "
341 "equal to Expression interpolation points");
342 }
343 }
344 }
345
346 // Array to hold evaluated Expression
347 std::size_t num_cells = cells0.size();
348 std::size_t num_points = e0.num_points();
349 std::vector<T> fdata(num_cells * num_points * value_size);
350 md::mdspan<const T, md::dextents<std::size_t, 3>> f(fdata.data(), num_cells,
351 num_points, value_size);
352
353 // Evaluate Expression at points
354 std::vector<std::int32_t> _cells0(cells0.begin(), cells0.end());
355 tabulate_expression(std::span(fdata), e0, *mesh0,
356 md::mdspan(_cells0.data(), _cells0.size()));
357
358 // Reshape evaluated data to fit interpolate.
359 // Expression returns matrix of shape (num_cells, num_points *
360 // value_size), i.e. xyzxyz ordering of dof values per cell per
361 // point. The interpolation uses xxyyzz input, ordered for all
362 // points of each cell, i.e. (value_size, num_cells*num_points).
363 std::vector<T> fdata1(num_cells * num_points * value_size);
364 md::mdspan<T, md::dextents<std::size_t, 3>> f1(fdata1.data(), value_size,
365 num_cells, num_points);
366 for (std::size_t i = 0; i < f.extent(0); ++i)
367 for (std::size_t j = 0; j < f.extent(1); ++j)
368 for (std::size_t k = 0; k < f.extent(2); ++k)
369 f1(k, i, j) = f(i, j, k);
370
371 // Interpolate values into appropriate space
372 fem::interpolate<T>(u1, std::span<const T>(fdata1.data(), fdata1.size()),
373 {value_size, num_cells * num_points}, cells1);
374}
375
386template <dolfinx::scalar T, std::floating_point U>
388 mesh::CellRange auto&& cells)
389{
390 interpolate<T, U>(u1, cells, e0, cells);
391}
392
402template <dolfinx::scalar T, std::floating_point U>
404{
405 assert(u1.function_space());
406 assert(u1.function_space()->mesh());
407 int tdim = u1.function_space()->mesh()->topology()->dim();
408 auto map = u1.function_space()->mesh()->topology()->index_map(tdim);
409 assert(map);
411 u1, e0, std::ranges::iota_view(0, map->size_local() + map->num_ghosts()));
412}
413} // namespace dolfinx::fem
An Expression represents a mathematical expression evaluated at a pre-defined points on a reference c...
Definition Expression.h:45
const std::vector< std::shared_ptr< const Function< scalar_type, geometry_type > > > & coefficients() const
Expression coefficients.
Definition Expression.h:127
std::shared_ptr< const FunctionSpace< geometry_type > > argument_space() const
Argument function space.
Definition Expression.h:118
std::uint64_t coordinate_element_hash() const
Hash for coordinate element used to create the expression.
Definition Expression.h:205
std::vector< int > coefficient_offsets() const
Offset for each coefficient expansion array on a cell.
Definition Expression.h:146
std::size_t num_points() const
Number of evaluation points (X).
Definition Expression.h:187
const std::pair< std::vector< geometry_type >, std::array< std::size_t, 2 > > & X() const
Evaluation point coordinates on the reference entity.
Definition Expression.h:181
int value_size() const
Value size of the Expression result.
Definition Expression.h:168
int entity_dim() const
Topological dimension of the entities the Expression is evaluated on.
Definition Expression.h:195
const std::function< void(scalar_type *, const scalar_type *, const scalar_type *, const geometry_type *, const int *, const std::uint8_t *, void *)> & kernel() const
Function for tabulating the Expression.
Definition Expression.h:162
const std::vector< std::reference_wrapper< const dolfinx::mesh::EntityMap > > & entity_maps() const
Maps between entities of different meshes.
Definition Expression.h:199
Model of a finite element.
Definition FiniteElement.h:202
This class represents a finite element function space defined by a mesh, a finite element,...
Definition FunctionSpace.h:36
Definition Function.h:44
std::shared_ptr< const FunctionSpace< geometry_type > > function_space() const
Access the function space.
Definition Function.h:149
A bidirectional map relating entities in one topology to another.
Definition EntityMap.h:36
A Mesh consists of a set of connected and numbered mesh topological entities, and geometry data.
Definition Mesh.h:25
Topology stores the topology of a mesh, consisting of mesh entities and connectivity (incidence relat...
Definition Topology.h:52
Concept for mdspan of rank 1 or 2.
Definition traits.h:57
Requirement on range of cell indices.
Definition Topology.h:35
void check_expression_entities(const fem::Expression< T, U > &e, const mesh::Mesh< U > &mesh, std::size_t rank)
Check that an Expression can be evaluated over entities of a mesh.
Definition expression_evaluate.h:63
Finite element method functionality.
Definition assemble_expression_impl.h:28
void tabulate_expression(std::span< T > values, const fem::Expression< T, U > &e, md::mdspan< const T, md::dextents< std::size_t, 2 > > coeffs, std::span< const T > constants, const mesh::Mesh< U > &mesh, fem::MDSpan2 auto entities, std::optional< std::pair< std::reference_wrapper< const FiniteElement< U > >, std::size_t > > element)
Evaluate an Expression on cells, facets, ridges or peaks.
Definition expression_evaluate.h:169
std::pair< std::vector< T >, int > pack_coefficients(const fem::Expression< T, U > &e, const mesh::Mesh< U > &mesh, fem::MDSpan2 auto entities)
Pack the coefficients of an Expression over entities of a mesh.
Definition expression_evaluate.h:121
std::vector< T > pack_constants(const std::vector< std::reference_wrapper< const fem::Constant< T > > > &c)
Pack constants of an Expression or Form into a single array ready for assembly.
Definition pack.h:478
void interpolate(Function< T, U > &u1, mesh::CellRange auto &&cells1, const Expression< T, U > &e0, mesh::CellRange auto &&cells0)
Interpolate an Expression into a Function over a subset of cells.
Definition expression_evaluate.h:284
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
Functions supporting the packing of coefficient data.