9 #include "FunctionSpace.h"
10 #include <dolfinx/fem/DofMap.h>
11 #include <dolfinx/fem/FiniteElement.h>
12 #include <dolfinx/mesh/Mesh.h>
15 #include <xtensor/xadapt.hpp>
16 #include <xtensor/xtensor.hpp>
17 #include <xtensor/xview.hpp>
18 #include <xtl/xspan.hpp>
36 xt::xtensor<double, 2>
38 const xtl::span<const std::int32_t>& cells);
45 void interpolate(Function<T>& u,
const Function<T>& v);
61 const std::function<xt::xarray<T>(
const xt::xtensor<double, 2>&)>& f,
62 const xt::xtensor<double, 2>& x,
63 const xtl::span<const std::int32_t>& cells);
84 const std::function<
void(xt::xarray<T>&,
const xt::xtensor<double, 2>&)>& f,
85 const xt::xtensor<double, 2>& x,
86 const xtl::span<const std::int32_t>& cells);
92 void interpolate_from_any(Function<T>& u,
const Function<T>& v)
94 assert(v.function_space());
95 const auto element = u.function_space()->element();
97 if (v.function_space()->element()->hash() != element->hash())
99 throw std::runtime_error(
"Restricting finite elements function in "
100 "different elements not supported.");
103 const auto mesh = u.function_space()->mesh();
105 assert(v.function_space()->mesh());
106 if (mesh->id() != v.function_space()->mesh()->id())
108 throw std::runtime_error(
109 "Interpolation on different meshes not supported (yet).");
111 const int tdim = mesh->topology().dim();
114 assert(v.function_space());
115 std::shared_ptr<const fem::DofMap> dofmap_v = v.function_space()->dofmap();
117 auto map = mesh->topology().index_map(tdim);
120 std::vector<T>& coeffs = u.x()->mutable_array();
123 const auto dofmap_u = u.function_space()->dofmap();
124 const std::vector<T>& v_array = v.x()->array();
125 const int num_cells = map->size_local() + map->num_ghosts();
126 const int bs = dofmap_v->bs();
127 assert(bs == dofmap_u->bs());
128 for (
int c = 0; c < num_cells; ++c)
130 xtl::span<const std::int32_t> dofs_v = dofmap_v->cell_dofs(c);
131 xtl::span<const std::int32_t> cell_dofs = dofmap_u->cell_dofs(c);
132 assert(dofs_v.size() == cell_dofs.size());
133 for (std::size_t i = 0; i < dofs_v.size(); ++i)
135 for (
int k = 0; k < bs; ++k)
136 coeffs[bs * cell_dofs[i] + k] = v_array[bs * dofs_v[i] + k];
144 template <
typename T>
148 const std::shared_ptr<const FiniteElement> element
154 element->value_rank() != rank_v)
156 throw std::runtime_error(
"Cannot interpolate function into function space. "
158 + std::to_string(rank_v)
159 +
") does not match rank of function space ("
160 + std::to_string(element->value_rank()) +
")");
164 for (
int i = 0; i < element->value_rank(); ++i)
166 if (
int v_dim = v.
function_space()->element()->value_dimension(i);
167 element->value_dimension(i) != v_dim)
169 throw std::runtime_error(
170 "Cannot interpolate function into function space. "
172 + std::to_string(i) +
" of function (" + std::to_string(v_dim)
173 +
") does not match dimension " + std::to_string(i)
174 +
" of function space(" + std::to_string(element->value_dimension(i))
179 detail::interpolate_from_any(u, v);
182 template <
typename T>
185 const std::function<xt::xarray<T>(
const xt::xtensor<double, 2>&)>& f,
186 const xt::xtensor<double, 2>& x,
const xtl::span<const std::int32_t>& cells)
188 const std::shared_ptr<const FiniteElement> element
191 const int element_bs = element->block_size();
192 if (
int num_sub = element->num_sub_elements();
193 num_sub > 0 and num_sub != element_bs)
195 throw std::runtime_error(
"Cannot directly interpolate a mixed space. "
196 "Interpolate into subspaces.");
204 const int gdim = mesh->geometry().dim();
205 const int tdim = mesh->topology().dim();
208 const xt::xtensor<double, 2>& X = element->interpolation_points();
211 throw std::runtime_error(
212 "Interpolation into this space is not yet supported.");
214 mesh->topology_mutable().create_entity_permutations();
215 const std::vector<std::uint32_t>& cell_info
216 = mesh->topology().get_cell_permutation_info();
222 xt::xarray<T> values = f(x);
224 if (values.dimension() == 1)
226 if (element->value_size() != 1)
227 throw std::runtime_error(
"Interpolation data has the wrong shape.");
228 values.reshape({element->value_size(), x.shape(1)});
231 if (values.shape(0) != element->value_size())
232 throw std::runtime_error(
"Interpolation data has the wrong shape.");
234 if (values.shape(1) != cells.size() * X.shape(0))
235 throw std::runtime_error(
"Interpolation data has the wrong shape.");
240 const int dofmap_bs = dofmap->bs();
243 const int num_scalar_dofs = element->space_dimension() / element_bs;
244 const int value_size = element->value_size() / element_bs;
246 std::vector<T>& coeffs = u.
x()->mutable_array();
247 std::vector<T> _coeffs(num_scalar_dofs);
251 if (element->interpolation_ident())
253 for (std::int32_t c : cells)
255 xtl::span<const std::int32_t> dofs = dofmap->cell_dofs(c);
256 for (
int k = 0; k < element_bs; ++k)
258 for (
int i = 0; i < num_scalar_dofs; ++i)
259 _coeffs[i] = values(k, c * num_scalar_dofs + i);
260 element->apply_inverse_transpose_dof_transformation(
261 tcb::make_span(_coeffs), cell_info[c], 1);
262 for (
int i = 0; i < num_scalar_dofs; ++i)
264 const int dof = i * element_bs + k;
265 std::div_t pos = std::div(dof, dofmap_bs);
266 coeffs[dofmap_bs * dofs[pos.quot] + pos.rem] = _coeffs[i];
278 = mesh->geometry().dofmap();
280 const int num_dofs_g = x_dofmap.
num_links(0);
281 const xt::xtensor<double, 2>& x_g = mesh->geometry().x();
284 xt::xtensor<double, 3> J = xt::empty<double>({int(X.shape(0)), gdim, tdim});
285 xt::xtensor<double, 3> K = xt::empty<double>({int(X.shape(0)), tdim, gdim});
286 xt::xtensor<double, 1> detJ = xt::empty<double>({X.shape(0)});
288 xt::xtensor<double, 2> coordinate_dofs
289 = xt::empty<double>({num_dofs_g, gdim});
291 xt::xtensor<T, 3> reference_data({X.shape(0), 1, value_size});
292 xt::xtensor<T, 3> _vals({X.shape(0), 1, value_size});
295 xt::xtensor<double, 4> dphi
296 = xt::view(cmap.
tabulate(1, X), xt::range(1, tdim + 1), xt::all(),
297 xt::all(), xt::all());
299 for (std::int32_t c : cells)
301 auto x_dofs = x_dofmap.
links(c);
302 for (
int i = 0; i < num_dofs_g; ++i)
303 for (
int j = 0; j < gdim; ++j)
304 coordinate_dofs(i, j) = x_g(x_dofs[i], j);
311 xtl::span<const std::int32_t> dofs = dofmap->cell_dofs(c);
312 for (
int k = 0; k < element_bs; ++k)
315 for (
int m = 0; m < value_size; ++m)
317 std::copy_n(&values(k * value_size + m, c * X.shape(0)), X.shape(0),
318 xt::view(_vals, xt::all(), 0, m).begin());
322 element->map_pull_back(_vals, J, detJ, K, reference_data);
324 xt::xtensor<T, 2> ref_data
325 = xt::transpose(xt::view(reference_data, xt::all(), 0, xt::all()));
326 element->interpolate(ref_data, tcb::make_span(_coeffs));
327 element->apply_inverse_transpose_dof_transformation(
328 tcb::make_span(_coeffs), cell_info[c], 1);
330 assert(_coeffs.size() == num_scalar_dofs);
333 for (
int i = 0; i < num_scalar_dofs; ++i)
335 const int dof = i * element_bs + k;
336 std::div_t pos = std::div(dof, dofmap_bs);
337 coeffs[dofmap_bs * dofs[pos.quot] + pos.rem] = _coeffs[i];
344 template <
typename T>
347 const std::function<
void(xt::xarray<T>&,
const xt::xtensor<double, 2>&)>& f,
348 const xt::xtensor<double, 2>& x,
const xtl::span<const std::int32_t>& cells)
350 const std::shared_ptr<const FiniteElement> element
353 std::vector<int> vshape(element->value_rank(), 1);
354 for (std::size_t i = 0; i < vshape.size(); ++i)
355 vshape[i] = element->value_dimension(i);
356 const std::size_t value_size = std::accumulate(
357 std::begin(vshape), std::end(vshape), 1, std::multiplies<>());
359 auto fn = [value_size, &f](
const xt::xtensor<double, 2>& x) {
360 xt::xarray<T> values = xt::empty<T>({value_size, x.shape(1)});
365 interpolate<T>(u, fn, x, cells);