11#include "FunctionSpace.h"
16#include <dolfinx/la/utils.h>
17#include <dolfinx/mesh/Geometry.h>
18#include <dolfinx/mesh/Mesh.h>
19#include <dolfinx/mesh/Topology.h>
27namespace dolfinx::fem::impl
29bool has_bc(
auto& dofs,
auto& bc,
auto bs)
32 for (
int k = 0; k < bs; ++k)
39using mdspan2_t = md::mdspan<const std::int32_t, md::dextents<std::size_t, 2>>;
94template <
bool LiftingMode, dolfinx::scalar T, std::
floating_po
int U>
95void assemble_cells_matrix(
96 la::MatSet<T>
auto mat_set, MDSpan2Int32
auto x_dofmap,
97 MDSpan2Floating<U>
auto x, std::span<const std::int32_t> cells,
98 const DofMapPackCells
auto& dofmap0,
99 const fem::DofTransformKernel<T>
auto& P0,
100 const DofMapPackCells
auto& dofmap1,
101 const fem::DofTransformKernel<T>
auto& P1T,
102 std::span<const std::int8_t> bc0, std::span<const std::int8_t> bc1,
103 const FEkernel<T, U>
auto& kernel,
104 md::mdspan<
const T, md::dextents<std::size_t, 2>> coeffs,
105 std::span<const T> constants, std::span<const std::uint32_t> cell_info0,
106 std::span<const std::uint32_t> cell_info1, std::span<T> Ab,
107 std::span<U> cdofs_b)
112 const auto [dmap0, bs0, cells0] = dofmap0;
113 const auto [dmap1, bs1, cells1] = dofmap1;
115 std::size_t num_dofs0 = dmap0.extent(1);
116 std::size_t num_dofs1 = dmap1.extent(1);
117 std::size_t ndim0 = bs0 * num_dofs0;
118 std::size_t ndim1 = bs1 * num_dofs1;
120 const U* x_ptr = x.data_handle();
121 const std::int32_t gdim = x.extent(1);
122 const std::int32_t* x_dofmap_ptr = x_dofmap.data_handle();
123 const std::int32_t num_x_dofs_cell = x_dofmap.extent(1);
125 assert(Ab.size() >= ndim0 * ndim1);
126 assert(cdofs_b.size() >= 3 * x_dofmap.extent(1));
127 auto Ae = Ab.first(ndim0 * ndim1);
135 const T* coeffs_data = coeffs.data_handle();
136 const std::size_t cstride = coeffs.extent(1);
139 assert(cells0.size() ==
cells.size());
140 assert(cells1.size() ==
cells.size());
141 for (std::size_t c = 0; c <
cells.size(); ++c)
146 std::int32_t cell0 = cells0[c];
147 std::int32_t cell1 = cells1[c];
149 std::span dofs0(dmap0.data_handle() + cell0 * num_dofs0, num_dofs0);
150 std::span dofs1(dmap1.data_handle() + cell1 * num_dofs1, num_dofs1);
153 if constexpr (LiftingMode)
155 if (!has_bc(dofs1, bc1, bs1))
160 for (std::int32_t i = 0; i < num_x_dofs_cell; ++i)
162 const U* _x_ptr = x_ptr + x_dofmap_ptr[
cell * num_x_dofs_cell + i] * gdim;
163 std::copy_n(_x_ptr, gdim, cdofs_b.data() + 3 * i);
167 std::ranges::fill(Ae, 0);
168 kernel(Ae.data(), coeffs_data + c * cstride, constants.data(),
169 cdofs_b.data(),
nullptr,
nullptr,
nullptr);
173 P0(Ae, cell_info0, cell0, ndim1);
175 P1T(Ae, cell_info1, cell1, ndim0);
179 if constexpr (!LiftingMode)
184 for (std::size_t i = 0; i < num_dofs0; ++i)
186 for (
int k = 0; k < bs0; ++k)
188 if (bc0[bs0 * dofs0[i] + k])
191 const int row = bs0 * i + k;
192 std::fill_n(std::next(Ae.begin(), ndim1 * row), ndim1, 0);
200 for (std::size_t j = 0; j < num_dofs1; ++j)
202 for (
int k = 0; k < bs1; ++k)
204 if (bc1[bs1 * dofs1[j] + k])
207 int col = bs1 * j + k;
208 for (std::size_t row = 0; row < ndim0; ++row)
209 Ae[row * ndim1 + col] = 0;
216 mat_set(dofs0, dofs1, Ae);
282template <
bool LiftingMode, dolfinx::scalar T, std::
floating_po
int U>
283void assemble_entities(
284 la::MatSet<T>
auto mat_set, MDSpan2Int32
auto x_dofmap,
285 MDSpan2Floating<U>
auto x,
286 md::mdspan<
const std::int32_t,
287 std::extents<std::size_t, md::dynamic_extent, 2>>
289 const DofMapPackEntities
auto& dofmap0,
290 const fem::DofTransformKernel<T>
auto& P0,
291 const DofMapPackEntities
auto& dofmap1,
292 const fem::DofTransformKernel<T>
auto& P1T,
293 std::span<const std::int8_t> bc0, std::span<const std::int8_t> bc1,
294 const FEkernel<T, U>
auto& kernel,
295 md::mdspan<
const T, md::dextents<std::size_t, 2>> coeffs,
296 std::span<const T> constants, std::span<const std::uint32_t> cell_info0,
297 std::span<const std::uint32_t> cell_info1,
298 md::mdspan<
const std::uint8_t, md::dextents<std::size_t, 2>> perms,
299 std::span<T> Ab, std::span<U> cdofs_b)
301 if (entities.empty())
304 const auto [dmap0, bs0, entities0] = dofmap0;
305 const auto [dmap1, bs1, entities1] = dofmap1;
307 std::size_t num_dofs0 = dmap0.extent(1);
308 std::size_t num_dofs1 = dmap1.extent(1);
309 std::size_t ndim0 = bs0 * num_dofs0;
310 std::size_t ndim1 = bs1 * num_dofs1;
311 assert(entities0.size() == entities.size());
312 assert(entities1.size() == entities.size());
313 assert(Ab.size() >= ndim0 * ndim1);
314 assert(cdofs_b.size() >= 3 * x_dofmap.extent(1));
315 auto Ae = Ab.first(ndim0 * ndim1);
317 const U* x_ptr = x.data_handle();
318 const std::int32_t gdim = x.extent(1);
319 const std::int32_t* x_dofmap_ptr = x_dofmap.data_handle();
320 const std::int32_t num_x_dofs_cell = x_dofmap.extent(1);
328 const T* coeffs_data = coeffs.data_handle();
329 const std::size_t cstride = coeffs.extent(1);
331 for (std::size_t f = 0; f < entities.extent(0); ++f)
336 std::int32_t
cell = entities(f, 0);
337 std::int32_t local_entity = entities(f, 1);
338 std::int32_t cell0 = entities0(f, 0);
339 std::int32_t cell1 = entities1(f, 0);
341 std::span dofs0(dmap0.data_handle() + cell0 * num_dofs0, num_dofs0);
342 std::span dofs1(dmap1.data_handle() + cell1 * num_dofs1, num_dofs1);
345 if constexpr (LiftingMode)
347 if (!has_bc(dofs1, bc1, bs1))
352 for (std::int32_t i = 0; i < num_x_dofs_cell; ++i)
354 const U* _x_ptr = x_ptr + x_dofmap_ptr[
cell * num_x_dofs_cell + i] * gdim;
355 std::copy_n(_x_ptr, gdim, cdofs_b.data() + 3 * i);
359 std::uint8_t perm = perms.empty() ? 0 : perms(
cell, local_entity);
362 std::ranges::fill(Ae, 0);
363 kernel(Ae.data(), coeffs_data + f * cstride, constants.data(),
364 cdofs_b.data(), &local_entity, &perm,
nullptr);
366 P0(Ae, cell_info0, cell0, ndim1);
368 P1T(Ae, cell_info1, cell1, ndim0);
371 if constexpr (!LiftingMode)
376 for (std::size_t i = 0; i < num_dofs0; ++i)
378 for (
int k = 0; k < bs0; ++k)
380 if (bc0[bs0 * dofs0[i] + k])
383 const int row = bs0 * i + k;
384 std::fill_n(std::next(Ae.begin(), ndim1 * row), ndim1, 0);
392 for (std::size_t j = 0; j < num_dofs1; ++j)
394 for (
int k = 0; k < bs1; ++k)
396 if (bc1[bs1 * dofs1[j] + k])
399 int col = bs1 * j + k;
400 for (std::size_t row = 0; row < ndim0; ++row)
401 Ae[row * ndim1 + col] = 0;
408 mat_set(dofs0, dofs1, Ae);
473template <
bool LiftingMode, dolfinx::scalar T, std::
floating_po
int U>
474void assemble_interior_facets(
475 la::MatSet<T>
auto mat_set, MDSpan2Int32
auto x_dofmap,
476 MDSpan2Floating<U>
auto x,
477 md::mdspan<
const std::int32_t,
478 std::extents<std::size_t, md::dynamic_extent, 2, 2>>
480 const DofMapPackFacets
auto& dofmap0,
481 const fem::DofTransformKernel<T>
auto& P0,
482 const DofMapPackFacets
auto& dofmap1,
483 const fem::DofTransformKernel<T>
auto& P1T,
484 std::span<const std::int8_t> bc0, std::span<const std::int8_t> bc1,
485 const FEkernel<T, U>
auto& kernel,
486 md::mdspan<
const T, md::extents<std::size_t, md::dynamic_extent, 2,
489 std::span<const T> constants, std::span<const std::uint32_t> cell_info0,
490 std::span<const std::uint32_t> cell_info1,
491 md::mdspan<
const std::uint8_t, md::dextents<std::size_t, 2>> perms,
492 std::span<T> Ab, std::span<U> cdofs_b, std::span<std::int32_t> dofs_b,
493 std::span<T> Ae_block_b)
498 const auto [dmap0, bs0, facets0] = dofmap0;
499 const auto [dmap1, bs1, facets1] = dofmap1;
502 assert(cdofs_b.size() >= 2 * 3 * x_dofmap.extent(1));
503 auto cdofs0 = cdofs_b.first(3 * x_dofmap.extent(1));
504 auto cdofs1 = cdofs_b.last(3 * x_dofmap.extent(1));
506 const U* x_ptr = x.data_handle();
507 const std::int32_t gdim = x.extent(1);
508 const std::int32_t* x_dofmap_ptr = x_dofmap.data_handle();
509 const std::int32_t num_x_dofs_cell = x_dofmap.extent(1);
511 std::size_t dmap0_size = dmap0.extent(1);
512 std::size_t dmap1_size = dmap1.extent(1);
513 std::size_t num_rows = bs0 * 2 * dmap0_size;
514 std::size_t num_cols = bs1 * 2 * dmap1_size;
517 assert(dofs_b.size() >= (2 * dmap0_size) + (2 * dmap1_size));
518 auto dmapjoint0 = dofs_b.first(2 * dmap0_size);
519 auto dmapjoint1 = dofs_b.last(2 * dmap1_size);
521 assert(facets0.size() == facets.size());
522 assert(facets1.size() == facets.size());
523 assert(Ab.size() >= num_rows * num_cols);
524 auto Ae = Ab.first(num_rows * num_cols);
532 assert(Ae_block_b.size() >= dmap0_size * bs0 * dmap1_size * bs1);
534 const T* coeffs_data = coeffs.data_handle();
535 const std::size_t cstride = 2 * coeffs.extent(2);
537 auto insert_block = [&Ae_block_b, &Ae, &bs0, &bs1, &num_cols,
538 &mat_set](std::span<const std::int32_t> rdofs,
539 std::span<const std::int32_t> cdofs,
540 std::size_t row_offset, std::size_t col_offset)
542 if (rdofs.empty() or cdofs.empty())
544 auto Ae_block = Ae_block_b.first(rdofs.size() * bs0 * cdofs.size() * bs1);
545 for (std::size_t i = 0; i < rdofs.size() * bs0; ++i)
548 = std::next(Ae.begin(), (row_offset + i) * num_cols + col_offset);
549 std::copy_n(row, cdofs.size() * bs1,
550 std::next(Ae_block.begin(), i * cdofs.size() * bs1));
552 mat_set(rdofs, cdofs, Ae_block);
561 for (std::size_t f = 0; f < facets.extent(0); ++f)
565 std::array
cells{facets(f, 0, 0), facets(f, 1, 0)};
566 std::array cells0{facets0(f, 0, 0), facets0(f, 1, 0)};
567 std::array cells1{facets1(f, 0, 0), facets1(f, 1, 0)};
570 std::array local_facet{facets(f, 0, 1), facets(f, 1, 1)};
573 for (std::int32_t i = 0; i < num_x_dofs_cell; ++i)
576 = x_ptr + x_dofmap_ptr[
cells[0] * num_x_dofs_cell + i] * gdim;
577 std::copy_n(_x_ptr0, gdim, cdofs0.data() + 3 * i);
579 = x_ptr + x_dofmap_ptr[
cells[1] * num_x_dofs_cell + i] * gdim;
580 std::copy_n(_x_ptr1, gdim, cdofs1.data() + 3 * i);
587 std::span<const std::int32_t> dmap0_cell0
589 ? std::span(dmap0.data_handle() + cells0[0] * dmap0_size,
591 : std::span<const std::int32_t>();
592 std::span<const std::int32_t> dmap0_cell1
594 ? std::span(dmap0.data_handle() + cells0[1] * dmap0_size,
596 : std::span<const std::int32_t>();
598 std::ranges::copy(dmap0_cell0, dmapjoint0.begin());
599 std::ranges::copy(dmap0_cell1, std::next(dmapjoint0.begin(), dmap0_size));
602 std::span<const std::int32_t> dmap1_cell0
604 ? std::span(dmap1.data_handle() + cells1[0] * dmap1_size,
606 : std::span<const std::int32_t>();
607 std::span<const std::int32_t> dmap1_cell1
609 ? std::span(dmap1.data_handle() + cells1[1] * dmap1_size,
611 : std::span<const std::int32_t>();
613 std::ranges::copy(dmap1_cell0, dmapjoint1.begin());
614 std::ranges::copy(dmap1_cell1, std::next(dmapjoint1.begin(), dmap1_size));
617 if constexpr (LiftingMode)
619 if (!has_bc(dmapjoint1, bc1, bs1))
624 std::ranges::fill(Ae, 0);
625 std::array perm = perms.empty()
626 ? std::array<std::uint8_t, 2>{0, 0}
627 : std::array{perms(cells[0], local_facet[0]),
628 perms(cells[1], local_facet[1])};
629 kernel(Ae.data(), coeffs_data + f * cstride, constants.data(),
630 cdofs_b.data(), local_facet.data(), perm.data(),
nullptr);
640 if (p0_set and cells0[0] >= 0)
641 P0(Ae, cell_info0, cells0[0], num_cols);
642 if (p0_set and cells0[1] >= 0)
644 std::span sub_Ae0(Ae.data() + bs0 * dmap0_size * num_cols,
645 bs0 * dmap0_size * num_cols);
646 P0(sub_Ae0, cell_info0, cells0[1], num_cols);
648 if (p1t_set and cells1[0] >= 0)
649 P1T(Ae, cell_info1, cells1[0], num_rows);
651 if (p1t_set and cells1[1] >= 0)
653 for (std::size_t row = 0; row < num_rows; ++row)
657 std::span sub_Ae1(Ae.data() + row * num_cols + bs1 * dmap1_size,
659 P1T(sub_Ae1, cell_info1, cells1[1], 1);
664 if constexpr (!LiftingMode)
669 for (std::size_t i = 0; i < dmapjoint0.size(); ++i)
671 for (
int k = 0; k < bs0; ++k)
673 if (bc0[bs0 * dmapjoint0[i] + k])
676 std::fill_n(std::next(Ae.begin(), num_cols * (bs0 * i + k)),
685 for (std::size_t j = 0; j < dmapjoint1.size(); ++j)
687 for (
int k = 0; k < bs1; ++k)
689 if (bc1[bs1 * dmapjoint1[j] + k])
692 for (std::size_t m = 0; m < num_rows; ++m)
693 Ae[m * num_cols + bs1 * j + k] = 0;
706 if (cells0[0] >= 0 and cells0[1] >= 0 and cells1[0] >= 0 and cells1[1] >= 0)
707 mat_set(dmapjoint0, dmapjoint1, Ae);
710 insert_block(dmap0_cell0, dmap1_cell0, 0, 0);
711 insert_block(dmap0_cell0, dmap1_cell1, 0, bs1 * dmap1_size);
712 insert_block(dmap0_cell1, dmap1_cell0, bs0 * dmap0_size, 0);
713 insert_block(dmap0_cell1, dmap1_cell1, bs0 * dmap0_size,
747template <
bool LiftingMode, dolfinx::scalar T, std::
floating_po
int U>
749 la::MatSet<T>
auto mat_set,
const Form<T, U>& a,
750 md::mdspan<
const U, md::extents<std::size_t, md::dynamic_extent, 3>> x,
751 std::span<const T> constants,
752 const std::map<std::pair<IntegralType, int>,
753 std::pair<std::span<const T>,
int>>& coefficients,
754 std::span<const std::int8_t> bc0, std::span<const std::int8_t> bc1)
757 std::shared_ptr<const mesh::Mesh<U>> mesh = a.mesh();
761 auto mesh0 = a.function_spaces().at(0)->mesh();
765 auto mesh1 = a.function_spaces().at(1)->mesh();
774 const int num_cell_types = mesh->topology()->cell_types().size();
775 for (
int cell_type_idx = 0; cell_type_idx < num_cell_types; ++cell_type_idx)
778 mdspan2_t x_dofmap = mesh->geometry().dofmaps().at(cell_type_idx);
781 std::shared_ptr<const fem::DofMap> dofmap0
782 = a.function_spaces().at(0)->dofmaps().at(cell_type_idx);
783 std::shared_ptr<const fem::DofMap> dofmap1
784 = a.function_spaces().at(1)->dofmaps().at(cell_type_idx);
787 md::mdspan<const std::int32_t, md::dextents<std::size_t, 2>> dofs0
789 const int bs0 = dofmap0->bs();
790 md::mdspan<const std::int32_t, md::dextents<std::size_t, 2>> dofs1
792 const int bs1 = dofmap1->bs();
796 std::vector<T> Ab((2 * bs0 * dofs0.extent(1))
797 * (2 * bs1 * dofs1.extent(1)));
798 std::vector<U> cdofs_b(2 * 3 * x_dofmap.extent(1));
799 std::size_t dmap0_size = dofmap0->map().extent(1);
800 std::size_t dmap1_size = dofmap1->map().extent(1);
801 std::vector<std::int32_t> dmap_b((2 * dmap0_size) + (2 * dmap1_size));
802 std::vector<T> Ae_block_b(dmap0_size * bs0 * dmap1_size * bs1);
804 auto element0 = a.function_spaces().at(0)->elements(cell_type_idx);
806 auto element1 = a.function_spaces().at(1)->elements(cell_type_idx);
808 const fem::DofTransformKernel<T>
auto& P0
810 const fem::DofTransformKernel<T>
auto& P1T
811 = element1->template dof_transformation_right_fn<T>(
814 std::span<const std::uint32_t> cell_info0;
815 std::span<const std::uint32_t> cell_info1;
816 if (element0->needs_dof_transformations()
817 or element1->needs_dof_transformations()
818 or a.needs_facet_permutations())
820 mesh0->topology_mutable()->create_entity_permutations();
821 mesh1->topology_mutable()->create_entity_permutations();
822 cell_info0 = std::span(mesh0->topology()->get_cell_permutation_info());
823 cell_info1 = std::span(mesh1->topology()->get_cell_permutation_info());
834 assert(
cells.size() * cstride == coeffs.size());
835 if (bs0 == 1 and bs1 == 1)
837 impl::assemble_cells_matrix<LiftingMode>(
838 mat_set, x_dofmap, x, cells,
839 std::tuple{dofs0, std::integral_constant<int, 1>{}, cells0}, P0,
840 std::tuple{dofs1, std::integral_constant<int, 1>{}, cells1}, P1T,
841 bc0, bc1, fn, md::mdspan(coeffs.data(),
cells.size(), cstride),
842 constants, cell_info0, cell_info1, std::span(Ab),
845 else if (bs0 == 3 and bs1 == 3)
847 impl::assemble_cells_matrix<LiftingMode>(
848 mat_set, x_dofmap, x, cells,
849 std::tuple{dofs0, std::integral_constant<int, 3>{}, cells0}, P0,
850 std::tuple{dofs1, std::integral_constant<int, 3>{}, cells1}, P1T,
851 bc0, bc1, fn, md::mdspan(coeffs.data(),
cells.size(), cstride),
852 constants, cell_info0, cell_info1, std::span(Ab),
857 impl::assemble_cells_matrix<LiftingMode>(
858 mat_set, x_dofmap, x, cells, std::tuple{dofs0, bs0, cells0}, P0,
859 std::tuple{dofs1, bs1, cells1}, P1T, bc0, bc1, fn,
860 md::mdspan(coeffs.data(),
cells.size(), cstride), constants,
861 cell_info0, cell_info1, std::span(Ab), std::span(cdofs_b));
865 md::mdspan<const std::uint8_t, md::dextents<std::size_t, 2>> facet_perms;
866 if (a.needs_facet_permutations())
868 mesh::CellType cell_type = mesh->topology()->cell_types()[cell_type_idx];
869 int num_facets_per_cell
871 mesh->topology_mutable()->create_entity_permutations();
872 const std::vector<std::uint8_t>& p
873 = mesh->topology()->get_facet_permutations();
874 facet_perms = md::mdspan(p.data(), p.size() / num_facets_per_cell,
875 num_facets_per_cell);
881 if (num_cell_types > 1)
883 throw std::invalid_argument(
"Interior facet integrals with mixed "
884 "topology aren't supported yet");
888 = md::mdspan<
const std::int32_t,
889 md::extents<std::size_t, md::dynamic_extent, 2, 2>>;
891 = md::mdspan<
const T, md::extents<std::size_t, md::dynamic_extent, 2,
892 md::dynamic_extent>>;
896 auto& [coeffs, cstride]
902 assert((facets.size() / 4) * 2 * cstride == coeffs.size());
903 if (bs0 == 1 and bs1 == 1)
905 impl::assemble_interior_facets<LiftingMode>(
906 mat_set, x_dofmap, x,
907 mdspanx22_t(facets.data(), facets.size() / 4, 2, 2),
908 std::tuple{dofs0, std::integral_constant<int, 1>{},
909 mdspanx22_t(facets0.data(), facets0.size() / 4, 2, 2)},
911 std::tuple{dofs1, std::integral_constant<int, 1>{},
912 mdspanx22_t(facets1.data(), facets1.size() / 4, 2, 2)},
914 mdspanx2x_t(coeffs.data(), facets.size() / 4, 2, cstride),
915 constants, cell_info0, cell_info1, facet_perms, std::span(Ab),
916 std::span(cdofs_b), dmap_b, std::span(Ae_block_b));
918 else if (bs0 == 3 and bs1 == 3)
920 impl::assemble_interior_facets<LiftingMode>(
921 mat_set, x_dofmap, x,
922 mdspanx22_t(facets.data(), facets.size() / 4, 2, 2),
923 std::tuple{dofs0, std::integral_constant<int, 3>{},
924 mdspanx22_t(facets0.data(), facets0.size() / 4, 2, 2)},
926 std::tuple{dofs1, std::integral_constant<int, 3>{},
927 mdspanx22_t(facets1.data(), facets1.size() / 4, 2, 2)},
929 mdspanx2x_t(coeffs.data(), facets.size() / 4, 2, cstride),
930 constants, cell_info0, cell_info1, facet_perms, std::span(Ab),
931 std::span(cdofs_b), dmap_b, std::span(Ae_block_b));
935 impl::assemble_interior_facets<LiftingMode>(
936 mat_set, x_dofmap, x,
937 mdspanx22_t(facets.data(), facets.size() / 4, 2, 2),
938 std::tuple{dofs0, bs0,
939 mdspanx22_t(facets0.data(), facets0.size() / 4, 2, 2)},
941 std::tuple{dofs1, bs1,
942 mdspanx22_t(facets1.data(), facets1.size() / 4, 2, 2)},
944 mdspanx2x_t(coeffs.data(), facets.size() / 4, 2, cstride),
945 constants, cell_info0, cell_info1, facet_perms, std::span(Ab),
946 std::span(cdofs_b), dmap_b, std::span(Ae_block_b));
953 md::mdspan<const std::uint8_t, md::dextents<std::size_t, 2>> perms
956 : md::mdspan<
const std::uint8_t,
957 md::dextents<std::size_t, 2>>{};
959 for (
int i = 0; i < a.num_integrals(itg_type, cell_type_idx); ++i)
961 if (num_cell_types > 1)
963 throw std::invalid_argument(
"Exterior facet integrals with mixed "
964 "topology aren't supported yet");
968 = md::mdspan<
const std::int32_t,
969 md::extents<std::size_t, md::dynamic_extent, 2>>;
971 auto fn = a.kernel(itg_type, i, 0);
973 auto& [coeffs, cstride] = coefficients.at({itg_type, i});
975 std::span e = a.domain(itg_type, i, 0);
976 mdspanx2_t entities(e.data(), e.size() / 2, 2);
977 std::span e0 = a.domain_arg(itg_type, 0, i, 0);
978 mdspanx2_t entities0(e0.data(), e0.size() / 2, 2);
979 std::span e1 = a.domain_arg(itg_type, 1, i, 0);
980 mdspanx2_t entities1(e1.data(), e1.size() / 2, 2);
981 assert((entities.size() / 2) * cstride == coeffs.size());
982 if (bs0 == 1 and bs1 == 1)
984 impl::assemble_entities<LiftingMode>(
985 mat_set, x_dofmap, x, entities,
986 std::tuple{dofs0, std::integral_constant<int, 1>{}, entities0},
988 std::tuple{dofs1, std::integral_constant<int, 1>{}, entities1},
990 md::mdspan(coeffs.data(), entities.extent(0), cstride), constants,
991 cell_info0, cell_info1, perms, std::span(Ab), std::span(cdofs_b));
993 else if (bs0 == 3 and bs1 == 3)
995 impl::assemble_entities<LiftingMode>(
996 mat_set, x_dofmap, x, entities,
997 std::tuple{dofs0, std::integral_constant<int, 3>{}, entities0},
999 std::tuple{dofs1, std::integral_constant<int, 3>{}, entities1},
1001 md::mdspan(coeffs.data(), entities.extent(0), cstride), constants,
1002 cell_info0, cell_info1, perms, std::span(Ab), std::span(cdofs_b));
1006 impl::assemble_entities<LiftingMode>(
1007 mat_set, x_dofmap, x, entities, std::tuple{dofs0, bs0, entities0},
1008 P0, std::tuple{dofs1, bs1, entities1}, P1T, bc0, bc1, fn,
1009 md::mdspan(coeffs.data(), entities.extent(0), cstride), constants,
1010 cell_info0, cell_info1, perms, std::span(Ab), std::span(cdofs_b));
Degree-of-freedom map representations and tools.
Functions supporting finite element method operations.
void cells(la::SparsityPattern &pattern, const std::pair< R0, R1 > &cells, std::array< std::reference_wrapper< const DofMap >, 2 > dofmaps)
Iterate over cells and insert entries into sparsity pattern.
Definition sparsitybuild.h:37
@ transpose
Transpose.
Definition FiniteElement.h:30
@ standard
Standard.
Definition FiniteElement.h:29
@ vertex
Vertex.
Definition Form.h:45
@ interior_facet
Interior facet.
Definition Form.h:44
@ ridge
Ridge.
Definition Form.h:46
@ cell
Cell.
Definition Form.h:42
@ exterior_facet
Exterior facet.
Definition Form.h:43
constexpr bool is_transform_set(const F &fn)
Whether a DofTransformKernel fn should be invoked.
Definition traits.h:33
CellType
Cell type identifier.
Definition cell_types.h:22
int cell_num_entities(CellType type, int dim)
Number of entities of dimension.
Definition cell_types.cpp:92