54 std::reference_wrapper<const DofMap>>
57 std::reference_wrapper<const DofMap>>
61 auto& e0 = V0.first.get();
62 const DofMap& dofmap0 = V0.second.get();
63 auto& e1 = V1.first.get();
64 const DofMap& dofmap1 = V1.second.get();
66 using cmdspan2_t = MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
67 const U, MDSPAN_IMPL_STANDARD_NAMESPACE::dextents<std::size_t, 2>>;
68 using mdspan2_t = MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
69 U, MDSPAN_IMPL_STANDARD_NAMESPACE::dextents<std::size_t, 2>>;
70 using cmdspan4_t = MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
71 const U, MDSPAN_IMPL_STANDARD_NAMESPACE::dextents<std::size_t, 4>>;
74 if (e0.map_type() != basix::maps::type::identity)
75 throw std::runtime_error(
"Wrong finite element space for V0.");
76 if (e0.block_size() != 1)
77 throw std::runtime_error(
"Block size is greater than 1 for V0.");
78 if (e0.reference_value_size() != 1)
79 throw std::runtime_error(
"Wrong value size for V0.");
81 if (e1.map_type() != basix::maps::type::covariantPiola)
82 throw std::runtime_error(
"Wrong finite element space for V1.");
83 if (e1.block_size() != 1)
84 throw std::runtime_error(
"Block size is greater than 1 for V1.");
87 const auto [X, Xshape] = e1.interpolation_points();
91 const int ndofs0 = e0.space_dimension();
92 const int tdim = topology.
dim();
93 std::vector<U> phi0_b((tdim + 1) * Xshape[0] * ndofs0 * 1);
94 cmdspan4_t phi0(phi0_b.data(), tdim + 1, Xshape[0], ndofs0, 1);
95 e0.tabulate(phi0_b, X, Xshape, 1);
99 cmdspan2_t dphi_reshaped(
100 phi0_b.data() + phi0.extent(3) * phi0.extent(2) * phi0.extent(1),
101 tdim * phi0.extent(1), phi0.extent(2));
104 auto apply_inverse_dof_transform
105 = e1.template get_dof_transformation_function<T>(
true,
true,
false);
109 const std::vector<std::uint32_t>& cell_info
115 std::vector<T> Ab(e1.space_dimension() * ndofs0);
117 MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
118 T, MDSPAN_IMPL_STANDARD_NAMESPACE::dextents<std::size_t, 2>>
119 A(Ab.data(), e1.space_dimension(), ndofs0);
120 const auto [Pi, shape] = e1.interpolation_operator();
121 cmdspan2_t _Pi(Pi.data(), shape);
122 math::dot(_Pi, dphi_reshaped, A);
126 auto cell_map = topology.
index_map(tdim);
128 std::int32_t num_cells = cell_map->size_local();
129 std::vector<T> Ae(Ab.size());
130 for (std::int32_t c = 0; c < num_cells; ++c)
132 std::copy(Ab.cbegin(), Ab.cend(), Ae.begin());
133 apply_inverse_dof_transform(Ae, cell_info, c, ndofs0);
158 auto mesh = V0.
mesh();
162 const int tdim = mesh->topology()->dim();
163 const int gdim = mesh->geometry().dim();
166 std::shared_ptr<const FiniteElement<U>> e0 = V0.
element();
168 std::shared_ptr<const FiniteElement<U>> e1 = V1.
element();
171 std::span<const std::uint32_t> cell_info;
172 if (e1->needs_dof_transformations() or e0->needs_dof_transformations())
174 mesh->topology_mutable()->create_entity_permutations();
175 cell_info = std::span(mesh->topology()->get_cell_permutation_info());
179 auto dofmap0 = V0.
dofmap();
181 auto dofmap1 = V1.
dofmap();
185 const int bs0 = e0->block_size();
186 const int bs1 = e1->block_size();
187 auto apply_dof_transformation0
188 = e0->template get_dof_transformation_function<U>(
false,
false,
false);
189 auto apply_inverse_dof_transform1
190 = e1->template get_dof_transformation_function<T>(
true,
true,
false);
193 const std::size_t space_dim0 = e0->space_dimension();
194 const std::size_t space_dim1 = e1->space_dimension();
195 const std::size_t dim0 = space_dim0 / bs0;
196 const std::size_t value_size_ref0 = e0->reference_value_size() / bs0;
197 const std::size_t value_size0 = e0->value_size() / bs0;
198 const std::size_t value_size1 = e1->value_size() / bs1;
201 auto cmaps = mesh->geometry().cmaps();
202 assert(cmaps.size() == 1);
205 auto x_dofmap = mesh->geometry().dofmap();
206 const std::size_t num_dofs_g = cmap.
dim();
207 std::span<const U> x_g = mesh->geometry().x();
209 using mdspan2_t = MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
210 U, MDSPAN_IMPL_STANDARD_NAMESPACE::dextents<std::size_t, 2>>;
211 using cmdspan2_t = MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
212 const U, MDSPAN_IMPL_STANDARD_NAMESPACE::dextents<std::size_t, 2>>;
213 using cmdspan3_t = MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
214 const U, MDSPAN_IMPL_STANDARD_NAMESPACE::dextents<std::size_t, 3>>;
215 using cmdspan4_t = MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
216 const U, MDSPAN_IMPL_STANDARD_NAMESPACE::dextents<std::size_t, 4>>;
217 using mdspan3_t = MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
218 U, MDSPAN_IMPL_STANDARD_NAMESPACE::dextents<std::size_t, 3>>;
221 const auto [X, Xshape] = e1->interpolation_points();
222 std::array<std::size_t, 4> phi_shape = cmap.
tabulate_shape(1, Xshape[0]);
223 std::vector<U> phi_b(
224 std::reduce(phi_shape.begin(), phi_shape.end(), 1, std::multiplies{}));
225 cmdspan4_t phi(phi_b.data(), phi_shape);
229 std::vector<U> basis_derivatives_reference0_b(Xshape[0] * dim0
231 cmdspan4_t basis_derivatives_reference0(basis_derivatives_reference0_b.data(),
232 1, Xshape[0], dim0, value_size_ref0);
233 e0->tabulate(basis_derivatives_reference0_b, X, Xshape, 0);
236 std::transform(basis_derivatives_reference0_b.begin(),
237 basis_derivatives_reference0_b.end(),
238 basis_derivatives_reference0_b.begin(),
239 [atol = 1e-14](
auto x)
240 { return std::abs(x) < atol ? 0.0 : x; });
243 std::vector<U> basis_reference0_b(Xshape[0] * dim0 * value_size_ref0);
244 mdspan3_t basis_reference0(basis_reference0_b.data(), Xshape[0], dim0,
246 std::vector<U> J_b(Xshape[0] * gdim * tdim);
247 mdspan3_t J(J_b.data(), Xshape[0], gdim, tdim);
248 std::vector<U> K_b(Xshape[0] * tdim * gdim);
249 mdspan3_t K(K_b.data(), Xshape[0], tdim, gdim);
250 std::vector<U> detJ(Xshape[0]);
251 std::vector<U> det_scratch(2 * tdim * gdim);
256 const auto [_Pi_1, pi_shape] = e1->interpolation_operator();
257 cmdspan2_t Pi_1(_Pi_1.data(), pi_shape);
259 bool interpolation_ident = e1->interpolation_ident();
261 using u_t = MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
262 U, MDSPAN_IMPL_STANDARD_NAMESPACE::dextents<std::size_t, 2>>;
263 using U_t = MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
264 const U, MDSPAN_IMPL_STANDARD_NAMESPACE::dextents<std::size_t, 2>>;
265 using J_t = MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
266 const U, MDSPAN_IMPL_STANDARD_NAMESPACE::dextents<std::size_t, 2>>;
267 using K_t = MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
268 const U, MDSPAN_IMPL_STANDARD_NAMESPACE::dextents<std::size_t, 2>>;
269 auto push_forward_fn0
270 = e0->basix_element().template map_fn<u_t, U_t, J_t, K_t>();
274 std::vector<U> basis_values_b(Xshape[0] * bs0 * dim0 * e1->value_size());
275 mdspan3_t basis_values(basis_values_b.data(), Xshape[0], bs0 * dim0,
277 std::vector<U> mapped_values_b(Xshape[0] * bs0 * dim0 * e1->value_size());
278 mdspan3_t mapped_values(mapped_values_b.data(), Xshape[0], bs0 * dim0,
282 = e1->basix_element().template map_fn<u_t, U_t, K_t, J_t>();
284 std::vector<U> coord_dofs_b(num_dofs_g * gdim);
285 mdspan2_t coord_dofs(coord_dofs_b.data(), num_dofs_g, gdim);
286 std::vector<U> basis0_b(Xshape[0] * dim0 * value_size0);
287 mdspan3_t basis0(basis0_b.data(), Xshape[0], dim0, value_size0);
290 std::vector<T> Ab(space_dim0 * space_dim1);
291 std::vector<T> local1(space_dim1);
294 auto cell_map = mesh->topology()->index_map(tdim);
296 std::int32_t num_cells = cell_map->size_local();
297 for (std::int32_t c = 0; c < num_cells; ++c)
301 = MDSPAN_IMPL_STANDARD_NAMESPACE::MDSPAN_IMPL_PROPOSED_NAMESPACE::
302 submdspan(x_dofmap, c, MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
303 for (std::size_t i = 0; i < x_dofs.size(); ++i)
305 for (std::size_t j = 0; j < gdim; ++j)
306 coord_dofs(i, j) = x_g[3 * x_dofs[i] + j];
310 std::fill(J_b.begin(), J_b.end(), 0);
311 for (std::size_t p = 0; p < Xshape[0]; ++p)
314 = MDSPAN_IMPL_STANDARD_NAMESPACE::MDSPAN_IMPL_PROPOSED_NAMESPACE::
315 submdspan(phi, std::pair(1, tdim + 1), p,
316 MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent, 0);
317 auto _J = MDSPAN_IMPL_STANDARD_NAMESPACE::MDSPAN_IMPL_PROPOSED_NAMESPACE::
318 submdspan(J, p, MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent,
319 MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
321 auto _K = MDSPAN_IMPL_STANDARD_NAMESPACE::MDSPAN_IMPL_PROPOSED_NAMESPACE::
322 submdspan(K, p, MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent,
323 MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
330 for (std::size_t k0 = 0; k0 < basis_reference0.extent(0); ++k0)
331 for (std::size_t k1 = 0; k1 < basis_reference0.extent(1); ++k1)
332 for (std::size_t k2 = 0; k2 < basis_reference0.extent(2); ++k2)
333 basis_reference0(k0, k1, k2)
334 = basis_derivatives_reference0(0, k0, k1, k2);
335 for (std::size_t p = 0; p < Xshape[0]; ++p)
337 apply_dof_transformation0(
338 std::span(basis_reference0.data_handle() + p * dim0 * value_size_ref0,
339 dim0 * value_size_ref0),
340 cell_info, c, value_size_ref0);
343 for (std::size_t p = 0; p < basis0.extent(0); ++p)
345 auto _u = MDSPAN_IMPL_STANDARD_NAMESPACE::MDSPAN_IMPL_PROPOSED_NAMESPACE::
346 submdspan(basis0, p, MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent,
347 MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
348 auto _U = MDSPAN_IMPL_STANDARD_NAMESPACE::MDSPAN_IMPL_PROPOSED_NAMESPACE::
349 submdspan(basis_reference0, p,
350 MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent,
351 MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
352 auto _K = MDSPAN_IMPL_STANDARD_NAMESPACE::MDSPAN_IMPL_PROPOSED_NAMESPACE::
353 submdspan(K, p, MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent,
354 MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
355 auto _J = MDSPAN_IMPL_STANDARD_NAMESPACE::MDSPAN_IMPL_PROPOSED_NAMESPACE::
356 submdspan(J, p, MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent,
357 MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
358 push_forward_fn0(_u, _U, _J, detJ[p], _K);
362 for (std::size_t p = 0; p < Xshape[0]; ++p)
363 for (std::size_t i = 0; i < dim0; ++i)
364 for (std::size_t j = 0; j < value_size0; ++j)
365 for (
int k = 0; k < bs0; ++k)
366 basis_values(p, i * bs0 + k, j * bs0 + k) = basis0(p, i, j);
369 for (std::size_t p = 0; p < basis_values.extent(0); ++p)
371 auto _u = MDSPAN_IMPL_STANDARD_NAMESPACE::MDSPAN_IMPL_PROPOSED_NAMESPACE::
372 submdspan(basis_values, p,
373 MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent,
374 MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
375 auto _U = MDSPAN_IMPL_STANDARD_NAMESPACE::MDSPAN_IMPL_PROPOSED_NAMESPACE::
376 submdspan(mapped_values, p,
377 MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent,
378 MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
379 auto _K = MDSPAN_IMPL_STANDARD_NAMESPACE::MDSPAN_IMPL_PROPOSED_NAMESPACE::
380 submdspan(K, p, MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent,
381 MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
382 auto _J = MDSPAN_IMPL_STANDARD_NAMESPACE::MDSPAN_IMPL_PROPOSED_NAMESPACE::
383 submdspan(J, p, MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent,
384 MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
385 pull_back_fn1(_U, _u, _K, 1.0 / detJ[p], _J);
390 if (interpolation_ident)
392 MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
393 T, MDSPAN_IMPL_STANDARD_NAMESPACE::dextents<std::size_t, 3>>
394 A(Ab.data(), Xshape[0], e1->value_size(), space_dim0);
395 for (std::size_t i = 0; i < mapped_values.extent(0); ++i)
396 for (std::size_t j = 0; j < mapped_values.extent(1); ++j)
397 for (std::size_t k = 0; k < mapped_values.extent(2); ++k)
398 A(i, k, j) = mapped_values(i, j, k);
402 for (std::size_t i = 0; i < mapped_values.extent(1); ++i)
405 = MDSPAN_IMPL_STANDARD_NAMESPACE::MDSPAN_IMPL_PROPOSED_NAMESPACE::
406 submdspan(mapped_values,
407 MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent, i,
408 MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
409 impl::interpolation_apply(Pi_1, values, std::span(local1), bs1);
410 for (std::size_t j = 0; j < local1.size(); j++)
411 Ab[space_dim0 * j + i] = local1[j];
415 apply_inverse_dof_transform1(Ab, cell_info, c, space_dim0);
416 mat_set(dofmap1->cell_dofs(c), dofmap0->cell_dofs(c), Ab);