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
sparse_matrix_tools.h
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) 2022 - 2025 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
13#ifndef dealii_sparse_matrix_tools_h
14#define dealii_sparse_matrix_tools_h
15
16#include <deal.II/base/config.h>
17
19
21
23
25
30{
53 template <typename SparseMatrixType,
54 typename SparsityPatternType,
55 typename SparseMatrixType2,
56 typename SparsityPatternType2>
57 void
58 restrict_to_serial_sparse_matrix(const SparseMatrixType &sparse_matrix_in,
59 const SparsityPatternType &sparsity_pattern,
60 const IndexSet &requested_is,
61 SparseMatrixType2 &system_matrix_out,
62 SparsityPatternType2 &sparsity_pattern_out);
63
76 template <typename SparseMatrixType,
77 typename SparsityPatternType,
78 typename SparseMatrixType2,
79 typename SparsityPatternType2>
80 void
81 restrict_to_serial_sparse_matrix(const SparseMatrixType &sparse_matrix_in,
82 const SparsityPatternType &sparsity_pattern,
83 const IndexSet &index_set_0,
84 const IndexSet &index_set_1,
85 SparseMatrixType2 &system_matrix_out,
86 SparsityPatternType2 &sparsity_pattern_out);
87
103 template <int dim,
104 int spacedim,
105 typename SparseMatrixType,
106 typename SparsityPatternType,
107 typename Number>
108 void
109 restrict_to_cells(const SparseMatrixType &system_matrix,
110 const SparsityPatternType &sparsity_pattern,
111 const DoFHandler<dim, spacedim> &dof_handler,
112 std::vector<FullMatrix<Number>> &blocks);
113
127 template <typename SparseMatrixType,
128 typename SparsityPatternType,
129 typename Number>
130 void
132 const SparseMatrixType &sparse_matrix_in,
133 const SparsityPatternType &sparsity_pattern,
134 const std::vector<std::vector<types::global_dof_index>> &indices,
135 std::vector<FullMatrix<Number>> &blocks);
136
137
138#ifndef DOXYGEN
139 /*---------------------- Inline functions ---------------------------------*/
140
141 namespace internal
142 {
143 template <typename T>
144 using get_mpi_communicator_t =
145 decltype(std::declval<const T>().get_mpi_communicator());
146
147 template <typename T>
148 constexpr bool has_get_mpi_communicator =
149 ::internal::is_supported_operation<get_mpi_communicator_t, T>;
150
151 template <typename T>
152 using local_size_t = decltype(std::declval<const T>().local_size());
153
154 template <typename T>
155 constexpr bool has_local_size =
156 ::internal::is_supported_operation<local_size_t, T>;
157
158 template <typename SparseMatrixType,
159 std::enable_if_t<has_get_mpi_communicator<SparseMatrixType>,
160 SparseMatrixType> * = nullptr>
162 get_mpi_communicator(const SparseMatrixType &sparse_matrix)
163 {
164 return sparse_matrix.get_mpi_communicator();
165 }
166
167 template <typename SparseMatrixType,
168 std::enable_if_t<!has_get_mpi_communicator<SparseMatrixType>,
169 SparseMatrixType> * = nullptr>
171 get_mpi_communicator(const SparseMatrixType & /*sparse_matrix*/)
172 {
173 return MPI_COMM_SELF;
174 }
175
176 template <typename SparseMatrixType,
177 std::enable_if_t<has_local_size<SparseMatrixType>,
178 SparseMatrixType> * = nullptr>
179 unsigned int
180 get_local_size(const SparseMatrixType &sparse_matrix)
181 {
182 return sparse_matrix.local_size();
183 }
184
185 template <typename SparseMatrixType,
186 std::enable_if_t<!has_local_size<SparseMatrixType>,
187 SparseMatrixType> * = nullptr>
188 unsigned int
189 get_local_size(const SparseMatrixType &sparse_matrix)
190 {
191 AssertDimension(sparse_matrix.m(), sparse_matrix.n());
192
193 return sparse_matrix.m();
194 }
195
196 // Helper function to extract for a distributed sparse matrix rows
197 // potentially not owned by the current process.
198 template <typename Number,
199 typename SparseMatrixType,
200 typename SparsityPatternType>
201 std::vector<std::vector<std::pair<types::global_dof_index, Number>>>
202 extract_remote_rows(const SparseMatrixType &system_matrix,
203 const SparsityPatternType &sparsity_pattern,
204 const IndexSet &locally_active_dofs,
205 const MPI_Comm comm)
206 {
207 std::vector<unsigned int> dummy(locally_active_dofs.n_elements());
208
209 const auto local_size = get_local_size(system_matrix);
210 const auto [prefix_sum, total_sum] =
212 IndexSet locally_owned_dofs(total_sum);
213 locally_owned_dofs.add_range(prefix_sum, prefix_sum + local_size);
214
215 using T1 = std::vector<
216 std::pair<types::global_dof_index,
217 std::vector<std::pair<types::global_dof_index, Number>>>>;
218
219 std::map<unsigned int, IndexSet> requesters;
220 std::tie(std::ignore, requesters) =
222 locally_active_dofs,
223 comm);
224
225 std::vector<std::vector<std::pair<types::global_dof_index, Number>>>
226 locally_relevant_matrix_entries(locally_active_dofs.n_elements());
227
228
229 std::vector<unsigned int> ranks;
230 ranks.reserve(requesters.size());
231
232 for (const auto &i : requesters)
233 ranks.push_back(i.first);
234
235 std::vector<std::vector<unsigned int>> row_to_procs(
236 locally_owned_dofs.n_elements());
237
238 for (const auto &requester : requesters)
239 for (const auto &index : requester.second)
240 row_to_procs[locally_owned_dofs.index_within_set(index)].push_back(
241 requester.first);
242
243 std::map<unsigned int, T1> data;
244
245 std::pair<types::global_dof_index,
246 std::vector<std::pair<types::global_dof_index, Number>>>
247 buffer;
248
249 for (unsigned int i = 0; i < row_to_procs.size(); ++i)
250 {
251 if (row_to_procs[i].empty())
252 continue;
253
254 const auto row = locally_owned_dofs.nth_index_in_set(i);
255 auto entry = system_matrix.begin(row);
256
257 const unsigned int row_length = sparsity_pattern.row_length(row);
258
259 buffer.first = row;
260 buffer.second.resize(row_length);
261
262 for (unsigned int j = 0; j < row_length; ++j, ++entry)
263 buffer.second[j] = {entry->column(), entry->value()};
264
265 for (const auto &proc : row_to_procs[i])
266 data[proc].emplace_back(buffer);
267 }
268
269 ::Utilities::MPI::ConsensusAlgorithms::selector<T1>(
270 ranks,
271 [&](const unsigned int other_rank) { return data[other_rank]; },
272 [&](const unsigned int &, const T1 &buffer_recv) {
273 for (const auto &i : buffer_recv)
274 {
275 auto &dst =
276 locally_relevant_matrix_entries[locally_active_dofs
277 .index_within_set(i.first)];
278 dst = i.second;
279 std::sort(dst.begin(),
280 dst.end(),
281 [](const auto &a, const auto &b) {
282 return a.first < b.first;
283 });
284 }
285 },
286 comm);
287
288 return locally_relevant_matrix_entries;
289 }
290 } // namespace internal
291
292
293
294 template <typename SparseMatrixType,
295 typename SparsityPatternType,
296 typename SparseMatrixType2,
297 typename SparsityPatternType2>
298 void
299 restrict_to_serial_sparse_matrix(const SparseMatrixType &system_matrix,
300 const SparsityPatternType &sparsity_pattern,
301 const IndexSet &index_set_0,
302 const IndexSet &index_set_1,
303 SparseMatrixType2 &system_matrix_out,
304 SparsityPatternType2 &sparsity_pattern_out)
305 {
306 Assert(index_set_1.size() == 0 || index_set_0.size() == index_set_1.size(),
308
309 auto index_set_1_cleared = index_set_1;
310 if (index_set_1.size() != 0)
311 index_set_1_cleared.subtract_set(index_set_0);
312
313 const auto index_within_set = [&index_set_0,
314 &index_set_1_cleared](const auto n) {
315 if (index_set_0.is_element(n))
316 return index_set_0.index_within_set(n);
317 else
318 return index_set_0.n_elements() +
319 index_set_1_cleared.index_within_set(n);
320 };
321
322 // 1) collect needed rows
323 auto index_set_union = index_set_0;
324
325 if (index_set_1.size() != 0)
326 index_set_union.add_indices(index_set_1_cleared);
327
328 // TODO: actually only communicate remote rows as in the case of
329 // SparseMatrixTools::restrict_to_cells()
330 const auto locally_relevant_matrix_entries =
331 internal::extract_remote_rows<typename SparseMatrixType2::value_type>(
332 system_matrix,
333 sparsity_pattern,
334 index_set_union,
335 internal::get_mpi_communicator(system_matrix));
336
337
338 // 2) create sparsity pattern
339 const unsigned int n_rows = index_set_union.n_elements();
340 const unsigned int n_cols = index_set_union.n_elements();
341 const unsigned int entries_per_row =
342 locally_relevant_matrix_entries.empty() ?
343 0 :
344 std::max_element(locally_relevant_matrix_entries.begin(),
345 locally_relevant_matrix_entries.end(),
346 [](const auto &a, const auto &b) {
347 return a.size() < b.size();
348 })
349 ->size();
350
351 sparsity_pattern_out.reinit(n_rows, n_cols, entries_per_row);
352
353 std::vector<types::global_dof_index> temp_indices;
354 std::vector<typename SparseMatrixType2::value_type> temp_values;
355
356 for (unsigned int row = 0; row < index_set_union.n_elements(); ++row)
357 {
358 const auto &global_row_entries = locally_relevant_matrix_entries[row];
359
360 temp_indices.clear();
361 temp_indices.reserve(global_row_entries.size());
362
363 for (const auto &global_row_entry : global_row_entries)
364 {
365 const auto global_index = std::get<0>(global_row_entry);
366
367 if (index_set_union.is_element(global_index))
368 temp_indices.push_back(index_within_set(global_index));
369 }
370
371 sparsity_pattern_out.add_entries(
372 index_within_set(index_set_union.nth_index_in_set(row)),
373 temp_indices.begin(),
374 temp_indices.end());
375 }
376
377 sparsity_pattern_out.compress();
378
379 // 3) setup matrix
380 system_matrix_out.reinit(sparsity_pattern_out);
381
382 // 4) fill entries
383 for (unsigned int row = 0; row < index_set_union.n_elements(); ++row)
384 {
385 const auto &global_row_entries = locally_relevant_matrix_entries[row];
386
387 temp_indices.clear();
388 temp_values.clear();
389
390 temp_indices.reserve(global_row_entries.size());
391 temp_values.reserve(global_row_entries.size());
392
393 for (const auto &global_row_entry : global_row_entries)
394 {
395 const auto global_index = std::get<0>(global_row_entry);
396
397 if (index_set_union.is_element(global_index))
398 {
399 temp_indices.push_back(index_within_set(global_index));
400 temp_values.push_back(std::get<1>(global_row_entry));
401 }
402 }
403
404 system_matrix_out.add(index_within_set(
405 index_set_union.nth_index_in_set(row)),
406 temp_indices,
407 temp_values);
408 }
409
410 system_matrix_out.compress(VectorOperation::add);
411 }
412
413
414
415 template <typename SparseMatrixType,
416 typename SparsityPatternType,
417 typename SparseMatrixType2,
418 typename SparsityPatternType2>
419 void
420 restrict_to_serial_sparse_matrix(const SparseMatrixType &system_matrix,
421 const SparsityPatternType &sparsity_pattern,
422 const IndexSet &requested_is,
423 SparseMatrixType2 &system_matrix_out,
424 SparsityPatternType2 &sparsity_pattern_out)
425 {
427 sparsity_pattern,
428 requested_is,
429 IndexSet(), // simply pass empty index set
430 system_matrix_out,
431 sparsity_pattern_out);
432 }
433
434
435
436 template <typename SparseMatrixType,
437 typename SparsityPatternType,
438 typename Number>
439 void
441 const SparseMatrixType &system_matrix,
442 const SparsityPatternType &sparsity_pattern,
443 const std::vector<std::vector<types::global_dof_index>> &indices,
444 std::vector<FullMatrix<Number>> &blocks)
445 {
446 // 0) determine which rows are locally owned and which ones are remote
447 const auto local_size = internal::get_local_size(system_matrix);
448 const auto prefix_sum = Utilities::MPI::partial_and_total_sum(
449 local_size, internal::get_mpi_communicator(system_matrix));
450 IndexSet locally_owned_dofs(std::get<1>(prefix_sum));
451 locally_owned_dofs.add_range(std::get<0>(prefix_sum),
452 std::get<0>(prefix_sum) + local_size);
453
454 std::vector<::types::global_dof_index> ghost_indices_vector;
455
456 for (const auto &i : indices)
457 ghost_indices_vector.insert(ghost_indices_vector.end(),
458 i.begin(),
459 i.end());
460
461 std::sort(ghost_indices_vector.begin(), ghost_indices_vector.end());
462
463 IndexSet locally_active_dofs(std::get<1>(prefix_sum));
464 locally_active_dofs.add_indices(ghost_indices_vector.begin(),
465 ghost_indices_vector.end());
466
467 locally_active_dofs.subtract_set(locally_owned_dofs);
468
469 // 1) collect remote rows of sparse matrix
470 const auto locally_relevant_matrix_entries =
471 internal::extract_remote_rows<Number>(system_matrix,
472 sparsity_pattern,
473 locally_active_dofs,
474 internal::get_mpi_communicator(
475 system_matrix));
476
477
478 // 2) loop over all cells and "revert" assembly
479 blocks.clear();
480 blocks.resize(indices.size());
481
482 for (unsigned int c = 0; c < indices.size(); ++c)
483 {
484 if (indices[c].empty())
485 continue;
486
487 const auto &local_dof_indices = indices[c];
488 auto &cell_matrix = blocks[c];
489
490 // allocate memory
491 const unsigned int dofs_per_cell = indices[c].size();
492
493 cell_matrix = FullMatrix<Number>(dofs_per_cell, dofs_per_cell);
494
495 // loop over all entries of the restricted element matrix and
496 // do different things if rows are locally owned or not and
497 // if column entries of that row exist or not
498 for (unsigned int i = 0; i < dofs_per_cell; ++i)
499 for (unsigned int j = 0; j < dofs_per_cell; ++j)
500 {
501 if (locally_owned_dofs.is_element(
502 local_dof_indices[i])) // row is local
503 {
504 if constexpr (std::is_same_v<SparseMatrixType,
506 {
507 const types::global_dof_index ind =
508 system_matrix.get_sparsity_pattern()(
509 local_dof_indices[i], local_dof_indices[j]);
510
511 // If SparsityPattern::operator()` found the entry, then
512 // we can access the corresponding value without a
513 // second search in the sparse matrix, otherwise the
514 // matrix entry at that index is zero because it does
515 // not exist in the sparsity pattern
517 {
519 accessor(&system_matrix, ind);
520 cell_matrix(i, j) = accessor.value();
521 }
522 else
523 cell_matrix(i, j) = 0.0;
524 }
525 else
526 cell_matrix(i, j) =
527 sparsity_pattern.exists(local_dof_indices[i],
528 local_dof_indices[j]) ?
529 system_matrix(local_dof_indices[i],
530 local_dof_indices[j]) :
531 0.0;
532 }
533 else // row is ghost
534 {
535 Assert(locally_active_dofs.is_element(local_dof_indices[i]),
537
538 const auto &row_entries =
539 locally_relevant_matrix_entries[locally_active_dofs
541 local_dof_indices[i])];
542
543 const auto ptr =
544 std::lower_bound(row_entries.begin(),
545 row_entries.end(),
546 std::pair<types::global_dof_index, Number>{
547 local_dof_indices[j], /*dummy*/ 0.0},
548 [](const auto a, const auto b) {
549 return a.first < b.first;
550 });
551
552 if (ptr != row_entries.end() &&
553 local_dof_indices[j] == ptr->first)
554 cell_matrix(i, j) = ptr->second;
555 else
556 cell_matrix(i, j) = 0.0;
557 }
558 }
559 }
560 }
561
562
563
564 template <int dim,
565 int spacedim,
566 typename SparseMatrixType,
567 typename SparsityPatternType,
568 typename Number>
569 void
570 restrict_to_cells(const SparseMatrixType &system_matrix,
571 const SparsityPatternType &sparsity_pattern,
572 const DoFHandler<dim, spacedim> &dof_handler,
573 std::vector<FullMatrix<Number>> &blocks)
574 {
575 std::vector<std::vector<types::global_dof_index>> all_dof_indices;
576 all_dof_indices.resize(dof_handler.get_triangulation().n_active_cells());
577
578 for (const auto &cell : dof_handler.active_cell_iterators())
579 {
580 if (cell->is_locally_owned() == false)
581 continue;
582
583 auto &local_dof_indices = all_dof_indices[cell->active_cell_index()];
584 local_dof_indices.resize(cell->get_fe().n_dofs_per_cell());
585 cell->get_dof_indices(local_dof_indices);
586 }
587
588 restrict_to_full_matrices(system_matrix,
589 sparsity_pattern,
590 all_dof_indices,
591 blocks);
592 }
593#endif
594
595} // namespace SparseMatrixTools
596
598
599#endif
*  iterator end()
*  *  for(const auto &cell :triangulation.active_cell_iterators())
*  *  iterator begin()
***mech_lbc_system increment_interpolation_handlers push_back(scale_z_handler)
const Triangulation< dim, spacedim > & get_triangulation() const
size_type size() const
Definition index_set.h:1759
size_type index_within_set(const size_type global_index) const
Definition index_set.h:1977
size_type n_elements() const
Definition index_set.h:1917
bool is_element(const size_type index) const
Definition index_set.h:1877
void subtract_set(const IndexSet &other)
Definition index_set.cc:496
void add_indices(const ForwardIterator &begin, const ForwardIterator &end)
Definition index_set.h:1814
static constexpr size_type invalid_entry
unsigned int n_active_cells() const
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
Point< 2 > second
Definition grid_out.cc:4640
Point< 2 > first
Definition grid_out.cc:4639
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
static ::ExceptionBase & ExcInternalError()
std::vector< index_type > data
Definition mpi.cc:734
std::vector< std::vector< std::pair< unsigned int, std::vector< std::pair< types::global_dof_index, types::global_dof_index > > > > > requesters
Definition mpi.cc:958
const MPI_Comm comm
Definition mpi.cc:912
void cell_matrix(FullMatrix< double > &M, const FEValuesBase< dim > &fe, const FEValuesBase< dim > &fetest, const ArrayView< const std::vector< double > > &velocity, const double factor=1.)
Definition advection.h:72
*  *  *  RotationFunction< dim, Number >::RotationFunction Number(dim)
*  *  *  *  std::vector< Number > ThermoPlasticMaterial< dim, ViscoplasticYieldLaw, Number >::get_state_parameters   const
void restrict_to_cells(const SparseMatrixType &system_matrix, const SparsityPatternType &sparsity_pattern, const DoFHandler< dim, spacedim > &dof_handler, std::vector< FullMatrix< Number > > &blocks)
void restrict_to_serial_sparse_matrix(const SparseMatrixType &sparse_matrix_in, const SparsityPatternType &sparsity_pattern, const IndexSet &requested_is, SparseMatrixType2 &system_matrix_out, SparsityPatternType2 &sparsity_pattern_out)
void restrict_to_full_matrices(const SparseMatrixType &sparse_matrix_in, const SparsityPatternType &sparsity_pattern, const std::vector< std::vector< types::global_dof_index > > &indices, std::vector< FullMatrix< Number > > &blocks)
TrilinosWrappers::types::int_type global_index(const Epetra_BlockMap &map, const ::types::global_dof_index i)
std::pair< std::vector< unsigned int >, std::map< unsigned int, IndexSet > > compute_index_owner_and_requesters(const IndexSet &owned_indices, const IndexSet &indices_to_look_up, const MPI_Comm &comm)
Definition mpi.cc:1871
std::pair< T, T > partial_and_total_sum(const T &value, const MPI_Comm comm)
unsigned int global_dof_index
Definition types.h:92