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