DOLFINx 0.12.0.0
DOLFINx C++
Loading...
Searching...
No Matches
petsc.h
1// Copyright (C) 2018-2026 Garth N. Wells and Jack S. Hale
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#ifdef HAS_PETSC
10
11#include "Form.h"
12#include "Function.h"
13#include "assembler.h"
14#include "pack.h"
15#include "sparsitypattern.h"
16#include <array>
17#include <cassert>
18#include <concepts>
19#include <cstdint>
20#include <dolfinx/common/IndexMap.h>
21#include <dolfinx/la/petsc.h>
22#include <format>
23#include <functional>
24#include <iterator>
25#include <map>
26#include <memory>
27#include <numeric>
28#include <optional>
29#include <petscmat.h>
30#include <petscvec.h>
31#include <ranges>
32#include <span>
33#include <stdexcept>
34#include <utility>
35#include <vector>
36
37namespace dolfinx::fem
38{
39template <dolfinx::scalar T, std::floating_point U>
40class DirichletBC;
41
43namespace petsc
44{
45namespace impl
46{
55template <std::floating_point T>
56void check_matis_mesh(const mesh::Mesh<T>& mesh,
57 const std::optional<std::string>& type)
58{
59 if (!type or *type != MATIS)
60 return;
61
62 auto topology = mesh.topology();
63 assert(topology);
64 std::shared_ptr<const common::IndexMap> cells
65 = topology->index_map(topology->dim());
66 assert(cells);
67 if (cells->num_ghosts() > 0)
68 {
69 throw std::invalid_argument(
70 "A MATIS matrix requires one non-overlapping subdomain per process. "
71 "Create the mesh with GhostMode::none.");
72 }
73}
74} // namespace impl
75
85template <std::floating_point T>
87 std::optional<std::string> type = std::nullopt)
88{
89 impl::check_matis_mesh(*a.mesh(), type);
91 pattern.finalize();
92 return la::petsc::create_matrix(a.mesh()->comm(), pattern, type);
93}
94
107template <std::floating_point T>
109 const std::vector<std::vector<const Form<PetscScalar, T>*>>& a,
110 std::optional<std::string> type = std::nullopt)
111{
112 // Extract and check row/column ranges
113 std::array<std::vector<std::shared_ptr<const FunctionSpace<T>>>, 2> V
115 std::array<std::vector<int>, 2> bs_dofs;
116 for (std::size_t i = 0; i < 2; ++i)
117 {
118 for (auto& _V : V[i])
119 bs_dofs[i].push_back(_V->dofmap()->bs());
120 }
121
122 // Build sparsity pattern for each block
123 std::shared_ptr<const mesh::Mesh<T>> mesh;
124 std::vector<std::vector<std::unique_ptr<la::SparsityPattern>>> patterns(
125 V[0].size());
126 for (std::size_t row = 0; row < V[0].size(); ++row)
127 {
128 for (std::size_t col = 0; col < V[1].size(); ++col)
129 {
130 if (const Form<PetscScalar, T>* form = a[row][col]; form)
131 {
132 patterns[row].push_back(std::make_unique<la::SparsityPattern>(
134 if (!mesh)
135 mesh = form->mesh();
136 }
137 else
138 patterns[row].push_back(nullptr);
139 }
140 }
141
142 if (!mesh)
143 throw std::invalid_argument("Could not find a Mesh.");
144
145 impl::check_matis_mesh(*mesh, type);
146
147 // Compute offsets for the fields
148 std::array<std::vector<std::pair<
149 std::reference_wrapper<const common::IndexMap>, int>>,
150 2>
151 maps;
152 for (std::size_t d = 0; d < 2; ++d)
153 {
154 for (auto& space : V[d])
155 {
156 maps[d].emplace_back(*space->dofmap()->index_map,
157 space->dofmap()->index_map_bs());
158 }
159 }
160
161 // Create merged sparsity pattern
162 std::vector<std::vector<const la::SparsityPattern*>> p(V[0].size());
163 for (std::size_t row = 0; row < V[0].size(); ++row)
164 for (std::size_t col = 0; col < V[1].size(); ++col)
165 p[row].push_back(patterns[row][col].get());
166
167 la::SparsityPattern pattern(mesh->comm(), p, maps, bs_dofs);
168 pattern.finalize();
169
170 // TODO: Index map concatenation has already been computed inside
171 // the SparsityPattern constructor, but we also need it here to
172 // build the PETSc local-to-global map. Compute outside and pass
173 // into SparsityPattern constructor.
174
175 // Create row and column local-to-global maps (field0, field1, field2,
176 // etc), i.e. ghosts of field0 appear before owned indices of field1
177 std::array<std::vector<PetscInt>, 2> _maps;
178 for (int d = 0; d < 2; ++d)
179 {
180 if (d == 1 and V[0] == V[1])
181 {
182 // Row and column spaces are identical, so the concatenated
183 // index map for d=1 is identical to the one already computed
184 // for d=0 -- reuse it rather than paying for a second,
185 // communication-heavy call to stack_index_maps.
186 _maps[1] = _maps[0];
187 continue;
188 }
189
190 const std::vector<
191 std::pair<std::reference_wrapper<const common::IndexMap>, int>>& map
192 = maps[d];
193 std::vector<PetscInt>& _map = _maps[d];
194
195 // Concatenate the block index map in the row and column directions
196 const auto [rank_offset, local_offset, ghosts, _]
198 const std::size_t num_ghosts
199 = std::accumulate(ghosts.begin(), ghosts.end(), std::size_t(0),
200 [](std::size_t n, auto& g) { return n + g.size(); });
201 _map.reserve(local_offset.back() + num_ghosts);
202 for (std::size_t f = 0; f < map.size(); ++f)
203 {
204 auto offset = local_offset[f];
205 const common::IndexMap& imap = map[f].first.get();
206 int bs = map[f].second;
207 auto owned
208 = std::views::iota(std::int32_t(0), bs * imap.size_local())
209 | std::views::transform([offset, rank_offset](std::int32_t i)
210 { return i + rank_offset + offset; });
211 _map.insert(_map.end(), owned.begin(), owned.end());
212 _map.insert(_map.end(), ghosts[f].begin(), ghosts[f].end());
213 }
214 }
215
216 // Create the local-to-global maps on the mesh communicator. MATIS
217 // requires them to share the matrix communicator
218 ISLocalToGlobalMapping l2g0 = nullptr, l2g1 = nullptr;
220 ISLocalToGlobalMappingCreate(mesh->comm(), 1, _maps[0].size(),
221 _maps[0].data(), PETSC_COPY_VALUES, &l2g0),
222 "ISLocalToGlobalMappingCreate");
223 if (V[0] != V[1])
224 {
226 ISLocalToGlobalMappingCreate(mesh->comm(), 1, _maps[1].size(),
227 _maps[1].data(), PETSC_COPY_VALUES, &l2g1),
228 "ISLocalToGlobalMappingCreate");
229 }
230
231 // Initialise the matrix. MATIS builds its preallocation from the
232 // maps, so they are passed to the constructor
233 Mat A = la::petsc::create_matrix(mesh->comm(), pattern, type, l2g0,
234 l2g1 ? l2g1 : l2g0);
235 common::petsc::check(ISLocalToGlobalMappingDestroy(&l2g0),
236 "ISLocalToGlobalMappingDestroy");
237 if (l2g1)
238 {
239 common::petsc::check(ISLocalToGlobalMappingDestroy(&l2g1),
240 "ISLocalToGlobalMappingDestroy");
241 }
242
243 return A;
244}
245
249template <std::floating_point T>
251 const std::vector<std::vector<const Form<PetscScalar, T>*>>& a,
252 std::optional<std::vector<std::vector<std::optional<std::string>>>> types)
253{
254 if (a.empty())
255 {
256 throw std::invalid_argument(
257 "Rectangular array of forms must be non-empty.");
258 }
259
260 // Extract and check row/column ranges
262
263 // Loop over each form and create matrix
264 int rows = a.size();
265 int cols = a.front().size();
266 std::vector<Mat> mats(rows * cols, nullptr);
267 std::shared_ptr<const mesh::Mesh<T>> mesh;
268 for (int i = 0; i < rows; ++i)
269 {
270 for (int j = 0; j < cols; ++j)
271 {
272 if (const Form<PetscScalar, T>* form = a[i][j]; form)
273 {
274 if (types)
275 mats[i * cols + j] = create_matrix(*form, types->at(i).at(j));
276 else
277 mats[i * cols + j] = create_matrix(*form, std::nullopt);
278 mesh = form->mesh();
279 }
280 }
281 }
282
283 if (!mesh)
284 throw std::invalid_argument("Could not find a Mesh.");
285
286 // Initialise block (MatNest) matrix. On error, destroy the
287 // already-created sub-matrices in `mats` before propagating, since
288 // the nest (which would otherwise take joint ownership of them) was
289 // never successfully assembled.
290 Mat A;
291 try
292 {
293 common::petsc::check(MatCreate(mesh->comm(), &A), "MatCreate");
294 common::petsc::check(MatSetType(A, MATNEST), "MatSetType");
296 MatNestSetSubMats(A, rows, nullptr, cols, nullptr, mats.data()),
297 "MatNestSetSubMats");
298 common::petsc::check(MatSetUp(A), "MatSetUp");
299 }
300 catch (...)
301 {
302 for (Mat& m : mats)
303 if (m)
304 common::petsc::check(MatDestroy(&m), "MatDestroy");
305 throw;
306 }
307
308 // De-reference Mat objects
309 for (Mat& m : mats)
310 if (m)
311 common::petsc::check(MatDestroy(&m), "MatDestroy");
312
313 return A;
314}
315
320 const std::vector<
321 std::pair<std::reference_wrapper<const common::IndexMap>, int>>& maps);
322
325 const std::vector<
326 std::pair<std::reference_wrapper<const common::IndexMap>, int>>& maps);
327
328// -- Vectors ----------------------------------------------------------------
329
342template <std::floating_point T>
344 Vec b, const Form<PetscScalar, T>& L,
345 std::span<const PetscScalar> constants,
346 const std::map<std::pair<IntegralType, int>,
347 std::pair<std::span<const PetscScalar>, int>>& coeffs)
348{
349 Vec b_local;
350 common::petsc::check(VecGhostGetLocalForm(b, &b_local),
351 "VecGhostGetLocalForm");
352 PetscInt n = 0;
353 common::petsc::check(VecGetSize(b_local, &n), "VecGetSize");
354 PetscScalar* array = nullptr;
355 common::petsc::check(VecGetArray(b_local, &array), "VecGetArray");
356 std::span<PetscScalar> _b(array, n);
357 fem::assemble_vector(_b, L, constants, coeffs);
358 common::petsc::check(VecRestoreArray(b_local, &array), "VecRestoreArray");
359 common::petsc::check(VecGhostRestoreLocalForm(b, &b_local),
360 "VecGhostRestoreLocalForm");
361}
362
373template <std::floating_point T>
375{
376 Vec b_local;
377 common::petsc::check(VecGhostGetLocalForm(b, &b_local),
378 "VecGhostGetLocalForm");
379 PetscInt n = 0;
380 common::petsc::check(VecGetSize(b_local, &n), "VecGetSize");
381 PetscScalar* array = nullptr;
382 common::petsc::check(VecGetArray(b_local, &array), "VecGetArray");
383 std::span<PetscScalar> _b(array, n);
385 common::petsc::check(VecRestoreArray(b_local, &array), "VecRestoreArray");
386 common::petsc::check(VecGhostRestoreLocalForm(b, &b_local),
387 "VecGhostRestoreLocalForm");
388}
389
390// FIXME: clarify zeroing of vector
391
425template <std::floating_point T>
427 Vec b,
428 const std::vector<
429 std::optional<std::reference_wrapper<const Form<PetscScalar, T>>>>& a,
430 const std::vector<std::span<const PetscScalar>>& constants,
431 const std::vector<std::map<std::pair<IntegralType, int>,
432 std::pair<std::span<const PetscScalar>, int>>>&
433 coeffs,
434 const std::vector<std::span<const std::int8_t>>& bc_markers1,
435 const std::vector<std::span<const PetscScalar>>& bc_values1,
436 const std::vector<Vec>& x0, PetscScalar alpha)
437{
438 if (!x0.empty() and x0.size() != a.size())
439 throw std::invalid_argument("Mismatch between x0 and a in apply_lifting.");
440
441 Vec b_local;
442 common::petsc::check(VecGhostGetLocalForm(b, &b_local),
443 "VecGhostGetLocalForm");
444 PetscInt n = 0;
445 common::petsc::check(VecGetSize(b_local, &n), "VecGetSize");
446 PetscScalar* array = nullptr;
447 common::petsc::check(VecGetArray(b_local, &array), "VecGetArray");
448 std::span<PetscScalar> _b(array, n);
449
450 if (x0.empty())
451 {
452 fem::apply_lifting(_b, a, constants, coeffs, bc_markers1, bc_values1, {},
453 alpha);
454 }
455 else
456 {
457 std::vector<std::span<const PetscScalar>> x0_ref;
458 std::vector<Vec> x0_local(a.size());
459 std::vector<const PetscScalar*> x0_array(a.size());
460 for (std::size_t i = 0; i < a.size(); ++i)
461 {
462 assert(x0[i]);
463 common::petsc::check(VecGhostGetLocalForm(x0[i], &x0_local[i]),
464 "VecGhostGetLocalForm");
465 PetscInt n0 = 0;
466 common::petsc::check(VecGetSize(x0_local[i], &n0), "VecGetSize");
467 common::petsc::check(VecGetArrayRead(x0_local[i], &x0_array[i]),
468 "VecGetArrayRead");
469 x0_ref.emplace_back(x0_array[i], n0);
470 }
471
472 fem::apply_lifting(_b, a, constants, coeffs, bc_markers1, bc_values1,
473 x0_ref, alpha);
474
475 for (std::size_t i = 0; i < x0_local.size(); ++i)
476 {
477 common::petsc::check(VecRestoreArrayRead(x0_local[i], &x0_array[i]),
478 "VecRestoreArrayRead");
479 common::petsc::check(VecGhostRestoreLocalForm(x0[i], &x0_local[i]),
480 "VecGhostRestoreLocalForm");
481 }
482 }
483
484 common::petsc::check(VecRestoreArray(b_local, &array), "VecRestoreArray");
485 common::petsc::check(VecGhostRestoreLocalForm(b, &b_local),
486 "VecGhostRestoreLocalForm");
487}
488
519template <std::floating_point T>
521 Vec b,
522 const std::vector<
523 std::optional<std::reference_wrapper<const Form<PetscScalar, T>>>>& a,
524 const std::vector<
525 std::vector<std::reference_wrapper<const DirichletBC<PetscScalar, T>>>>&
526 bcs1,
527 const std::vector<Vec>& x0, PetscScalar alpha)
528{
529 std::vector<std::map<std::pair<IntegralType, int>,
530 std::pair<std::vector<PetscScalar>, int>>>
531 coeffs;
532 std::vector<std::vector<PetscScalar>> constants;
533 for (const auto& _a : a)
534 {
535 if (_a)
536 {
537 auto coefficients = allocate_coefficient_storage(_a->get());
538 pack_coefficients(_a->get(), coefficients);
539 coeffs.push_back(coefficients);
540 constants.push_back(pack_constants(_a->get()));
541 }
542 else
543 {
544 coeffs.emplace_back();
545 constants.emplace_back();
546 }
547 }
548
549 std::vector<std::span<const PetscScalar>> _constants(constants.begin(),
550 constants.end());
551 std::vector<std::map<std::pair<IntegralType, int>,
552 std::pair<std::span<const PetscScalar>, int>>>
553 _coeffs;
554 std::ranges::transform(coeffs, std::back_inserter(_coeffs),
555 [](auto& c) { return make_coefficients_span(c); });
556
557 auto [bc_markers1, bc_values1] = fem::impl::bc_lifting_data(a, bcs1);
558 apply_lifting(b, a, _constants, _coeffs,
559 std::vector<std::span<const std::int8_t>>(bc_markers1.begin(),
560 bc_markers1.end()),
561 std::vector<std::span<const PetscScalar>>(bc_values1.begin(),
562 bc_values1.end()),
563 x0, alpha);
564}
565
566// -- Setting bcs ------------------------------------------------------------
567
568// FIXME: Move these function elsewhere?
569
582template <std::floating_point T>
583void set_bc(Vec b,
584 const std::vector<
585 std::reference_wrapper<const DirichletBC<PetscScalar, T>>>& bcs,
586 std::optional<const Vec> x0, PetscScalar alpha = 1)
587{
588 PetscInt n = 0;
589 common::petsc::check(VecGetLocalSize(b, &n), "VecGetLocalSize");
590 PetscScalar* array = nullptr;
591 common::petsc::check(VecGetArray(b, &array), "VecGetArray");
592 std::span<PetscScalar> _b(array, n);
593 if (x0.has_value())
594 {
595 Vec x0_local;
596 common::petsc::check(VecGhostGetLocalForm(x0.value(), &x0_local),
597 "VecGhostGetLocalForm");
598 PetscInt n0 = 0;
599 common::petsc::check(VecGetSize(x0_local, &n0), "VecGetSize");
600 const PetscScalar* x0_array = nullptr;
601 common::petsc::check(VecGetArrayRead(x0_local, &x0_array),
602 "VecGetArrayRead");
603 std::span<const PetscScalar> _x0(x0_array, n0);
604 for (auto& bc : bcs)
605 bc.get().set(_b, _x0, alpha);
606 common::petsc::check(VecRestoreArrayRead(x0_local, &x0_array),
607 "VecRestoreArrayRead");
608 common::petsc::check(VecGhostRestoreLocalForm(x0.value(), &x0_local),
609 "VecGhostRestoreLocalForm");
610 }
611 else
612 {
613 for (auto& bc : bcs)
614 bc.get().set(_b, std::nullopt, alpha);
615 }
616 common::petsc::check(VecRestoreArray(b, &array), "VecRestoreArray");
617}
618
619// -- Nonlinear problem assembly ---------------------------------------------
620
621namespace impl
622{
627template <std::floating_point T>
628void assign(const Vec x, Function<PetscScalar, T>& u)
629{
630 Vec x_local = nullptr;
631 common::petsc::check(VecGhostGetLocalForm(x, &x_local),
632 "VecGhostGetLocalForm");
633 PetscInt n = 0;
634 common::petsc::check(VecGetSize(x_local, &n), "VecGetSize");
635
636 std::span<PetscScalar> _u = u.x()->array();
637 if (static_cast<std::size_t>(n) != _u.size())
638 {
639 throw std::invalid_argument(std::format(
640 "Vector has {} local entries, function has {}.", n, _u.size()));
641 }
642
643 const PetscScalar* array = nullptr;
644 common::petsc::check(VecGetArrayRead(x_local, &array), "VecGetArrayRead");
645 std::ranges::copy(std::span<const PetscScalar>(array, n), _u.begin());
646 common::petsc::check(VecRestoreArrayRead(x_local, &array),
647 "VecRestoreArrayRead");
648 common::petsc::check(VecGhostRestoreLocalForm(x, &x_local),
649 "VecGhostRestoreLocalForm");
650}
651
678template <std::floating_point T>
679void assemble_operator(Mat A, const Form<PetscScalar, T>& a,
680 std::span<const std::int8_t> dof_marker0,
681 std::span<const std::int8_t> dof_marker1)
682{
683 common::petsc::check(MatZeroEntries(A), "MatZeroEntries");
684
685 // Block and dof indices coincide at block size 1. Avoid the generic
686 // blocked PETSc path, which expands these indices before insertion.
687 if (a.function_spaces()[0]->dofmap()->index_map_bs() == 1
688 and a.function_spaces()[1]->dofmap()->index_map_bs() == 1)
689 {
691 dof_marker0, dof_marker1);
692 }
693 else
694 {
696 dof_marker0, dof_marker1);
697 }
698
699 // The unit diagonal is only meaningful when the rows and columns are
700 // indexed by the same space
701 if (a.function_spaces()[0] == a.function_spaces()[1])
702 {
703 // Locally owned constrained rows
704 std::shared_ptr<const DofMap> dofmap0
705 = a.function_spaces()[0]->dofmaps().front();
706 // dof_marker0 is empty when no rows are constrained
707 const std::int32_t num_owned
708 = dof_marker0.empty()
709 ? 0
710 : dofmap0->index_map_bs() * dofmap0->index_map->size_local();
711 std::vector<std::int32_t> rows;
712 std::ranges::copy_if(
713 std::views::iota(std::int32_t(0), num_owned), std::back_inserter(rows),
714 [&dof_marker0](std::int32_t i) { return dof_marker0[i] != 0; });
715
716 // Assembly zeroed these rows, so adding sets the diagonal. Adding
717 // avoids a flush to switch from ADD_VALUES to INSERT_VALUES.
719 rows);
720 }
721
722 common::petsc::check(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY),
723 "MatAssemblyBegin");
724 common::petsc::check(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY), "MatAssemblyEnd");
725}
726} // namespace impl
727
753template <std::floating_point T>
755 const Vec x, Vec b, const Form<PetscScalar, T>& F,
756 const Form<PetscScalar, T>& J,
757 const std::vector<
758 std::reference_wrapper<const DirichletBC<PetscScalar, T>>>& bcs,
760{
761 common::petsc::check(VecGhostUpdateBegin(x, INSERT_VALUES, SCATTER_FORWARD),
762 "VecGhostUpdateBegin");
763 common::petsc::check(VecGhostUpdateEnd(x, INSERT_VALUES, SCATTER_FORWARD),
764 "VecGhostUpdateEnd");
765 impl::assign(x, u);
766
767 // Zero the local form, as assembly accumulates into ghost entries
768 Vec b_local = nullptr;
769 common::petsc::check(VecGhostGetLocalForm(b, &b_local),
770 "VecGhostGetLocalForm");
771 common::petsc::check(VecZeroEntries(b_local), "VecZeroEntries");
772 common::petsc::check(VecGhostRestoreLocalForm(b, &b_local),
773 "VecGhostRestoreLocalForm");
774
775 assemble_vector(b, F);
776
777 // Constrained dof markers and values g on the trial space of J (owned
778 // and ghost), both empty if there are no bcs
779 const std::vector<
780 std::optional<std::reference_wrapper<const Form<PetscScalar, T>>>>
781 a{J};
782 auto [bc_markers1, bc_values1] = fem::impl::bc_lifting_data(
783 a, std::vector<std::vector<
784 std::reference_wrapper<const DirichletBC<PetscScalar, T>>>>{bcs});
785
786 // Lifting: b <- b + J (g - x)
787 const std::vector<PetscScalar> constants = pack_constants(J);
788 auto coeffs = allocate_coefficient_storage(J);
789 pack_coefficients(J, coeffs);
790 apply_lifting(b, a, {std::span<const PetscScalar>(constants)},
791 {make_coefficients_span(coeffs)},
792 {std::span<const std::int8_t>(bc_markers1.front())},
793 {std::span<const PetscScalar>(bc_values1.front())}, {x},
794 PetscScalar(-1));
795
796 common::petsc::check(VecGhostUpdateBegin(b, ADD_VALUES, SCATTER_REVERSE),
797 "VecGhostUpdateBegin");
798 common::petsc::check(VecGhostUpdateEnd(b, ADD_VALUES, SCATTER_REVERSE),
799 "VecGhostUpdateEnd");
800
801 // Set b = x - g on owned constrained dofs
802 if (!bcs.empty())
803 {
804 PetscScalar* b_array = nullptr;
805 common::petsc::check(VecGetArray(b, &b_array), "VecGetArray");
806 const PetscScalar* x_array = nullptr;
807 common::petsc::check(VecGetArrayRead(x, &x_array), "VecGetArrayRead");
808 for (auto& bc : bcs)
809 {
810 auto [dofs, owned] = bc.get().dof_indices();
811 for (std::int32_t dof : dofs.first(owned))
812 b_array[dof] = x_array[dof] - bc_values1.front()[dof];
813 }
814 common::petsc::check(VecRestoreArrayRead(x, &x_array),
815 "VecRestoreArrayRead");
816 common::petsc::check(VecRestoreArray(b, &b_array), "VecRestoreArray");
817 }
818
819 common::petsc::check(VecGhostUpdateBegin(b, INSERT_VALUES, SCATTER_FORWARD),
820 "VecGhostUpdateBegin");
821 common::petsc::check(VecGhostUpdateEnd(b, INSERT_VALUES, SCATTER_FORWARD),
822 "VecGhostUpdateEnd");
823}
824
858template <std::floating_point T>
860 const Vec x, Mat Jmat, Mat Pmat, const Form<PetscScalar, T>& J,
861 const std::vector<
862 std::reference_wrapper<const DirichletBC<PetscScalar, T>>>& bcs,
863 Function<PetscScalar, T>& u, const Form<PetscScalar, T>* P = nullptr)
864{
865 // Checked before any collective call so that all ranks throw together
866 if (P and P->function_spaces() != J.function_spaces())
867 {
868 throw std::invalid_argument(
869 "Preconditioner form must have the same function spaces as the "
870 "Jacobian form.");
871 }
872
873 common::petsc::check(VecGhostUpdateBegin(x, INSERT_VALUES, SCATTER_FORWARD),
874 "VecGhostUpdateBegin");
875 common::petsc::check(VecGhostUpdateEnd(x, INSERT_VALUES, SCATTER_FORWARD),
876 "VecGhostUpdateEnd");
877 impl::assign(x, u);
878
879 // Markers depend only on the space, so they are built once here and
880 // the preconditioner, over the same spaces, shares them
881 std::array<std::vector<std::int8_t>, 2> markers;
882 auto [dof_marker0, dof_marker1]
883 = fem::impl::bc_dof_markers_pair(J, bcs, markers);
884
885 impl::assemble_operator(Jmat, J, dof_marker0, dof_marker1);
886 if (P)
887 impl::assemble_operator(Pmat, *P, dof_marker0, dof_marker1);
888}
889
890} // namespace petsc
891} // namespace dolfinx::fem
892
893#endif
Functions supporting assembly of a finite element fem::Form.
std::pair< std::vector< std::vector< std::int8_t > >, std::vector< std::vector< T > > > bc_lifting_data(const std::vector< std::optional< std::reference_wrapper< const Form< T, U > > > > &a, const std::vector< std::vector< std::reference_wrapper< const DirichletBC< T, U > > > > &bcs1)
Constrained dof markers and boundary condition values on the trial space of each form in a,...
Definition assembler.h:235
std::array< std::span< const std::int8_t >, 2 > bc_dof_markers_pair(const Form< T, U > &a, const std::vector< std::reference_wrapper< const DirichletBC< T, U > > > &bcs, std::array< std::vector< std::int8_t >, 2 > &storage)
Mark the dofs of the test and trial spaces of a that the boundary conditions in bcs constrain.
Definition assembler.h:215
Distribution of a global index range [0, N) across MPI ranks.
Definition IndexMap.h:191
std::int32_t size_local() const noexcept
Return the number of owned indices.
Definition IndexMap.cpp:1081
Definition DirichletBC.h:261
A representation of finite element variational forms.
Definition Form.h:177
std::shared_ptr< const mesh::Mesh< geometry_type > > mesh() const
Common mesh for the form (the 'integration domain').
Definition Form.h:395
const std::vector< std::shared_ptr< const FunctionSpace< geometry_type > > > & function_spaces() const
Function spaces for all arguments.
Definition Form.h:403
Definition Function.h:44
std::shared_ptr< const la::Vector< value_type > > x() const
Underlying vector (const version).
Definition Function.h:151
Definition SparsityPattern.h:28
void finalize()
Finalize sparsity pattern and communicate off-process entries.
Definition SparsityPattern.cpp:513
static auto set_block_fn(Mat A, InsertMode mode)
Return a function with an interface for adding or inserting values into the matrix A using blocked in...
Definition petsc.h:316
static auto set_fn(Mat A, InsertMode mode)
Return a function with an interface for adding or inserting values into the matrix A (calls MatSetVal...
Definition petsc.h:280
A Mesh consists of a set of connected and numbered mesh topological entities, and geometry data.
Definition Mesh.h:25
void check(PetscErrorCode ierr, std::string_view petsc_function, std::source_location loc=std::source_location::current())
Throw a std::runtime_error via error() if ierr indicates a PETSc call failed.
Definition petsc.h:41
std::tuple< std::int64_t, std::vector< std::int32_t >, std::vector< std::vector< std::int64_t > >, std::vector< std::vector< int > > > stack_index_maps(const std::vector< std::pair< std::reference_wrapper< const IndexMap >, int > > &maps)
Compute layout data for a concatenated index map.
Definition IndexMap.cpp:767
Helper functions for assembly into PETSc data structures.
Definition petsc.h:44
Mat create_matrix(const Form< PetscScalar, T > &a, std::optional< std::string > type=std::nullopt)
Create a matrix.
Definition petsc.h:86
void assemble_jacobian(const Vec x, Mat Jmat, Mat Pmat, const Form< PetscScalar, T > &J, const std::vector< std::reference_wrapper< const DirichletBC< PetscScalar, T > > > &bcs, Function< PetscScalar, T > &u, const Form< PetscScalar, T > *P=nullptr)
Assemble the Jacobian of a nonlinear problem into Jmat, and a preconditioner into Pmat.
Definition petsc.h:859
void apply_lifting(Vec b, const std::vector< std::optional< std::reference_wrapper< const Form< PetscScalar, T > > > > &a, const std::vector< std::span< const PetscScalar > > &constants, const std::vector< std::map< std::pair< IntegralType, int >, std::pair< std::span< const PetscScalar >, int > > > &coeffs, const std::vector< std::span< const std::int8_t > > &bc_markers1, const std::vector< std::span< const PetscScalar > > &bc_values1, const std::vector< Vec > &x0, PetscScalar alpha)
Modify RHS vector to account for Dirichlet boundary conditions, with the constrained dofs and their v...
Definition petsc.h:426
Mat create_matrix_block(const std::vector< std::vector< const Form< PetscScalar, T > * > > &a, std::optional< std::string > type=std::nullopt)
Initialise a monolithic matrix for an array of bilinear forms.
Definition petsc.h:108
Mat create_matrix_nest(const std::vector< std::vector< const Form< PetscScalar, T > * > > &a, std::optional< std::vector< std::vector< std::optional< std::string > > > > types)
Create nested (MatNest) matrix.
Definition petsc.h:250
void assemble_vector(Vec b, const Form< PetscScalar, T > &L, std::span< const PetscScalar > constants, const std::map< std::pair< IntegralType, int >, std::pair< std::span< const PetscScalar >, int > > &coeffs)
Assemble linear form into an already allocated PETSc vector.
Definition petsc.h:343
void set_bc(Vec b, const std::vector< std::reference_wrapper< const DirichletBC< PetscScalar, T > > > &bcs, std::optional< const Vec > x0, PetscScalar alpha=1)
Entries in b that are constrained by a Dirichlet boundary conditions are set to alpha * (x_bc - x0),...
Definition petsc.h:583
Vec create_vector_block(const std::vector< std::pair< std::reference_wrapper< const common::IndexMap >, int > > &maps)
Initialise monolithic vector. Vector is not zeroed.
Definition petsc.cpp:21
void assemble_residual(const Vec x, Vec b, const Form< PetscScalar, T > &F, const Form< PetscScalar, T > &J, const std::vector< std::reference_wrapper< const DirichletBC< PetscScalar, T > > > &bcs, Function< PetscScalar, T > &u)
Assemble the residual of a nonlinear problem into b, with Dirichlet conditions applied.
Definition petsc.h:754
Vec create_vector_nest(const std::vector< std::pair< std::reference_wrapper< const common::IndexMap >, int > > &maps)
Create nested (VecNest) vector. Vector is not zeroed.
Definition petsc.cpp:65
Finite element method functionality.
Definition assemble_expression_impl.h:28
void assemble_matrix(la::MatSet< T > auto mat_add, const Form< T, U > &a, std::span< const T > constants, const std::map< std::pair< IntegralType, int >, std::pair< std::span< const T >, int > > &coefficients, std::span< const std::int8_t > dof_marker0, std::span< const std::int8_t > dof_marker1)
Assemble bilinear form into a matrix. Matrix must already be initialised. Does not zero or finalise t...
Definition assembler.h:588
std::vector< std::vector< std::array< std::shared_ptr< const FunctionSpace< U > >, 2 > > > extract_function_spaces(const std::vector< std::vector< const Form< T, U > * > > &a)
Extract test (0) and trial (1) function spaces pairs for each bilinear form for a rectangular array o...
Definition sparsitypattern.h:41
std::map< std::pair< IntegralType, int >, std::pair< std::span< const T >, int > > make_coefficients_span(const std::map< std::pair< IntegralType, int >, std::pair< std::vector< T >, int > > &coeffs)
Create a map of std::spans from a map of std::vectors.
Definition assembler.h:54
void pack_coefficients(const Form< T, U > &form, std::map< std::pair< IntegralType, int >, std::pair< std::vector< T >, int > > &coeffs)
Pack coefficients of a Form.
Definition pack.h:267
std::pair< std::vector< T >, int > allocate_coefficient_storage(const Form< T, U > &form, IntegralType integral_type, int idx)
Allocate storage for coefficients of a pair (integral_type, idx) from a Form.
Definition pack.h:189
void assemble_vector(V &&b, const Form< T, U > &L, std::span< const T > constants, const std::map< std::pair< IntegralType, int >, std::pair< std::span< const T >, int > > &coefficients)
Assemble linear form into a vector.
Definition assembler.h:140
void apply_lifting(V &&b, const std::vector< std::optional< std::reference_wrapper< const Form< T, U > > > > &a, const std::vector< std::span< const T > > &constants, const std::vector< std::map< std::pair< IntegralType, int >, std::pair< std::span< const T >, int > > > &coeffs, const std::vector< std::span< const std::int8_t > > &bc_markers1, const std::vector< std::span< const T > > &bc_values1, const std::vector< std::span< const T > > &x0, T alpha)
Modify the right-hand side vector to account for constraints (Dirichlet boundary condition constraint...
Definition assembler.h:311
la::SparsityPattern create_sparsity_pattern(const Form< T, U > &a)
Create a sparsity pattern for a given form.
Definition sparsitypattern.h:66
std::vector< T > pack_constants(const std::vector< std::reference_wrapper< const fem::Constant< T > > > &c)
Pack constants of an Expression or Form into a single array ready for assembly.
Definition pack.h:459
std::array< std::vector< std::shared_ptr< const FunctionSpace< T > > >, 2 > common_function_spaces(const std::vector< std::vector< std::array< std::shared_ptr< const FunctionSpace< T > >, 2 > > > &V)
Extract FunctionSpaces for (0) rows blocks and (1) columns blocks from a rectangular array of (test,...
Definition FunctionSpace.h:476
Mat create_matrix(MPI_Comm comm, const SparsityPattern &sp, std::optional< std::string_view > type=std::nullopt, std::optional< ISLocalToGlobalMapping > rlgmap=std::nullopt, std::optional< ISLocalToGlobalMapping > clgmap=std::nullopt)
Create a PETSc Mat. Caller is responsible for destroying the returned object.
Definition petsc.cpp:262
void set_diagonal(MatSet< T > auto &&set_fn, const common::LocalIndexRange auto &rows, T diagonal=T(1))
Set a value on the diagonal of a matrix for specified rows.
Definition utils.h:51
Mesh data structures and algorithms on meshes.
Definition DofMap.h:32
Functions supporting the packing of coefficient data.
Functions for constructing finite element sparsity patterns.