@@ -156,16 +156,24 @@ void assemble_cells_matrix(
156156 }
157157}
158158
159- // / @brief Execute kernel over exterior facets and accumulate result in
160- // / a matrix.
159+ // / @brief Execute kernel over entities of codimension ≥ 1 and accumulate result
160+ // / in a matrix.
161+ // /
162+ // / Each entity is represented by (i) a cell that the entity is attached to
163+ // / and (ii) the local index of the entity with respect to the cell. The
164+ // / kernel is executed for each entity. The kernel can access data
165+ // / (e.g., coefficients, basis functions) associated with the attached cell.
166+ // / However, entities may be attached to more than one cell. This function
167+ // / therefore computes 'one-sided' integrals, i.e. evaluates integrals as seen
168+ // / from cell used to define the entity.
161169// /
162170// / @tparam T Matrix/form scalar type.
163171// / @param[in] mat_set Function that accumulates computed entries into a
164172// / matrix.
165173// / @param[in] x_dofmap Dofmap for the mesh geometry.
166174// / @param[in] x Mesh geometry (coordinates).
167- // / @param[in] facets Facet indices (in the integration domain mesh) to
168- // / execute the kernel over.
175+ // / @param[in] entities Integration entities (in the integration domain mesh) to
176+ // / execute the kernel over. These are pairs (cell, local entity index)
169177// / @param[in] dofmap0 Test function (row) degree-of-freedom data
170178// / holding the (0) dofmap, (1) dofmap block size and (2) dofmap cell
171179// / indices.
@@ -188,17 +196,17 @@ void assemble_cells_matrix(
188196// / function mesh.
189197// / @param[in] cell_info1 Cell permutation information for the trial
190198// / function mesh.
191- // / @param[in] perms Facet permutation integer. Empty if facet
199+ // / @param[in] perms Entity permutation integer. Empty if entity
192200// / permutations are not required.
193201template <dolfinx::scalar T>
194- void assemble_exterior_facets (
202+ void assemble_entities (
195203 la::MatSet<T> auto mat_set, mdspan2_t x_dofmap,
196204 md::mdspan<const scalar_value_t <T>,
197205 md::extents<std::size_t , md::dynamic_extent, 3 >>
198206 x,
199207 md::mdspan<const std::int32_t ,
200208 std::extents<std::size_t , md::dynamic_extent, 2 >>
201- facets ,
209+ entities ,
202210 std::tuple<mdspan2_t , int ,
203211 md::mdspan<const std::int32_t ,
204212 std::extents<std::size_t , md::dynamic_extent, 2 >>>
@@ -215,11 +223,11 @@ void assemble_exterior_facets(
215223 std::span<const std::uint32_t > cell_info1,
216224 md::mdspan<const std::uint8_t , md::dextents<std::size_t , 2 >> perms)
217225{
218- if (facets .empty ())
226+ if (entities .empty ())
219227 return ;
220228
221- const auto [dmap0, bs0, facets0 ] = dofmap0;
222- const auto [dmap1, bs1, facets1 ] = dofmap1;
229+ const auto [dmap0, bs0, entities0 ] = dofmap0;
230+ const auto [dmap1, bs1, entities1 ] = dofmap1;
223231
224232 // Data structures used in assembly
225233 std::vector<scalar_value_t <T>> cdofs (3 * x_dofmap.extent (1 ));
@@ -228,30 +236,30 @@ void assemble_exterior_facets(
228236 const int ndim0 = bs0 * num_dofs0;
229237 const int ndim1 = bs1 * num_dofs1;
230238 std::vector<T> Ae (ndim0 * ndim1);
231- assert (facets0 .size () == facets .size ());
232- assert (facets1 .size () == facets .size ());
233- for (std::size_t f = 0 ; f < facets .extent (0 ); ++f)
239+ assert (entities0 .size () == entities .size ());
240+ assert (entities1 .size () == entities .size ());
241+ for (std::size_t f = 0 ; f < entities .extent (0 ); ++f)
234242 {
235- // Cell in the integration domain, local facet index relative to the
243+ // Cell in the integration domain, local entity index relative to the
236244 // integration domain cell, and cells in the test and trial function
237245 // meshes
238- std::int32_t cell = facets (f, 0 );
239- std::int32_t local_facet = facets (f, 1 );
240- std::int32_t cell0 = facets0 (f, 0 );
241- std::int32_t cell1 = facets1 (f, 0 );
246+ std::int32_t cell = entities (f, 0 );
247+ std::int32_t local_entity = entities (f, 1 );
248+ std::int32_t cell0 = entities0 (f, 0 );
249+ std::int32_t cell1 = entities1 (f, 0 );
242250
243251 // Get cell coordinates/geometry
244252 auto x_dofs = md::submdspan (x_dofmap, cell, md::full_extent);
245253 for (std::size_t i = 0 ; i < x_dofs.size (); ++i)
246254 std::copy_n (&x (x_dofs[i], 0 ), 3 , std::next (cdofs.begin (), 3 * i));
247255
248256 // Permutations
249- std::uint8_t perm = perms.empty () ? 0 : perms (cell, local_facet );
257+ std::uint8_t perm = perms.empty () ? 0 : perms (cell, local_entity );
250258
251259 // Tabulate tensor
252260 std::ranges::fill (Ae, 0 );
253261 kernel (Ae.data (), &coeffs (f, 0 ), constants.data (), cdofs.data (),
254- &local_facet , &perm, nullptr );
262+ &local_entity , &perm, nullptr );
255263 P0 (Ae, cell_info0, cell0, ndim1);
256264 P1T (Ae, cell_info1, cell1, ndim0);
257265
@@ -605,7 +613,7 @@ void assemble_matrix(
605613 cell_info0, cell_info1);
606614 }
607615
608- md::mdspan<const std::uint8_t , md::dextents<std::size_t , 2 >> perms ;
616+ md::mdspan<const std::uint8_t , md::dextents<std::size_t , 2 >> facet_perms ;
609617 if (a.needs_facet_permutations ())
610618 {
611619 mesh::CellType cell_type = mesh->topology ()->cell_types ()[cell_type_idx];
@@ -614,40 +622,8 @@ void assemble_matrix(
614622 mesh->topology_mutable ()->create_entity_permutations ();
615623 const std::vector<std::uint8_t >& p
616624 = mesh->topology ()->get_facet_permutations ();
617- perms = md::mdspan (p.data (), p.size () / num_facets_per_cell,
618- num_facets_per_cell);
619- }
620-
621- for (int i = 0 ;
622- i < a.num_integrals (IntegralType::exterior_facet, cell_type_idx); ++i)
623- {
624- if (num_cell_types > 1 )
625- {
626- throw std::runtime_error (" Exterior facet integrals with mixed "
627- " topology aren't supported yet" );
628- }
629-
630- using mdspanx2_t
631- = md::mdspan<const std::int32_t ,
632- md::extents<std::size_t , md::dynamic_extent, 2 >>;
633-
634- auto fn = a.kernel (IntegralType::exterior_facet, i, 0 );
635- assert (fn);
636- auto & [coeffs, cstride]
637- = coefficients.at ({IntegralType::exterior_facet, i});
638-
639- std::span f = a.domain (IntegralType::exterior_facet, i, 0 );
640- mdspanx2_t facets (f.data (), f.size () / 2 , 2 );
641- std::span f0 = a.domain_arg (IntegralType::exterior_facet, 0 , i, 0 );
642- mdspanx2_t facets0 (f0.data (), f0.size () / 2 , 2 );
643- std::span f1 = a.domain_arg (IntegralType::exterior_facet, 1 , i, 0 );
644- mdspanx2_t facets1 (f1.data (), f1.size () / 2 , 2 );
645- assert ((facets.size () / 2 ) * cstride == coeffs.size ());
646- impl::assemble_exterior_facets (
647- mat_set, x_dofmap, x, facets, {dofs0, bs0, facets0}, P0 ,
648- {dofs1, bs1, facets1}, P1T , bc0, bc1, fn,
649- md::mdspan (coeffs.data (), facets.extent (0 ), cstride), constants,
650- cell_info0, cell_info1, perms);
625+ facet_perms = md::mdspan (p.data (), p.size () / num_facets_per_cell,
626+ num_facets_per_cell);
651627 }
652628
653629 for (int i = 0 ;
@@ -685,7 +661,47 @@ void assemble_matrix(
685661 mdspanx22_t (facets1.data (), facets1.size () / 4 , 2 , 2 )},
686662 P1T , bc0, bc1, fn,
687663 mdspanx2x_t (coeffs.data (), facets.size () / 4 , 2 , cstride), constants,
688- cell_info0, cell_info1, perms);
664+ cell_info0, cell_info1, facet_perms);
665+ }
666+
667+ for (auto itg_type : {fem::IntegralType::exterior_facet,
668+ fem::IntegralType::vertex, fem::IntegralType::ridge})
669+ {
670+ md::mdspan<const std::uint8_t , md::dextents<std::size_t , 2 >> perms
671+ = itg_type == fem::IntegralType::exterior_facet
672+ ? facet_perms
673+ : md::mdspan<const std::uint8_t ,
674+ md::dextents<std::size_t , 2 >>{};
675+
676+ for (int i = 0 ; i < a.num_integrals (itg_type, cell_type_idx); ++i)
677+ {
678+ if (num_cell_types > 1 )
679+ {
680+ throw std::runtime_error (" Exterior facet integrals with mixed "
681+ " topology aren't supported yet" );
682+ }
683+
684+ using mdspanx2_t
685+ = md::mdspan<const std::int32_t ,
686+ md::extents<std::size_t , md::dynamic_extent, 2 >>;
687+
688+ auto fn = a.kernel (itg_type, i, 0 );
689+ assert (fn);
690+ auto & [coeffs, cstride] = coefficients.at ({itg_type, i});
691+
692+ std::span e = a.domain (itg_type, i, 0 );
693+ mdspanx2_t entities (e.data (), e.size () / 2 , 2 );
694+ std::span e0 = a.domain_arg (itg_type, 0 , i, 0 );
695+ mdspanx2_t entities0 (e0 .data (), e0 .size () / 2 , 2 );
696+ std::span e1 = a.domain_arg (itg_type, 1 , i, 0 );
697+ mdspanx2_t entities1 (e1 .data (), e1 .size () / 2 , 2 );
698+ assert ((entities.size () / 2 ) * cstride == coeffs.size ());
699+ impl::assemble_entities (
700+ mat_set, x_dofmap, x, entities, {dofs0, bs0, entities0}, P0 ,
701+ {dofs1, bs1, entities1}, P1T , bc0, bc1, fn,
702+ md::mdspan (coeffs.data (), entities.extent (0 ), cstride), constants,
703+ cell_info0, cell_info1, perms);
704+ }
689705 }
690706 }
691707}
0 commit comments