Note: this is documentation for an old release. View the latest documentation at docs.fenicsproject.org/dolfinx/v0.9.0/cpp/doxygen/df/df5/Function_8h_source.html
DOLFINx 0.6.0
DOLFINx C++ interface
Loading...
Searching...
No Matches
Function.h
1// Copyright (C) 2003-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 "DofMap.h"
10#include "FiniteElement.h"
11#include "FunctionSpace.h"
12#include "interpolate.h"
13#include <dolfinx/common/IndexMap.h>
14#include <dolfinx/la/Vector.h>
15#include <dolfinx/mesh/Geometry.h>
16#include <dolfinx/mesh/Mesh.h>
17#include <dolfinx/mesh/Topology.h>
18#include <functional>
19#include <memory>
20#include <numeric>
21#include <span>
22#include <string>
23#include <utility>
24#include <vector>
25
26namespace dolfinx::fem
27{
28class FunctionSpace;
29template <typename T>
30class Expression;
31
32template <typename T>
33class Expression;
34
41template <typename T>
43{
44public:
46 using value_type = T;
47
50 explicit Function(std::shared_ptr<const FunctionSpace> V)
51 : _function_space(V),
52 _x(std::make_shared<la::Vector<T>>(V->dofmap()->index_map,
53 V->dofmap()->index_map_bs()))
54 {
55 if (!V->component().empty())
56 {
57 throw std::runtime_error("Cannot create Function from subspace. Consider "
58 "collapsing the function space");
59 }
60 }
61
69 Function(std::shared_ptr<const FunctionSpace> V,
70 std::shared_ptr<la::Vector<T>> x)
71 : _function_space(V), _x(x)
72 {
73 // We do not check for a subspace since this constructor is used for
74 // creating subfunctions
75
76 // Assertion uses '<=' to deal with sub-functions
77 assert(V->dofmap());
78 assert(V->dofmap()->index_map->size_global() * V->dofmap()->index_map_bs()
79 <= _x->bs() * _x->map()->size_global());
80 }
81
82 // Copy constructor
83 Function(const Function& v) = delete;
84
86 Function(Function&& v) = default;
87
89 ~Function() = default;
90
92 Function& operator=(Function&& v) = default;
93
94 // Assignment
95 Function& operator=(const Function& v) = delete;
96
100 Function sub(int i) const
101 {
102 auto sub_space = _function_space->sub({i});
103 assert(sub_space);
104 return Function(sub_space, _x);
105 }
106
111 {
112 // Create new collapsed FunctionSpace
113 auto [V, map] = _function_space->collapse();
114
115 // Create new vector
116 auto x = std::make_shared<la::Vector<T>>(V.dofmap()->index_map,
117 V.dofmap()->index_map_bs());
118
119 // Copy values into new vector
120 std::span<const T> x_old = _x->array();
121 std::span<T> x_new = x->mutable_array();
122 for (std::size_t i = 0; i < map.size(); ++i)
123 {
124 assert((int)i < x_new.size());
125 assert(map[i] < x_old.size());
126 x_new[i] = x_old[map[i]];
127 }
128
129 return Function(std::make_shared<FunctionSpace>(std::move(V)), x);
130 }
131
134 std::shared_ptr<const FunctionSpace> function_space() const
135 {
136 return _function_space;
137 }
138
140 std::shared_ptr<const la::Vector<T>> x() const { return _x; }
141
143 std::shared_ptr<la::Vector<T>> x() { return _x; }
144
148 void interpolate(const Function<T>& v, std::span<const std::int32_t> cells)
149 {
150 fem::interpolate(*this, v, cells);
151 }
152
156 {
157 assert(_function_space);
158 assert(_function_space->mesh());
159 int tdim = _function_space->mesh()->topology().dim();
160 auto cell_map = _function_space->mesh()->topology().index_map(tdim);
161 assert(cell_map);
162 std::int32_t num_cells = cell_map->size_local() + cell_map->num_ghosts();
163 std::vector<std::int32_t> cells(num_cells, 0);
164 std::iota(cells.begin(), cells.end(), 0);
165
166 fem::interpolate(*this, v, cells);
167 }
168
173 const std::function<std::pair<std::vector<T>, std::vector<std::size_t>>(
174 std::experimental::mdspan<
175 const double,
176 std::experimental::extents<
177 std::size_t, 3, std::experimental::dynamic_extent>>)>& f,
178 std::span<const std::int32_t> cells)
179 {
180 assert(_function_space);
181 assert(_function_space->element());
182 assert(_function_space->mesh());
183 const std::vector<double> x = fem::interpolation_coords(
184 *_function_space->element(), *_function_space->mesh(), cells);
185 namespace stdex = std::experimental;
186 stdex::mdspan<const double,
187 stdex::extents<std::size_t, 3, stdex::dynamic_extent>>
188 _x(x.data(), 3, x.size() / 3);
189
190 const auto [fx, fshape] = f(_x);
191 assert(fshape.size() <= 2);
192 if (int vs = _function_space->element()->value_size();
193 vs == 1 and fshape.size() == 1)
194 {
195 // Check for scalar-valued functions
196 if (fshape.front() != x.size() / 3)
197 throw std::runtime_error("Data returned by callable has wrong length");
198 }
199 else
200 {
201 // Check for vector/tensor value
202 if (fshape.size() != 2)
203 throw std::runtime_error("Expected 2D array of data");
204
205 if (fshape[0] != vs)
206 {
207 throw std::runtime_error(
208 "Data returned by callable has wrong shape(0) size");
209 }
210 if (fshape[1] != x.size() / 3)
211 {
212 throw std::runtime_error(
213 "Data returned by callable has wrong shape(1) size");
214 }
215 }
216
217 std::array<std::size_t, 2> _fshape;
218 if (fshape.size() == 1)
219 _fshape = {1, fshape[0]};
220 else
221 _fshape = {fshape[0], fshape[1]};
222
223 fem::interpolate(*this, std::span<const T>(fx.data(), fx.size()), _fshape,
224 cells);
225 }
226
230 const std::function<std::pair<std::vector<T>, std::vector<std::size_t>>(
231 std::experimental::mdspan<
232 const double,
233 std::experimental::extents<
234 std::size_t, 3, std::experimental::dynamic_extent>>)>& f)
235 {
236 assert(_function_space);
237 assert(_function_space->mesh());
238 const int tdim = _function_space->mesh()->topology().dim();
239 auto cell_map = _function_space->mesh()->topology().index_map(tdim);
240 assert(cell_map);
241 std::int32_t num_cells = cell_map->size_local() + cell_map->num_ghosts();
242 std::vector<std::int32_t> cells(num_cells, 0);
243 std::iota(cells.begin(), cells.end(), 0);
244 interpolate(f, cells);
245 }
246
253 void interpolate(const Expression<T>& e, std::span<const std::int32_t> cells)
254 {
255 // Check that spaces are compatible
256 assert(_function_space);
257 assert(_function_space->element());
258 std::size_t value_size = e.value_size();
260 throw std::runtime_error("Cannot interpolate Expression with Argument");
261
262 if (value_size != _function_space->element()->value_size())
263 {
264 throw std::runtime_error(
265 "Function value size not equal to Expression value size");
266 }
267
268 {
269 // Compatibility check
270 auto [X0, shape0] = e.X();
271 auto [X1, shape1] = _function_space->element()->interpolation_points();
272 if (shape0 != shape1)
273 {
274 throw std::runtime_error(
275 "Function element interpolation points has different shape to "
276 "Expression interpolation points");
277 }
278 for (std::size_t i = 0; i < X0.size(); ++i)
279 {
280 if (std::abs(X0[i] - X1[i]) > 1.0e-10)
281 {
282 throw std::runtime_error("Function element interpolation points not "
283 "equal to Expression interpolation points");
284 }
285 }
286 }
287
288 namespace stdex = std::experimental;
289
290 // Array to hold evaluated Expression
291 std::size_t num_cells = cells.size();
292 std::size_t num_points = e.X().second[0];
293 std::vector<T> fdata(num_cells * num_points * value_size);
294 stdex::mdspan<const T, stdex::dextents<std::size_t, 3>> f(
295 fdata.data(), num_cells, num_points, value_size);
296
297 // Evaluate Expression at points
298 e.eval(cells, fdata, {num_cells, num_points * value_size});
299
300 // Reshape evaluated data to fit interpolate
301 // Expression returns matrix of shape (num_cells, num_points *
302 // value_size), i.e. xyzxyz ordering of dof values per cell per point.
303 // The interpolation uses xxyyzz input, ordered for all points of each
304 // cell, i.e. (value_size, num_cells*num_points)
305
306 std::vector<T> fdata1(num_cells * num_points * value_size);
307 stdex::mdspan<T, stdex::dextents<std::size_t, 3>> f1(
308 fdata1.data(), value_size, num_cells, num_points);
309 for (std::size_t i = 0; i < f.extent(0); ++i)
310 for (std::size_t j = 0; j < f.extent(1); ++j)
311 for (std::size_t k = 0; k < f.extent(2); ++k)
312 f1(k, i, j) = f(i, j, k);
313
314 // Interpolate values into appropriate space
315 fem::interpolate(*this, std::span<const T>(fdata1.data(), fdata1.size()),
316 {value_size, num_cells * num_points}, cells);
317 }
318
322 {
323 assert(_function_space);
324 assert(_function_space->mesh());
325 const int tdim = _function_space->mesh()->topology().dim();
326 auto cell_map = _function_space->mesh()->topology().index_map(tdim);
327 assert(cell_map);
328 std::int32_t num_cells = cell_map->size_local() + cell_map->num_ghosts();
329 std::vector<std::int32_t> cells(num_cells, 0);
330 std::iota(cells.begin(), cells.end(), 0);
331 interpolate(e, cells);
332 }
333
346 void eval(std::span<const double> x, std::array<std::size_t, 2> xshape,
347 std::span<const std::int32_t> cells, std::span<T> u,
348 std::array<std::size_t, 2> ushape) const
349 {
350 if (cells.empty())
351 return;
352
353 assert(x.size() == xshape[0] * xshape[1]);
354 assert(u.size() == ushape[0] * ushape[1]);
355
356 // TODO: This could be easily made more efficient by exploiting points
357 // being ordered by the cell to which they belong.
358
359 if (xshape[0] != cells.size())
360 {
361 throw std::runtime_error(
362 "Number of points and number of cells must be equal.");
363 }
364 if (xshape[0] != ushape[0])
365 {
366 throw std::runtime_error(
367 "Length of array for Function values must be the "
368 "same as the number of points.");
369 }
370
371 // Get mesh
372 assert(_function_space);
373 std::shared_ptr<const mesh::Mesh> mesh = _function_space->mesh();
374 assert(mesh);
375 const std::size_t gdim = mesh->geometry().dim();
376 const std::size_t tdim = mesh->topology().dim();
377 auto map = mesh->topology().index_map(tdim);
378
379 // Get geometry data
381 = mesh->geometry().dofmap();
382 const std::size_t num_dofs_g = mesh->geometry().cmap().dim();
383 std::span<const double> x_g = mesh->geometry().x();
384
385 // Get coordinate map
386 const CoordinateElement& cmap = mesh->geometry().cmap();
387
388 // Get element
389 std::shared_ptr<const FiniteElement> element = _function_space->element();
390 assert(element);
391 const int bs_element = element->block_size();
392 const std::size_t reference_value_size
393 = element->reference_value_size() / bs_element;
394 const std::size_t value_size = element->value_size() / bs_element;
395 const std::size_t space_dimension = element->space_dimension() / bs_element;
396
397 // If the space has sub elements, concatenate the evaluations on the
398 // sub elements
399 const int num_sub_elements = element->num_sub_elements();
400 if (num_sub_elements > 1 and num_sub_elements != bs_element)
401 {
402 throw std::runtime_error("Function::eval is not supported for mixed "
403 "elements. Extract subspaces.");
404 }
405
406 // Create work vector for expansion coefficients
407 std::vector<T> coefficients(space_dimension * bs_element);
408
409 // Get dofmap
410 std::shared_ptr<const DofMap> dofmap = _function_space->dofmap();
411 assert(dofmap);
412 const int bs_dof = dofmap->bs();
413
414 std::span<const std::uint32_t> cell_info;
415 if (element->needs_dof_transformations())
416 {
417 mesh->topology_mutable().create_entity_permutations();
418 cell_info = std::span(mesh->topology().get_cell_permutation_info());
419 }
420
421 namespace stdex = std::experimental;
422 using cmdspan4_t
423 = stdex::mdspan<const double, stdex::dextents<std::size_t, 4>>;
424 using mdspan2_t = stdex::mdspan<double, stdex::dextents<std::size_t, 2>>;
425 using mdspan3_t = stdex::mdspan<double, stdex::dextents<std::size_t, 3>>;
426
427 std::vector<double> coord_dofs_b(num_dofs_g * gdim);
428 mdspan2_t coord_dofs(coord_dofs_b.data(), num_dofs_g, gdim);
429 std::vector<double> xp_b(1 * gdim);
430 mdspan2_t xp(xp_b.data(), 1, gdim);
431
432 // Loop over points
433 std::fill(u.data(), u.data() + u.size(), 0.0);
434 std::span<const T> _v = _x->array();
435
436 // Evaluate geometry basis at point (0, 0, 0) on the reference cell.
437 // Used in affine case.
438 std::array<std::size_t, 4> phi0_shape = cmap.tabulate_shape(1, 1);
439 std::vector<double> phi0_b(std::reduce(phi0_shape.begin(), phi0_shape.end(),
440 1, std::multiplies{}));
441 cmdspan4_t phi0(phi0_b.data(), phi0_shape);
442 cmap.tabulate(1, std::vector<double>(tdim), {1, tdim}, phi0_b);
443 auto dphi0 = stdex::submdspan(phi0, std::pair(1, tdim + 1), 0,
444 stdex::full_extent, 0);
445
446 // Data structure for evaluating geometry basis at specific points.
447 // Used in non-affine case.
448 std::array<std::size_t, 4> phi_shape = cmap.tabulate_shape(1, 1);
449 std::vector<double> phi_b(
450 std::reduce(phi_shape.begin(), phi_shape.end(), 1, std::multiplies{}));
451 cmdspan4_t phi(phi_b.data(), phi_shape);
452 auto dphi = stdex::submdspan(phi, std::pair(1, tdim + 1), 0,
453 stdex::full_extent, 0);
454
455 // Reference coordinates for each point
456 std::vector<double> Xb(xshape[0] * tdim);
457 mdspan2_t X(Xb.data(), xshape[0], tdim);
458
459 // Geometry data at each point
460 std::vector<double> J_b(xshape[0] * gdim * tdim);
461 mdspan3_t J(J_b.data(), xshape[0], gdim, tdim);
462 std::vector<double> K_b(xshape[0] * tdim * gdim);
463 mdspan3_t K(K_b.data(), xshape[0], tdim, gdim);
464 std::vector<double> detJ(xshape[0]);
465 std::vector<double> det_scratch(2 * gdim * tdim);
466
467 // Prepare geometry data in each cell
468 for (std::size_t p = 0; p < cells.size(); ++p)
469 {
470 const int cell_index = cells[p];
471
472 // Skip negative cell indices
473 if (cell_index < 0)
474 continue;
475
476 // Get cell geometry (coordinate dofs)
477 auto x_dofs = x_dofmap.links(cell_index);
478 assert(x_dofs.size() == num_dofs_g);
479 for (std::size_t i = 0; i < num_dofs_g; ++i)
480 {
481 const int pos = 3 * x_dofs[i];
482 for (std::size_t j = 0; j < gdim; ++j)
483 coord_dofs(i, j) = x_g[pos + j];
484 }
485
486 for (std::size_t j = 0; j < gdim; ++j)
487 xp(0, j) = x[p * xshape[1] + j];
488
489 auto _J = stdex::submdspan(J, p, stdex::full_extent, stdex::full_extent);
490 auto _K = stdex::submdspan(K, p, stdex::full_extent, stdex::full_extent);
491
492 std::array<double, 3> Xpb = {0, 0, 0};
493 stdex::mdspan<double,
494 stdex::extents<std::size_t, 1, stdex::dynamic_extent>>
495 Xp(Xpb.data(), 1, tdim);
496
497 // Compute reference coordinates X, and J, detJ and K
498 if (cmap.is_affine())
499 {
500 CoordinateElement::compute_jacobian(dphi0, coord_dofs, _J);
502 std::array<double, 3> x0 = {0, 0, 0};
503 for (std::size_t i = 0; i < coord_dofs.extent(1); ++i)
504 x0[i] += coord_dofs(0, i);
506 detJ[p]
508 }
509 else
510 {
511 // Pull-back physical point xp to reference coordinate Xp
512 cmap.pull_back_nonaffine(Xp, xp, coord_dofs);
513
514 cmap.tabulate(1, std::span(Xpb.data(), tdim), {1, tdim}, phi_b);
515 CoordinateElement::compute_jacobian(dphi, coord_dofs, _J);
517 detJ[p]
519 }
520
521 for (std::size_t j = 0; j < X.extent(1); ++j)
522 X(p, j) = Xpb[j];
523 }
524
525 // Prepare basis function data structures
526 std::vector<double> basis_derivatives_reference_values_b(
527 1 * xshape[0] * space_dimension * reference_value_size);
528 cmdspan4_t basis_derivatives_reference_values(
529 basis_derivatives_reference_values_b.data(), 1, xshape[0],
530 space_dimension, reference_value_size);
531 std::vector<double> basis_values_b(space_dimension * value_size);
532 mdspan2_t basis_values(basis_values_b.data(), space_dimension, value_size);
533
534 // Compute basis on reference element
535 element->tabulate(basis_derivatives_reference_values_b, Xb,
536 {X.extent(0), X.extent(1)}, 0);
537
538 using xu_t = stdex::mdspan<double, stdex::dextents<std::size_t, 2>>;
539 using xU_t = stdex::mdspan<const double, stdex::dextents<std::size_t, 2>>;
540 using xJ_t = stdex::mdspan<const double, stdex::dextents<std::size_t, 2>>;
541 using xK_t = stdex::mdspan<const double, stdex::dextents<std::size_t, 2>>;
542 auto push_forward_fn
543 = element->basix_element().map_fn<xu_t, xU_t, xJ_t, xK_t>();
544
545 auto apply_dof_transformation
546 = element->get_dof_transformation_function<double>();
547 const std::size_t num_basis_values = space_dimension * reference_value_size;
548
549 for (std::size_t p = 0; p < cells.size(); ++p)
550 {
551 const int cell_index = cells[p];
552
553 // Skip negative cell indices
554 if (cell_index < 0)
555 continue;
556
557 // Permute the reference values to account for the cell's
558 // orientation
559 apply_dof_transformation(
560 std::span(basis_derivatives_reference_values_b.data()
561 + p * num_basis_values,
562 num_basis_values),
563 cell_info, cell_index, reference_value_size);
564
565 {
566 auto _U = stdex::submdspan(basis_derivatives_reference_values, 0, p,
567 stdex::full_extent, stdex::full_extent);
568 auto _J
569 = stdex::submdspan(J, p, stdex::full_extent, stdex::full_extent);
570 auto _K
571 = stdex::submdspan(K, p, stdex::full_extent, stdex::full_extent);
572 push_forward_fn(basis_values, _U, _J, detJ[p], _K);
573 }
574
575 // Get degrees of freedom for current cell
576 std::span<const std::int32_t> dofs = dofmap->cell_dofs(cell_index);
577 for (std::size_t i = 0; i < dofs.size(); ++i)
578 for (int k = 0; k < bs_dof; ++k)
579 coefficients[bs_dof * i + k] = _v[bs_dof * dofs[i] + k];
580
581 // Compute expansion
582 for (int k = 0; k < bs_element; ++k)
583 {
584 for (std::size_t i = 0; i < space_dimension; ++i)
585 {
586 for (std::size_t j = 0; j < value_size; ++j)
587 {
588 u[p * ushape[1] + (j * bs_element + k)]
589 += coefficients[bs_element * i + k] * basis_values(i, j);
590 }
591 }
592 }
593 }
594 }
595
597 std::string name = "u";
598
599private:
600 // The function space
601 std::shared_ptr<const FunctionSpace> _function_space;
602
603 // The vector of expansion coefficients (local)
604 std::shared_ptr<la::Vector<T>> _x;
605};
606} // namespace dolfinx::fem
Degree-of-freedom map representations and tools.
A CoordinateElement manages coordinate mappings for isoparametric cells.
Definition: CoordinateElement.h:32
static void compute_jacobian(const U &dphi, const V &cell_geometry, W &&J)
Compute Jacobian for a cell with given geometry using the basis functions and first order derivatives...
Definition: CoordinateElement.h:100
static void pull_back_affine(U &&X, const V &K, const std::array< double, 3 > &x0, const W &x)
Compute reference coordinates X for physical coordinates x for an affine map. For the affine case,...
Definition: CoordinateElement.h:184
static void compute_jacobian_inverse(const U &J, V &&K)
Compute the inverse of the Jacobian.
Definition: CoordinateElement.h:109
std::array< std::size_t, 4 > tabulate_shape(std::size_t nd, std::size_t num_points) const
Shape of array to fill when calling FiniteElement::tabulate
Definition: CoordinateElement.cpp:42
void pull_back_nonaffine(mdspan2_t X, cmdspan2_t x, cmdspan2_t cell_geometry, double tol=1.0e-8, int maxit=10) const
Compute reference coordinates X for physical coordinates x for a non-affine map.
Definition: CoordinateElement.cpp:62
void tabulate(int nd, std::span< const double > X, std::array< std::size_t, 2 > shape, std::span< double > basis) const
Evaluate basis values and derivatives at set of points.
Definition: CoordinateElement.cpp:47
bool is_affine() const noexcept
Check is geometry map is affine.
Definition: CoordinateElement.h:241
static double compute_jacobian_determinant(const U &J, std::span< typename U::value_type > w)
Compute the determinant of the Jacobian.
Definition: CoordinateElement.h:126
Represents a mathematical expression evaluated at a pre-defined set of points on the reference cell....
Definition: Expression.h:34
void eval(std::span< const std::int32_t > cells, std::span< T > values, std::array< std::size_t, 2 > vshape) const
Evaluate the expression on cells.
Definition: Expression.h:139
int value_size() const
Get value size.
Definition: Expression.h:230
std::pair< std::vector< double >, std::array< std::size_t, 2 > > X() const
Evaluation points on the reference cell.
Definition: Expression.h:242
std::shared_ptr< const FunctionSpace > argument_function_space() const
Get argument function space.
Definition: Expression.h:97
This class represents a function in a finite element function space , given by.
Definition: Function.h:43
void interpolate(const Expression< T > &e)
Interpolate an Expression (based on UFL) on all cells.
Definition: Function.h:321
void interpolate(const Function< T > &v)
Interpolate a Function.
Definition: Function.h:155
void interpolate(const std::function< std::pair< std::vector< T >, std::vector< std::size_t > >(std::experimental::mdspan< const double, std::experimental::extents< std::size_t, 3, std::experimental::dynamic_extent > >)> &f, std::span< const std::int32_t > cells)
Interpolate an expression function on a list of cells.
Definition: Function.h:172
Function collapse() const
Collapse a subfunction (view into a Function) to a stand-alone Function.
Definition: Function.h:110
Function sub(int i) const
Extract subfunction (view into the Function)
Definition: Function.h:100
void eval(std::span< const double > x, std::array< std::size_t, 2 > xshape, std::span< const std::int32_t > cells, std::span< T > u, std::array< std::size_t, 2 > ushape) const
Evaluate the Function at points.
Definition: Function.h:346
std::shared_ptr< const FunctionSpace > function_space() const
Access the function space.
Definition: Function.h:134
std::string name
Name.
Definition: Function.h:597
Function(std::shared_ptr< const FunctionSpace > V)
Create function on given function space.
Definition: Function.h:50
void interpolate(const std::function< std::pair< std::vector< T >, std::vector< std::size_t > >(std::experimental::mdspan< const double, std::experimental::extents< std::size_t, 3, std::experimental::dynamic_extent > >)> &f)
Interpolate an expression function on the whole domain.
Definition: Function.h:229
std::shared_ptr< la::Vector< T > > x()
Underlying vector.
Definition: Function.h:143
std::shared_ptr< const la::Vector< T > > x() const
Underlying vector.
Definition: Function.h:140
Function(std::shared_ptr< const FunctionSpace > V, std::shared_ptr< la::Vector< T > > x)
Create function on given function space with a given vector.
Definition: Function.h:69
void interpolate(const Function< T > &v, std::span< const std::int32_t > cells)
Interpolate a Function.
Definition: Function.h:148
void interpolate(const Expression< T > &e, std::span< const std::int32_t > cells)
Interpolate an Expression (based on UFL)
Definition: Function.h:253
~Function()=default
Destructor.
Function(Function &&v)=default
Move constructor.
Function & operator=(Function &&v)=default
Move assignment.
T value_type
Field type for the Function, e.g. double.
Definition: Function.h:46
This class provides a static adjacency list data structure. It is commonly used to store directed gra...
Definition: AdjacencyList.h:27
std::span< T > links(int node)
Get the links (edges) for given node.
Definition: AdjacencyList.h:109
Distributed vector.
Definition: Vector.h:26
Finite element method functionality.
Definition: assemble_matrix_impl.h:25
void interpolate(Function< T > &u, std::span< const T > f, std::array< std::size_t, 2 > fshape, std::span< const std::int32_t > cells)
Interpolate an expression f(x) in a finite element space.
Definition: interpolate.h:561
std::vector< double > interpolation_coords(const fem::FiniteElement &element, const mesh::Mesh &mesh, std::span< const std::int32_t > cells)
Compute the evaluation points in the physical space at which an expression should be computed to inte...
Definition: interpolate.cpp:16