11#include "FunctionSpace.h"
15#include <dolfinx/la/utils.h>
16#include <dolfinx/mesh/Geometry.h>
17#include <dolfinx/mesh/Mesh.h>
18#include <dolfinx/mesh/Topology.h>
25namespace dolfinx::fem::impl
27bool has_bc(
auto& dofs,
auto& bc,
auto bs)
30 for (
int k = 0; k < bs; ++k)
81template <
bool LiftingMode,
typename AB, MDSpan2Int32 XD, std::floating_point U,
82 dolfinx::scalar T =
typename std::remove_cvref_t<AB>::value_type>
83 requires ScratchBuffer<AB, T>
84void assemble_cells_matrix(
85 la::MatSet<T>
auto mat_set, GeometryPack<XD, U> geometry,
86 const IndexList
auto& cells,
const FormArgumentCells<T>
auto& arg0,
87 const FormArgumentCells<T>
auto& arg1, std::span<const std::int8_t> bc0,
88 std::span<const std::int8_t> bc1,
const FEkernel<T, U>
auto& kernel,
89 std::span<const T> constants,
90 md::mdspan<
const T, md::dextents<std::size_t, 2>> coeffs, AB Ab,
91 ScratchBuffer<U>
auto cdofs_b)
93 if (std::ranges::empty(cells))
99 const auto& P0 = arg0.transform;
100 const auto& P1T = arg1.transform;
101 std::span<const std::uint32_t> cell_info0 = arg0.cell_info;
102 std::span<const std::uint32_t> cell_info1 = arg1.cell_info;
103 const auto dmap0 = arg0.dofmap.map;
104 const auto bs0 = arg0.dofmap.bs;
107 const auto& cells0 = arg0.dofmap.entities;
108 const auto dmap1 = arg1.dofmap.map;
109 const auto bs1 = arg1.dofmap.bs;
110 const auto& cells1 = arg1.dofmap.entities;
112 const auto num_dofs0 = dmap0.extent(1);
113 const auto num_dofs1 = dmap1.extent(1);
114 constexpr std::size_t nd0 = static_dofs_per_cell<
decltype(dmap0)>;
115 constexpr std::size_t nd1 = static_dofs_per_cell<
decltype(dmap1)>;
116 const std::size_t ndim0 = bs0 * num_dofs0;
117 const std::size_t ndim1 = bs1 * num_dofs1;
118 const auto num_x_dofs_cell = geometry.dofmap.extent(1);
120 assert(Ab.size() == ndim0 * ndim1);
121 assert(cdofs_b.size() == 3 *
static_cast<std::size_t
>(num_x_dofs_cell));
126 const T* coeffs_data = coeffs.data_handle();
127 const std::size_t cstride = coeffs.extent(1);
130 const std::size_t num_cells = std::ranges::size(cells);
131 assert(std::ranges::size(cells0) == num_cells);
132 assert(std::ranges::size(cells1) == num_cells);
133 for (std::size_t c = 0; c < num_cells; ++c)
138 std::int32_t cell0 = cells0[c];
139 std::int32_t cell1 = cells1[c];
141 std::span<const std::int32_t, nd0> dofs0(
142 dmap0.data_handle() + cell0 * num_dofs0, num_dofs0);
143 std::span<const std::int32_t, nd1> dofs1(
144 dmap1.data_handle() + cell1 * num_dofs1, num_dofs1);
147 if constexpr (LiftingMode)
149 if (!has_bc(dofs1, bc1, bs1))
153 gather_cell_coordinates(geometry,
cell, cdofs_b.data());
156 std::ranges::fill(Ab, T(0));
157 kernel(Ab.data(), coeffs_data + c * cstride, constants.data(),
158 cdofs_b.data(),
nullptr,
nullptr,
nullptr);
162 P0(Ab, cell_info0, cell0, ndim1);
164 P1T(Ab, cell_info1, cell1, ndim0);
168 if constexpr (!LiftingMode)
173 for (std::size_t i = 0; i < num_dofs0; ++i)
175 for (
int k = 0; k < bs0; ++k)
177 if (bc0[bs0 * dofs0[i] + k])
180 const int row = bs0 * i + k;
181 std::fill_n(std::next(Ab.begin(), ndim1 * row), ndim1, T(0));
189 for (std::size_t j = 0; j < num_dofs1; ++j)
191 for (
int k = 0; k < bs1; ++k)
193 if (bc1[bs1 * dofs1[j] + k])
196 int col = bs1 * j + k;
197 for (std::size_t row = 0; row < ndim0; ++row)
198 Ab[row * ndim1 + col] = 0;
205 mat_set(dofs0, dofs1, Ab);
264template <
bool LiftingMode,
typename AB, MDSpan2Int32 XD, std::floating_point U,
265 dolfinx::scalar T =
typename std::remove_cvref_t<AB>::value_type>
266 requires ScratchBuffer<AB, T>
267void assemble_entities_matrix(
268 la::MatSet<T>
auto mat_set, GeometryPack<XD, U> geometry,
269 md::mdspan<
const std::int32_t,
270 std::extents<std::size_t, md::dynamic_extent, 2>>
272 const FormArgumentEntities<T>
auto& arg0,
273 const FormArgumentEntities<T>
auto& arg1, std::span<const std::int8_t> bc0,
274 std::span<const std::int8_t> bc1,
const FEkernel<T, U>
auto& kernel,
275 std::span<const T> constants,
276 md::mdspan<
const T, md::dextents<std::size_t, 2>> coeffs,
277 md::mdspan<
const std::uint8_t, md::dextents<std::size_t, 2>> perms, AB Ab,
278 ScratchBuffer<U>
auto cdofs_b)
280 if (entities.empty())
286 const auto& P0 = arg0.transform;
287 const auto& P1T = arg1.transform;
288 std::span<const std::uint32_t> cell_info0 = arg0.cell_info;
289 std::span<const std::uint32_t> cell_info1 = arg1.cell_info;
290 const auto dmap0 = arg0.dofmap.map;
291 const auto bs0 = arg0.dofmap.bs;
292 const auto entities0 = arg0.dofmap.entities;
293 const auto dmap1 = arg1.dofmap.map;
294 const auto bs1 = arg1.dofmap.bs;
295 const auto entities1 = arg1.dofmap.entities;
297 const auto num_dofs0 = dmap0.extent(1);
298 const auto num_dofs1 = dmap1.extent(1);
299 constexpr std::size_t nd0 = static_dofs_per_cell<
decltype(dmap0)>;
300 constexpr std::size_t nd1 = static_dofs_per_cell<
decltype(dmap1)>;
301 const std::size_t ndim0 = bs0 * num_dofs0;
302 const std::size_t ndim1 = bs1 * num_dofs1;
303 const auto num_x_dofs_cell = geometry.dofmap.extent(1);
304 assert(entities0.size() == entities.size());
305 assert(entities1.size() == entities.size());
306 assert(Ab.size() == ndim0 * ndim1);
307 assert(cdofs_b.size() == 3 *
static_cast<std::size_t
>(num_x_dofs_cell));
315 const T* coeffs_data = coeffs.data_handle();
316 const std::size_t cstride = coeffs.extent(1);
318 for (std::size_t f = 0; f < entities.extent(0); ++f)
323 std::int32_t
cell = entities(f, 0);
324 std::int32_t local_entity = entities(f, 1);
325 std::int32_t cell0 = entities0(f, 0);
326 std::int32_t cell1 = entities1(f, 0);
328 std::span<const std::int32_t, nd0> dofs0(
329 dmap0.data_handle() + cell0 * num_dofs0, num_dofs0);
330 std::span<const std::int32_t, nd1> dofs1(
331 dmap1.data_handle() + cell1 * num_dofs1, num_dofs1);
334 if constexpr (LiftingMode)
336 if (!has_bc(dofs1, bc1, bs1))
340 gather_cell_coordinates(geometry,
cell, cdofs_b.data());
343 std::uint8_t perm = perms.empty() ? 0 : perms(
cell, local_entity);
346 std::ranges::fill(Ab, T(0));
347 kernel(Ab.data(), coeffs_data + f * cstride, constants.data(),
348 cdofs_b.data(), &local_entity, &perm,
nullptr);
350 P0(Ab, cell_info0, cell0, ndim1);
352 P1T(Ab, cell_info1, cell1, ndim0);
355 if constexpr (!LiftingMode)
360 for (std::size_t i = 0; i < num_dofs0; ++i)
362 for (
int k = 0; k < bs0; ++k)
364 if (bc0[bs0 * dofs0[i] + k])
367 const int row = bs0 * i + k;
368 std::fill_n(std::next(Ab.begin(), ndim1 * row), ndim1, T(0));
376 for (std::size_t j = 0; j < num_dofs1; ++j)
378 for (
int k = 0; k < bs1; ++k)
380 if (bc1[bs1 * dofs1[j] + k])
383 int col = bs1 * j + k;
384 for (std::size_t row = 0; row < ndim0; ++row)
385 Ab[row * ndim1 + col] = 0;
392 mat_set(dofs0, dofs1, Ab);
452template <
bool LiftingMode,
typename AB, MDSpan2Int32 XD, std::floating_point U,
453 dolfinx::scalar T =
typename std::remove_cvref_t<AB>::value_type>
454 requires ScratchBuffer<AB, T>
455void assemble_interior_facets_matrix(
456 la::MatSet<T>
auto mat_set, GeometryPack<XD, U> geometry,
457 md::mdspan<
const std::int32_t,
458 std::extents<std::size_t, md::dynamic_extent, 2, 2>>
460 const FormArgumentFacets<T>
auto& arg0,
461 const FormArgumentFacets<T>
auto& arg1, std::span<const std::int8_t> bc0,
462 std::span<const std::int8_t> bc1,
const FEkernel<T, U>
auto& kernel,
463 std::span<const T> constants,
464 md::mdspan<
const T, md::extents<std::size_t, md::dynamic_extent, 2,
467 md::mdspan<
const std::uint8_t, md::dextents<std::size_t, 2>> perms, AB Ab,
468 ScratchBuffer<U>
auto cdofs_b, ScratchBuffer<std::int32_t>
auto dofs_b,
469 ScratchBuffer<T>
auto Ae_block_b)
477 const auto& P0 = arg0.transform;
478 const auto& P1T = arg1.transform;
479 std::span<const std::uint32_t> cell_info0 = arg0.cell_info;
480 std::span<const std::uint32_t> cell_info1 = arg1.cell_info;
481 const auto dmap0 = arg0.dofmap.map;
482 const auto bs0 = arg0.dofmap.bs;
483 const auto facets0 = arg0.dofmap.entities;
484 const auto dmap1 = arg1.dofmap.map;
485 const auto bs1 = arg1.dofmap.bs;
486 const auto facets1 = arg1.dofmap.entities;
489 const auto num_x_dofs_cell = geometry.dofmap.extent(1);
490 assert(cdofs_b.size() == 2 * 3 *
static_cast<std::size_t
>(num_x_dofs_cell));
491 U* cdofs0 = cdofs_b.data();
492 U* cdofs1 = cdofs_b.data() + 3 * num_x_dofs_cell;
494 const auto dmap0_size = dmap0.extent(1);
495 const auto dmap1_size = dmap1.extent(1);
498 constexpr std::size_t nd0
499 = std::remove_cvref_t<
decltype(dmap0)>::static_extent(1);
500 constexpr std::size_t nd1
501 = std::remove_cvref_t<
decltype(dmap1)>::static_extent(1);
502 constexpr std::size_t njoint0
503 = nd0 == md::dynamic_extent ? std::dynamic_extent : 2 * nd0;
504 constexpr std::size_t njoint1
505 = nd1 == md::dynamic_extent ? std::dynamic_extent : 2 * nd1;
506 std::size_t num_rows = bs0 * 2 * dmap0_size;
507 std::size_t num_cols = bs1 * 2 * dmap1_size;
510 assert(dofs_b.size() == (2 * dmap0_size) + (2 * dmap1_size));
511 std::span<std::int32_t> dofs_all(dofs_b);
512 std::span<std::int32_t, njoint0> dmapjoint0(dofs_all.data(), 2 * dmap0_size);
513 std::span<std::int32_t, njoint1> dmapjoint1(dofs_all.data() + 2 * dmap0_size,
516 assert(facets0.size() == facets.size());
517 assert(facets1.size() == facets.size());
518 assert(Ab.size() == num_rows * num_cols);
526 assert(Ae_block_b.size() == dmap0_size * bs0 * dmap1_size * bs1);
527 std::span<T> Ae_block_all(Ae_block_b);
529 const T* coeffs_data = coeffs.data_handle();
530 const std::size_t cstride = 2 * coeffs.extent(2);
532 auto insert_block = [&Ae_block_all, &Ab, &bs0, &bs1, &num_cols,
533 &mat_set](std::span<const std::int32_t> rdofs,
534 std::span<const std::int32_t> cdofs,
535 std::size_t row_offset, std::size_t col_offset)
537 if (rdofs.empty() or cdofs.empty())
539 auto Ae_block = Ae_block_all.first(rdofs.size() * bs0 * cdofs.size() * bs1);
540 for (std::size_t i = 0; i < rdofs.size() * bs0; ++i)
543 = std::next(Ab.begin(), (row_offset + i) * num_cols + col_offset);
544 std::copy_n(row, cdofs.size() * bs1,
545 std::next(Ae_block.begin(), i * cdofs.size() * bs1));
547 mat_set(rdofs, cdofs, Ae_block);
556 for (std::size_t f = 0; f < facets.extent(0); ++f)
560 std::array
cells{facets(f, 0, 0), facets(f, 1, 0)};
561 std::array cells0{facets0(f, 0, 0), facets0(f, 1, 0)};
562 std::array cells1{facets1(f, 0, 0), facets1(f, 1, 0)};
565 std::array local_facet{facets(f, 0, 1), facets(f, 1, 1)};
568 gather_cell_coordinates(geometry, cells[0], cdofs0);
569 gather_cell_coordinates(geometry, cells[1], cdofs1);
575 std::span<const std::int32_t> dmap0_cell0
577 ? std::span(dmap0.data_handle() + cells0[0] * dmap0_size,
579 : std::span<const std::int32_t>();
580 std::span<const std::int32_t> dmap0_cell1
582 ? std::span(dmap0.data_handle() + cells0[1] * dmap0_size,
584 : std::span<const std::int32_t>();
586 std::ranges::copy(dmap0_cell0, dmapjoint0.begin());
587 std::ranges::copy(dmap0_cell1, std::next(dmapjoint0.begin(), dmap0_size));
590 std::span<const std::int32_t> dmap1_cell0
592 ? std::span(dmap1.data_handle() + cells1[0] * dmap1_size,
594 : std::span<const std::int32_t>();
595 std::span<const std::int32_t> dmap1_cell1
597 ? std::span(dmap1.data_handle() + cells1[1] * dmap1_size,
599 : std::span<const std::int32_t>();
605 if constexpr (LiftingMode)
607 if (!has_bc(dmap1_cell0, bc1, bs1) and !has_bc(dmap1_cell1, bc1, bs1))
611 std::ranges::copy(dmap1_cell0, dmapjoint1.begin());
612 std::ranges::copy(dmap1_cell1, std::next(dmapjoint1.begin(), dmap1_size));
615 std::ranges::fill(Ab, T(0));
616 std::array perm = perms.empty()
617 ? std::array<std::uint8_t, 2>{0, 0}
618 : std::array{perms(cells[0], local_facet[0]),
619 perms(cells[1], local_facet[1])};
620 kernel(Ab.data(), coeffs_data + f * cstride, constants.data(),
621 cdofs_b.data(), local_facet.data(), perm.data(),
nullptr);
631 if (p0_set and cells0[0] >= 0)
632 P0(Ab, cell_info0, cells0[0], num_cols);
633 if (p0_set and cells0[1] >= 0)
635 std::span sub_Ae0(Ab.data() + bs0 * dmap0_size * num_cols,
636 bs0 * dmap0_size * num_cols);
637 P0(sub_Ae0, cell_info0, cells0[1], num_cols);
639 if (p1t_set and cells1[0] >= 0)
640 P1T(Ab, cell_info1, cells1[0], num_rows);
642 if (p1t_set and cells1[1] >= 0)
644 for (std::size_t row = 0; row < num_rows; ++row)
648 std::span sub_Ae1(Ab.data() + row * num_cols + bs1 * dmap1_size,
650 P1T(sub_Ae1, cell_info1, cells1[1], 1);
655 if constexpr (!LiftingMode)
660 for (std::size_t i = 0; i < dmapjoint0.size(); ++i)
662 for (
int k = 0; k < bs0; ++k)
664 if (bc0[bs0 * dmapjoint0[i] + k])
667 std::fill_n(std::next(Ab.begin(), num_cols * (bs0 * i + k)),
676 for (std::size_t j = 0; j < dmapjoint1.size(); ++j)
678 for (
int k = 0; k < bs1; ++k)
680 if (bc1[bs1 * dmapjoint1[j] + k])
683 for (std::size_t m = 0; m < num_rows; ++m)
684 Ab[m * num_cols + bs1 * j + k] = 0;
697 if (cells0[0] >= 0 and cells0[1] >= 0 and cells1[0] >= 0 and cells1[1] >= 0)
698 mat_set(dmapjoint0, dmapjoint1, Ab);
701 insert_block(dmap0_cell0, dmap1_cell0, 0, 0);
702 insert_block(dmap0_cell0, dmap1_cell1, 0, bs1 * dmap1_size);
703 insert_block(dmap0_cell1, dmap1_cell0, bs0 * dmap0_size, 0);
704 insert_block(dmap0_cell1, dmap1_cell1, bs0 * dmap0_size,
738template <
bool LiftingMode, dolfinx::scalar T, std::
floating_po
int U>
740 la::MatSet<T>
auto mat_set,
const Form<T, U>& a,
741 md::mdspan<
const U, md::extents<std::size_t, md::dynamic_extent, 3>> x,
742 std::span<const T> constants,
743 const std::map<std::pair<IntegralType, int>,
744 std::pair<std::span<const T>,
int>>& coefficients,
745 std::span<const std::int8_t> bc0, std::span<const std::int8_t> bc1)
748 std::shared_ptr<const mesh::Mesh<U>> mesh = a.mesh();
752 auto mesh0 = a.function_spaces().at(0)->mesh();
756 auto mesh1 = a.function_spaces().at(1)->mesh();
765 const int num_cell_types = mesh->topology()->cell_types().size();
766 for (
int cell_type_idx = 0; cell_type_idx < num_cell_types; ++cell_type_idx)
769 mdspan2_t x_dofmap = mesh->geometry().dofmaps().at(cell_type_idx);
770 GeometryPack geometry{x_dofmap, x};
773 std::shared_ptr<const fem::DofMap> dofmap0
774 = a.function_spaces().at(0)->dofmaps().at(cell_type_idx);
775 std::shared_ptr<const fem::DofMap> dofmap1
776 = a.function_spaces().at(1)->dofmaps().at(cell_type_idx);
779 md::mdspan<const std::int32_t, md::dextents<std::size_t, 2>> dofs0
781 const int bs0 = dofmap0->bs();
782 md::mdspan<const std::int32_t, md::dextents<std::size_t, 2>> dofs1
784 const int bs1 = dofmap1->bs();
790 std::vector<T> Ab((2 * bs0 * dofs0.extent(1))
791 * (2 * bs1 * dofs1.extent(1)));
792 std::vector<U> cdofs_b(2 * 3 * x_dofmap.extent(1));
793 std::span Ab1 = std::span(Ab).first((bs0 * dofs0.extent(1))
794 * (bs1 * dofs1.extent(1)));
795 std::span cdofs_b1 = std::span(cdofs_b).first(3 * x_dofmap.extent(1));
796 std::size_t dmap0_size = dofmap0->map().extent(1);
797 std::size_t dmap1_size = dofmap1->map().extent(1);
798 std::vector<std::int32_t> dmap_b((2 * dmap0_size) + (2 * dmap1_size));
799 std::vector<T> Ae_block_b(dmap0_size * bs0 * dmap1_size * bs1);
801 auto element0 = a.function_spaces().at(0)->elements(cell_type_idx);
803 auto element1 = a.function_spaces().at(1)->elements(cell_type_idx);
805 const fem::DofTransformKernel<T>
auto& P0
807 const fem::DofTransformKernel<T>
auto& P1T
808 = element1->template dof_transformation_right_fn<T>(
811 std::span<const std::uint32_t> cell_info0;
812 std::span<const std::uint32_t> cell_info1;
813 if (element0->needs_dof_transformations()
814 or element1->needs_dof_transformations())
816 mesh0->topology_mutable()->create_cell_permutations();
817 mesh1->topology_mutable()->create_cell_permutations();
818 cell_info0 = std::span(mesh0->topology()->get_cell_permutation_info());
819 cell_info1 = std::span(mesh1->topology()->get_cell_permutation_info());
830 assert(
cells.size() * cstride == coeffs.size());
833 [&mat_set, &geometry, &cells, &dofs0, &cells0, &P0, &cell_info0,
834 &dofs1, &cells1, &P1T, &cell_info1, &bc0, &bc1, &fn, &coeffs,
835 cstride, &constants, &Ab1, &cdofs_b1](
auto bs0,
auto bs1)
837 impl::assemble_cells_matrix<LiftingMode>(
838 mat_set, geometry, cells,
839 FormArgument{DofMapPack{dofs0, bs0, cells0}, P0, cell_info0},
840 FormArgument{DofMapPack{dofs1, bs1, cells1}, P1T, cell_info1},
841 bc0, bc1, fn, constants,
842 md::mdspan(coeffs.data(),
cells.size(), cstride), Ab1,
847 md::mdspan<const std::uint8_t, md::dextents<std::size_t, 2>> facet_perms;
848 if (a.needs_facet_permutations())
850 facet_perms = impl::entity_permutations(
852 mesh->topology()->cell_types()[cell_type_idx]);
858 if (num_cell_types > 1)
860 throw std::invalid_argument(
"Interior facet integrals with mixed "
861 "topology aren't supported yet");
865 = md::mdspan<
const std::int32_t,
866 md::extents<std::size_t, md::dynamic_extent, 2, 2>>;
868 = md::mdspan<
const T, md::extents<std::size_t, md::dynamic_extent, 2,
869 md::dynamic_extent>>;
873 auto& [coeffs, cstride]
879 assert((facets.size() / 4) * 2 * cstride == coeffs.size());
882 [&mat_set, &geometry, &facets, &dofs0, &facets0, &P0, &cell_info0,
883 &dofs1, &facets1, &P1T, &cell_info1, &bc0, &bc1, &fn, &coeffs,
884 cstride, &constants, &facet_perms, &Ab, &cdofs_b, &dmap_b,
885 &Ae_block_b](
auto bs0,
auto bs1)
887 impl::assemble_interior_facets_matrix<LiftingMode>(
889 mdspanx22_t(facets.data(), facets.size() / 4, 2, 2),
890 FormArgument{DofMapPack{dofs0, bs0,
891 mdspanx22_t(facets0.data(),
892 facets0.size() / 4, 2, 2)},
894 FormArgument{DofMapPack{dofs1, bs1,
895 mdspanx22_t(facets1.data(),
896 facets1.size() / 4, 2, 2)},
898 bc0, bc1, fn, constants,
899 mdspanx2x_t(coeffs.data(), facets.size() / 4, 2, cstride),
900 facet_perms, std::span(Ab), std::span(cdofs_b),
901 std::span(dmap_b), std::span(Ae_block_b));
908 const int num_itg = a.num_integrals(itg_type, cell_type_idx);
915 md::mdspan<const std::uint8_t, md::dextents<std::size_t, 2>> perms;
916 if (a.needs_facet_permutations())
918 perms = impl::entity_permutations(
919 *mesh->topology_mutable(), itg_type,
920 mesh->topology()->cell_types()[cell_type_idx]);
923 for (
int i = 0; i < num_itg; ++i)
925 if (num_cell_types > 1)
927 throw std::invalid_argument(
"Exterior facet integrals with mixed "
928 "topology aren't supported yet");
932 = md::mdspan<
const std::int32_t,
933 md::extents<std::size_t, md::dynamic_extent, 2>>;
935 auto fn = a.kernel(itg_type, i, 0);
937 auto& [coeffs, cstride] = coefficients.at({itg_type, i});
939 std::span e = a.domain(itg_type, i, 0);
940 mdspanx2_t entities(e.data(), e.size() / 2, 2);
941 std::span e0 = a.domain_arg(itg_type, 0, i, 0);
942 mdspanx2_t entities0(e0.data(), e0.size() / 2, 2);
943 std::span e1 = a.domain_arg(itg_type, 1, i, 0);
944 mdspanx2_t entities1(e1.data(), e1.size() / 2, 2);
945 assert((entities.size() / 2) * cstride == coeffs.size());
948 [&mat_set, &geometry, &entities, &dofs0, &entities0, &P0,
949 &cell_info0, &dofs1, &entities1, &P1T, &cell_info1, &bc0, &bc1,
950 &fn, &coeffs, cstride, &constants, &perms, &Ab1,
951 &cdofs_b1](
auto bs0,
auto bs1)
953 impl::assemble_entities_matrix<LiftingMode>(
954 mat_set, geometry, entities,
955 FormArgument{DofMapPack{dofs0, bs0, entities0}, P0,
957 FormArgument{DofMapPack{dofs1, bs1, entities1}, P1T,
959 bc0, bc1, fn, constants,
960 md::mdspan(coeffs.data(), entities.extent(0), cstride), perms,
Degree-of-freedom map representations and tools.
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:32
@ standard
Standard.
Definition FiniteElement.h:31
@ vertex
Vertex.
Definition Form.h:47
@ interior_facet
Interior facet.
Definition Form.h:46
@ ridge
Ridge.
Definition Form.h:48
@ cell
Cell.
Definition Form.h:44
@ exterior_facet
Exterior facet.
Definition Form.h:45
constexpr bool is_transform_set(const F &fn)
Whether a DofTransformKernel fn should be invoked.
Definition traits.h:34