DOLFINx 0.10.0.0
DOLFINx C++ interface
Loading...
Searching...
No Matches
petsc.h
1// Copyright (C) 2018-2021 Garth N. Wells
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 "assembler.h"
13#include "utils.h"
14#include <concepts>
15#include <dolfinx/la/petsc.h>
16#include <functional>
17#include <map>
18#include <memory>
19#include <petscmat.h>
20#include <petscvec.h>
21#include <span>
22#include <utility>
23#include <vector>
24
25namespace dolfinx::common
26{
27class IndexMap;
28}
29
30namespace dolfinx::fem
31{
32template <dolfinx::scalar T, std::floating_point U>
33class DirichletBC;
34
36namespace petsc
37{
44template <std::floating_point T>
45Mat create_matrix(const Form<PetscScalar, T>& a,
46 std::string type = std::string())
47{
48 la::SparsityPattern pattern = fem::create_sparsity_pattern(a);
49 pattern.finalize();
50 return la::petsc::create_matrix(a.mesh()->comm(), pattern, type);
51}
52
62template <std::floating_point T>
63Mat create_matrix_block(
64 const std::vector<std::vector<const Form<PetscScalar, T>*>>& a,
65 std::string type = std::string())
66{
67 // Extract and check row/column ranges
68 std::array<std::vector<std::shared_ptr<const FunctionSpace<T>>>, 2> V
69 = fem::common_function_spaces(extract_function_spaces(a));
70 std::array<std::vector<int>, 2> bs_dofs;
71 for (std::size_t i = 0; i < 2; ++i)
72 {
73 for (auto& _V : V[i])
74 bs_dofs[i].push_back(_V->dofmap()->bs());
75 }
76
77 // Build sparsity pattern for each block
78 std::shared_ptr<const mesh::Mesh<T>> mesh;
79 std::vector<std::vector<std::unique_ptr<la::SparsityPattern>>> patterns(
80 V[0].size());
81 for (std::size_t row = 0; row < V[0].size(); ++row)
82 {
83 for (std::size_t col = 0; col < V[1].size(); ++col)
84 {
85 if (const Form<PetscScalar, T>* form = a[row][col]; form)
86 {
87 patterns[row].push_back(std::make_unique<la::SparsityPattern>(
89 if (!mesh)
90 mesh = form->mesh();
91 }
92 else
93 patterns[row].push_back(nullptr);
94 }
95 }
96
97 if (!mesh)
98 throw std::runtime_error("Could not find a Mesh.");
99
100 // Compute offsets for the fields
101 std::array<std::vector<std::pair<
102 std::reference_wrapper<const common::IndexMap>, int>>,
103 2>
104 maps;
105 for (std::size_t d = 0; d < 2; ++d)
106 {
107 for (auto& space : V[d])
108 {
109 maps[d].emplace_back(*space->dofmap()->index_map,
110 space->dofmap()->index_map_bs());
111 }
112 }
113
114 // Create merged sparsity pattern
115 std::vector<std::vector<const la::SparsityPattern*>> p(V[0].size());
116 for (std::size_t row = 0; row < V[0].size(); ++row)
117 for (std::size_t col = 0; col < V[1].size(); ++col)
118 p[row].push_back(patterns[row][col].get());
119
120 la::SparsityPattern pattern(mesh->comm(), p, maps, bs_dofs);
121 pattern.finalize();
122
123 // FIXME: Add option to pass customised local-to-global map to PETSc
124 // Mat constructor
125
126 // Initialise matrix
127 Mat A = la::petsc::create_matrix(mesh->comm(), pattern, type);
128
129 // Create row and column local-to-global maps (field0, field1, field2,
130 // etc), i.e. ghosts of field0 appear before owned indices of field1
131 std::array<std::vector<PetscInt>, 2> _maps;
132 for (int d = 0; d < 2; ++d)
133 {
134 // TODO: Index map concatenation has already been computed inside
135 // the SparsityPattern constructor, but we also need it here to
136 // build the PETSc local-to-global map. Compute outside and pass
137 // into SparsityPattern constructor.
138 // TODO: avoid concatenating the same maps twice in case that V[0]
139 // == V[1].
140
141 const std::vector<
142 std::pair<std::reference_wrapper<const common::IndexMap>, int>>& map
143 = maps[d];
144 std::vector<PetscInt>& _map = _maps[d];
145
146 // Concatenate the block index map in the row and column directions
147 const auto [rank_offset, local_offset, ghosts, _]
148 = common::stack_index_maps(map);
149 for (std::size_t f = 0; f < map.size(); ++f)
150 {
151 auto offset = local_offset[f];
152 const common::IndexMap& imap = map[f].first.get();
153 int bs = map[f].second;
154 for (std::int32_t i = 0; i < bs * imap.size_local(); ++i)
155 _map.push_back(i + rank_offset + offset);
156 for (std::int32_t i = 0; i < bs * imap.num_ghosts(); ++i)
157 _map.push_back(ghosts[f][i]);
158 }
159 }
160
161 // Create PETSc local-to-global map/index sets and attach to matrix
162 ISLocalToGlobalMapping petsc_local_to_global0;
163 ISLocalToGlobalMappingCreate(MPI_COMM_SELF, 1, _maps[0].size(),
164 _maps[0].data(), PETSC_COPY_VALUES,
165 &petsc_local_to_global0);
166 if (V[0] == V[1])
167 {
168 MatSetLocalToGlobalMapping(A, petsc_local_to_global0,
169 petsc_local_to_global0);
170 ISLocalToGlobalMappingDestroy(&petsc_local_to_global0);
171 }
172 else
173 {
174
175 ISLocalToGlobalMapping petsc_local_to_global1;
176 ISLocalToGlobalMappingCreate(MPI_COMM_SELF, 1, _maps[1].size(),
177 _maps[1].data(), PETSC_COPY_VALUES,
178 &petsc_local_to_global1);
179 MatSetLocalToGlobalMapping(A, petsc_local_to_global0,
180 petsc_local_to_global1);
181 ISLocalToGlobalMappingDestroy(&petsc_local_to_global0);
182 ISLocalToGlobalMappingDestroy(&petsc_local_to_global1);
183 }
184
185 return A;
186}
187
191template <std::floating_point T>
192Mat create_matrix_nest(
193 const std::vector<std::vector<const Form<PetscScalar, T>*>>& a,
194 const std::vector<std::vector<std::string>>& types)
195{
196 // Extract and check row/column ranges
197 auto V = fem::common_function_spaces(extract_function_spaces(a));
198
199 std::vector<std::vector<std::string>> _types(
200 a.size(), std::vector<std::string>(a.front().size()));
201 if (!types.empty())
202 _types = types;
203
204 // Loop over each form and create matrix
205 int rows = a.size();
206 int cols = a.front().size();
207 std::vector<Mat> mats(rows * cols, nullptr);
208 std::shared_ptr<const mesh::Mesh<T>> mesh;
209 for (int i = 0; i < rows; ++i)
210 {
211 for (int j = 0; j < cols; ++j)
212 {
213 if (const Form<PetscScalar, T>* form = a[i][j]; form)
214 {
215 mats[i * cols + j] = create_matrix(*form, _types[i][j]);
216 mesh = form->mesh();
217 }
218 }
219 }
220
221 if (!mesh)
222 throw std::runtime_error("Could not find a Mesh.");
223
224 // Initialise block (MatNest) matrix
225 Mat A;
226 MatCreate(mesh->comm(), &A);
227 MatSetType(A, MATNEST);
228 MatNestSetSubMats(A, rows, nullptr, cols, nullptr, mats.data());
229 MatSetUp(A);
230
231 // De-reference Mat objects
232 for (std::size_t i = 0; i < mats.size(); ++i)
233 {
234 if (mats[i])
235 MatDestroy(&mats[i]);
236 }
237
238 return A;
239}
240
244Vec create_vector_block(
245 const std::vector<
246 std::pair<std::reference_wrapper<const common::IndexMap>, int>>& maps);
247
249Vec create_vector_nest(
250 const std::vector<
251 std::pair<std::reference_wrapper<const common::IndexMap>, int>>& maps);
252
253// -- Vectors ----------------------------------------------------------------
254
267template <std::floating_point T>
268void assemble_vector(
269 Vec b, const Form<PetscScalar, T>& L,
270 std::span<const PetscScalar> constants,
271 const std::map<std::pair<IntegralType, int>,
272 std::pair<std::span<const PetscScalar>, int>>& coeffs)
273{
274 Vec b_local;
275 VecGhostGetLocalForm(b, &b_local);
276 PetscInt n = 0;
277 VecGetSize(b_local, &n);
278 PetscScalar* array = nullptr;
279 VecGetArray(b_local, &array);
280 std::span<PetscScalar> _b(array, n);
281 fem::assemble_vector(_b, L, constants, coeffs);
282 VecRestoreArray(b_local, &array);
283 VecGhostRestoreLocalForm(b, &b_local);
284}
285
295template <std::floating_point T>
296void assemble_vector(Vec b, const Form<PetscScalar, T>& L)
297{
298 Vec b_local;
299 VecGhostGetLocalForm(b, &b_local);
300 PetscInt n = 0;
301 VecGetSize(b_local, &n);
302 PetscScalar* array = nullptr;
303 VecGetArray(b_local, &array);
304 std::span<PetscScalar> _b(array, n);
305 fem::assemble_vector(_b, L);
306 VecRestoreArray(b_local, &array);
307 VecGhostRestoreLocalForm(b, &b_local);
308}
309
310// FIXME: clarify how x0 is used
311// FIXME: if bcs entries are set
312
313// FIXME: need to pass an array of Vec for x0?
314// FIXME: clarify zeroing of vector
315
331template <std::floating_point T>
332void apply_lifting(
333 Vec b,
334 std::vector<
335 std::optional<std::reference_wrapper<const Form<PetscScalar, T>>>>
336 a,
337 const std::vector<std::span<const PetscScalar>>& constants,
338 const std::vector<std::map<std::pair<IntegralType, int>,
339 std::pair<std::span<const PetscScalar>, int>>>&
340 coeffs,
341 const std::vector<
342 std::vector<std::reference_wrapper<const DirichletBC<PetscScalar, T>>>>&
343 bcs1,
344 const std::vector<Vec>& x0, PetscScalar alpha)
345{
346 Vec b_local;
347 VecGhostGetLocalForm(b, &b_local);
348 PetscInt n = 0;
349 VecGetSize(b_local, &n);
350 PetscScalar* array = nullptr;
351 VecGetArray(b_local, &array);
352 std::span<PetscScalar> _b(array, n);
353
354 if (x0.empty())
355 fem::apply_lifting(_b, a, constants, coeffs, bcs1, {}, alpha);
356 else
357 {
358 std::vector<std::span<const PetscScalar>> x0_ref;
359 std::vector<Vec> x0_local(a.size());
360 std::vector<const PetscScalar*> x0_array(a.size());
361 for (std::size_t i = 0; i < a.size(); ++i)
362 {
363 assert(x0[i]);
364 VecGhostGetLocalForm(x0[i], &x0_local[i]);
365 PetscInt n = 0;
366 VecGetSize(x0_local[i], &n);
367 VecGetArrayRead(x0_local[i], &x0_array[i]);
368 x0_ref.emplace_back(x0_array[i], n);
369 }
370
371 std::vector x0_tmp(x0_ref.begin(), x0_ref.end());
372 fem::apply_lifting(_b, a, constants, coeffs, bcs1, x0_tmp, alpha);
373
374 for (std::size_t i = 0; i < x0_local.size(); ++i)
375 {
376 VecRestoreArrayRead(x0_local[i], &x0_array[i]);
377 VecGhostRestoreLocalForm(x0[i], &x0_local[i]);
378 }
379 }
380
381 VecRestoreArray(b_local, &array);
382 VecGhostRestoreLocalForm(b, &b_local);
383}
384
385// FIXME: clarify how x0 is used
386// FIXME: if bcs entries are set
387
388// FIXME: need to pass an array of Vec for x0?
389// FIXME: clarify zeroing of vector
390
403template <std::floating_point T>
404void apply_lifting(
405 Vec b,
406 std::vector<
407 std::optional<std::reference_wrapper<const Form<PetscScalar, double>>>>
408 a,
409 const std::vector<std::vector<
410 std::reference_wrapper<const DirichletBC<PetscScalar, double>>>>& bcs1,
411 const std::vector<Vec>& x0, PetscScalar alpha)
412{
413 Vec b_local;
414 VecGhostGetLocalForm(b, &b_local);
415 PetscInt n = 0;
416 VecGetSize(b_local, &n);
417 PetscScalar* array = nullptr;
418 VecGetArray(b_local, &array);
419 std::span<PetscScalar> _b(array, n);
420
421 if (x0.empty())
422 fem::apply_lifting<PetscScalar>(_b, a, bcs1, {}, alpha);
423 else
424 {
425 std::vector<std::span<const PetscScalar>> x0_ref;
426 std::vector<Vec> x0_local(a.size());
427 std::vector<const PetscScalar*> x0_array(a.size());
428 for (std::size_t i = 0; i < a.size(); ++i)
429 {
430 assert(x0[i]);
431 VecGhostGetLocalForm(x0[i], &x0_local[i]);
432 PetscInt n = 0;
433 VecGetSize(x0_local[i], &n);
434 VecGetArrayRead(x0_local[i], &x0_array[i]);
435 x0_ref.emplace_back(x0_array[i], n);
436 }
437
438 std::vector x0_tmp(x0_ref.begin(), x0_ref.end());
439 fem::apply_lifting<PetscScalar>(_b, a, bcs1, x0_tmp, alpha);
440
441 for (std::size_t i = 0; i < x0_local.size(); ++i)
442 {
443 VecRestoreArrayRead(x0_local[i], &x0_array[i]);
444 VecGhostRestoreLocalForm(x0[i], &x0_local[i]);
445 }
446 }
447
448 VecRestoreArray(b_local, &array);
449 VecGhostRestoreLocalForm(b, &b_local);
450}
451
452// -- Setting bcs ------------------------------------------------------------
453
454// FIXME: Move these function elsewhere?
455
456// FIXME: clarify x0
457// FIXME: clarify what happens with ghosts
458
462template <std::floating_point T>
463void set_bc(
464 Vec b,
465 const std::vector<std::reference_wrapper<const DirichletBC<PetscScalar, T>>> bcs,
466 const Vec x0, PetscScalar alpha = 1)
467{
468 PetscInt n = 0;
469 VecGetLocalSize(b, &n);
470 PetscScalar* array = nullptr;
471 VecGetArray(b, &array);
472 std::span<PetscScalar> _b(array, n);
473 if (x0)
474 {
475 Vec x0_local;
476 VecGhostGetLocalForm(x0, &x0_local);
477 PetscInt n = 0;
478 VecGetSize(x0_local, &n);
479 const PetscScalar* array = nullptr;
480 VecGetArrayRead(x0_local, &array);
481 std::span<const PetscScalar> _x0(array, n);
482 for (auto& bc : bcs)
483 bc.set(_b, _x0, alpha);
484 VecRestoreArrayRead(x0_local, &array);
485 VecGhostRestoreLocalForm(x0, &x0_local);
486 }
487 else
488 {
489 for (auto& bc : bcs)
490 bc->set(_b, std::nullopt, alpha);
491 }
492 VecRestoreArray(b, &array);
493}
494
495} // namespace petsc
496} // namespace dolfinx::fem
497
498#endif
Functions supporting finite element method operations.
int size(MPI_Comm comm)
Definition MPI.cpp:72
Miscellaneous classes, functions and types.
Definition dolfinx_common.h:8
Finite element method functionality.
Definition assemble_matrix_impl.h:26
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 utils.h:127
la::SparsityPattern create_sparsity_pattern(const Form< T, U > &a)
Create a sparsity pattern for a given form.
Definition utils.h:152