9 #include "FunctionSpace.h"
10 #include "interpolate.h"
11 #include <dolfinx/common/IndexMap.h>
12 #include <dolfinx/common/UniqueIdGenerator.h>
13 #include <dolfinx/common/array2d.h>
14 #include <dolfinx/fem/DofMap.h>
15 #include <dolfinx/fem/FiniteElement.h>
16 #include <dolfinx/la/PETScVector.h>
17 #include <dolfinx/la/Vector.h>
18 #include <dolfinx/mesh/Geometry.h>
19 #include <dolfinx/mesh/Mesh.h>
20 #include <dolfinx/mesh/Topology.h>
29 #include <xtensor/xadapt.hpp>
30 #include <xtensor/xio.hpp>
31 #include <xtensor/xtensor.hpp>
32 #include <xtl/xspan.hpp>
52 explicit Function(std::shared_ptr<const FunctionSpace> V)
53 : _id(common::UniqueIdGenerator::
id()), _function_space(V),
54 _x(std::make_shared<la::Vector<T>>(V->dofmap()->index_map,
55 V->dofmap()->index_map_bs()))
57 if (!V->component().empty())
59 throw std::runtime_error(
"Cannot create Function from subspace. Consider "
60 "collapsing the function space");
70 Function(std::shared_ptr<const FunctionSpace> V,
72 : _id(common::UniqueIdGenerator::
id()), _function_space(V), _x(
x)
79 assert(V->dofmap()->index_map->size_global() * V->dofmap()->index_map_bs()
80 <= _x->bs() * _x->map()->size_global());
88 :
name(std::move(v.
name)), _id(std::move(v._id)),
89 _function_space(std::move(v._function_space)), _x(std::move(v._x)),
90 _petsc_vector(std::exchange(v._petsc_vector, nullptr))
98 VecDestroy(&_petsc_vector);
104 name = std::move(v.name);
105 _id = std::move(v._id);
106 _function_space = std::move(v._function_space);
107 _x = std::move(v._x);
108 std::swap(_petsc_vector, v._petsc_vector);
121 auto sub_space = _function_space->
sub({i});
132 const auto [function_space_new, collapsed_map]
136 assert(function_space_new);
137 auto vector_new = std::make_shared<la::Vector<T>>(
138 function_space_new->dofmap()->index_map,
139 function_space_new->dofmap()->index_map_bs());
142 const std::vector<T>& x_old = _x->array();
143 std::vector<T>& x_new = vector_new->mutable_array();
144 for (std::size_t i = 0; i < collapsed_map.size(); ++i)
146 assert((
int)i < x_new.size());
147 assert(collapsed_map[i] < x_old.size());
148 x_new[i] = x_old[collapsed_map[i]];
151 return Function(function_space_new, vector_new);
158 return _function_space;
167 assert(_function_space->dofmap());
168 assert(_function_space->dofmap()->index_map);
169 if (_x->bs() * _x->map()->size_global()
170 != _function_space->dofmap()->index_map->size_global()
171 * _function_space->dofmap()->index_map_bs())
173 throw std::runtime_error(
174 "Cannot access a non-const vector from a subfunction");
178 if constexpr (std::is_same<T, PetscScalar>::value)
183 *_function_space->dofmap()->index_map,
184 _function_space->dofmap()->index_map_bs(), _x->mutable_array());
187 return _petsc_vector;
191 throw std::runtime_error(
192 "Cannot return PETSc vector wrapper. Type mismatch");
197 std::shared_ptr<const la::Vector<T>>
x()
const {
return _x; }
200 std::shared_ptr<la::Vector<T>>
x() {
return _x; }
209 const std::function<xt::xarray<T>(
const xt::xtensor<double, 2>&)>& f)
211 assert(_function_space);
212 assert(_function_space->element());
213 assert(_function_space->mesh());
214 const int tdim = _function_space->mesh()->topology().dim();
215 auto cell_map = _function_space->mesh()->topology().index_map(tdim);
217 const int num_cells = cell_map->size_local() + cell_map->num_ghosts();
218 std::vector<std::int32_t> cells(num_cells, 0);
219 std::iota(cells.begin(), cells.end(), 0);
223 *_function_space->element(), *_function_space->mesh(), cells);
237 void eval(
const xt::xtensor<double, 2>&
x,
238 const xtl::span<const std::int32_t>& cells,
239 xt::xtensor<T, 2>& u)
const
244 if (
x.shape(0) != cells.size())
246 throw std::runtime_error(
247 "Number of points and number of cells must be equal.");
249 if (
x.shape(0) != u.shape(0))
251 throw std::runtime_error(
252 "Length of array for Function values must be the "
253 "same as the number of points.");
257 assert(_function_space);
258 std::shared_ptr<const mesh::Mesh> mesh = _function_space->mesh();
260 const std::size_t gdim = mesh->geometry().dim();
261 const std::size_t tdim = mesh->topology().dim();
262 auto map = mesh->topology().index_map(tdim);
266 = mesh->geometry().dofmap();
268 const std::size_t num_dofs_g = x_dofmap.
num_links(0);
269 const xt::xtensor<double, 2>& x_g = mesh->geometry().x();
275 assert(_function_space->element());
276 std::shared_ptr<const fem::FiniteElement> element
277 = _function_space->element();
279 const int bs_element = element->block_size();
280 const std::size_t reference_value_size
281 = element->reference_value_size() / bs_element;
282 const std::size_t value_size = element->value_size() / bs_element;
283 const std::size_t space_dimension = element->space_dimension() / bs_element;
287 const int num_sub_elements = element->num_sub_elements();
288 if (num_sub_elements > 1 and num_sub_elements != bs_element)
290 throw std::runtime_error(
"Function::eval is not supported for mixed "
291 "elements. Extract subspaces.");
295 xt::xtensor<double, 2> X({1, tdim});
296 xt::xtensor<double, 3> J
297 = xt::zeros<double>({
static_cast<std::size_t
>(1), gdim, tdim});
298 xt::xtensor<double, 3> K
299 = xt::zeros<double>({
static_cast<std::size_t
>(1), tdim, gdim});
300 xt::xtensor<double, 1> detJ = xt::zeros<double>({1});
303 xt::xtensor<double, 3> basis_reference_values(
304 {1, space_dimension, reference_value_size});
305 xt::xtensor<double, 3> basis_values(
306 {
static_cast<std::size_t
>(1), space_dimension, value_size});
309 std::vector<T> coefficients(space_dimension * bs_element);
312 std::shared_ptr<const fem::DofMap> dofmap = _function_space->dofmap();
314 const int bs_dof = dofmap->bs();
316 mesh->topology_mutable().create_entity_permutations();
317 const std::vector<std::uint32_t>& cell_info
318 = mesh->topology().get_cell_permutation_info();
319 xt::xtensor<double, 2> coordinate_dofs
320 = xt::zeros<double>({num_dofs_g, gdim});
321 xt::xtensor<double, 2> xp
322 = xt::zeros<double>({
static_cast<std::size_t
>(1), gdim});
325 std::fill(u.data(), u.data() + u.size(), 0.0);
326 const std::vector<T>& _v = _x->mutable_array();
327 for (std::size_t p = 0; p < cells.size(); ++p)
329 const int cell_index = cells[p];
336 auto x_dofs = x_dofmap.
links(cell_index);
337 for (std::size_t i = 0; i < num_dofs_g; ++i)
338 for (std::size_t j = 0; j < gdim; ++j)
339 coordinate_dofs(i, j) = x_g(x_dofs[i], j);
341 for (std::size_t j = 0; j < gdim; ++j)
345 cmap.
pull_back(X, J, detJ, K, xp, coordinate_dofs);
348 element->evaluate_reference_basis(basis_reference_values, X);
351 element->apply_dof_transformation(
352 xtl::span(basis_reference_values.data(),
353 basis_reference_values.size()),
354 cell_info[cell_index], reference_value_size);
357 element->transform_reference_basis(basis_values, basis_reference_values,
361 xtl::span<const std::int32_t> dofs = dofmap->cell_dofs(cell_index);
362 for (std::size_t i = 0; i < dofs.size(); ++i)
363 for (
int k = 0; k < bs_dof; ++k)
364 coefficients[bs_dof * i + k] = _v[bs_dof * dofs[i] + k];
367 auto u_row = xt::row(u, p);
368 for (
int k = 0; k < bs_element; ++k)
370 for (std::size_t i = 0; i < space_dimension; ++i)
372 for (std::size_t j = 0; j < value_size; ++j)
374 u_row[j * bs_element + k]
375 += coefficients[bs_element * i + k] * basis_values(0, i, j);
386 assert(_function_space);
387 std::shared_ptr<const mesh::Mesh> mesh = _function_space->mesh();
389 const int tdim = mesh->topology().dim();
392 const std::size_t value_size_loc = _function_space->element()->value_size();
395 xt::xtensor<T, 2> point_values(
396 {mesh->geometry().
x().shape(0), value_size_loc});
400 = mesh->geometry().dofmap();
403 const int num_dofs_g = x_dofmap.
num_links(0);
404 const xt::xtensor<double, 2>& x_g = mesh->geometry().x();
408 auto map = mesh->topology().index_map(tdim);
410 const std::int32_t num_cells = map->size_local() + map->num_ghosts();
412 std::vector<std::int32_t> cells(x_g.shape(0));
413 for (std::int32_t c = 0; c < num_cells; ++c)
416 xtl::span<const std::int32_t> dofs = x_dofmap.links(c);
417 for (
int i = 0; i < num_dofs_g; ++i)
421 eval(x_g, cells, point_values);
430 std::size_t
id()
const {
return _id; }
437 std::shared_ptr<const FunctionSpace> _function_space;
440 std::shared_ptr<la::Vector<T>> _x;
443 mutable Vec _petsc_vector =
nullptr;