10#include "FiniteElement.h"
11#include "FunctionSpace.h"
13#include <dolfinx/common/IndexMap.h>
14#include <dolfinx/common/math.h>
15#include <dolfinx/mesh/Mesh.h>
50 namespace stdex = std::experimental;
52 = stdex::mdspan<const double, stdex::dextents<std::size_t, 2>>;
53 using mdspan2_t = stdex::mdspan<double, stdex::dextents<std::size_t, 2>>;
55 = stdex::mdspan<const double, stdex::dextents<std::size_t, 4>>;
58 std::shared_ptr<const mesh::Mesh> mesh = V1.
mesh();
62 std::shared_ptr<const FiniteElement> e0 = V0.
element();
64 if (e0->map_type() != basix::maps::type::identity)
65 throw std::runtime_error(
"Wrong finite element space for V0.");
66 if (e0->block_size() != 1)
67 throw std::runtime_error(
"Block size is greater than 1 for V0.");
68 if (e0->reference_value_size() != 1)
69 throw std::runtime_error(
"Wrong value size for V0.");
71 std::shared_ptr<const FiniteElement> e1 = V1.
element();
73 if (e1->map_type() != basix::maps::type::covariantPiola)
74 throw std::runtime_error(
"Wrong finite element space for V1.");
75 if (e1->block_size() != 1)
76 throw std::runtime_error(
"Block size is greater than 1 for V1.");
79 const auto [X, Xshape] = e1->interpolation_points();
83 const int ndofs0 = e0->space_dimension();
84 const int tdim = mesh->topology().dim();
85 std::vector<double> phi0_b((tdim + 1) * Xshape[0] * ndofs0 * 1);
86 cmdspan4_t phi0(phi0_b.data(), tdim + 1, Xshape[0], ndofs0, 1);
87 e0->tabulate(phi0_b, X, Xshape, 1);
91 cmdspan2_t dphi_reshaped(
92 phi0_b.data() + phi0.extent(3) * phi0.extent(2) * phi0.extent(1),
93 tdim * phi0.extent(1), phi0.extent(2));
96 auto apply_inverse_dof_transform
97 = e1->get_dof_transformation_function<T>(
true,
true,
false);
100 mesh->topology_mutable().create_entity_permutations();
101 const std::vector<std::uint32_t>& cell_info
102 = mesh->topology().get_cell_permutation_info();
105 std::shared_ptr<const DofMap> dofmap0 = V0.
dofmap();
107 std::shared_ptr<const DofMap> dofmap1 = V1.
dofmap();
111 std::vector<T> Ab(e1->space_dimension() * ndofs0);
113 stdex::mdspan<T, stdex::dextents<std::size_t, 2>> A(
114 Ab.data(), e1->space_dimension(), ndofs0);
115 const auto [Pi, shape] = e1->interpolation_operator();
116 cmdspan2_t _Pi(Pi.data(), shape);
117 math::dot(_Pi, dphi_reshaped, A);
121 auto cell_map = mesh->topology().index_map(tdim);
123 std::int32_t num_cells = cell_map->size_local();
124 std::vector<T> Ae(Ab.size());
125 for (std::int32_t c = 0; c < num_cells; ++c)
127 std::copy(Ab.cbegin(), Ab.cend(), Ae.begin());
128 apply_inverse_dof_transform(Ae, cell_info, c, ndofs0);
129 mat_set(dofmap1->cell_dofs(c), dofmap0->cell_dofs(c), Ae);
153 auto mesh = V0.
mesh();
157 const int tdim = mesh->topology().dim();
158 const int gdim = mesh->geometry().dim();
161 std::shared_ptr<const FiniteElement> e0 = V0.
element();
163 std::shared_ptr<const FiniteElement> e1 = V1.
element();
166 std::span<const std::uint32_t> cell_info;
167 if (e1->needs_dof_transformations() or e0->needs_dof_transformations())
169 mesh->topology_mutable().create_entity_permutations();
170 cell_info = std::span(mesh->topology().get_cell_permutation_info());
174 auto dofmap0 = V0.
dofmap();
176 auto dofmap1 = V1.
dofmap();
180 const int bs0 = e0->block_size();
181 const int bs1 = e1->block_size();
182 const auto apply_dof_transformation0
183 = e0->get_dof_transformation_function<
double>(
false,
false,
false);
184 const auto apply_inverse_dof_transform1
185 = e1->get_dof_transformation_function<T>(
true,
true,
false);
188 const std::size_t space_dim0 = e0->space_dimension();
189 const std::size_t space_dim1 = e1->space_dimension();
190 const std::size_t dim0 = space_dim0 / bs0;
191 const std::size_t value_size_ref0 = e0->reference_value_size() / bs0;
192 const std::size_t value_size0 = e0->value_size() / bs0;
193 const std::size_t value_size1 = e1->value_size() / bs1;
198 = mesh->geometry().dofmap();
199 const std::size_t num_dofs_g = cmap.
dim();
200 std::span<const double> x_g = mesh->geometry().x();
202 namespace stdex = std::experimental;
203 using mdspan2_t = stdex::mdspan<double, stdex::dextents<std::size_t, 2>>;
205 = stdex::mdspan<const double, stdex::dextents<std::size_t, 2>>;
207 = stdex::mdspan<const double, stdex::dextents<std::size_t, 3>>;
209 = stdex::mdspan<const double, stdex::dextents<std::size_t, 4>>;
210 using mdspan3_t = stdex::mdspan<double, stdex::dextents<std::size_t, 3>>;
213 const auto [X, Xshape] = e1->interpolation_points();
214 std::array<std::size_t, 4> phi_shape = cmap.
tabulate_shape(1, Xshape[0]);
215 std::vector<double> phi_b(
216 std::reduce(phi_shape.begin(), phi_shape.end(), 1, std::multiplies{}));
217 cmdspan4_t phi(phi_b.data(), phi_shape);
221 std::vector<double> basis_derivatives_reference0_b(Xshape[0] * dim0
223 cmdspan4_t basis_derivatives_reference0(basis_derivatives_reference0_b.data(),
224 1, Xshape[0], dim0, value_size_ref0);
225 e0->tabulate(basis_derivatives_reference0_b, X, Xshape, 0);
228 std::transform(basis_derivatives_reference0_b.begin(),
229 basis_derivatives_reference0_b.end(),
230 basis_derivatives_reference0_b.begin(),
231 [atol = 1e-14](
auto x)
232 { return std::abs(x) < atol ? 0.0 : x; });
235 std::vector<double> basis_reference0_b(Xshape[0] * dim0 * value_size_ref0);
236 mdspan3_t basis_reference0(basis_reference0_b.data(), Xshape[0], dim0,
238 std::vector<double> J_b(Xshape[0] * gdim * tdim);
239 mdspan3_t J(J_b.data(), Xshape[0], gdim, tdim);
240 std::vector<double> K_b(Xshape[0] * tdim * gdim);
241 mdspan3_t K(K_b.data(), Xshape[0], tdim, gdim);
242 std::vector<double> detJ(Xshape[0]);
243 std::vector<double> det_scratch(2 * tdim * gdim);
248 const auto [_Pi_1, pi_shape] = e1->interpolation_operator();
249 cmdspan2_t Pi_1(_Pi_1.data(), pi_shape);
251 bool interpolation_ident = e1->interpolation_ident();
253 namespace stdex = std::experimental;
254 using u_t = stdex::mdspan<double, stdex::dextents<std::size_t, 2>>;
255 using U_t = stdex::mdspan<const double, stdex::dextents<std::size_t, 2>>;
256 using J_t = stdex::mdspan<const double, stdex::dextents<std::size_t, 2>>;
257 using K_t = stdex::mdspan<const double, stdex::dextents<std::size_t, 2>>;
258 auto push_forward_fn0 = e0->basix_element().map_fn<u_t, U_t, J_t, K_t>();
262 std::vector<double> basis_values_b(Xshape[0] * bs0 * dim0 * e1->value_size());
263 mdspan3_t basis_values(basis_values_b.data(), Xshape[0], bs0 * dim0,
265 std::vector<double> mapped_values_b(Xshape[0] * bs0 * dim0
267 mdspan3_t mapped_values(mapped_values_b.data(), Xshape[0], bs0 * dim0,
270 auto pull_back_fn1 = e1->basix_element().map_fn<u_t, U_t, K_t, J_t>();
272 std::vector<double> coord_dofs_b(num_dofs_g * gdim);
273 mdspan2_t coord_dofs(coord_dofs_b.data(), num_dofs_g, gdim);
274 std::vector<double> basis0_b(Xshape[0] * dim0 * value_size0);
275 mdspan3_t basis0(basis0_b.data(), Xshape[0], dim0, value_size0);
278 std::vector<T> Ab(space_dim0 * space_dim1);
279 std::vector<T> local1(space_dim1);
282 auto cell_map = mesh->topology().index_map(tdim);
284 std::int32_t num_cells = cell_map->size_local();
285 for (std::int32_t c = 0; c < num_cells; ++c)
288 auto x_dofs = x_dofmap.
links(c);
289 for (std::size_t i = 0; i < x_dofs.size(); ++i)
291 for (std::size_t j = 0; j < gdim; ++j)
292 coord_dofs(i, j) = x_g[3 * x_dofs[i] + j];
296 std::fill(J_b.begin(), J_b.end(), 0);
297 for (std::size_t p = 0; p < Xshape[0]; ++p)
299 auto dphi = stdex::submdspan(phi, std::pair(1, tdim + 1), p,
300 stdex::full_extent, 0);
301 auto _J = stdex::submdspan(J, p, stdex::full_extent, stdex::full_extent);
303 auto _K = stdex::submdspan(K, p, stdex::full_extent, stdex::full_extent);
310 for (std::size_t k0 = 0; k0 < basis_reference0.extent(0); ++k0)
311 for (std::size_t k1 = 0; k1 < basis_reference0.extent(1); ++k1)
312 for (std::size_t k2 = 0; k2 < basis_reference0.extent(2); ++k2)
313 basis_reference0(k0, k1, k2)
314 = basis_derivatives_reference0(0, k0, k1, k2);
315 for (std::size_t p = 0; p < Xshape[0]; ++p)
317 apply_dof_transformation0(
318 std::span(basis_reference0.data_handle() + p * dim0 * value_size_ref0,
319 dim0 * value_size_ref0),
320 cell_info, c, value_size_ref0);
323 for (std::size_t p = 0; p < basis0.extent(0); ++p)
326 = stdex::submdspan(basis0, p, stdex::full_extent, stdex::full_extent);
327 auto _U = stdex::submdspan(basis_reference0, p, stdex::full_extent,
329 auto _K = stdex::submdspan(K, p, stdex::full_extent, stdex::full_extent);
330 auto _J = stdex::submdspan(J, p, stdex::full_extent, stdex::full_extent);
331 push_forward_fn0(_u, _U, _J, detJ[p], _K);
335 for (std::size_t p = 0; p < Xshape[0]; ++p)
336 for (std::size_t i = 0; i < dim0; ++i)
337 for (std::size_t j = 0; j < value_size0; ++j)
338 for (
int k = 0; k < bs0; ++k)
339 basis_values(p, i * bs0 + k, j * bs0 + k) = basis0(p, i, j);
342 for (std::size_t p = 0; p < basis_values.extent(0); ++p)
344 auto _u = stdex::submdspan(basis_values, p, stdex::full_extent,
346 auto _U = stdex::submdspan(mapped_values, p, stdex::full_extent,
348 auto _K = stdex::submdspan(K, p, stdex::full_extent, stdex::full_extent);
349 auto _J = stdex::submdspan(J, p, stdex::full_extent, stdex::full_extent);
350 pull_back_fn1(_U, _u, _K, 1.0 / detJ[p], _J);
355 if (interpolation_ident)
357 stdex::mdspan<T, stdex::dextents<std::size_t, 3>> A(
358 Ab.data(), Xshape[0], e1->value_size(), space_dim0);
359 for (std::size_t i = 0; i < mapped_values.extent(0); ++i)
360 for (std::size_t j = 0; j < mapped_values.extent(1); ++j)
361 for (std::size_t k = 0; k < mapped_values.extent(2); ++k)
362 A(i, k, j) = mapped_values(i, j, k);
366 for (std::size_t i = 0; i < mapped_values.extent(1); ++i)
368 auto values = stdex::submdspan(mapped_values, stdex::full_extent, i,
370 impl::interpolation_apply(Pi_1, values, std::span(local1), bs1);
371 for (std::size_t j = 0; j < local1.size(); j++)
372 Ab[space_dim0 * j + i] = local1[j];
376 apply_inverse_dof_transform1(Ab, cell_info, c, space_dim0);
377 mat_set(dofmap1->cell_dofs(c), dofmap0->cell_dofs(c), Ab);
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 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 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
int dim() const
The dimension of the geometry element space.
Definition: CoordinateElement.cpp:183
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
This class represents a finite element function space defined by a mesh, a finite element,...
Definition: FunctionSpace.h:31
std::shared_ptr< const DofMap > dofmap() const
The dofmap.
Definition: FunctionSpace.cpp:253
std::shared_ptr< const mesh::Mesh > mesh() const
The mesh.
Definition: FunctionSpace.cpp:246
std::shared_ptr< const FiniteElement > element() const
The finite element.
Definition: FunctionSpace.cpp:248
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
Finite element method functionality.
Definition: assemble_matrix_impl.h:25
void interpolation_matrix(const FunctionSpace &V0, const FunctionSpace &V1, auto &&mat_set)
Assemble an interpolation operator matrix.
Definition: discreteoperators.h:149
void discrete_gradient(const FunctionSpace &V0, const FunctionSpace &V1, auto &&mat_set)
Assemble a discrete gradient operator.
Definition: discreteoperators.h:47