DOLFINx 0.12.0.0
DOLFINx C++
Loading...
Searching...
No Matches
assemble_vector_impl.h
1// Copyright (C) 2018-2025 Garth N. Wells and Paul T. Kühner
2//
3// This file is part of DOLFINx (https://www.fenicsproject.org)
4//
5// SPDX-License-Identifier: LGPL-3.0-or-later
6
7#pragma once
8
9#include "Constant.h"
10#include "DirichletBC.h"
11#include "DofMap.h"
12#include "Form.h"
13#include "traits.h"
14#include "utils.h"
15#include <algorithm>
16#include <basix/mdspan.hpp>
17#include <cstdint>
18#include <dolfinx/common/IndexMap.h>
19#include <dolfinx/mesh/Geometry.h>
20#include <dolfinx/mesh/Mesh.h>
21#include <dolfinx/mesh/Topology.h>
22#include <functional>
23#include <memory>
24#include <optional>
25#include <span>
26#include <vector>
27
28namespace dolfinx::fem
29{
30template <dolfinx::scalar T, std::floating_point U>
31class DirichletBC;
32
33}
34namespace dolfinx::fem::impl
35{
37using mdspan2_t = md::mdspan<const std::int32_t, md::dextents<std::size_t, 2>>;
39
64template <int _bs = -1, typename V, std::floating_point U,
65 dolfinx::scalar T = typename std::remove_cvref_t<V>::value_type>
66 requires std::is_same_v<typename std::remove_cvref_t<V>::value_type, T>
67
68void assemble_cells(
69 fem::DofTransformKernel<T> auto P0, V&& b, mdspan2_t x_dofmap,
70 md::mdspan<const U, md::extents<std::size_t, md::dynamic_extent, 3>> x,
71 std::span<const std::int32_t> cells,
72 std::tuple<mdspan2_t, int, std::span<const std::int32_t>> dofmap,
73 FEkernel<T, U> auto kernel, std::span<const T> constants,
74 md::mdspan<const T, md::dextents<std::size_t, 2>> coeffs,
75 std::span<const std::uint32_t> cell_info0)
76{
77 if (cells.empty())
78 return;
79
80 const auto [dmap, bs, cells0] = dofmap;
81 assert(_bs < 0 or _bs == bs);
82
83 // Create data structures used in assembly
84 std::vector<U> cdofs(3 * x_dofmap.extent(1));
85 std::vector<T> be(bs * dmap.extent(1));
86
87 // Iterate over active cells
88 for (std::size_t index = 0; index < cells.size(); ++index)
89 {
90 // Integration domain celland test function cell
91 std::int32_t c = cells[index];
92 std::int32_t c0 = cells0[index];
93
94 // Get cell coordinates/geometry
95 auto x_dofs = md::submdspan(x_dofmap, c, md::full_extent);
96 for (std::size_t i = 0; i < x_dofs.size(); ++i)
97 std::copy_n(&x(x_dofs[i], 0), 3, std::next(cdofs.begin(), 3 * i));
98
99 // Tabulate vector for cell
100 std::ranges::fill(be, 0);
101 kernel(be.data(), &coeffs(index, 0), constants.data(), cdofs.data(),
102 nullptr, nullptr, nullptr);
103 P0(be, cell_info0, c0, 1);
104
105 // Scatter cell vector to 'global' vector array
106 auto dofs = md::submdspan(dmap, c0, md::full_extent);
107 if constexpr (_bs > 0)
108 {
109 for (std::size_t i = 0; i < dofs.size(); ++i)
110 for (int k = 0; k < _bs; ++k)
111 b[_bs * dofs[i] + k] += be[_bs * i + k];
112 }
113 else
114 {
115 for (std::size_t i = 0; i < dofs.size(); ++i)
116 for (int k = 0; k < bs; ++k)
117 b[bs * dofs[i] + k] += be[bs * i + k];
118 }
119 }
120}
121
156template <int _bs = -1, typename V, std::floating_point U,
157 dolfinx::scalar T = typename std::remove_cvref_t<V>::value_type>
158 requires std::is_same_v<typename std::remove_cvref_t<V>::value_type, T>
159void assemble_entities(
160 fem::DofTransformKernel<T> auto P0, V&& b, mdspan2_t x_dofmap,
161 md::mdspan<const U, md::extents<std::size_t, md::dynamic_extent, 3>> x,
162 md::mdspan<const std::int32_t,
163 std::extents<std::size_t, md::dynamic_extent, 2>>
164 entities,
165 std::tuple<mdspan2_t, int,
166 md::mdspan<const std::int32_t,
167 std::extents<std::size_t, md::dynamic_extent, 2>>>
168 dofmap,
169 FEkernel<T, U> auto kernel, std::span<const T> constants,
170 md::mdspan<const T, md::dextents<std::size_t, 2>> coeffs,
171 std::span<const std::uint32_t> cell_info0,
172 md::mdspan<const std::uint8_t, md::dextents<std::size_t, 2>> perms)
173{
174 if (entities.empty())
175 return;
176
177 const auto [dmap, bs, entities0] = dofmap;
178 assert(_bs < 0 or _bs == bs);
179
180 // Create data structures used in assembly
181 const int num_dofs = dmap.extent(1);
182 std::vector<U> cdofs(3 * x_dofmap.extent(1));
183 std::vector<T> be(bs * num_dofs);
184 assert(entities0.size() == entities.size());
185 for (std::size_t f = 0; f < entities.extent(0); ++f)
186 {
187 // Cell in the integration domain, local facet index relative to the
188 // integration domain cell, and cell in the test function mesh
189 std::int32_t cell = entities(f, 0);
190 std::int32_t local_entity = entities(f, 1);
191 std::int32_t cell0 = entities0(f, 0);
192
193 // Get cell coordinates/geometry
194 auto x_dofs = md::submdspan(x_dofmap, cell, md::full_extent);
195 for (std::size_t i = 0; i < x_dofs.size(); ++i)
196 std::copy_n(&x(x_dofs[i], 0), 3, std::next(cdofs.begin(), 3 * i));
197
198 // Permutations
199 std::uint8_t perm = perms.empty() ? 0 : perms(cell, local_entity);
200
201 // Tabulate element vector
202 std::ranges::fill(be, 0);
203 kernel(be.data(), &coeffs(f, 0), constants.data(), cdofs.data(),
204 &local_entity, &perm, nullptr);
205 P0(be, cell_info0, cell0, 1);
206
207 // Add element vector to global vector
208 auto dofs = md::submdspan(dmap, cell0, md::full_extent);
209 if constexpr (_bs > 0)
210 {
211 for (std::size_t i = 0; i < dofs.size(); ++i)
212 for (int k = 0; k < _bs; ++k)
213 b[_bs * dofs[i] + k] += be[_bs * i + k];
214 }
215 else
216 {
217 for (std::size_t i = 0; i < dofs.size(); ++i)
218 for (int k = 0; k < bs; ++k)
219 b[bs * dofs[i] + k] += be[bs * i + k];
220 }
221 }
222}
223
250template <int _bs = -1, typename V, std::floating_point U,
251 dolfinx::scalar T = typename std::remove_cvref_t<V>::value_type>
252 requires std::is_same_v<typename std::remove_cvref_t<V>::value_type, T>
253void assemble_interior_facets(
254 fem::DofTransformKernel<T> auto P0, V&& b, mdspan2_t x_dofmap,
255 md::mdspan<const U, md::extents<std::size_t, md::dynamic_extent, 3>> x,
256 md::mdspan<const std::int32_t,
257 std::extents<std::size_t, md::dynamic_extent, 2, 2>>
258 facets,
259 std::tuple<const DofMap&, int,
260 md::mdspan<const std::int32_t,
261 std::extents<std::size_t, md::dynamic_extent, 2, 2>>>
262 dofmap,
263 FEkernel<T, U> auto kernel, std::span<const T> constants,
264 md::mdspan<const T, md::extents<std::size_t, md::dynamic_extent, 2,
265 md::dynamic_extent>>
266 coeffs,
267 std::span<const std::uint32_t> cell_info0,
268 md::mdspan<const std::uint8_t, md::dextents<std::size_t, 2>> perms)
269{
270 using X = U;
271
272 if (facets.empty())
273 return;
274
275 const auto [dmap, bs, facets0] = dofmap;
276 assert(_bs < 0 or _bs == bs);
277
278 // Create data structures used in assembly
279 std::vector<X> cdofs(2 * x_dofmap.extent(1) * 3);
280 std::span<X> cdofs0(cdofs.data(), x_dofmap.extent(1) * 3);
281 std::span<X> cdofs1(cdofs.data() + x_dofmap.extent(1) * 3,
282 x_dofmap.extent(1) * 3);
283
284 const std::size_t dmap_size = dmap.map().extent(1);
285 std::vector<T> be(bs * 2 * dmap_size);
286
287 assert(facets0.size() == facets.size());
288 for (std::size_t f = 0; f < facets.extent(0); ++f)
289 {
290 // Cells in integration domain and test function domain meshes
291 std::array<std::int32_t, 2> cells{facets(f, 0, 0), facets(f, 1, 0)};
292 std::array<std::int32_t, 2> cells0{facets0(f, 0, 0), facets0(f, 1, 0)};
293
294 // Local facet indices
295 std::array<std::int32_t, 2> local_facet{facets(f, 0, 1), facets(f, 1, 1)};
296
297 // Get cell geometry
298 auto x_dofs0 = md::submdspan(x_dofmap, cells[0], md::full_extent);
299 for (std::size_t i = 0; i < x_dofs0.size(); ++i)
300 std::copy_n(&x(x_dofs0[i], 0), 3, std::next(cdofs0.begin(), 3 * i));
301 auto x_dofs1 = md::submdspan(x_dofmap, cells[1], md::full_extent);
302 for (std::size_t i = 0; i < x_dofs1.size(); ++i)
303 std::copy_n(&x(x_dofs1[i], 0), 3, std::next(cdofs1.begin(), 3 * i));
304
305 // Get dofmaps for cells. When integrating over interfaces between
306 // two domains, the test function might only be defined on one side,
307 // so we check which cells exist in the test function domain.
308 std::span dmap0 = cells0[0] >= 0 ? dmap.cell_dofs(cells0[0])
309 : std::span<const std::int32_t>();
310 std::span dmap1 = cells0[1] >= 0 ? dmap.cell_dofs(cells0[1])
311 : std::span<const std::int32_t>();
312
313 // Tabulate element vector
314 std::ranges::fill(be, 0);
315 std::array perm = perms.empty()
316 ? std::array<std::uint8_t, 2>{0, 0}
317 : std::array{perms(cells[0], local_facet[0]),
318 perms(cells[1], local_facet[1])};
319 kernel(be.data(), &coeffs(f, 0, 0), constants.data(), cdofs.data(),
320 local_facet.data(), perm.data(), nullptr);
321
322 if (cells0[0] >= 0)
323 P0(be, cell_info0, cells0[0], 1);
324 if (cells0[1] >= 0)
325 {
326 std::span sub_be(be.data() + bs * dmap_size, bs * dmap_size);
327 P0(sub_be, cell_info0, cells0[1], 1);
328 }
329
330 // Add element vector to global vector
331 if constexpr (_bs > 0)
332 {
333 for (std::size_t i = 0; i < dmap0.size(); ++i)
334 for (int k = 0; k < _bs; ++k)
335 b[_bs * dmap0[i] + k] += be[_bs * i + k];
336 for (std::size_t i = 0; i < dmap1.size(); ++i)
337 for (int k = 0; k < _bs; ++k)
338 b[_bs * dmap1[i] + k] += be[_bs * (i + dmap_size) + k];
339 }
340 else
341 {
342 for (std::size_t i = 0; i < dmap0.size(); ++i)
343 for (int k = 0; k < bs; ++k)
344 b[bs * dmap0[i] + k] += be[bs * i + k];
345 for (std::size_t i = 0; i < dmap1.size(); ++i)
346 for (int k = 0; k < bs; ++k)
347 b[bs * dmap1[i] + k] += be[bs * (i + dmap_size) + k];
348 }
349 }
350}
351
369template <dolfinx::scalar T, std::floating_point U, int BS0 = -1, int BS1 = -1,
370 typename V>
371 requires std::is_same_v<typename std::remove_cvref_t<V>::value_type, T>
372void lift_bc_impl(
373 V&& b, const Form<T, U>& a, std::span<const T> constants,
374 const std::map<std::pair<IntegralType, int>,
375 std::pair<std::span<const T>, int>>& coefficients,
376 std::span<const T> bc_values1, std::span<const std::int8_t> bc_markers1,
377 std::span<const T> x0, T alpha)
378{
379 // Deduce runtime block sizes as fallback when compile-time sizes not given.
380 // The block size of the dofmap and indexmap is the same on all
381 // sub-topologies.
382 const int bs0
383 = BS0 > 0 ? BS0 : a.function_spaces()[0]->dofmaps().front()->bs();
384 const int bs1
385 = BS1 > 0 ? BS1 : a.function_spaces()[1]->dofmaps().front()->bs();
386
387 // Use default [=] capture for bs0, bs1 which may be compile-time constants
388 auto lifting_fn
389 = [=, &b, &bc_values1, &bc_markers1,
390 &x0](std::span<const std::int32_t> rows,
391 std::span<const std::int32_t> cols, std::span<const T> Ae)
392 {
393 const std::size_t nc = cols.size() * bs1;
394 for (std::size_t i = 0; i < cols.size(); ++i)
395 {
396 for (int k = 0; k < bs1; ++k)
397 {
398 const std::int32_t ii = cols[i] * bs1 + k;
399 if (bc_markers1[ii])
400 {
401 const T x_bc = bc_values1[ii];
402 const T _x0 = x0.empty() ? 0 : x0[ii];
403 for (std::size_t j = 0; j < rows.size(); ++j)
404 {
405 for (int m = 0; m < bs0; ++m)
406 {
407 const std::int32_t jj = rows[j] * bs0 + m;
408 b[jj] -= Ae[(j * bs0 + m) * nc + (i * bs1 + k)] * alpha
409 * (x_bc - _x0);
410 }
411 }
412 }
413 }
414 }
415 };
416
417 // Repurpose the assemble_matrix assembler to work on the vector b instead.
418 // Use LiftingMode=true so the kernel is only called on cells that have
419 // BC-constrained DOFs in the column space.
420 assemble_matrix<T, U, true>(lifting_fn, a, constants, coefficients, {},
421 bc_markers1);
422}
423
438template <typename V, std::floating_point U,
439 dolfinx::scalar T = typename std::remove_cvref_t<V>::value_type>
440 requires std::is_same_v<typename std::remove_cvref_t<V>::value_type, T>
441void lift_bc(V&& b, const Form<T, U>& a, std::span<const T> constants,
442 const std::map<std::pair<IntegralType, int>,
443 std::pair<std::span<const T>, int>>& coefficients,
444 std::span<const T> bc_values1,
445 std::span<const std::int8_t> bc_markers1, std::span<const T> x0,
446 T alpha)
447{
448
449 // Get dofmap for columns and rows of a
450 assert(a.function_spaces().at(0));
451 assert(a.function_spaces().at(1));
452 const int bs0 = a.function_spaces()[0]->dofmaps().front()->bs();
453 const int bs1 = a.function_spaces()[1]->dofmaps().front()->bs();
454
455 spdlog::debug("lifting: bs0={}, bs1={}", bs0, bs1);
456
457 if (bs0 == 1 && bs1 == 1)
458 {
459 lift_bc_impl<T, U, 1, 1>(std::forward<V>(b), a, constants, coefficients,
460 bc_values1, bc_markers1, x0, alpha);
461 }
462 else if (bs0 == 3 && bs1 == 3)
463 {
464 lift_bc_impl<T, U, 3, 3>(std::forward<V>(b), a, constants, coefficients,
465 bc_values1, bc_markers1, x0, alpha);
466 }
467 else
468 {
469 lift_bc_impl<T, U>(std::forward<V>(b), a, constants, coefficients,
470 bc_values1, bc_markers1, x0, alpha);
471 }
472}
473
494template <typename V, std::floating_point U,
495 dolfinx::scalar T = typename std::remove_cvref_t<V>::value_type>
496 requires std::is_same_v<typename std::remove_cvref_t<V>::value_type, T>
497void apply_lifting(
498 V&& b,
499 std::vector<std::optional<std::reference_wrapper<const Form<T, U>>>> a,
500 const std::vector<std::span<const T>>& constants,
501 const std::vector<std::map<std::pair<IntegralType, int>,
502 std::pair<std::span<const T>, int>>>& coeffs,
503 const std::vector<
504 std::vector<std::reference_wrapper<const DirichletBC<T, U>>>>& bcs1,
505 const std::vector<std::span<const T>>& x0, T alpha)
506{
507 if (!x0.empty() and x0.size() != a.size())
508 {
509 throw std::runtime_error(
510 "Mismatch in size between x0 and bilinear form in assembler.");
511 }
512
513 if (a.size() != bcs1.size())
514 {
515 throw std::runtime_error(
516 "Mismatch in size between a and bcs in assembler.");
517 }
518
519 for (std::size_t j = 0; j < a.size(); ++j)
520 {
521 std::vector<std::int8_t> bc_markers1;
522 std::vector<T> bc_values1;
523 if (a[j] and !bcs1[j].empty())
524 {
525 assert(a[j]->get().function_spaces().at(0));
526 auto V1 = a[j]->get().function_spaces()[1];
527
528 std::span<const T> _x0;
529 if (!x0.empty())
530 _x0 = x0[j];
531
532 assert(V1);
533 const auto& dofmap = V1->dofmaps().front();
534 auto map1 = dofmap->index_map;
535 const int bs1 = dofmap->index_map_bs();
536 assert(map1);
537 const int crange = bs1 * (map1->size_local() + map1->num_ghosts());
538 bc_markers1.assign(crange, false);
539 bc_values1.assign(crange, 0);
540 for (auto& bc : bcs1[j])
541 {
542 bc.get().mark_dofs(bc_markers1);
543 bc.get().set(bc_values1, std::nullopt, 1);
544 }
545
546 lift_bc(b, a[j]->get(), constants[j], coeffs[j],
547 std::span<const T>(bc_values1), bc_markers1, _x0, alpha);
548 }
549 }
550}
551
559template <typename V, std::floating_point U,
560 dolfinx::scalar T = typename std::remove_cvref_t<V>::value_type>
561 requires std::is_same_v<typename std::remove_cvref_t<V>::value_type, T>
562void assemble_vector(
563 V&& b, const Form<T, U>& L,
564 md::mdspan<const U, md::extents<std::size_t, md::dynamic_extent, 3>> x,
565 std::span<const T> constants,
566 const std::map<std::pair<IntegralType, int>,
567 std::pair<std::span<const T>, int>>& coefficients)
568{
569 // Integration domain mesh
570 std::shared_ptr<const mesh::Mesh<U>> mesh = L.mesh();
571 assert(mesh);
572
573 // Test function mesh
574 auto mesh0 = L.function_spaces().at(0)->mesh();
575 assert(mesh0);
576
577 const int num_cell_types = mesh->topology()->cell_types().size();
578 for (int cell_type_idx = 0; cell_type_idx < num_cell_types; ++cell_type_idx)
579 {
580 // Geometry dofmap and data
581 mdspan2_t x_dofmap = mesh->geometry().dofmaps().at(cell_type_idx);
582
583 // Get dofmap data
584 assert(L.function_spaces().at(0));
585 auto element = L.function_spaces().at(0)->elements(cell_type_idx);
586 assert(element);
587 std::shared_ptr<const fem::DofMap> dofmap
588 = L.function_spaces().at(0)->dofmaps().at(cell_type_idx);
589 assert(dofmap);
590 auto dofs = dofmap->map();
591 const int bs = dofmap->bs();
592
593 fem::DofTransformKernel<T> auto P0
594 = element->template dof_transformation_fn<T>(doftransform::standard);
595
596 std::span<const std::uint32_t> cell_info0;
597 if (element->needs_dof_transformations() or L.needs_facet_permutations())
598 {
599 mesh0->topology_mutable()->create_entity_permutations();
600 cell_info0 = std::span(mesh0->topology()->get_cell_permutation_info());
601 }
602
603 for (int i = 0; i < L.num_integrals(IntegralType::cell, 0); ++i)
604 {
605 auto fn = L.kernel(IntegralType::cell, i, cell_type_idx);
606 assert(fn);
607 std::span cells = L.domain(IntegralType::cell, i, cell_type_idx);
608 std::span cells0 = L.domain_arg(IntegralType::cell, 0, i, cell_type_idx);
609 auto& [coeffs, cstride] = coefficients.at({IntegralType::cell, i});
610 assert(cells.size() * cstride == coeffs.size());
611 if (bs == 1)
612 {
613 impl::assemble_cells<1>(
614 P0, b, x_dofmap, x, cells, {dofs, bs, cells0}, fn, constants,
615 md::mdspan(coeffs.data(), cells.size(), cstride), cell_info0);
616 }
617 else if (bs == 3)
618 {
619 impl::assemble_cells<3>(
620 P0, b, x_dofmap, x, cells, {dofs, bs, cells0}, fn, constants,
621 md::mdspan(coeffs.data(), cells.size(), cstride), cell_info0);
622 }
623 else
624 {
625 impl::assemble_cells(
626 P0, b, x_dofmap, x, cells, {dofs, bs, cells0}, fn, constants,
627 md::mdspan(coeffs.data(), cells.size(), cstride), cell_info0);
628 }
629 }
630
631 md::mdspan<const std::uint8_t, md::dextents<std::size_t, 2>> facet_perms;
632 if (L.needs_facet_permutations())
633 {
634 mesh::CellType cell_type = mesh->topology()->cell_types()[cell_type_idx];
635 int num_facets_per_cell
636 = mesh::cell_num_entities(cell_type, mesh->topology()->dim() - 1);
637 mesh->topology_mutable()->create_entity_permutations();
638 const std::vector<std::uint8_t>& p
639 = mesh->topology()->get_facet_permutations();
640 facet_perms = md::mdspan(p.data(), p.size() / num_facets_per_cell,
641 num_facets_per_cell);
642 }
643
644 using mdspanx2_t
645 = md::mdspan<const std::int32_t,
646 md::extents<std::size_t, md::dynamic_extent, 2>>;
647
648 for (int i = 0; i < L.num_integrals(IntegralType::interior_facet, 0); ++i)
649 {
650 using mdspanx22_t
651 = md::mdspan<const std::int32_t,
652 md::extents<std::size_t, md::dynamic_extent, 2, 2>>;
653 using mdspanx2x_t
654 = md::mdspan<const T, md::extents<std::size_t, md::dynamic_extent, 2,
655 md::dynamic_extent>>;
656
657 auto fn = L.kernel(IntegralType::interior_facet, i, 0);
658 assert(fn);
659 auto& [coeffs, cstride]
660 = coefficients.at({IntegralType::interior_facet, i});
661 std::span facets = L.domain(IntegralType::interior_facet, i, 0);
662 std::span facets1 = L.domain_arg(IntegralType::interior_facet, 0, i, 0);
663 assert((facets.size() / 4) * 2 * cstride == coeffs.size());
664 if (bs == 1)
665 {
666 impl::assemble_interior_facets<1>(
667 P0, b, x_dofmap, x,
668 mdspanx22_t(facets.data(), facets.size() / 4, 2, 2),
669 {*dofmap, bs,
670 mdspanx22_t(facets1.data(), facets1.size() / 4, 2, 2)},
671 fn, constants,
672 mdspanx2x_t(coeffs.data(), facets.size() / 4, 2, cstride),
673 cell_info0, facet_perms);
674 }
675 else if (bs == 3)
676 {
677 impl::assemble_interior_facets<3>(
678 P0, b, x_dofmap, x,
679 mdspanx22_t(facets.data(), facets.size() / 4, 2, 2),
680 {*dofmap, bs,
681 mdspanx22_t(facets1.data(), facets1.size() / 4, 2, 2)},
682 fn, constants,
683 mdspanx2x_t(coeffs.data(), facets.size() / 4, 2, cstride),
684 cell_info0, facet_perms);
685 }
686 else
687 {
688 impl::assemble_interior_facets(
689 P0, b, x_dofmap, x,
690 mdspanx22_t(facets.data(), facets.size() / 4, 2, 2),
691 {*dofmap, bs,
692 mdspanx22_t(facets1.data(), facets1.size() / 4, 2, 2)},
693 fn, constants,
694 mdspanx2x_t(coeffs.data(), facets.size() / 4, 2, cstride),
695 cell_info0, facet_perms);
696 }
697 }
698
699 for (auto itg_type : {fem::IntegralType::exterior_facet,
701 {
702 md::mdspan<const std::uint8_t, md::dextents<std::size_t, 2>> perms
704 ? facet_perms
705 : md::mdspan<const std::uint8_t,
706 md::dextents<std::size_t, 2>>{};
707 for (int i = 0; i < L.num_integrals(itg_type, 0); ++i)
708 {
709 auto fn = L.kernel(itg_type, i, 0);
710 assert(fn);
711 auto& [coeffs, cstride] = coefficients.at({itg_type, i});
712 std::span e = L.domain(itg_type, i, 0);
713 mdspanx2_t entities(e.data(), e.size() / 2, 2);
714 std::span e1 = L.domain_arg(itg_type, 0, i, 0);
715 mdspanx2_t entities1(e1.data(), e1.size() / 2, 2);
716 assert((entities.size() / 2) * cstride == coeffs.size());
717 if (bs == 1)
718 {
719 impl::assemble_entities<1>(
720 P0, b, x_dofmap, x, entities, {dofs, bs, entities1}, fn,
721 constants, md::mdspan(coeffs.data(), entities.extent(0), cstride),
722 cell_info0, perms);
723 }
724 else if (bs == 3)
725 {
726 impl::assemble_entities<3>(
727 P0, b, x_dofmap, x, entities, {dofs, bs, entities1}, fn,
728 constants,
729 md::mdspan(coeffs.data(), entities.size() / 2, cstride),
730 cell_info0, perms);
731 }
732 else
733 {
734 impl::assemble_entities(
735 P0, b, x_dofmap, x, entities, {dofs, bs, entities1}, fn,
736 constants,
737 md::mdspan(coeffs.data(), entities.size() / 2, cstride),
738 cell_info0, perms);
739 }
740 }
741 }
742 }
743}
744
751template <typename V, std::floating_point U,
752 dolfinx::scalar T = typename std::remove_cvref_t<V>::value_type>
753 requires std::is_same_v<typename std::remove_cvref_t<V>::value_type, T>
754void assemble_vector(
755 V&& b, const Form<T, U>& L, std::span<const T> constants,
756 const std::map<std::pair<IntegralType, int>,
757 std::pair<std::span<const T>, int>>& coefficients)
758{
759 using mdspanx3_t
760 = md::mdspan<const U, md::extents<std::size_t, md::dynamic_extent, 3>>;
761
762 std::shared_ptr<const mesh::Mesh<U>> mesh = L.mesh();
763 assert(mesh);
764 auto x = mesh->geometry().x();
765 impl::assemble_vector(b, L, mdspanx3_t(x.data(), x.size() / 3, 3), constants,
766 coefficients);
767}
768} // namespace dolfinx::fem::impl
Degree-of-freedom map representations and tools.
Definition DirichletBC.h:258
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
Finite element method functionality.
Definition assemble_expression_impl.h:23
@ standard
Standard.
Definition FiniteElement.h:27
@ vertex
Vertex.
Definition Form.h:43
@ interior_facet
Interior facet.
Definition Form.h:42
@ ridge
Ridge.
Definition Form.h:44
@ cell
Cell.
Definition Form.h:40
@ exterior_facet
Exterior facet.
Definition Form.h:41
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