deal.II version GIT relicensing-6842-g793a97d2aa 2026-10-02 14:00:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
petsc_parallel_block_sparse_matrix.cc
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2004 - 2026 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
14
17
18
19#ifdef DEAL_II_WITH_PETSC
20
21# include <petscmat.h>
22
23
24
25#endif
26
28
29#ifdef DEAL_II_WITH_PETSC
30
31namespace
32{
33 // A dummy utility routine to create an empty matrix in case we import
34 // a MATNEST with NULL blocks
35 static Mat
36 create_dummy_mat(MPI_Comm comm,
37 PetscInt lr,
38 PetscInt gr,
39 PetscInt lc,
40 PetscInt gc)
41 {
42 Mat dummy;
43 PetscErrorCode ierr;
44
45 ierr = MatCreate(comm, &dummy);
46 AssertThrow(ierr == 0, ::ExcPETScError(ierr));
47 ierr = MatSetSizes(dummy, lr, lc, gr, gc);
48 AssertThrow(ierr == 0, ::ExcPETScError(ierr));
49 ierr = MatSetType(dummy, MATAIJ);
50 AssertThrow(ierr == 0, ::ExcPETScError(ierr));
51 ierr = MatSeqAIJSetPreallocation(dummy, 0, nullptr);
52 AssertThrow(ierr == 0, ::ExcPETScError(ierr));
53 ierr = MatMPIAIJSetPreallocation(dummy, 0, nullptr, 0, nullptr);
54 AssertThrow(ierr == 0, ::ExcPETScError(ierr));
55 ierr = MatSetUp(dummy);
56 AssertThrow(ierr == 0, ::ExcPETScError(ierr));
57 ierr = MatSetOption(dummy, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE);
58 AssertThrow(ierr == 0, ::ExcPETScError(ierr));
59 ierr = MatAssemblyBegin(dummy, MAT_FINAL_ASSEMBLY);
60 AssertThrow(ierr == 0, ::ExcPETScError(ierr));
61 ierr = MatAssemblyEnd(dummy, MAT_FINAL_ASSEMBLY);
62 AssertThrow(ierr == 0, ::ExcPETScError(ierr));
63 return dummy;
64 }
65} // namespace
66
67
68namespace PETScWrappers
69{
70 namespace MPI
71 {
74 {
76
77 return *this;
78 }
79
80
81
83 {
84 PetscErrorCode ierr = MatDestroy(&petsc_nest_matrix);
85 AssertNothrow(ierr == 0, ExcPETScError(ierr));
86 }
87
88
89
90# ifndef DOXYGEN
91 void
92 BlockSparseMatrix::reinit(const size_type n_block_rows,
93 const size_type n_block_columns)
94 {
95 // first delete previous content of
96 // the subobjects array
97 clear();
98
99 // then resize. set sizes of blocks to
100 // zero. user will later have to call
101 // collect_sizes for this
102 this->sub_objects.reinit(n_block_rows, n_block_columns);
103 this->row_block_indices.reinit(n_block_rows, 0);
104 this->column_block_indices.reinit(n_block_columns, 0);
105
106 // and reinitialize the blocks
107 for (size_type r = 0; r < this->n_block_rows(); ++r)
108 for (size_type c = 0; c < this->n_block_cols(); ++c)
109 {
110 BlockType *p = new BlockType();
111 this->sub_objects[r][c] = p;
112 }
113 }
114# endif
115
116
117
118 void
119 BlockSparseMatrix::reinit(const std::vector<IndexSet> &rows,
120 const std::vector<IndexSet> &cols,
121 const BlockDynamicSparsityPattern &bdsp,
122 const MPI_Comm com)
123 {
124 Assert(rows.size() == bdsp.n_block_rows(), ExcMessage("invalid size"));
125 Assert(cols.size() == bdsp.n_block_cols(), ExcMessage("invalid size"));
126
127
128 clear();
129 this->sub_objects.reinit(bdsp.n_block_rows(), bdsp.n_block_cols());
130
131 std::vector<types::global_dof_index> row_sizes;
132 row_sizes.reserve(bdsp.n_block_rows());
133 for (unsigned int r = 0; r < bdsp.n_block_rows(); ++r)
134 row_sizes.push_back(bdsp.block(r, 0).n_rows());
135 this->row_block_indices.reinit(row_sizes);
136
137 std::vector<types::global_dof_index> col_sizes;
138 col_sizes.reserve(bdsp.n_block_cols());
139 for (unsigned int c = 0; c < bdsp.n_block_cols(); ++c)
140 col_sizes.push_back(bdsp.block(0, c).n_cols());
141 this->column_block_indices.reinit(col_sizes);
142
143 for (unsigned int r = 0; r < this->n_block_rows(); ++r)
144 for (unsigned int c = 0; c < this->n_block_cols(); ++c)
145 {
146 Assert(rows[r].size() == bdsp.block(r, c).n_rows(),
147 ExcMessage("invalid size"));
148 Assert(cols[c].size() == bdsp.block(r, c).n_cols(),
149 ExcMessage("invalid size"));
150
151 BlockType *p = new BlockType();
152 p->reinit(rows[r], cols[c], bdsp.block(r, c), com);
153 this->sub_objects[r][c] = p;
154 }
155
156 this->collect_sizes();
157 }
158
159 void
160 BlockSparseMatrix::reinit(const std::vector<IndexSet> &sizes,
161 const BlockDynamicSparsityPattern &bdsp,
162 const MPI_Comm com)
163 {
164 reinit(sizes, sizes, bdsp, com);
165 }
166
167
168
169 void
171 {
172 auto m = this->n_block_rows();
173 auto n = this->n_block_cols();
174 PetscErrorCode ierr;
175
176 // Create empty matrices if needed
177 // This is needed by the base class
178 // not by MATNEST
179 std::vector<size_type> row_sizes(m, size_type(-1));
180 std::vector<size_type> col_sizes(n, size_type(-1));
181 std::vector<size_type> row_local_sizes(m, size_type(-1));
182 std::vector<size_type> col_local_sizes(n, size_type(-1));
183 MPI_Comm comm = MPI_COMM_NULL;
184 for (size_type r = 0; r < m; r++)
185 {
186 for (size_type c = 0; c < n; c++)
187 {
188 if (this->sub_objects[r][c])
189 {
190 comm = this->sub_objects[r][c]->get_mpi_communicator();
191 row_sizes[r] = this->sub_objects[r][c]->m();
192 col_sizes[c] = this->sub_objects[r][c]->n();
193 row_local_sizes[r] = this->sub_objects[r][c]->local_size();
194 col_local_sizes[c] =
195 this->sub_objects[r][c]->local_domain_size();
196 }
197 }
198 }
199 for (size_type r = 0; r < m; r++)
200 {
201 for (size_type c = 0; c < n; c++)
202 {
203 if (!this->sub_objects[r][c])
204 {
205 Assert(
206 row_sizes[r] != size_type(-1),
208 "When passing empty sub-blocks of a block matrix, you need to make "
209 "sure that at least one block in each block row and block column is "
210 "non-empty. However, block row " +
211 std::to_string(r) +
212 " is completely empty "
213 "and so it is not possible to determine how many rows it should have."));
214 Assert(
215 col_sizes[c] != size_type(-1),
217 "When passing empty sub-blocks of a block matrix, you need to make "
218 "sure that at least one block in each block row and block column is "
219 "non-empty. However, block column " +
220 std::to_string(c) +
221 " is completely empty "
222 "and so it is not possible to determine how many columns it should have."));
223 Mat dummy =
224 create_dummy_mat(comm,
225 static_cast<PetscInt>(row_local_sizes[r]),
226 static_cast<PetscInt>(row_sizes[r]),
227 static_cast<PetscInt>(col_local_sizes[c]),
228 static_cast<PetscInt>(col_sizes[c]));
229 this->sub_objects[r][c] = new BlockType(dummy);
230
231 // the new object got a reference on dummy, we can safely
232 // call destroy here
233 ierr = MatDestroy(&dummy);
234 AssertThrow(ierr == 0, ExcPETScError(ierr));
235 }
236 }
237 }
238 }
239
240
241 void
248
249 void
251 {
252 auto m = this->n_block_rows();
253 auto n = this->n_block_cols();
254 PetscErrorCode ierr;
255
256 MPI_Comm comm = PETSC_COMM_SELF;
257
258 ierr = MatDestroy(&petsc_nest_matrix);
259 AssertThrow(ierr == 0, ExcPETScError(ierr));
260 std::vector<Mat> psub_objects(m * n);
261 for (unsigned int r = 0; r < m; r++)
262 for (unsigned int c = 0; c < n; c++)
263 {
264 comm = this->sub_objects[r][c]->get_mpi_communicator();
265 psub_objects[r * n + c] = this->sub_objects[r][c]->petsc_matrix();
266 }
267 ierr = MatCreateNest(
268 comm, m, nullptr, n, nullptr, psub_objects.data(), &petsc_nest_matrix);
269 AssertThrow(ierr == 0, ExcPETScError(ierr));
270
271 ierr = MatNestSetVecType(petsc_nest_matrix, VECNEST);
272 AssertThrow(ierr == 0, ExcPETScError(ierr));
273 }
274
275
276
277 void
283
284
285
286 std::vector<IndexSet>
288 {
289 std::vector<IndexSet> index_sets;
290
291 index_sets.reserve(this->n_block_cols());
292 for (unsigned int i = 0; i < this->n_block_cols(); ++i)
293 index_sets.push_back(this->block(0, i).locally_owned_domain_indices());
294
295 return index_sets;
296 }
297
298
299
300 std::vector<IndexSet>
302 {
303 std::vector<IndexSet> index_sets;
304
305 index_sets.reserve(this->n_block_rows());
306 for (unsigned int i = 0; i < this->n_block_rows(); ++i)
307 index_sets.push_back(this->block(i, 0).locally_owned_range_indices());
308
309 return index_sets;
310 }
311
312
313
314 std::uint64_t
316 {
317 std::uint64_t n_nonzero = 0;
318 for (size_type rows = 0; rows < this->n_block_rows(); ++rows)
319 for (size_type cols = 0; cols < this->n_block_cols(); ++cols)
320 n_nonzero += this->block(rows, cols).n_nonzero_elements();
321
322 return n_nonzero;
323 }
324
325
326
329 {
330 return PetscObjectComm(reinterpret_cast<PetscObject>(petsc_nest_matrix));
331 }
332
333 BlockSparseMatrix::operator const Mat &() const
334 {
335 return petsc_nest_matrix;
336 }
337
338
339
340 Mat &
345
346 void
348 {
349 clear();
350
351 PetscBool isnest;
352 PetscInt nr = 1, nc = 1;
353
354 PetscErrorCode ierr =
355 PetscObjectTypeCompare(reinterpret_cast<PetscObject>(A),
356 MATNEST,
357 &isnest);
358 AssertThrow(ierr == 0, ExcPETScError(ierr));
359 std::vector<Mat> mats;
360 bool need_empty_matrices = false;
361 if (isnest)
362 {
363 ierr = MatNestGetSize(A, &nr, &nc);
364 AssertThrow(ierr == 0, ExcPETScError(ierr));
365 for (PetscInt i = 0; i < nr; ++i)
366 {
367 for (PetscInt j = 0; j < nc; ++j)
368 {
369 Mat sA;
370 ierr = MatNestGetSubMat(A, i, j, &sA);
371 mats.push_back(sA);
372 if (!sA)
373 need_empty_matrices = true;
374 }
375 }
376 }
377 else
378 {
379 mats.push_back(A);
380 }
381
382 std::vector<size_type> r_block_sizes(nr, 0);
383 std::vector<size_type> c_block_sizes(nc, 0);
384 this->row_block_indices.reinit(r_block_sizes);
385 this->column_block_indices.reinit(c_block_sizes);
386 this->sub_objects.reinit(nr, nc);
387 for (PetscInt i = 0; i < nr; ++i)
388 {
389 for (PetscInt j = 0; j < nc; ++j)
390 {
391 if (mats[i * nc + j])
392 this->sub_objects[i][j] = new BlockType(mats[i * nc + j]);
393 else
394 this->sub_objects[i][j] = nullptr;
395 }
396 }
397 if (need_empty_matrices)
399
401 if (need_empty_matrices || !isnest)
402 {
404 }
405 else
406 {
407 ierr = PetscObjectReference(reinterpret_cast<PetscObject>(A));
408 AssertThrow(ierr == 0, ExcPETScError(ierr));
409 PetscErrorCode ierr = MatDestroy(&petsc_nest_matrix);
410 AssertThrow(ierr == 0, ExcPETScError(ierr));
412 }
413 }
414
415 } // namespace MPI
416} // namespace PETScWrappers
417
418
419
420#endif
void reinit(const unsigned int n_blocks, const size_type n_elements_per_block)
unsigned int n_block_rows() const
void compress(VectorOperation::values operation)
unsigned int n_block_cols() const
BlockType & block(const unsigned int row, const unsigned int column)
Table< 2, ObserverPointer< BlockType, BlockMatrixBase< SparseMatrix > > > sub_objects
SparsityPatternType & block(const size_type row, const size_type column)
EnableObserverPointer & operator=(const EnableObserverPointer &)
void reinit(const size_type n_block_rows, const size_type n_block_columns)
BlockSparseMatrix & operator=(const BlockSparseMatrix &)
void compress(VectorOperation::values operation)
std::size_t n_nonzero_elements() const
virtual void reinit(const SparsityPattern &sparsity)
size_type n_rows() const
size_type n_cols() const
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define Assert(cond, exc)
#define AssertNothrow(cond, exc)
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
std::size_t size
Definition mpi.cc:733
const MPI_Comm comm
Definition mpi.cc:912
void petsc_increment_state_counter(Vec v)