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