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