deal.II version GIT relicensing-6834-g5b78e6bcdf 2026-10-01 11:20: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
matrix_tools_once.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) 2016 - 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
17
21
22#include <deal.II/fe/fe.h>
24
26
31#include <deal.II/lac/vector.h>
32
34
35#ifdef DEAL_II_WITH_PETSC
40#endif
41
42#ifdef DEAL_II_WITH_TRILINOS
47#endif
48
49#include <algorithm>
50#include <cmath>
51
52
54
55namespace MatrixTools
56{
57#ifdef DEAL_II_WITH_PETSC
58 void
60 const std::map<types::global_dof_index, PetscScalar> &boundary_values,
63 PETScWrappers::VectorBase &right_hand_side,
64 const bool eliminate_columns)
65 {
66 Assert(matrix.n() == right_hand_side.size(),
67 ExcDimensionMismatch(matrix.n(), right_hand_side.size()));
68 Assert(matrix.n() == solution.size(),
69 ExcDimensionMismatch(matrix.n(), solution.size()));
70
71 // if no boundary values are to be applied, then
72 // jump straight to the compress() calls that we still have
73 // to perform because they are collective operations
74 if (boundary_values.size() > 0)
75 {
76 const std::pair<types::global_dof_index, types::global_dof_index>
77 local_range = matrix.local_range();
78 Assert(local_range == right_hand_side.local_range(),
81
82 // determine the first nonzero diagonal
83 // entry from within the part of the
84 // matrix that we can see. if we can't
85 // find such an entry, take one
86 PetscScalar average_nonzero_diagonal_entry = 1;
88 i < local_range.second;
89 ++i)
90 if (matrix.diag_element(i) != PetscScalar())
91 {
92 average_nonzero_diagonal_entry = std::abs(matrix.diag_element(i));
93 break;
94 }
95
96 // figure out which rows of the matrix we
97 // have to eliminate on this processor
98 std::vector<types::global_dof_index> constrained_rows;
99 for (const auto &boundary_value : boundary_values)
100 if ((boundary_value.first >= local_range.first) &&
101 (boundary_value.first < local_range.second))
102 constrained_rows.push_back(boundary_value.first);
103
104 // then eliminate these rows and set
105 // their diagonal entry to what we have
106 // determined above. note that for petsc
107 // matrices interleaving read with write
108 // operations is very expensive. thus, we
109 // here always replace the diagonal
110 // element, rather than first checking
111 // whether it is nonzero and in that case
112 // preserving it. this is different from
113 // the case of deal.II sparse matrices
114 // treated in the other functions.
115 if (eliminate_columns)
116 matrix.clear_rows_columns(constrained_rows,
117 average_nonzero_diagonal_entry);
118 else
119 matrix.clear_rows(constrained_rows, average_nonzero_diagonal_entry);
120
121 std::vector<types::global_dof_index> indices;
122 std::vector<PetscScalar> solution_values;
123 for (const auto &boundary_value : boundary_values)
124 if ((boundary_value.first >= local_range.first) &&
125 (boundary_value.first < local_range.second))
126 {
127 indices.push_back(boundary_value.first);
128 solution_values.push_back(boundary_value.second);
129 }
130 solution.set(indices, solution_values);
131
132 // now also set appropriate values for the rhs
133 for (auto &solution_value : solution_values)
134 solution_value *= average_nonzero_diagonal_entry;
135
136 right_hand_side.set(indices, solution_values);
137 }
138 else
139 {
140 // clear_rows() is a collective operation so we still have to call
141 // it:
142 std::vector<types::global_dof_index> constrained_rows;
143 if (eliminate_columns)
144 matrix.clear_rows_columns(constrained_rows, 1.);
145 else
146 matrix.clear_rows(constrained_rows, 1.);
147 }
148
149 // clean up
151 right_hand_side.compress(VectorOperation::insert);
152 }
153
154
155 void
157 const std::map<types::global_dof_index, PetscScalar> &boundary_values,
160 PETScWrappers::MPI::BlockVector &right_hand_side,
161 const bool eliminate_columns)
162 {
163 Assert(eliminate_columns == false, ExcNotImplemented());
164 Assert(matrix.n() == right_hand_side.size(),
165 ExcDimensionMismatch(matrix.n(), right_hand_side.size()));
166 Assert(matrix.n() == solution.size(),
167 ExcDimensionMismatch(matrix.n(), solution.size()));
168 Assert(matrix.n_block_rows() == matrix.n_block_cols(), ExcNotQuadratic());
169
170 const unsigned int n_blocks = matrix.n_block_rows();
171
172 // We need to find the subdivision
173 // into blocks for the boundary values.
174 // To this end, generate a vector of
175 // maps with the respective indices.
176 std::vector<std::map<::types::global_dof_index, PetscScalar>>
177 block_boundary_values(n_blocks);
178 {
179 int block = 0;
180 ::types::global_dof_index offset = 0;
181 for (const auto &boundary_value : boundary_values)
182 {
183 if (boundary_value.first >= matrix.block(block, 0).m() + offset)
184 {
185 offset += matrix.block(block, 0).m();
186 ++block;
187 }
188 const types::global_dof_index index = boundary_value.first - offset;
189 block_boundary_values[block].insert(
190 std::pair<types::global_dof_index, PetscScalar>(
191 index, boundary_value.second));
192 }
193 }
194
195 // Now call the non-block variants on
196 // the diagonal subblocks and the
197 // solution/rhs.
198 for (unsigned int block = 0; block < n_blocks; ++block)
199 apply_boundary_values(block_boundary_values[block],
200 matrix.block(block, block),
201 solution.block(block),
202 right_hand_side.block(block),
203 eliminate_columns);
204
205 // Finally, we need to do something
206 // about the off-diagonal matrices. This
207 // is luckily not difficult. Just clear
208 // the whole row.
209 for (unsigned int block_m = 0; block_m < n_blocks; ++block_m)
210 {
211 const std::pair<types::global_dof_index, types::global_dof_index>
212 local_range = matrix.block(block_m, 0).local_range();
213
214 std::vector<types::global_dof_index> constrained_rows;
215 for (std::map<types::global_dof_index, PetscScalar>::const_iterator
216 dof = block_boundary_values[block_m].begin();
217 dof != block_boundary_values[block_m].end();
218 ++dof)
219 if ((dof->first >= local_range.first) &&
220 (dof->first < local_range.second))
221 constrained_rows.push_back(dof->first);
222
223 for (unsigned int block_n = 0; block_n < n_blocks; ++block_n)
224 if (block_m != block_n)
225 matrix.block(block_m, block_n).clear_rows(constrained_rows);
226 }
227 }
228
229#endif
230
231
232
233#ifdef DEAL_II_TRILINOS_WITH_EPETRA
234
235 namespace internal
236 {
238 {
239 template <typename TrilinosMatrix, typename TrilinosVector>
240 void
242 TrilinosScalar> &boundary_values,
243 TrilinosMatrix &matrix,
244 TrilinosVector &solution,
245 TrilinosVector &right_hand_side,
246 const bool eliminate_columns)
247 {
248 Assert(eliminate_columns == false, ExcNotImplemented());
249 Assert(matrix.n() == right_hand_side.size(),
250 ExcDimensionMismatch(matrix.n(), right_hand_side.size()));
251 Assert(matrix.n() == solution.size(),
252 ExcDimensionMismatch(matrix.m(), solution.size()));
253
254 // if no boundary values are to be applied, then
255 // jump straight to the compress() calls that we still have
256 // to perform because they are collective operations
257 if (boundary_values.size() > 0)
258 {
259 const std::pair<types::global_dof_index, types::global_dof_index>
260 local_range = matrix.local_range();
261 Assert(local_range == right_hand_side.local_range(),
263 Assert(local_range == solution.local_range(), ExcInternalError());
264
265 // determine the first nonzero diagonal
266 // entry from within the part of the
267 // matrix that we can see. if we can't
268 // find such an entry, take one
269 TrilinosScalar average_nonzero_diagonal_entry = 1;
271 i < local_range.second;
272 ++i)
273 if (matrix.diag_element(i) != 0)
274 {
275 average_nonzero_diagonal_entry =
276 std::fabs(matrix.diag_element(i));
277 break;
278 }
279
280 // figure out which rows of the matrix we
281 // have to eliminate on this processor
282 std::vector<types::global_dof_index> constrained_rows;
283 for (const auto &boundary_value : boundary_values)
284 if ((boundary_value.first >= local_range.first) &&
285 (boundary_value.first < local_range.second))
286 constrained_rows.push_back(boundary_value.first);
287
288 // then eliminate these rows and
289 // set their diagonal entry to
290 // what we have determined
291 // above. if the value already is
292 // nonzero, it will be preserved,
293 // in accordance with the basic
294 // matrix classes in deal.II.
295 matrix.clear_rows(constrained_rows, average_nonzero_diagonal_entry);
296
297 std::vector<types::global_dof_index> indices;
298 std::vector<TrilinosScalar> solution_values;
299 for (const auto &boundary_value : boundary_values)
300 if ((boundary_value.first >= local_range.first) &&
301 (boundary_value.first < local_range.second))
302 {
303 indices.push_back(boundary_value.first);
304 solution_values.push_back(boundary_value.second);
305 }
306 solution.set(indices, solution_values);
307
308 // now also set appropriate
309 // values for the rhs
310 for (unsigned int i = 0; i < solution_values.size(); ++i)
311 solution_values[i] *= matrix.diag_element(indices[i]);
312
313 right_hand_side.set(indices, solution_values);
314 }
315 else
316 {
317 // clear_rows() is a collective operation so we still have to call
318 // it:
319 std::vector<types::global_dof_index> constrained_rows;
320 matrix.clear_rows(constrained_rows, 1.);
321 }
322
323 // clean up
324 matrix.compress(VectorOperation::insert);
325 solution.compress(VectorOperation::insert);
326 right_hand_side.compress(VectorOperation::insert);
327 }
328
329
330
331 template <typename TrilinosMatrix, typename TrilinosBlockVector>
332 void
334 const std::map<types::global_dof_index, TrilinosScalar>
335 &boundary_values,
336 TrilinosMatrix &matrix,
337 TrilinosBlockVector &solution,
338 TrilinosBlockVector &right_hand_side,
339 const bool eliminate_columns)
340 {
341 Assert(eliminate_columns == false, ExcNotImplemented());
342
343 Assert(matrix.n() == right_hand_side.size(),
344 ExcDimensionMismatch(matrix.n(), right_hand_side.size()));
345 Assert(matrix.n() == solution.size(),
346 ExcDimensionMismatch(matrix.n(), solution.size()));
347 Assert(matrix.n_block_rows() == matrix.n_block_cols(),
349
350 const unsigned int n_blocks = matrix.n_block_rows();
351
352 // We need to find the subdivision
353 // into blocks for the boundary values.
354 // To this end, generate a vector of
355 // maps with the respective indices.
356 std::vector<std::map<types::global_dof_index, TrilinosScalar>>
357 block_boundary_values(n_blocks);
358 {
359 int block = 0;
360 types::global_dof_index offset = 0;
361 for (const auto &boundary_value : boundary_values)
362 {
363 if (boundary_value.first >= matrix.block(block, 0).m() + offset)
364 {
365 offset += matrix.block(block, 0).m();
366 ++block;
367 }
368 const types::global_dof_index index =
369 boundary_value.first - offset;
370 block_boundary_values[block].insert(
371 std::pair<types::global_dof_index, TrilinosScalar>(
372 index, boundary_value.second));
373 }
374 }
375
376 // Now call the non-block variants on
377 // the diagonal subblocks and the
378 // solution/rhs.
379 for (unsigned int block = 0; block < n_blocks; ++block)
380 TrilinosWrappers::apply_boundary_values(block_boundary_values[block],
381 matrix.block(block, block),
382 solution.block(block),
383 right_hand_side.block(block),
384 eliminate_columns);
385
386 // Finally, we need to do something
387 // about the off-diagonal matrices. This
388 // is luckily not difficult. Just clear
389 // the whole row.
390 for (unsigned int block_m = 0; block_m < n_blocks; ++block_m)
391 {
392 const std::pair<types::global_dof_index, types::global_dof_index>
393 local_range = matrix.block(block_m, 0).local_range();
394
395 std::vector<types::global_dof_index> constrained_rows;
396 for (std::map<types::global_dof_index,
397 TrilinosScalar>::const_iterator dof =
398 block_boundary_values[block_m].begin();
399 dof != block_boundary_values[block_m].end();
400 ++dof)
401 if ((dof->first >= local_range.first) &&
402 (dof->first < local_range.second))
403 constrained_rows.push_back(dof->first);
404
405 for (unsigned int block_n = 0; block_n < n_blocks; ++block_n)
406 if (block_m != block_n)
407 matrix.block(block_m, block_n).clear_rows(constrained_rows);
408 }
409 }
410 } // namespace TrilinosWrappers
411 } // namespace internal
412
413
414
415 void
417 const std::map<types::global_dof_index, TrilinosScalar> &boundary_values,
420 TrilinosWrappers::MPI::Vector &right_hand_side,
421 const bool eliminate_columns)
422 {
423 // simply redirect to the generic function
424 // used for both trilinos matrix types
426 boundary_values, matrix, solution, right_hand_side, eliminate_columns);
427 }
428
429
430
431 void
433 const std::map<types::global_dof_index, TrilinosScalar> &boundary_values,
436 TrilinosWrappers::MPI::BlockVector &right_hand_side,
437 const bool eliminate_columns)
438 {
440 boundary_values, matrix, solution, right_hand_side, eliminate_columns);
441 }
442
443#endif
444
445} // namespace MatrixTools
446
*  *  iterator begin()
virtual size_type size() const override
BlockType & block(const unsigned int i)
std::pair< size_type, size_type > local_range() const
void compress(const VectorOperation::values operation)
void set(const std::vector< size_type > &indices, const std::vector< PetscScalar > &values)
size_type size() const override
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcNotQuadratic()
std::pair< types::global_dof_index, types::global_dof_index > local_range
Definition mpi.cc:814
void apply_block_boundary_values(const std::map< types::global_dof_index, TrilinosScalar > &boundary_values, TrilinosMatrix &matrix, TrilinosBlockVector &solution, TrilinosBlockVector &right_hand_side, const bool eliminate_columns)
void apply_boundary_values(const std::map< types::global_dof_index, TrilinosScalar > &boundary_values, TrilinosMatrix &matrix, TrilinosVector &solution, TrilinosVector &right_hand_side, const bool eliminate_columns)
void apply_boundary_values(const std::map< types::global_dof_index, number > &boundary_values, SparseMatrix< number > &matrix, Vector< number > &solution, Vector< number > &right_hand_side, const bool eliminate_columns=true)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
double TrilinosScalar
Definition types.h:188