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
trilinos_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) 2008 - 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
15
16#ifdef DEAL_II_WITH_TRILINOS
17
20
27
28# include <boost/container/small_vector.hpp>
29
31# ifdef DEAL_II_TRILINOS_WITH_EPETRAEXT
32# include <EpetraExt_MatrixMatrix.h>
33# endif
34# include <Epetra_Export.h>
35# include <Teuchos_RCP.hpp>
36# include <ml_epetra_utils.h>
37# include <ml_struct.h>
39
40# include <memory>
41
42
43#endif // DEAL_II_WITH_TRILINOS
44
46
47#ifdef DEAL_II_WITH_TRILINOS
48
49namespace TrilinosWrappers
50{
51 namespace internal
52 {
53 template <typename VectorType>
54 typename VectorType::value_type *
55 begin(VectorType &V)
56 {
57 return V.begin();
58 }
59
60 template <typename VectorType>
61 const typename VectorType::value_type *
62 begin(const VectorType &V)
63 {
64 return V.begin();
65 }
66
67 template <typename VectorType>
68 typename VectorType::value_type *
69 end(VectorType &V)
70 {
71 return V.end();
72 }
73
74 template <typename VectorType>
75 const typename VectorType::value_type *
76 end(const VectorType &V)
77 {
78 return V.end();
79 }
80
81 template <>
82 double *
84 {
85 return V.trilinos_vector()[0];
86 }
87
88 template <>
89 const double *
91 {
92 return V.trilinos_vector()[0];
93 }
94
95 template <>
96 double *
98 {
99 return V.trilinos_vector()[0] + V.trilinos_vector().MyLength();
100 }
101
102 template <>
103 const double *
105 {
106 return V.trilinos_vector()[0] + V.trilinos_vector().MyLength();
107 }
108 } // namespace internal
109
110
111 namespace SparseMatrixIterators
112 {
113 void
115 {
116 // if we are asked to visit the past-the-end line, then simply
117 // release all our caches and go on with life.
118 //
119 // do the same if the row we're supposed to visit is not locally
120 // owned. this is simply going to make non-locally owned rows
121 // look like they're empty
122 if ((this->a_row == matrix->m()) ||
123 (matrix->in_local_range(this->a_row) == false))
124 {
125 colnum_cache.reset();
126 value_cache.reset();
127
128 return;
129 }
130
131 // get a representation of the present row
132 int ncols;
134 matrix->row_length(this->a_row);
135 if (value_cache.get() == nullptr)
136 {
137 value_cache = std::make_shared<std::vector<TrilinosScalar>>(colnums);
138 colnum_cache = std::make_shared<std::vector<size_type>>(colnums);
139 }
140 else
141 {
142 value_cache->resize(colnums);
143 colnum_cache->resize(colnums);
144 }
145
146 const int ierr = matrix->trilinos_matrix().ExtractGlobalRowCopy(
147 this->a_row,
148 colnums,
149 ncols,
150 value_cache->data(),
151 reinterpret_cast<TrilinosWrappers::types::int_type *>(
152 colnum_cache->data()));
153 AssertDimension(ncols, colnums);
154 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
155
156 // copy it into our caches if the
157 // line isn't empty. if it is, then
158 // we've done something wrong, since
159 // we shouldn't have initialized an
160 // iterator for an empty line (what
161 // would it point to?)
162 }
163 } // namespace SparseMatrixIterators
164
165
166 // The constructor is actually the
167 // only point where we have to check
168 // whether we build a serial or a
169 // parallel Trilinos matrix.
170 // Actually, it does not even matter
171 // how many threads there are, but
172 // only if we use an MPI compiler or
173 // a standard compiler. So, even one
174 // thread on a configuration with
175 // MPI will still get a parallel
176 // interface.
178 : column_space_map(new Epetra_Map(0, 0, Utilities::Trilinos::comm_self()))
179 , matrix(
180 new Epetra_FECrsMatrix(View, *column_space_map, *column_space_map, 0))
181 , last_action(Zero)
182 , compressed(true)
183 {
184 matrix->FillComplete();
185 }
186
187
188
190 const size_type n,
191 const unsigned int n_max_entries_per_row)
192 : column_space_map(
193 new Epetra_Map(static_cast<TrilinosWrappers::types::int_type>(n),
194 0,
195 Utilities::Trilinos::comm_self()))
196 ,
197
198 // on one processor only, we know how the
199 // columns of the matrix will be
200 // distributed (everything on one
201 // processor), so we can hand in this
202 // information to the constructor. we
203 // can't do so in parallel, where the
204 // information from columns is only
205 // available when entries have been added
206 matrix(new Epetra_FECrsMatrix(
207 Copy,
208 Epetra_Map(static_cast<TrilinosWrappers::types::int_type>(m),
209 0,
210 Utilities::Trilinos::comm_self()),
211 *column_space_map,
212 n_max_entries_per_row,
213 false))
214 , last_action(Zero)
215 , compressed(false)
216 {}
217
218
219
221 const size_type n,
222 const std::vector<unsigned int> &n_entries_per_row)
223 : column_space_map(
224 new Epetra_Map(static_cast<TrilinosWrappers::types::int_type>(n),
225 0,
226 Utilities::Trilinos::comm_self()))
227 , matrix(new Epetra_FECrsMatrix(
228 Copy,
229 Epetra_Map(static_cast<TrilinosWrappers::types::int_type>(m),
230 0,
231 Utilities::Trilinos::comm_self()),
232 *column_space_map,
233 reinterpret_cast<int *>(
234 const_cast<unsigned int *>(n_entries_per_row.data())),
235 false))
236 , last_action(Zero)
237 , compressed(false)
238 {}
239
240
241
242 SparseMatrix::SparseMatrix(const IndexSet &parallel_partitioning,
243 const MPI_Comm communicator,
244 const unsigned int n_max_entries_per_row)
245 : column_space_map(new Epetra_Map(
246 parallel_partitioning.make_trilinos_map(communicator, false)))
247 , matrix(new Epetra_FECrsMatrix(Copy,
248 *column_space_map,
249 n_max_entries_per_row,
250 false))
251 , last_action(Zero)
252 , compressed(false)
253 {}
254
255
256
257 SparseMatrix::SparseMatrix(const IndexSet &parallel_partitioning,
258 const MPI_Comm communicator)
259 : SparseMatrix(parallel_partitioning, communicator, 0)
260 {}
261
262
263
264 SparseMatrix::SparseMatrix(const IndexSet &parallel_partitioning)
265 : SparseMatrix(parallel_partitioning, MPI_COMM_WORLD, 0)
266 {}
267
268
269
270 SparseMatrix::SparseMatrix(const IndexSet &parallel_partitioning,
271 const MPI_Comm communicator,
272 const std::vector<unsigned int> &n_entries_per_row)
273 : column_space_map(new Epetra_Map(
274 parallel_partitioning.make_trilinos_map(communicator, false)))
275 , matrix(new Epetra_FECrsMatrix(Copy,
276 *column_space_map,
277 reinterpret_cast<int *>(
278 const_cast<unsigned int *>(
279 n_entries_per_row.data())),
280 false))
281 , last_action(Zero)
282 , compressed(false)
283 {}
284
285
286
287 SparseMatrix::SparseMatrix(const IndexSet &row_parallel_partitioning,
288 const IndexSet &col_parallel_partitioning,
289 const MPI_Comm communicator,
290 const size_type n_max_entries_per_row)
291 : column_space_map(new Epetra_Map(
292 col_parallel_partitioning.make_trilinos_map(communicator, false)))
293 , matrix(new Epetra_FECrsMatrix(
294 Copy,
295 row_parallel_partitioning.make_trilinos_map(communicator, false),
296 n_max_entries_per_row,
297 false))
298 , last_action(Zero)
299 , compressed(false)
300 {}
301
302
303
304 SparseMatrix::SparseMatrix(const IndexSet &row_parallel_partitioning,
305 const IndexSet &col_parallel_partitioning,
306 const MPI_Comm communicator)
307 : SparseMatrix(row_parallel_partitioning,
308 col_parallel_partitioning,
309 communicator,
310 0)
311 {}
312
313
314
315 SparseMatrix::SparseMatrix(const IndexSet &row_parallel_partitioning,
316 const IndexSet &col_parallel_partitioning)
317 : SparseMatrix(row_parallel_partitioning,
318 col_parallel_partitioning,
319 MPI_COMM_WORLD,
320 0)
321 {}
322
323
324
325 SparseMatrix::SparseMatrix(const IndexSet &row_parallel_partitioning,
326 const IndexSet &col_parallel_partitioning,
327 const MPI_Comm communicator,
328 const std::vector<unsigned int> &n_entries_per_row)
329 : column_space_map(new Epetra_Map(
330 col_parallel_partitioning.make_trilinos_map(communicator, false)))
331 , matrix(new Epetra_FECrsMatrix(
332 Copy,
333 row_parallel_partitioning.make_trilinos_map(communicator, false),
334 reinterpret_cast<int *>(
335 const_cast<unsigned int *>(n_entries_per_row.data())),
336 false))
337 , last_action(Zero)
338 , compressed(false)
339 {}
340
341
342
344 : column_space_map(new Epetra_Map(sparsity_pattern.domain_partitioner()))
345 , matrix(
346 new Epetra_FECrsMatrix(Copy,
347 sparsity_pattern.trilinos_sparsity_pattern(),
348 false))
349 , last_action(Zero)
350 , compressed(true)
351 {
352 Assert(sparsity_pattern.trilinos_sparsity_pattern().Filled() == true,
354 "The Trilinos sparsity pattern has not been compressed."));
356 }
357
358
359
361 : column_space_map(std::move(other.column_space_map))
362 , matrix(std::move(other.matrix))
363 , nonlocal_matrix(std::move(other.nonlocal_matrix))
364 , nonlocal_matrix_exporter(std::move(other.nonlocal_matrix_exporter))
365 , last_action(other.last_action)
366 , compressed(other.compressed)
367 {
368 other.last_action = Zero;
369 other.compressed = false;
370 }
371
372
373
374 void
376 {
377 if (this == &rhs)
378 return;
379
380 nonlocal_matrix.reset();
382
383 // check whether we need to update the whole matrix layout (we have
384 // different maps or if we detect a row where the columns of the two
385 // matrices do not match)
386 bool needs_deep_copy =
387 !matrix->RowMap().SameAs(rhs.matrix->RowMap()) ||
388 !matrix->ColMap().SameAs(rhs.matrix->ColMap()) ||
389 !matrix->DomainMap().SameAs(rhs.matrix->DomainMap()) ||
391 if (!needs_deep_copy)
392 {
393 // Try to copy all the rows of the matrix one by one. In case of error
394 // (i.e., the column indices are different), we need to abort and blow
395 // away the matrix.
396 for (const auto row : locally_owned_range_indices())
397 {
398 const int row_local = matrix->RowMap().LID(
399 static_cast<TrilinosWrappers::types::int_type>(row));
400 Assert((row_local >= 0), ExcAccessToNonlocalRow(row));
401
402 int n_entries, rhs_n_entries;
403 TrilinosScalar *value_ptr, *rhs_value_ptr;
404 int *index_ptr, *rhs_index_ptr;
405 int ierr = rhs.matrix->ExtractMyRowView(row_local,
406 rhs_n_entries,
407 rhs_value_ptr,
408 rhs_index_ptr);
409 Assert(ierr == 0, ExcTrilinosError(ierr));
410
411 ierr = matrix->ExtractMyRowView(row_local,
412 n_entries,
413 value_ptr,
414 index_ptr);
415 Assert(ierr == 0, ExcTrilinosError(ierr));
416
417 if (n_entries != rhs_n_entries ||
418 std::memcmp(static_cast<void *>(index_ptr),
419 static_cast<void *>(rhs_index_ptr),
420 sizeof(int) * n_entries) != 0)
421 {
422 needs_deep_copy = true;
423 break;
424 }
425
426 for (int i = 0; i < n_entries; ++i)
427 value_ptr[i] = rhs_value_ptr[i];
428 }
429 }
430
431 if (needs_deep_copy)
432 {
434 std::make_unique<Epetra_Map>(rhs.trilinos_matrix().DomainMap());
435
436 // release memory before reallocation
437 matrix = std::make_unique<Epetra_FECrsMatrix>(*rhs.matrix);
438
439 matrix->FillComplete(*column_space_map, matrix->RowMap());
440 }
441
442 if (rhs.nonlocal_matrix.get() != nullptr)
444 std::make_unique<Epetra_CrsMatrix>(Copy, rhs.nonlocal_matrix->Graph());
445 }
446
447
448
449 namespace
450 {
451 template <typename SparsityPatternType>
452 void
453 reinit_matrix(const IndexSet &row_parallel_partitioning,
454 const IndexSet &column_parallel_partitioning,
455 const SparsityPatternType &sparsity_pattern,
456 const bool exchange_data,
457 const MPI_Comm communicator,
458 std::unique_ptr<Epetra_Map> &column_space_map,
459 std::unique_ptr<Epetra_FECrsMatrix> &matrix,
460 std::unique_ptr<Epetra_CrsMatrix> &nonlocal_matrix,
461 std::unique_ptr<Epetra_Export> &nonlocal_matrix_exporter)
462 {
463 // release memory before reallocation
464 matrix.reset();
465 nonlocal_matrix.reset();
466 nonlocal_matrix_exporter.reset();
467
468 column_space_map = std::make_unique<Epetra_Map>(
469 column_parallel_partitioning.make_trilinos_map(communicator, false));
470
471 if (column_space_map->Comm().MyPID() == 0)
472 {
473 AssertDimension(sparsity_pattern.n_rows(),
474 row_parallel_partitioning.size());
475 AssertDimension(sparsity_pattern.n_cols(),
476 column_parallel_partitioning.size());
477 }
478
479 Epetra_Map row_space_map =
480 row_parallel_partitioning.make_trilinos_map(communicator, false);
481
482 // if we want to exchange data, build a usual Trilinos sparsity pattern
483 // and let that handle the exchange. otherwise, manually create a
484 // CrsGraph, which consumes considerably less memory because it can set
485 // correct number of indices right from the start
486 if (exchange_data)
487 {
488 SparsityPattern trilinos_sparsity;
489 trilinos_sparsity.reinit(row_parallel_partitioning,
490 column_parallel_partitioning,
491 sparsity_pattern,
492 communicator,
493 exchange_data);
494 matrix = std::make_unique<Epetra_FECrsMatrix>(
495 Copy, trilinos_sparsity.trilinos_sparsity_pattern(), false);
496
497 return;
498 }
499
501 row_space_map),
503 row_space_map) +
504 1;
505 std::vector<int> n_entries_per_row(last_row - first_row);
506
507 for (SparseMatrix::size_type row = first_row; row < last_row; ++row)
508 n_entries_per_row[row - first_row] = sparsity_pattern.row_length(row);
509
510 // The deal.II notation of a Sparsity pattern corresponds to the Epetra
511 // concept of a Graph. Hence, we generate a graph by copying the
512 // sparsity pattern into it, and then build up the matrix from the
513 // graph. This is considerable faster than directly filling elements
514 // into the matrix. Moreover, it consumes less memory, since the
515 // internal reordering is done on ints only, and we can leave the
516 // doubles aside.
517
518 // for more than one processor, need to specify only row map first and
519 // let the matrix entries decide about the column map (which says which
520 // columns are present in the matrix, not to be confused with the
521 // col_map that tells how the domain dofs of the matrix will be
522 // distributed). for only one processor, we can directly assign the
523 // columns as well. Compare this with bug # 4123 in the Sandia Bugzilla.
524 std::unique_ptr<Epetra_CrsGraph> graph;
525 if (row_space_map.Comm().NumProc() > 1)
526 graph = std::make_unique<Epetra_CrsGraph>(Copy,
527 row_space_map,
528 n_entries_per_row.data(),
529 true);
530 else
531 graph = std::make_unique<Epetra_CrsGraph>(Copy,
532 row_space_map,
533 *column_space_map,
534 n_entries_per_row.data(),
535 true);
536
537 // This functions assumes that the sparsity pattern sits on all
538 // processors (completely). The parallel version uses an Epetra graph
539 // that is already distributed.
540
541 // now insert the indices
542 std::vector<TrilinosWrappers::types::int_type> row_indices;
543
544 for (SparseMatrix::size_type row = first_row; row < last_row; ++row)
545 {
546 const int row_length = sparsity_pattern.row_length(row);
547 if (row_length == 0)
548 continue;
549
550 row_indices.resize(row_length, -1);
551 {
552 typename SparsityPatternType::iterator p =
553 sparsity_pattern.begin(row);
554 for (SparseMatrix::size_type col = 0;
555 p != sparsity_pattern.end(row);
556 ++p, ++col)
557 row_indices[col] = p->column();
558 }
559 graph->Epetra_CrsGraph::InsertGlobalIndices(row,
560 row_length,
561 row_indices.data());
562 }
563
564 // Eventually, optimize the graph structure (sort indices, make memory
565 // contiguous, etc). note that the documentation of the function indeed
566 // states that we first need to provide the column (domain) map and then
567 // the row (range) map
568 graph->FillComplete(*column_space_map, row_space_map);
569 graph->OptimizeStorage();
570
571 // check whether we got the number of columns right.
572 AssertDimension(sparsity_pattern.n_cols(),
574
575 // And now finally generate the matrix.
576 matrix = std::make_unique<Epetra_FECrsMatrix>(Copy, *graph, false);
577 }
578
579
580
581 // for the non-local graph, we need to circumvent the problem that some
582 // processors will not add into the non-local graph at all: We do not want
583 // to insert dummy elements on >5000 processors because that gets very
584 // slow. Thus, we set a flag in Epetra_CrsGraph that sets the correct
585 // flag. Since it is protected, we need to expose this information by
586 // deriving a class from Epetra_CrsGraph for the purpose of creating the
587 // data structure
588 class Epetra_CrsGraphMod : public Epetra_CrsGraph
589 {
590 public:
591 Epetra_CrsGraphMod(const Epetra_Map &row_map,
592 const int *n_entries_per_row)
593 : Epetra_CrsGraph(Copy, row_map, n_entries_per_row, true)
594 {}
595
596 void
597 SetIndicesAreGlobal()
598 {
599 this->Epetra_CrsGraph::SetIndicesAreGlobal(true);
600 }
601 };
602
603
604
605 // specialization for DynamicSparsityPattern which can provide us with
606 // more information about the non-locally owned rows
607 template <>
608 void
609 reinit_matrix(const IndexSet &row_parallel_partitioning,
610 const IndexSet &column_parallel_partitioning,
611 const DynamicSparsityPattern &sparsity_pattern,
612 const bool exchange_data,
613 const MPI_Comm communicator,
614 std::unique_ptr<Epetra_Map> &column_space_map,
615 std::unique_ptr<Epetra_FECrsMatrix> &matrix,
616 std::unique_ptr<Epetra_CrsMatrix> &nonlocal_matrix,
617 std::unique_ptr<Epetra_Export> &nonlocal_matrix_exporter)
618 {
619 matrix.reset();
620 nonlocal_matrix.reset();
621 nonlocal_matrix_exporter.reset();
622
623 column_space_map = std::make_unique<Epetra_Map>(
624 column_parallel_partitioning.make_trilinos_map(communicator, false));
625
626 AssertDimension(sparsity_pattern.n_rows(),
627 row_parallel_partitioning.size());
628 AssertDimension(sparsity_pattern.n_cols(),
629 column_parallel_partitioning.size());
630
631 Epetra_Map row_space_map =
632 row_parallel_partitioning.make_trilinos_map(communicator, false);
633
634 IndexSet relevant_rows(sparsity_pattern.row_index_set());
635 // serial case
636 if (relevant_rows.size() == 0)
637 {
638 relevant_rows.set_size(
640 relevant_rows.add_range(
641 0, TrilinosWrappers::n_global_elements(row_space_map));
642 }
643 relevant_rows.compress();
644 Assert(relevant_rows.n_elements() >=
645 static_cast<unsigned int>(row_space_map.NumMyElements()),
647 "Locally relevant rows of sparsity pattern must contain "
648 "all locally owned rows"));
649
650 // check whether the relevant rows correspond to exactly the same map as
651 // the owned rows. In that case, do not create the nonlocal graph and
652 // fill the columns by demand
653 const bool have_ghost_rows = [&]() {
654 const std::vector<::types::global_dof_index> indices =
655 relevant_rows.get_index_vector();
656 Epetra_Map relevant_map(
658 TrilinosWrappers::types::int_type(relevant_rows.n_elements()),
659 (indices.empty() ?
660 nullptr :
661 reinterpret_cast<const TrilinosWrappers::types::int_type *>(
662 indices.data())),
663 0,
664 row_space_map.Comm());
665 return !relevant_map.SameAs(row_space_map);
666 }();
667
668 std::vector<TrilinosWrappers::types::int_type> ghost_rows;
669 std::vector<int> n_entries_per_row(row_space_map.NumMyElements());
670 std::vector<int> n_entries_per_ghost_row;
671 {
673 for (const auto global_row : relevant_rows)
674 {
675 if (row_space_map.MyGID(
676 static_cast<TrilinosWrappers::types::int_type>(global_row)))
677 n_entries_per_row[own++] =
678 sparsity_pattern.row_length(global_row);
679 else if (sparsity_pattern.row_length(global_row) > 0)
680 {
681 ghost_rows.push_back(global_row);
682 n_entries_per_ghost_row.push_back(
683 sparsity_pattern.row_length(global_row));
684 }
685 }
686 }
687
688 Epetra_Map off_processor_map(-1,
689 ghost_rows.size(),
690 (ghost_rows.size() > 0) ?
691 (ghost_rows.data()) :
692 nullptr,
693 0,
694 row_space_map.Comm());
695
696 std::unique_ptr<Epetra_CrsGraph> graph;
697 std::unique_ptr<Epetra_CrsGraphMod> nonlocal_graph;
698 if (row_space_map.Comm().NumProc() > 1)
699 {
700 graph =
701 std::make_unique<Epetra_CrsGraph>(Copy,
702 row_space_map,
703 (n_entries_per_row.size() > 0) ?
704 (n_entries_per_row.data()) :
705 nullptr,
706 exchange_data ? false : true);
707 if (have_ghost_rows == true)
708 nonlocal_graph = std::make_unique<Epetra_CrsGraphMod>(
709 off_processor_map, n_entries_per_ghost_row.data());
710 }
711 else
712 graph =
713 std::make_unique<Epetra_CrsGraph>(Copy,
714 row_space_map,
715 *column_space_map,
716 (n_entries_per_row.size() > 0) ?
717 (n_entries_per_row.data()) :
718 nullptr,
719 true);
720
721 // now insert the indices, select between the right matrix
722 std::vector<TrilinosWrappers::types::int_type> row_indices;
723
724 for (const auto global_row : relevant_rows)
725 {
726 const int row_length = sparsity_pattern.row_length(global_row);
727 if (row_length == 0)
728 continue;
729
730 row_indices.resize(row_length, -1);
731 for (int col = 0; col < row_length; ++col)
732 row_indices[col] = sparsity_pattern.column_number(global_row, col);
733
734 if (row_space_map.MyGID(
735 static_cast<TrilinosWrappers::types::int_type>(global_row)))
736 graph->InsertGlobalIndices(global_row,
737 row_length,
738 row_indices.data());
739 else
740 {
741 Assert(nonlocal_graph.get() != nullptr, ExcInternalError());
742 nonlocal_graph->InsertGlobalIndices(global_row,
743 row_length,
744 row_indices.data());
745 }
746 }
747
748 // finalize nonlocal graph and create nonlocal matrix
749 if (nonlocal_graph.get() != nullptr)
750 {
751 // must make sure the IndicesAreGlobal flag is set on all processors
752 // because some processors might not call InsertGlobalIndices (and
753 // we do not want to insert dummy indices on all processors for
754 // large-scale simulations due to the bad impact on performance)
755 nonlocal_graph->SetIndicesAreGlobal();
756 Assert(nonlocal_graph->IndicesAreGlobal() == true,
758 nonlocal_graph->FillComplete(*column_space_map, row_space_map);
759 nonlocal_graph->OptimizeStorage();
760
761 // insert data from nonlocal graph into the final sparsity pattern
762 if (exchange_data)
763 {
764 Epetra_Export exporter(nonlocal_graph->RowMap(), row_space_map);
765 int ierr = graph->Export(*nonlocal_graph, exporter, Add);
766 Assert(ierr == 0, ExcTrilinosError(ierr));
767 }
768
769 nonlocal_matrix =
770 std::make_unique<Epetra_CrsMatrix>(Copy, *nonlocal_graph);
771 }
772
773 graph->FillComplete(*column_space_map, row_space_map);
774 graph->OptimizeStorage();
775
776 AssertDimension(sparsity_pattern.n_cols(),
778
779 matrix = std::make_unique<Epetra_FECrsMatrix>(Copy, *graph, false);
780 }
781 } // namespace
782
783
784
785 template <typename SparsityPatternType>
786 void
787 SparseMatrix::reinit(const SparsityPatternType &sparsity_pattern)
788 {
789 reinit_matrix(complete_index_set(sparsity_pattern.n_rows()),
790 complete_index_set(sparsity_pattern.n_cols()),
791 sparsity_pattern,
792 false,
793 MPI_COMM_SELF,
795 matrix,
798 }
799
800
801
802 template <typename SparsityPatternType>
803 std::enable_if_t<
804 !std::is_same_v<SparsityPatternType, ::SparseMatrix<double>>>
805 SparseMatrix::reinit(const IndexSet &row_parallel_partitioning,
806 const IndexSet &col_parallel_partitioning,
807 const SparsityPatternType &sparsity_pattern,
808 const MPI_Comm communicator,
809 const bool exchange_data)
810 {
811 reinit_matrix(row_parallel_partitioning,
812 col_parallel_partitioning,
813 sparsity_pattern,
814 exchange_data,
815 communicator,
817 matrix,
820
821 // In the end, the matrix needs to be compressed in order to be really
822 // ready.
823 last_action = Zero;
825 }
826
827
828
829 void
830 SparseMatrix::reinit(const SparsityPattern &sparsity_pattern)
831 {
832 matrix.reset();
834
835 // reinit with a (parallel) Trilinos sparsity pattern.
837 std::make_unique<Epetra_Map>(sparsity_pattern.domain_partitioner());
838 matrix = std::make_unique<Epetra_FECrsMatrix>(
839 Copy, sparsity_pattern.trilinos_sparsity_pattern(), false);
840
841 if (sparsity_pattern.nonlocal_graph.get() != nullptr)
843 std::make_unique<Epetra_CrsMatrix>(Copy,
844 *sparsity_pattern.nonlocal_graph);
845 else
846 nonlocal_matrix.reset();
847
848 last_action = Zero;
850 }
851
852
853
854 void
855 SparseMatrix::reinit(const SparseMatrix &sparse_matrix)
856 {
857 if (this == &sparse_matrix)
858 return;
859
861 std::make_unique<Epetra_Map>(sparse_matrix.trilinos_matrix().DomainMap());
862 matrix.reset();
864 matrix = std::make_unique<Epetra_FECrsMatrix>(
865 Copy, sparse_matrix.trilinos_sparsity_pattern(), false);
866
867 if (sparse_matrix.nonlocal_matrix != nullptr)
868 nonlocal_matrix = std::make_unique<Epetra_CrsMatrix>(
869 Copy, sparse_matrix.nonlocal_matrix->Graph());
870 else
871 nonlocal_matrix.reset();
872
873 last_action = Zero;
875 }
876
877
878
879 template <typename number>
880 void
882 const IndexSet &row_parallel_partitioning,
883 const IndexSet &col_parallel_partitioning,
884 const ::SparseMatrix<number> &dealii_sparse_matrix,
885 const MPI_Comm communicator,
886 const double drop_tolerance,
887 const bool copy_values,
888 const ::SparsityPattern *use_this_sparsity)
889 {
890 if (copy_values == false)
891 {
892 // in case we do not copy values, just
893 // call the other function.
894 if (use_this_sparsity == nullptr)
895 reinit(row_parallel_partitioning,
896 col_parallel_partitioning,
897 dealii_sparse_matrix.get_sparsity_pattern(),
898 communicator,
899 false);
900 else
901 reinit(row_parallel_partitioning,
902 col_parallel_partitioning,
903 *use_this_sparsity,
904 communicator,
905 false);
906 return;
907 }
908
909 const size_type n_rows = dealii_sparse_matrix.m();
910
911 AssertDimension(row_parallel_partitioning.size(), n_rows);
912 AssertDimension(col_parallel_partitioning.size(), dealii_sparse_matrix.n());
913
914 const ::SparsityPattern &sparsity_pattern =
915 (use_this_sparsity != nullptr) ?
916 *use_this_sparsity :
917 dealii_sparse_matrix.get_sparsity_pattern();
918
919 if (matrix.get() == nullptr || m() != n_rows ||
920 n_nonzero_elements() != sparsity_pattern.n_nonzero_elements())
921 {
922 reinit(row_parallel_partitioning,
923 col_parallel_partitioning,
924 sparsity_pattern,
925 communicator,
926 false);
927 }
928
929 // fill the values. the same as above: go through all rows of the
930 // matrix, and then all columns. since the sparsity patterns of the
931 // input matrix and the specified sparsity pattern might be different,
932 // need to go through the row for both these sparsity structures
933 // simultaneously in order to really set the correct values.
934 size_type maximum_row_length = matrix->MaxNumEntries();
935 std::vector<size_type> row_indices(maximum_row_length);
936 std::vector<TrilinosScalar> values(maximum_row_length);
937
938 for (size_type row = 0; row < n_rows; ++row)
939 // see if the row is locally stored on this processor
940 if (row_parallel_partitioning.is_element(row) == true)
941 {
942 ::SparsityPattern::iterator select_index =
943 sparsity_pattern.begin(row);
944 typename ::SparseMatrix<number>::const_iterator it =
945 dealii_sparse_matrix.begin(row);
946 size_type col = 0;
947 if (sparsity_pattern.n_rows() == sparsity_pattern.n_cols())
948 {
949 // optimized diagonal
950 AssertDimension(it->column(), row);
951 if (std::fabs(it->value()) > drop_tolerance)
952 {
953 values[col] = it->value();
954 row_indices[col++] = it->column();
955 }
956 ++select_index;
957 ++it;
958 }
959
960 while (it != dealii_sparse_matrix.end(row) &&
961 select_index != sparsity_pattern.end(row))
962 {
963 while (select_index->column() < it->column() &&
964 select_index != sparsity_pattern.end(row))
965 ++select_index;
966 while (it->column() < select_index->column() &&
967 it != dealii_sparse_matrix.end(row))
968 ++it;
969
970 if (it == dealii_sparse_matrix.end(row))
971 break;
972 if (std::fabs(it->value()) > drop_tolerance)
973 {
974 values[col] = it->value();
975 row_indices[col++] = it->column();
976 }
977 ++select_index;
978 ++it;
979 }
980 set(row,
981 col,
982 reinterpret_cast<size_type *>(row_indices.data()),
983 values.data(),
984 false);
985 }
987 }
988
989
990
991 template <typename number>
992 void
994 const ::SparseMatrix<number> &dealii_sparse_matrix,
995 const double drop_tolerance,
996 const bool copy_values,
997 const ::SparsityPattern *use_this_sparsity)
998 {
999 reinit(complete_index_set(dealii_sparse_matrix.m()),
1000 complete_index_set(dealii_sparse_matrix.n()),
1001 dealii_sparse_matrix,
1002 MPI_COMM_SELF,
1003 drop_tolerance,
1004 copy_values,
1005 use_this_sparsity);
1006 }
1007
1008
1009
1010 void
1011 SparseMatrix::reinit(const Epetra_CrsMatrix &input_matrix,
1012 const bool copy_values)
1013 {
1014 Assert(input_matrix.Filled() == true,
1015 ExcMessage("Input CrsMatrix has not called FillComplete()!"));
1016
1017 column_space_map = std::make_unique<Epetra_Map>(input_matrix.DomainMap());
1018
1019 const Epetra_CrsGraph *graph = &input_matrix.Graph();
1020
1021 nonlocal_matrix.reset();
1023 matrix.reset();
1024 matrix = std::make_unique<Epetra_FECrsMatrix>(Copy, *graph, false);
1025
1026 matrix->FillComplete(*column_space_map, input_matrix.RangeMap(), true);
1027
1028 if (copy_values == true)
1029 {
1030 // point to the first data entry in the two
1031 // matrices and copy the content
1032 const TrilinosScalar *in_values = input_matrix[0];
1033 TrilinosScalar *values = (*matrix)[0];
1034 const size_type my_nonzeros = input_matrix.NumMyNonzeros();
1035 std::memcpy(values, in_values, my_nonzeros * sizeof(TrilinosScalar));
1036 }
1037
1038 last_action = Zero;
1040 }
1041
1042
1043
1044 void
1046 {
1047 Epetra_CombineMode mode = last_action;
1048 if (last_action == Zero)
1049 {
1050 if ((operation == VectorOperation::add) ||
1051 (operation == VectorOperation::unknown))
1052 mode = Add;
1053 else if (operation == VectorOperation::insert)
1054 mode = Insert;
1055 else
1056 Assert(
1057 false,
1058 ExcMessage(
1059 "compress() can only be called with VectorOperation add, insert, or unknown"));
1060 }
1061 else
1062 {
1063 Assert(
1064 ((last_action == Add) && (operation != VectorOperation::insert)) ||
1065 ((last_action == Insert) && (operation != VectorOperation::add)),
1066 ExcMessage("Operation and argument to compress() do not match"));
1067 }
1068
1069 // flush buffers
1070 int ierr;
1071 if (nonlocal_matrix.get() != nullptr && mode == Add)
1072 {
1073 // do only export in case of an add() operation, otherwise the owning
1074 // processor must have set the correct entry
1075 nonlocal_matrix->FillComplete(*column_space_map, matrix->RowMap());
1076 if (nonlocal_matrix_exporter.get() == nullptr)
1078 std::make_unique<Epetra_Export>(nonlocal_matrix->RowMap(),
1079 matrix->RowMap());
1080 ierr =
1082 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
1083 ierr = matrix->FillComplete(*column_space_map, matrix->RowMap());
1084 nonlocal_matrix->PutScalar(0);
1085 }
1086 else
1087 ierr =
1088 matrix->GlobalAssemble(*column_space_map, matrix->RowMap(), true, mode);
1089
1090 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
1091
1092 ierr = matrix->OptimizeStorage();
1093 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
1094
1095 last_action = Zero;
1096
1097 compressed = true;
1098 }
1099
1100
1101
1102 void
1104 {
1105 // When we clear the matrix, reset
1106 // the pointer and generate an
1107 // empty matrix.
1109 std::make_unique<Epetra_Map>(0, 0, Utilities::Trilinos::comm_self());
1110 matrix = std::make_unique<Epetra_FECrsMatrix>(View, *column_space_map, 0);
1111 nonlocal_matrix.reset();
1113
1114 matrix->FillComplete();
1115
1116 compressed = true;
1117 }
1118
1119
1120
1121 void
1123 const TrilinosScalar new_diag_value)
1124 {
1125 Assert(matrix->Filled() == true, ExcMatrixNotCompressed());
1126
1127 // Only do this on the rows owned
1128 // locally on this processor.
1129 int local_row =
1130 matrix->LRID(static_cast<TrilinosWrappers::types::int_type>(row));
1131 if (local_row >= 0)
1132 {
1133 TrilinosScalar *values;
1134 int *col_indices;
1135 int num_entries;
1136 const int ierr =
1137 matrix->ExtractMyRowView(local_row, num_entries, values, col_indices);
1138
1139 Assert(ierr == 0, ExcTrilinosError(ierr));
1140
1141 const std::ptrdiff_t diag_index =
1142 std::find(col_indices, col_indices + num_entries, local_row) -
1143 col_indices;
1144
1145 for (TrilinosWrappers::types::int_type j = 0; j < num_entries; ++j)
1146 if (diag_index != j || new_diag_value == 0)
1147 values[j] = 0.;
1148
1149 if (diag_index != num_entries)
1150 values[diag_index] = new_diag_value;
1151 }
1152 }
1153
1154
1155
1156 void
1158 const TrilinosScalar new_diag_value)
1159 {
1160 for (const auto row : rows)
1161 clear_row(row, new_diag_value);
1162 }
1163
1164
1165
1168 {
1169 // Extract local indices in
1170 // the matrix.
1171 int trilinos_i =
1172 matrix->LRID(static_cast<TrilinosWrappers::types::int_type>(i)),
1173 trilinos_j =
1174 matrix->LCID(static_cast<TrilinosWrappers::types::int_type>(j));
1175 TrilinosScalar value = 0.;
1176
1177 // If the data is not on the
1178 // present processor, we throw
1179 // an exception. This is one of
1180 // the two tiny differences to
1181 // the el(i,j) call, which does
1182 // not throw any assertions.
1183 if (trilinos_i == -1)
1184 {
1185 Assert(false,
1187 i, j, local_range().first, local_range().second - 1));
1188 }
1189 else
1190 {
1191 // Check whether the matrix has
1192 // already been transformed to local
1193 // indices.
1194 Assert(matrix->Filled(), ExcMatrixNotCompressed());
1195
1196 // Prepare pointers for extraction
1197 // of a view of the row.
1198 int nnz_present = matrix->NumMyEntries(trilinos_i);
1199 int nnz_extracted;
1200 int *col_indices;
1201 TrilinosScalar *values;
1202
1203 // Generate the view and make
1204 // sure that we have not generated
1205 // an error.
1206 // TODO Check that col_indices are int and not long long
1207 int ierr = matrix->ExtractMyRowView(trilinos_i,
1208 nnz_extracted,
1209 values,
1210 col_indices);
1211 Assert(ierr == 0, ExcTrilinosError(ierr));
1212
1213 Assert(nnz_present == nnz_extracted,
1214 ExcDimensionMismatch(nnz_present, nnz_extracted));
1215
1216 // Search the index where we
1217 // look for the value, and then
1218 // finally get it.
1219 const std::ptrdiff_t local_col_index =
1220 std::find(col_indices, col_indices + nnz_present, trilinos_j) -
1221 col_indices;
1222
1223 // This is actually the only
1224 // difference to the el(i,j)
1225 // function, which means that
1226 // we throw an exception in
1227 // this case instead of just
1228 // returning zero for an
1229 // element that is not present
1230 // in the sparsity pattern.
1231 if (local_col_index == nnz_present)
1232 {
1233 Assert(false, ExcInvalidIndex(i, j));
1234 }
1235 else
1236 value = values[local_col_index];
1237 }
1238
1239 return value;
1240 }
1241
1242
1243
1245 SparseMatrix::el(const size_type i, const size_type j) const
1246 {
1247 // Extract local indices in
1248 // the matrix.
1249 int trilinos_i =
1250 matrix->LRID(static_cast<TrilinosWrappers::types::int_type>(i)),
1251 trilinos_j =
1252 matrix->LCID(static_cast<TrilinosWrappers::types::int_type>(j));
1253 TrilinosScalar value = 0.;
1254
1255 // If the data is not on the
1256 // present processor, we can't
1257 // continue. Just print out zero
1258 // as discussed in the
1259 // documentation of this
1260 // function. if you want error
1261 // checking, use operator().
1262 if ((trilinos_i == -1) || (trilinos_j == -1))
1263 return 0.;
1264 else
1265 {
1266 // Check whether the matrix
1267 // already is transformed to
1268 // local indices.
1269 Assert(matrix->Filled(), ExcMatrixNotCompressed());
1270
1271 // Prepare pointers for extraction
1272 // of a view of the row.
1273 int nnz_present = matrix->NumMyEntries(trilinos_i);
1274 int nnz_extracted;
1275 int *col_indices;
1276 TrilinosScalar *values;
1277
1278 // Generate the view and make
1279 // sure that we have not generated
1280 // an error.
1281 int ierr = matrix->ExtractMyRowView(trilinos_i,
1282 nnz_extracted,
1283 values,
1284 col_indices);
1285 Assert(ierr == 0, ExcTrilinosError(ierr));
1286
1287 Assert(nnz_present == nnz_extracted,
1288 ExcDimensionMismatch(nnz_present, nnz_extracted));
1289
1290 // Search the index where we
1291 // look for the value, and then
1292 // finally get it.
1293 const std::ptrdiff_t local_col_index =
1294 std::find(col_indices, col_indices + nnz_present, trilinos_j) -
1295 col_indices;
1296
1297 // This is actually the only
1298 // difference to the () function
1299 // querying (i,j), where we throw an
1300 // exception instead of just
1301 // returning zero for an element
1302 // that is not present in the
1303 // sparsity pattern.
1304 if (local_col_index == nnz_present)
1305 value = 0;
1306 else
1307 value = values[local_col_index];
1308 }
1309
1310 return value;
1311 }
1312
1313
1314
1317 {
1318 Assert(m() == n(), ExcNotQuadratic());
1319
1320 if constexpr (running_in_debug_mode())
1321 {
1322 // use operator() in debug mode because
1323 // it checks if this is a valid element
1324 // (in parallel)
1325 return operator()(i, i);
1326 }
1327 else
1328 {
1329 // Trilinos doesn't seem to have a
1330 // more efficient way to access the
1331 // diagonal than by just using the
1332 // standard el(i,j) function.
1333 return el(i, i);
1334 }
1335 }
1336
1337
1338
1339 unsigned int
1341 {
1342 Assert(row < m(), ExcInternalError());
1343
1344 // get a representation of the
1345 // present row
1346 int ncols = -1;
1347 int local_row =
1348 matrix->LRID(static_cast<TrilinosWrappers::types::int_type>(row));
1349 Assert((local_row >= 0), ExcAccessToNonlocalRow(row));
1350
1351 // on the processor who owns this
1352 // row, we'll have a non-negative
1353 // value.
1354 if (local_row >= 0)
1355 {
1356 int ierr = matrix->NumMyRowEntries(local_row, ncols);
1357 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
1358 }
1359
1360 return static_cast<unsigned int>(ncols);
1361 }
1362
1363
1364
1365 void
1366 SparseMatrix::set(const std::vector<size_type> &row_indices,
1367 const std::vector<size_type> &col_indices,
1368 const FullMatrix<TrilinosScalar> &values,
1369 const bool elide_zero_values)
1370 {
1371 Assert(row_indices.size() == values.m(),
1372 ExcDimensionMismatch(row_indices.size(), values.m()));
1373 Assert(col_indices.size() == values.n(),
1374 ExcDimensionMismatch(col_indices.size(), values.n()));
1375
1376 for (size_type i = 0; i < row_indices.size(); ++i)
1377 set(row_indices[i],
1378 col_indices.size(),
1379 col_indices.data(),
1380 &values(i, 0),
1381 elide_zero_values);
1382 }
1383
1384
1385
1386 void
1388 const std::vector<size_type> &col_indices,
1389 const std::vector<TrilinosScalar> &values,
1390 const bool elide_zero_values)
1391 {
1392 Assert(col_indices.size() == values.size(),
1393 ExcDimensionMismatch(col_indices.size(), values.size()));
1394
1395 set(row,
1396 col_indices.size(),
1397 col_indices.data(),
1398 values.data(),
1399 elide_zero_values);
1400 }
1401
1402
1403
1404 template <>
1405 void
1406 SparseMatrix::set<TrilinosScalar>(const size_type row,
1407 const size_type n_cols,
1408 const size_type *col_indices,
1409 const TrilinosScalar *values,
1410 const bool elide_zero_values)
1411 {
1412 AssertIndexRange(row, this->m());
1413
1414 int ierr;
1415 if (last_action == Add)
1416 {
1417 ierr =
1418 matrix->GlobalAssemble(*column_space_map, matrix->RowMap(), true);
1419
1420 Assert(ierr == 0, ExcTrilinosError(ierr));
1421 }
1422
1423 last_action = Insert;
1424
1425 const TrilinosWrappers::types::int_type *col_index_ptr;
1426 const TrilinosScalar *col_value_ptr;
1427 const TrilinosWrappers::types::int_type trilinos_row = row;
1429
1430 boost::container::small_vector<TrilinosScalar, 200> local_value_array(
1431 elide_zero_values ? n_cols : 0);
1432 boost::container::small_vector<TrilinosWrappers::types::int_type, 200>
1433 local_index_array(elide_zero_values ? n_cols : 0);
1434
1435 // If we don't elide zeros, the pointers are already available... need to
1436 // cast to non-const pointers as that is the format taken by Trilinos (but
1437 // we will not modify const data)
1438 if (elide_zero_values == false)
1439 {
1440 col_index_ptr =
1441 reinterpret_cast<const TrilinosWrappers::types::int_type *>(
1442 col_indices);
1443 col_value_ptr = values;
1444 n_columns = n_cols;
1445 }
1446 else
1447 {
1448 // Otherwise, extract nonzero values in each row and get the
1449 // respective indices.
1450 col_index_ptr = local_index_array.data();
1451 col_value_ptr = local_value_array.data();
1452
1453 n_columns = 0;
1454 for (size_type j = 0; j < n_cols; ++j)
1455 {
1456 const double value = values[j];
1457 AssertIsFinite(value);
1458 if (value != 0)
1459 {
1460 local_index_array[n_columns] = col_indices[j];
1461 local_value_array[n_columns] = value;
1462 ++n_columns;
1463 }
1464 }
1465
1466 AssertIndexRange(n_columns, n_cols + 1);
1467 }
1468
1469
1470 // If the calling matrix owns the row to which we want to insert values,
1471 // we can directly call the Epetra_CrsMatrix input function, which is much
1472 // faster than the Epetra_FECrsMatrix function. We distinguish between two
1473 // cases: the first one is when the matrix is not filled (i.e., it is
1474 // possible to add new elements to the sparsity pattern), and the second
1475 // one is when the pattern is already fixed. In the former case, we add
1476 // the possibility to insert new values, and in the second we just replace
1477 // data.
1478 if (matrix->RowMap().MyGID(
1479 static_cast<TrilinosWrappers::types::int_type>(row)) == true)
1480 {
1481 if (matrix->Filled() == false)
1482 {
1483 ierr = matrix->Epetra_CrsMatrix::InsertGlobalValues(
1484 row, static_cast<int>(n_columns), col_value_ptr, col_index_ptr);
1485
1486 // When inserting elements, we do not want to create exceptions in
1487 // the case when inserting non-local data (since that's what we
1488 // want to do right now).
1489 if (ierr > 0)
1490 ierr = 0;
1491 }
1492 else
1493 ierr = matrix->Epetra_CrsMatrix::ReplaceGlobalValues(row,
1494 n_columns,
1495 col_value_ptr,
1496 col_index_ptr);
1497 }
1498 else
1499 {
1500 // When we're at off-processor data, we have to stick with the
1501 // standard Insert/ReplaceGlobalValues function. Nevertheless, the way
1502 // we call it is the fastest one (any other will lead to repeated
1503 // allocation and deallocation of memory in order to call the function
1504 // we already use, which is very inefficient if writing one element at
1505 // a time).
1506 compressed = false;
1507
1508 if (matrix->Filled() == false)
1509 {
1510 ierr = matrix->InsertGlobalValues(1,
1511 &trilinos_row,
1512 n_columns,
1513 col_index_ptr,
1514 &col_value_ptr,
1515 Epetra_FECrsMatrix::ROW_MAJOR);
1516 if (ierr > 0)
1517 ierr = 0;
1518 }
1519 else
1520 ierr = matrix->ReplaceGlobalValues(1,
1521 &trilinos_row,
1522 n_columns,
1523 col_index_ptr,
1524 &col_value_ptr,
1525 Epetra_FECrsMatrix::ROW_MAJOR);
1526 // use the FECrsMatrix facilities for set even in the case when we
1527 // have explicitly set the off-processor rows because that only works
1528 // properly when adding elements, not when setting them (since we want
1529 // to only touch elements that have been set explicitly, and there is
1530 // no way on the receiving processor to identify them otherwise)
1531 }
1532
1533 Assert(ierr <= 0, ExcAccessToNonPresentElement(row, col_index_ptr[0]));
1534 AssertThrow(ierr >= 0, ExcTrilinosError(ierr));
1535 }
1536
1537
1538
1539 void
1540 SparseMatrix::add(const std::vector<size_type> &indices,
1541 const FullMatrix<TrilinosScalar> &values,
1542 const bool elide_zero_values)
1543 {
1544 Assert(indices.size() == values.m(),
1545 ExcDimensionMismatch(indices.size(), values.m()));
1546 Assert(values.m() == values.n(), ExcNotQuadratic());
1547
1548 for (size_type i = 0; i < indices.size(); ++i)
1549 add(indices[i],
1550 indices.size(),
1551 indices.data(),
1552 &values(i, 0),
1553 elide_zero_values);
1554 }
1555
1556
1557
1558 void
1559 SparseMatrix::add(const std::vector<size_type> &row_indices,
1560 const std::vector<size_type> &col_indices,
1561 const FullMatrix<TrilinosScalar> &values,
1562 const bool elide_zero_values)
1563 {
1564 Assert(row_indices.size() == values.m(),
1565 ExcDimensionMismatch(row_indices.size(), values.m()));
1566 Assert(col_indices.size() == values.n(),
1567 ExcDimensionMismatch(col_indices.size(), values.n()));
1568
1569 for (size_type i = 0; i < row_indices.size(); ++i)
1570 add(row_indices[i],
1571 col_indices.size(),
1572 col_indices.data(),
1573 &values(i, 0),
1574 elide_zero_values);
1575 }
1576
1577
1578
1579 void
1581 const std::vector<size_type> &col_indices,
1582 const std::vector<TrilinosScalar> &values,
1583 const bool elide_zero_values)
1584 {
1585 Assert(col_indices.size() == values.size(),
1586 ExcDimensionMismatch(col_indices.size(), values.size()));
1587
1588 add(row,
1589 col_indices.size(),
1590 col_indices.data(),
1591 values.data(),
1592 elide_zero_values);
1593 }
1594
1595
1596
1597 void
1599 const size_type n_cols,
1600 const size_type *col_indices,
1601 const TrilinosScalar *values,
1602 const bool elide_zero_values,
1603 const bool /*col_indices_are_sorted*/)
1604 {
1605 AssertIndexRange(row, this->m());
1606 for (size_type n = 0; n < n_cols; ++n)
1607 AssertIndexRange(col_indices[n], this->n());
1608
1609 int ierr;
1610 if (last_action == Insert)
1611 {
1612 // TODO: this could lead to a dead lock when only one processor
1613 // calls GlobalAssemble.
1614 ierr =
1615 matrix->GlobalAssemble(*column_space_map, matrix->RowMap(), false);
1616
1617 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
1618 }
1619
1620 last_action = Add;
1621
1622 const TrilinosWrappers::types::int_type *col_index_ptr;
1623 const TrilinosScalar *col_value_ptr;
1624 const TrilinosWrappers::types::int_type trilinos_row = row;
1626
1627 boost::container::small_vector<TrilinosScalar, 100> local_value_array(
1628 n_cols);
1629 boost::container::small_vector<TrilinosWrappers::types::int_type, 100>
1630 local_index_array(n_cols);
1631
1632 // If we don't elide zeros, the pointers are already available... need to
1633 // cast to non-const pointers as that is the format taken by Trilinos (but
1634 // we will not modify const data)
1635 if (elide_zero_values == false)
1636 {
1637 col_index_ptr =
1638 reinterpret_cast<const TrilinosWrappers::types::int_type *>(
1639 col_indices);
1640 col_value_ptr = values;
1641 n_columns = n_cols;
1642 if constexpr (running_in_debug_mode())
1643 {
1644 for (size_type j = 0; j < n_cols; ++j)
1645 AssertIsFinite(values[j]);
1646 }
1647 }
1648 else
1649 {
1650 // Otherwise, extract nonzero values in each row and the corresponding
1651 // index.
1652 col_index_ptr = local_index_array.data();
1653 col_value_ptr = local_value_array.data();
1654
1655 n_columns = 0;
1656 for (size_type j = 0; j < n_cols; ++j)
1657 {
1658 const double value = values[j];
1659
1660 AssertIsFinite(value);
1661 if (value != 0)
1662 {
1663 local_index_array[n_columns] = col_indices[j];
1664 local_value_array[n_columns] = value;
1665 ++n_columns;
1666 }
1667 }
1668
1669 AssertIndexRange(n_columns, n_cols + 1);
1670 }
1671 // Exit early if there is nothing to do
1672 if (n_columns == 0)
1673 {
1674 return;
1675 }
1676
1677 // If the calling processor owns the row to which we want to add values, we
1678 // can directly call the Epetra_CrsMatrix input function, which is much
1679 // faster than the Epetra_FECrsMatrix function.
1680 if (matrix->RowMap().MyGID(
1681 static_cast<TrilinosWrappers::types::int_type>(row)) == true)
1682 {
1683 ierr = matrix->Epetra_CrsMatrix::SumIntoGlobalValues(row,
1684 n_columns,
1685 col_value_ptr,
1686 col_index_ptr);
1687 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
1688 }
1689 else if (nonlocal_matrix.get() != nullptr)
1690 {
1691 compressed = false;
1692 // this is the case when we have explicitly set the off-processor rows
1693 // and want to create a separate matrix object for them (to retain
1694 // thread-safety)
1695 Assert(nonlocal_matrix->RowMap().LID(
1696 static_cast<TrilinosWrappers::types::int_type>(row)) != -1,
1697 ExcMessage("Attempted to write into off-processor matrix row "
1698 "that has not be specified as being writable upon "
1699 "initialization"));
1700 ierr = nonlocal_matrix->SumIntoGlobalValues(row,
1701 n_columns,
1702 col_value_ptr,
1703 col_index_ptr);
1704 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
1705 }
1706 else
1707 {
1708 // When we're at off-processor data, we have to stick with the
1709 // standard SumIntoGlobalValues function. Nevertheless, the way we
1710 // call it is the fastest one (any other will lead to repeated
1711 // allocation and deallocation of memory in order to call the function
1712 // we already use, which is very inefficient if writing one element at
1713 // a time).
1714 compressed = false;
1715
1716 ierr = matrix->SumIntoGlobalValues(1,
1717 &trilinos_row,
1718 n_columns,
1719 col_index_ptr,
1720 &col_value_ptr,
1721 Epetra_FECrsMatrix::ROW_MAJOR);
1722 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
1723 }
1724
1725 if constexpr (running_in_debug_mode())
1726 {
1727 if (ierr > 0)
1728 {
1729 std::cout << "------------------------------------------"
1730 << std::endl;
1731 std::cout << "Got error " << ierr << " in row " << row
1732 << " of proc " << matrix->RowMap().Comm().MyPID()
1733 << " when trying to add the columns:" << std::endl;
1734 for (TrilinosWrappers::types::int_type i = 0; i < n_columns; ++i)
1735 std::cout << col_index_ptr[i] << " ";
1736 std::cout << std::endl << std::endl;
1737 std::cout << "Matrix row "
1738 << (matrix->RowMap().MyGID(
1740 row)) == false ?
1741 "(nonlocal part)" :
1742 "")
1743 << " has the following indices:" << std::endl;
1744 std::vector<TrilinosWrappers::types::int_type> indices;
1745 const Epetra_CrsGraph *graph =
1746 (nonlocal_matrix.get() != nullptr &&
1747 matrix->RowMap().MyGID(
1748 static_cast<TrilinosWrappers::types::int_type>(row)) ==
1749 false) ?
1750 &nonlocal_matrix->Graph() :
1751 &matrix->Graph();
1752
1753 indices.resize(graph->NumGlobalIndices(row));
1754 int n_indices = 0;
1755 graph->ExtractGlobalRowCopy(row,
1756 indices.size(),
1757 n_indices,
1758 indices.data());
1759 AssertDimension(n_indices, indices.size());
1760
1761 for (TrilinosWrappers::types::int_type i = 0; i < n_indices; ++i)
1762 std::cout << indices[i] << " ";
1763 std::cout << std::endl << std::endl;
1764 Assert(ierr <= 0,
1765 ExcAccessToNonPresentElement(row, col_index_ptr[0]));
1766 }
1767 }
1768 Assert(ierr >= 0, ExcTrilinosError(ierr));
1769 }
1770
1771
1772
1773 SparseMatrix &
1775 {
1777 compress(VectorOperation::unknown); // TODO: why do we do this? Should we
1778 // not check for is_compressed?
1779
1780 // As checked above, we are only allowed to use d==0.0, so pass
1781 // a constant zero (instead of a run-time value 'd' that *happens* to
1782 // have a zero value) to the underlying class in hopes that the compiler
1783 // can optimize this somehow.
1784 const int ierr = matrix->PutScalar(/*d=*/0.0);
1785 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
1786
1787 if (nonlocal_matrix.get() != nullptr)
1788 {
1789 const int ierr = nonlocal_matrix->PutScalar(/*d=*/0.0);
1790 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
1791 }
1792
1793 return *this;
1794 }
1795
1796
1797
1798 void
1800 {
1801 AssertDimension(rhs.m(), m());
1802 AssertDimension(rhs.n(), n());
1805 Assert(matrix->RowMap().SameAs(rhs.matrix->RowMap()),
1806 ExcMessage("Can only add matrices with same distribution of rows"));
1807 Assert(matrix->Filled() && rhs.matrix->Filled(),
1808 ExcMessage("Addition of matrices only allowed if matrices are "
1809 "filled, i.e., compress() has been called"));
1810
1811 const bool same_col_map = matrix->ColMap().SameAs(rhs.matrix->ColMap());
1812
1813 for (const auto row : locally_owned_range_indices())
1814 {
1815 const int row_local = matrix->RowMap().LID(
1816 static_cast<TrilinosWrappers::types::int_type>(row));
1817 Assert((row_local >= 0), ExcAccessToNonlocalRow(row));
1818
1819 // First get a view to the matrix columns of both matrices. Note that
1820 // the data is in local index spaces so we need to be careful not only
1821 // to compare column indices in case they are derived from the same
1822 // map.
1823 int n_entries, rhs_n_entries;
1824 TrilinosScalar *value_ptr, *rhs_value_ptr;
1825 int *index_ptr, *rhs_index_ptr;
1826 int ierr = rhs.matrix->ExtractMyRowView(row_local,
1827 rhs_n_entries,
1828 rhs_value_ptr,
1829 rhs_index_ptr);
1830 Assert(ierr == 0, ExcTrilinosError(ierr));
1831
1832 ierr =
1833 matrix->ExtractMyRowView(row_local, n_entries, value_ptr, index_ptr);
1834 Assert(ierr == 0, ExcTrilinosError(ierr));
1835 bool expensive_checks = (n_entries != rhs_n_entries || !same_col_map);
1836 if (!expensive_checks)
1837 {
1838 // check if the column indices are the same. If yes, can simply
1839 // copy over the data.
1840 expensive_checks = std::memcmp(static_cast<void *>(index_ptr),
1841 static_cast<void *>(rhs_index_ptr),
1842 sizeof(int) * n_entries) != 0;
1843 if (!expensive_checks)
1844 for (int i = 0; i < n_entries; ++i)
1845 value_ptr[i] += rhs_value_ptr[i] * factor;
1846 }
1847 // Now to the expensive case where we need to check all column indices
1848 // against each other (transformed into global index space) and where
1849 // we need to make sure that all entries we are about to add into the
1850 // lhs matrix actually exist
1851 if (expensive_checks)
1852 {
1853 for (int i = 0; i < rhs_n_entries; ++i)
1854 {
1855 if (rhs_value_ptr[i] == 0.)
1856 continue;
1857 const TrilinosWrappers::types::int_type rhs_global_col =
1858 global_column_index(*rhs.matrix, rhs_index_ptr[i]);
1859 int local_col = matrix->ColMap().LID(rhs_global_col);
1860 int *local_index = Utilities::lower_bound(index_ptr,
1861 index_ptr + n_entries,
1862 local_col);
1863 Assert(local_index != index_ptr + n_entries &&
1864 *local_index == local_col,
1865 ExcMessage(
1866 "Adding the entries from the other matrix "
1867 "failed, because the sparsity pattern "
1868 "of that matrix includes more elements than the "
1869 "calling matrix, which is not allowed."));
1870 value_ptr[local_index - index_ptr] += factor * rhs_value_ptr[i];
1871 }
1872 }
1873 }
1874 }
1875
1876
1877
1878 void
1880 {
1881 // This only flips a flag that tells
1882 // Trilinos that any vmult operation
1883 // should be done with the
1884 // transpose. However, the matrix
1885 // structure is not reset.
1886 int ierr;
1887
1888 if (!matrix->UseTranspose())
1889 {
1890 ierr = matrix->SetUseTranspose(true);
1891 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
1892 }
1893 else
1894 {
1895 ierr = matrix->SetUseTranspose(false);
1896 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
1897 }
1898 }
1899
1900
1901
1902 SparseMatrix &
1904 {
1905 const int ierr = matrix->Scale(a);
1906 Assert(ierr == 0, ExcTrilinosError(ierr));
1907
1908 return *this;
1909 }
1910
1911
1912
1913 SparseMatrix &
1915 {
1916 Assert(a != 0, ExcDivideByZero());
1917
1918 const TrilinosScalar factor = 1. / a;
1919
1920 const int ierr = matrix->Scale(factor);
1921 Assert(ierr == 0, ExcTrilinosError(ierr));
1922
1923 return *this;
1924 }
1925
1926
1927
1930 {
1931 Assert(matrix->Filled(), ExcMatrixNotCompressed());
1932 return matrix->NormOne();
1933 }
1934
1935
1936
1939 {
1940 Assert(matrix->Filled(), ExcMatrixNotCompressed());
1941 return matrix->NormInf();
1942 }
1943
1944
1945
1948 {
1949 Assert(matrix->Filled(), ExcMatrixNotCompressed());
1950 return matrix->NormFrobenius();
1951 }
1952
1953
1954
1955 namespace internal
1956 {
1957 namespace SparseMatrixImplementation
1958 {
1959 template <typename VectorType>
1960 void
1961 check_vector_map_equality(const Epetra_CrsMatrix &,
1962 const VectorType &,
1963 const VectorType &)
1964 {}
1965
1966 void
1967 check_vector_map_equality(const Epetra_CrsMatrix &m,
1970 {
1971 Assert(in.trilinos_partitioner().SameAs(m.DomainMap()) == true,
1972 ExcMessage("The column partitioning of a matrix does not match "
1973 "the partitioning of a vector you are trying to "
1974 "multiply it with. Are you multiplying the "
1975 "matrix with a vector that has ghost elements?"));
1976 Assert(out.trilinos_partitioner().SameAs(m.RangeMap()) == true,
1977 ExcMessage("The row partitioning of a matrix does not match "
1978 "the partitioning of a vector you are trying to "
1979 "put the result of a matrix-vector product in. "
1980 "Are you trying to put the product of the "
1981 "matrix with a vector into a vector that has "
1982 "ghost elements?"));
1983 }
1984 } // namespace SparseMatrixImplementation
1985 } // namespace internal
1986
1987
1988 template <typename VectorType>
1989 void
1990 SparseMatrix::vmult(VectorType &dst, const VectorType &src) const
1991 {
1992 if constexpr (std::is_same_v<typename VectorType::value_type,
1994 {
1995 Assert(&src != &dst, ExcSourceEqualsDestination());
1996 Assert(matrix->Filled(), ExcMatrixNotCompressed());
1997
1999 src,
2000 dst);
2001 const size_type dst_local_size =
2002 internal::end(dst) - internal::begin(dst);
2003 AssertDimension(dst_local_size, matrix->RangeMap().NumMyPoints());
2004 const size_type src_local_size =
2005 internal::end(src) - internal::begin(src);
2006 AssertDimension(src_local_size, matrix->DomainMap().NumMyPoints());
2007
2008 Epetra_MultiVector tril_dst(
2009 View, matrix->RangeMap(), internal::begin(dst), dst_local_size, 1);
2010 Epetra_MultiVector tril_src(View,
2011 matrix->DomainMap(),
2012 const_cast<TrilinosScalar *>(
2013 internal::begin(src)),
2014 src_local_size,
2015 1);
2016
2017 const int ierr = matrix->Multiply(false, tril_src, tril_dst);
2018 Assert(ierr == 0, ExcTrilinosError(ierr));
2019 }
2020 else
2021 {
2023 }
2024 }
2025
2026
2027
2028 template <typename VectorType>
2029 void
2030 SparseMatrix::Tvmult(VectorType &dst, const VectorType &src) const
2031 {
2032 if constexpr (std::is_same_v<typename VectorType::value_type,
2034 {
2035 Assert(&src != &dst, ExcSourceEqualsDestination());
2036 Assert(matrix->Filled(), ExcMatrixNotCompressed());
2037
2039 dst,
2040 src);
2041 const size_type dst_local_size =
2042 internal::end(dst) - internal::begin(dst);
2043 AssertDimension(dst_local_size, matrix->DomainMap().NumMyPoints());
2044 const size_type src_local_size =
2045 internal::end(src) - internal::begin(src);
2046 AssertDimension(src_local_size, matrix->RangeMap().NumMyPoints());
2047
2048 Epetra_MultiVector tril_dst(
2049 View, matrix->DomainMap(), internal::begin(dst), dst_local_size, 1);
2050 Epetra_MultiVector tril_src(View,
2051 matrix->RangeMap(),
2052 const_cast<double *>(internal::begin(src)),
2053 src_local_size,
2054 1);
2055
2056 const int ierr = matrix->Multiply(true, tril_src, tril_dst);
2057 Assert(ierr == 0, ExcTrilinosError(ierr));
2058 }
2059 else
2060 {
2062 }
2063 }
2064
2065
2066
2067 template <typename VectorType>
2068 void
2069 SparseMatrix::vmult_add(VectorType &dst, const VectorType &src) const
2070 {
2071 Assert(&src != &dst, ExcSourceEqualsDestination());
2072
2073 // Reinit a temporary vector with fast argument set, which does not
2074 // overwrite the content (to save time).
2075 VectorType tmp_vector;
2076 tmp_vector.reinit(dst, true);
2077 vmult(tmp_vector, src);
2078 dst += tmp_vector;
2079 }
2080
2081
2082
2083 template <typename VectorType>
2084 void
2085 SparseMatrix::Tvmult_add(VectorType &dst, const VectorType &src) const
2086 {
2087 Assert(&src != &dst, ExcSourceEqualsDestination());
2088
2089 // Reinit a temporary vector with fast argument set, which does not
2090 // overwrite the content (to save time).
2091 VectorType tmp_vector;
2092 tmp_vector.reinit(dst, true);
2093 Tvmult(tmp_vector, src);
2094 dst += tmp_vector;
2095 }
2096
2097
2098
2101 {
2102 AssertDimension(m(), v.size());
2103 Assert(matrix->RowMap().SameAs(matrix->DomainMap()), ExcNotQuadratic());
2104
2105 MPI::Vector temp_vector;
2106 temp_vector.reinit(v, true);
2107
2108 vmult(temp_vector, v);
2109 return temp_vector * v;
2110 }
2111
2112
2113
2116 const MPI::Vector &v) const
2117 {
2118 AssertDimension(m(), u.size());
2119 AssertDimension(m(), v.size());
2120 Assert(matrix->RowMap().SameAs(matrix->DomainMap()), ExcNotQuadratic());
2121
2122 MPI::Vector temp_vector;
2123 temp_vector.reinit(v, true);
2124
2125 vmult(temp_vector, v);
2126 return u * temp_vector;
2127 }
2128
2129
2130
2131 namespace internals
2132 {
2133 void
2134 perform_mmult(const SparseMatrix &inputleft,
2135 const SparseMatrix &inputright,
2136 SparseMatrix &result,
2137 const MPI::Vector &V,
2138 const bool transpose_left)
2139 {
2140 const bool use_vector = (V.size() == inputright.m() ? true : false);
2141 if (transpose_left == false)
2142 {
2143 Assert(inputleft.n() == inputright.m(),
2144 ExcDimensionMismatch(inputleft.n(), inputright.m()));
2145 Assert(inputleft.trilinos_matrix().DomainMap().SameAs(
2146 inputright.trilinos_matrix().RangeMap()),
2147 ExcMessage("Parallel partitioning of A and B does not fit."));
2148 }
2149 else
2150 {
2151 Assert(inputleft.m() == inputright.m(),
2152 ExcDimensionMismatch(inputleft.m(), inputright.m()));
2153 Assert(inputleft.trilinos_matrix().RangeMap().SameAs(
2154 inputright.trilinos_matrix().RangeMap()),
2155 ExcMessage("Parallel partitioning of A and B does not fit."));
2156 }
2157
2158 result.clear();
2159
2160 // create a suitable operator B: in case
2161 // we do not use a vector, all we need to
2162 // do is to set the pointer. Otherwise,
2163 // we insert the data from B, but
2164 // multiply each row with the respective
2165 // vector element.
2166 Teuchos::RCP<Epetra_CrsMatrix> mod_B;
2167 if (use_vector == false)
2168 {
2169 mod_B = Teuchos::rcp(const_cast<Epetra_CrsMatrix *>(
2170 &inputright.trilinos_matrix()),
2171 false);
2172 }
2173 else
2174 {
2175 mod_B = Teuchos::rcp(
2176 new Epetra_CrsMatrix(Copy, inputright.trilinos_sparsity_pattern()),
2177 true);
2178 mod_B->FillComplete(inputright.trilinos_matrix().DomainMap(),
2179 inputright.trilinos_matrix().RangeMap());
2180 Assert(inputright.local_range() == V.local_range(),
2181 ExcMessage("Parallel distribution of matrix B and vector V "
2182 "does not match."));
2183
2184 const int local_N = inputright.local_size();
2185 for (int i = 0; i < local_N; ++i)
2186 {
2187 int N_entries = -1;
2188 double *new_data, *B_data;
2189 mod_B->ExtractMyRowView(i, N_entries, new_data);
2190 inputright.trilinos_matrix().ExtractMyRowView(i,
2191 N_entries,
2192 B_data);
2193 double value = V.trilinos_vector()[0][i];
2194 for (TrilinosWrappers::types::int_type j = 0; j < N_entries; ++j)
2195 new_data[j] = value * B_data[j];
2196 }
2197 }
2198
2199
2200 SparseMatrix tmp_result(transpose_left ?
2201 inputleft.locally_owned_domain_indices() :
2202 inputleft.locally_owned_range_indices(),
2203 inputright.locally_owned_domain_indices(),
2204 inputleft.get_mpi_communicator(),
2205 0);
2206
2207# ifdef DEAL_II_TRILINOS_WITH_EPETRAEXT
2208 EpetraExt::MatrixMatrix::Multiply(inputleft.trilinos_matrix(),
2209 transpose_left,
2210 *mod_B,
2211 false,
2212 const_cast<Epetra_CrsMatrix &>(
2213 tmp_result.trilinos_matrix()));
2214# else
2215 Assert(false,
2216 ExcMessage("This function requires that the Trilinos "
2217 "installation found while running the deal.II "
2218 "CMake scripts contains the optional Trilinos "
2219 "package 'EpetraExt'. However, this optional "
2220 "part of Trilinos was not found."));
2221# endif
2222 result.reinit(tmp_result.trilinos_matrix());
2223 }
2224 } // namespace internals
2225
2226
2227 void
2229 const SparseMatrix &B,
2230 const MPI::Vector &V) const
2231 {
2232 internals::perform_mmult(*this, B, C, V, false);
2233 }
2234
2235
2236
2237 void
2239 const SparseMatrix &B,
2240 const MPI::Vector &V) const
2241 {
2242 internals::perform_mmult(*this, B, C, V, true);
2243 }
2244
2245
2246
2247 void
2252
2253
2254
2255 // As of now, no particularly neat
2256 // output is generated in case of
2257 // multiple processors.
2258 void
2259 SparseMatrix::print(std::ostream &out,
2260 const bool print_detailed_trilinos_information) const
2261 {
2262 if (print_detailed_trilinos_information == true)
2263 out << *matrix;
2264 else
2265 {
2266 double *values;
2267 int *indices;
2268 int num_entries;
2269
2270 for (int i = 0; i < matrix->NumMyRows(); ++i)
2271 {
2272 const int ierr =
2273 matrix->ExtractMyRowView(i, num_entries, values, indices);
2274 Assert(ierr == 0, ExcTrilinosError(ierr));
2275
2276 for (TrilinosWrappers::types::int_type j = 0; j < num_entries; ++j)
2278 << ","
2280 << ") " << values[j] << std::endl;
2281 }
2282 }
2283
2284 AssertThrow(out.fail() == false, ExcIO());
2285 }
2286
2287
2288
2291 {
2292 size_type static_memory =
2293 sizeof(*this) + sizeof(*matrix) + sizeof(*matrix->Graph().DataPtr());
2294 return (
2296 matrix->NumMyNonzeros() +
2297 sizeof(int) * local_size() + static_memory);
2298 }
2299
2300
2301
2302 MPI_Comm
2304 {
2305 const Epetra_MpiComm *mpi_comm =
2306 dynamic_cast<const Epetra_MpiComm *>(&matrix->RangeMap().Comm());
2307 Assert(mpi_comm != nullptr, ExcInternalError());
2308 return mpi_comm->Comm();
2309 }
2310} // namespace TrilinosWrappers
2311
2312
2313namespace TrilinosWrappers
2314{
2315 namespace internal
2316 {
2317 namespace LinearOperatorImplementation
2318 {
2320
2322 : use_transpose(false)
2323 , communicator(MPI_COMM_SELF)
2324 , domain_map(IndexSet().make_trilinos_map(communicator.Comm()))
2325 , range_map(IndexSet().make_trilinos_map(communicator.Comm()))
2326 {
2327 vmult = [](Range &, const Domain &) {
2328 Assert(false,
2329 ExcMessage("Uninitialized TrilinosPayload::vmult called "
2330 "(Default constructor)"));
2331 };
2332
2333 Tvmult = [](Domain &, const Range &) {
2334 Assert(false,
2335 ExcMessage("Uninitialized TrilinosPayload::Tvmult called "
2336 "(Default constructor)"));
2337 };
2338
2339 inv_vmult = [](Domain &, const Range &) {
2340 Assert(false,
2341 ExcMessage("Uninitialized TrilinosPayload::inv_vmult called "
2342 "(Default constructor)"));
2343 };
2344
2345 inv_Tvmult = [](Range &, const Domain &) {
2346 Assert(false,
2347 ExcMessage("Uninitialized TrilinosPayload::inv_Tvmult called "
2348 "(Default constructor)"));
2349 };
2350 }
2351
2352
2353
2355 const TrilinosWrappers::SparseMatrix &matrix_exemplar,
2356 const TrilinosWrappers::SparseMatrix &matrix)
2357 : TrilinosPayload(const_cast<Epetra_CrsMatrix &>(
2358 matrix.trilinos_matrix()),
2359 /*op_supports_inverse_operations = */ false,
2360 matrix_exemplar.trilinos_matrix().UseTranspose(),
2361 matrix_exemplar.get_mpi_communicator(),
2362 matrix_exemplar.locally_owned_domain_indices(),
2363 matrix_exemplar.locally_owned_range_indices())
2364 {}
2365
2366
2367
2369 const TrilinosPayload &payload_exemplar,
2370 const TrilinosWrappers::SparseMatrix &matrix)
2371
2372 : TrilinosPayload(const_cast<Epetra_CrsMatrix &>(
2373 matrix.trilinos_matrix()),
2374 /*op_supports_inverse_operations = */ false,
2375 payload_exemplar.UseTranspose(),
2376 payload_exemplar.get_mpi_communicator(),
2377 payload_exemplar.locally_owned_domain_indices(),
2378 payload_exemplar.locally_owned_range_indices())
2379 {}
2380
2381
2382
2384 const TrilinosWrappers::SparseMatrix &matrix_exemplar,
2385 const TrilinosWrappers::PreconditionBase &preconditioner)
2386 : TrilinosPayload(preconditioner.trilinos_operator(),
2387 /*op_supports_inverse_operations = */ true,
2388 matrix_exemplar.trilinos_matrix().UseTranspose(),
2389 matrix_exemplar.get_mpi_communicator(),
2390 matrix_exemplar.locally_owned_domain_indices(),
2391 matrix_exemplar.locally_owned_range_indices())
2392 {}
2393
2394
2395
2397 const TrilinosWrappers::PreconditionBase &preconditioner_exemplar,
2398 const TrilinosWrappers::PreconditionBase &preconditioner)
2400 preconditioner.trilinos_operator(),
2401 /*op_supports_inverse_operations = */ true,
2402 preconditioner_exemplar.trilinos_operator().UseTranspose(),
2403 preconditioner_exemplar.get_mpi_communicator(),
2404 preconditioner_exemplar.locally_owned_domain_indices(),
2405 preconditioner_exemplar.locally_owned_range_indices())
2406 {}
2407
2408
2409
2411 const TrilinosPayload &payload_exemplar,
2412 const TrilinosWrappers::PreconditionBase &preconditioner)
2413 : TrilinosPayload(preconditioner.trilinos_operator(),
2414 /*op_supports_inverse_operations = */ true,
2415 payload_exemplar.UseTranspose(),
2416 payload_exemplar.get_mpi_communicator(),
2417 payload_exemplar.locally_owned_domain_indices(),
2418 payload_exemplar.locally_owned_range_indices())
2419 {}
2420
2421
2422
2424 : vmult(payload.vmult)
2425 , Tvmult(payload.Tvmult)
2426 , inv_vmult(payload.inv_vmult)
2427 , inv_Tvmult(payload.inv_Tvmult)
2428 , use_transpose(payload.use_transpose)
2429 , communicator(payload.communicator)
2430 , domain_map(payload.domain_map)
2431 , range_map(payload.range_map)
2432 {}
2433
2434
2435
2436 // Composite copy constructor
2437 // This is required for PackagedOperations
2439 const TrilinosPayload &second_op)
2440 : use_transpose(false)
2441 , // The combination of operators provides the exact
2442 // definition of the operation
2443 communicator(first_op.communicator)
2444 , domain_map(second_op.domain_map)
2445 , range_map(first_op.range_map)
2446 {}
2447
2448
2449
2452 {
2453 TrilinosPayload return_op(*this);
2454
2455 return_op.vmult = [](Range &tril_dst, const Range &tril_src) {
2456 tril_dst = tril_src;
2457 };
2458
2459 return_op.Tvmult = [](Range &tril_dst, const Range &tril_src) {
2460 tril_dst = tril_src;
2461 };
2462
2463 return_op.inv_vmult = [](Range &tril_dst, const Range &tril_src) {
2464 tril_dst = tril_src;
2465 };
2466
2467 return_op.inv_Tvmult = [](Range &tril_dst, const Range &tril_src) {
2468 tril_dst = tril_src;
2469 };
2470
2471 return return_op;
2472 }
2473
2474
2475
2478 {
2479 TrilinosPayload return_op(*this);
2480
2481 return_op.vmult = [](Range &tril_dst, const Domain &) {
2482 const int ierr = tril_dst.PutScalar(0.0);
2483
2484 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
2485 };
2486
2487 return_op.Tvmult = [](Domain &tril_dst, const Range &) {
2488 const int ierr = tril_dst.PutScalar(0.0);
2489
2490 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
2491 };
2492
2493 return_op.inv_vmult = [](Domain &tril_dst, const Range &) {
2494 AssertThrow(false,
2495 ExcMessage("Cannot compute inverse of null operator"));
2496
2497 const int ierr = tril_dst.PutScalar(0.0);
2498
2499 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
2500 };
2501
2502 return_op.inv_Tvmult = [](Range &tril_dst, const Domain &) {
2503 AssertThrow(false,
2504 ExcMessage("Cannot compute inverse of null operator"));
2505
2506 const int ierr = tril_dst.PutScalar(0.0);
2507
2508 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
2509 };
2510
2511 return return_op;
2512 }
2513
2514
2515
2518 {
2519 TrilinosPayload return_op(*this);
2520 return_op.transpose();
2521 return return_op;
2522 }
2523
2524
2525
2526 IndexSet
2531
2532
2533
2534 IndexSet
2539
2540
2541
2542 MPI_Comm
2544 {
2545 return communicator.Comm();
2546 }
2547
2548
2549
2550 void
2555
2556
2557
2558 bool
2560 {
2561 return use_transpose;
2562 }
2563
2564
2565
2566 int
2568 {
2570 {
2572 std::swap(domain_map, range_map);
2573 std::swap(vmult, Tvmult);
2574 std::swap(inv_vmult, inv_Tvmult);
2575 }
2576 return 0;
2577 }
2578
2579
2580
2581 int
2583 {
2584 // The transposedness of the operations is taken care of
2585 // when we hit the transpose flag.
2586 vmult(Y, X);
2587 return 0;
2588 }
2589
2590
2591
2592 int
2594 {
2595 // The transposedness of the operations is taken care of
2596 // when we hit the transpose flag.
2597 inv_vmult(X, Y);
2598 return 0;
2599 }
2600
2601
2602
2603 const char *
2605 {
2606 return "TrilinosPayload";
2607 }
2608
2609
2610
2611 const Epetra_Comm &
2613 {
2614 return communicator;
2615 }
2616
2617
2618
2619 const Epetra_Map &
2621 {
2622 return domain_map;
2623 }
2624
2625
2626
2627 const Epetra_Map &
2629 {
2630 return range_map;
2631 }
2632
2633
2634
2635 bool
2637 {
2638 return false;
2639 }
2640
2641
2642
2643 double
2645 {
2647 return 0.0;
2648 }
2649
2650
2651
2654 const TrilinosPayload &second_op)
2655 {
2656 using Domain = typename TrilinosPayload::Domain;
2657 using Range = typename TrilinosPayload::Range;
2658 using Intermediate = typename TrilinosPayload::VectorType;
2659 using GVMVectorType = TrilinosWrappers::MPI::Vector;
2660
2662 second_op.locally_owned_domain_indices(),
2663 ExcMessage(
2664 "Operators are set to work on incompatible IndexSets."));
2666 second_op.locally_owned_range_indices(),
2667 ExcMessage(
2668 "Operators are set to work on incompatible IndexSets."));
2669
2670 TrilinosPayload return_op(first_op, second_op);
2671
2672 // Capture by copy so the payloads are always valid
2673 return_op.vmult = [first_op, second_op](Range &tril_dst,
2674 const Domain &tril_src) {
2675 // Duplicated from LinearOperator::operator*
2676 // TODO: Template the constructor on GrowingVectorMemory vector type?
2678 VectorMemory<GVMVectorType>::Pointer i(vector_memory);
2679
2680 // Initialize intermediate vector
2681 const Epetra_Map &first_op_init_map = first_op.OperatorDomainMap();
2682 i->reinit(IndexSet(first_op_init_map),
2683 first_op.get_mpi_communicator(),
2684 /*bool omit_zeroing_entries =*/true);
2685
2686 // Duplicated from TrilinosWrappers::SparseMatrix::vmult
2687 const size_type i_local_size = i->end() - i->begin();
2688 AssertDimension(i_local_size, first_op_init_map.NumMyPoints());
2689 const Epetra_Map &second_op_init_map = second_op.OperatorDomainMap();
2690 AssertDimension(i_local_size, second_op_init_map.NumMyPoints());
2691 Intermediate tril_int(View,
2692 first_op_init_map,
2693 const_cast<TrilinosScalar *>(i->begin()),
2694 i_local_size,
2695 1);
2696
2697 // These operators may themselves be transposed or not, so we let them
2698 // decide what the intended outcome is
2699 second_op.Apply(tril_src, tril_int);
2700 first_op.Apply(tril_src, tril_dst);
2701 const int ierr = tril_dst.Update(1.0, tril_int, 1.0);
2702 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
2703 };
2704
2705 return_op.Tvmult = [first_op, second_op](Domain &tril_dst,
2706 const Range &tril_src) {
2707 // Duplicated from LinearOperator::operator*
2708 // TODO: Template the constructor on GrowingVectorMemory vector type?
2710 VectorMemory<GVMVectorType>::Pointer i(vector_memory);
2711
2712 // These operators may themselves be transposed or not, so we let them
2713 // decide what the intended outcome is
2714 // We must first transpose the operators to get the right IndexSets
2715 // for the input, intermediate and result vectors
2716 const_cast<TrilinosPayload &>(first_op).transpose();
2717 const_cast<TrilinosPayload &>(second_op).transpose();
2718
2719 // Initialize intermediate vector
2720 const Epetra_Map &first_op_init_map = first_op.OperatorRangeMap();
2721 i->reinit(IndexSet(first_op_init_map),
2722 first_op.get_mpi_communicator(),
2723 /*bool omit_zeroing_entries =*/true);
2724
2725 // Duplicated from TrilinosWrappers::SparseMatrix::vmult
2726 const size_type i_local_size = i->end() - i->begin();
2727 AssertDimension(i_local_size, first_op_init_map.NumMyPoints());
2728 const Epetra_Map &second_op_init_map = second_op.OperatorRangeMap();
2729 AssertDimension(i_local_size, second_op_init_map.NumMyPoints());
2730 Intermediate tril_int(View,
2731 first_op_init_map,
2732 const_cast<TrilinosScalar *>(i->begin()),
2733 i_local_size,
2734 1);
2735
2736 // These operators may themselves be transposed or not, so we let them
2737 // decide what the intended outcome is
2738 second_op.Apply(tril_src, tril_int);
2739 first_op.Apply(tril_src, tril_dst);
2740 const int ierr = tril_dst.Update(1.0, tril_int, 1.0);
2741 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
2742
2743 // Reset transpose flag
2744 const_cast<TrilinosPayload &>(first_op).transpose();
2745 const_cast<TrilinosPayload &>(second_op).transpose();
2746 };
2747
2748 return_op.inv_vmult = [first_op, second_op](Domain &tril_dst,
2749 const Range &tril_src) {
2750 // Duplicated from LinearOperator::operator*
2751 // TODO: Template the constructor on GrowingVectorMemory vector type?
2753 VectorMemory<GVMVectorType>::Pointer i(vector_memory);
2754
2755 // Initialize intermediate vector
2756 const Epetra_Map &first_op_init_map = first_op.OperatorRangeMap();
2757 i->reinit(IndexSet(first_op_init_map),
2758 first_op.get_mpi_communicator(),
2759 /*bool omit_zeroing_entries =*/true);
2760
2761 // Duplicated from TrilinosWrappers::SparseMatrix::vmult
2762 const size_type i_local_size = i->end() - i->begin();
2763 AssertDimension(i_local_size, first_op_init_map.NumMyPoints());
2764 const Epetra_Map &second_op_init_map = second_op.OperatorRangeMap();
2765 AssertDimension(i_local_size, second_op_init_map.NumMyPoints());
2766 Intermediate tril_int(View,
2767 first_op_init_map,
2768 const_cast<TrilinosScalar *>(i->begin()),
2769 i_local_size,
2770 1);
2771
2772 // These operators may themselves be transposed or not, so we let them
2773 // decide what the intended outcome is
2774 second_op.ApplyInverse(tril_src, tril_int);
2775 first_op.ApplyInverse(tril_src, tril_dst);
2776 const int ierr = tril_dst.Update(1.0, tril_int, 1.0);
2777 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
2778 };
2779
2780 return_op.inv_Tvmult = [first_op, second_op](Range &tril_dst,
2781 const Domain &tril_src) {
2782 // Duplicated from LinearOperator::operator*
2783 // TODO: Template the constructor on GrowingVectorMemory vector type?
2785 VectorMemory<GVMVectorType>::Pointer i(vector_memory);
2786
2787 // These operators may themselves be transposed or not, so we let them
2788 // decide what the intended outcome is
2789 // We must first transpose the operators to get the right IndexSets
2790 // for the input, intermediate and result vectors
2791 const_cast<TrilinosPayload &>(first_op).transpose();
2792 const_cast<TrilinosPayload &>(second_op).transpose();
2793
2794 // Initialize intermediate vector
2795 const Epetra_Map &first_op_init_map = first_op.OperatorDomainMap();
2796 i->reinit(IndexSet(first_op_init_map),
2797 first_op.get_mpi_communicator(),
2798 /*bool omit_zeroing_entries =*/true);
2799
2800 // Duplicated from TrilinosWrappers::SparseMatrix::vmult
2801 const size_type i_local_size = i->end() - i->begin();
2802 AssertDimension(i_local_size, first_op_init_map.NumMyPoints());
2803 const Epetra_Map &second_op_init_map = second_op.OperatorDomainMap();
2804 AssertDimension(i_local_size, second_op_init_map.NumMyPoints());
2805 Intermediate tril_int(View,
2806 first_op_init_map,
2807 const_cast<TrilinosScalar *>(i->begin()),
2808 i_local_size,
2809 1);
2810
2811 // These operators may themselves be transposed or not, so we let them
2812 // decide what the intended outcome is
2813 second_op.ApplyInverse(tril_src, tril_int);
2814 first_op.ApplyInverse(tril_src, tril_dst);
2815 const int ierr = tril_dst.Update(1.0, tril_int, 1.0);
2816 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
2817
2818 // Reset transpose flag
2819 const_cast<TrilinosPayload &>(first_op).transpose();
2820 const_cast<TrilinosPayload &>(second_op).transpose();
2821 };
2822
2823 return return_op;
2824 }
2825
2826
2827
2828 TrilinosPayload
2830 const TrilinosPayload &second_op)
2831 {
2832 using Domain = typename TrilinosPayload::Domain;
2833 using Range = typename TrilinosPayload::Range;
2834 using Intermediate = typename TrilinosPayload::VectorType;
2835 using GVMVectorType = TrilinosWrappers::MPI::Vector;
2836
2838 second_op.locally_owned_range_indices(),
2839 ExcMessage(
2840 "Operators are set to work on incompatible IndexSets."));
2841
2842 TrilinosPayload return_op(first_op, second_op);
2843
2844 // Capture by copy so the payloads are always valid
2845 return_op.vmult = [first_op, second_op](Range &tril_dst,
2846 const Domain &tril_src) {
2847 // Duplicated from LinearOperator::operator*
2848 // TODO: Template the constructor on GrowingVectorMemory vector type?
2850 VectorMemory<GVMVectorType>::Pointer i(vector_memory);
2851
2852 // Initialize intermediate vector
2853 const Epetra_Map &first_op_init_map = first_op.OperatorDomainMap();
2854 i->reinit(IndexSet(first_op_init_map),
2855 first_op.get_mpi_communicator(),
2856 /*bool omit_zeroing_entries =*/true);
2857
2858 // Duplicated from TrilinosWrappers::SparseMatrix::vmult
2859 const size_type i_local_size = i->end() - i->begin();
2860 AssertDimension(i_local_size, first_op_init_map.NumMyPoints());
2861 const Epetra_Map &second_op_init_map = second_op.OperatorRangeMap();
2862 AssertDimension(i_local_size, second_op_init_map.NumMyPoints());
2863 Intermediate tril_int(View,
2864 first_op_init_map,
2865 const_cast<TrilinosScalar *>(i->begin()),
2866 i_local_size,
2867 1);
2868
2869 // These operators may themselves be transposed or not, so we let them
2870 // decide what the intended outcome is
2871 second_op.Apply(tril_src, tril_int);
2872 first_op.Apply(tril_int, tril_dst);
2873 };
2874
2875 return_op.Tvmult = [first_op, second_op](Domain &tril_dst,
2876 const Range &tril_src) {
2877 // Duplicated from LinearOperator::operator*
2878 // TODO: Template the constructor on GrowingVectorMemory vector type?
2880 VectorMemory<GVMVectorType>::Pointer i(vector_memory);
2881
2882 // These operators may themselves be transposed or not, so we let them
2883 // decide what the intended outcome is
2884 // We must first transpose the operators to get the right IndexSets
2885 // for the input, intermediate and result vectors
2886 const_cast<TrilinosPayload &>(first_op).transpose();
2887 const_cast<TrilinosPayload &>(second_op).transpose();
2888
2889 // Initialize intermediate vector
2890 const Epetra_Map &first_op_init_map = first_op.OperatorRangeMap();
2891 i->reinit(IndexSet(first_op_init_map),
2892 first_op.get_mpi_communicator(),
2893 /*bool omit_zeroing_entries =*/true);
2894
2895 // Duplicated from TrilinosWrappers::SparseMatrix::vmult
2896 const size_type i_local_size = i->end() - i->begin();
2897 AssertDimension(i_local_size, first_op_init_map.NumMyPoints());
2898 const Epetra_Map &second_op_init_map = second_op.OperatorDomainMap();
2899 AssertDimension(i_local_size, second_op_init_map.NumMyPoints());
2900 Intermediate tril_int(View,
2901 first_op_init_map,
2902 const_cast<TrilinosScalar *>(i->begin()),
2903 i_local_size,
2904 1);
2905
2906 // Apply the operators in the reverse order to vmult
2907 first_op.Apply(tril_src, tril_int);
2908 second_op.Apply(tril_int, tril_dst);
2909
2910 // Reset transpose flag
2911 const_cast<TrilinosPayload &>(first_op).transpose();
2912 const_cast<TrilinosPayload &>(second_op).transpose();
2913 };
2914
2915 return_op.inv_vmult = [first_op, second_op](Domain &tril_dst,
2916 const Range &tril_src) {
2917 // Duplicated from LinearOperator::operator*
2918 // TODO: Template the constructor on GrowingVectorMemory vector type?
2920 VectorMemory<GVMVectorType>::Pointer i(vector_memory);
2921
2922 // Initialize intermediate vector
2923 const Epetra_Map &first_op_init_map = first_op.OperatorRangeMap();
2924 i->reinit(IndexSet(first_op_init_map),
2925 first_op.get_mpi_communicator(),
2926 /*bool omit_zeroing_entries =*/true);
2927
2928 // Duplicated from TrilinosWrappers::SparseMatrix::vmult
2929 const size_type i_local_size = i->end() - i->begin();
2930 AssertDimension(i_local_size, first_op_init_map.NumMyPoints());
2931 const Epetra_Map &second_op_init_map = second_op.OperatorDomainMap();
2932 AssertDimension(i_local_size, second_op_init_map.NumMyPoints());
2933 Intermediate tril_int(View,
2934 first_op_init_map,
2935 const_cast<TrilinosScalar *>(i->begin()),
2936 i_local_size,
2937 1);
2938
2939 // Apply the operators in the reverse order to vmult
2940 // and the same order as Tvmult
2941 first_op.ApplyInverse(tril_src, tril_int);
2942 second_op.ApplyInverse(tril_int, tril_dst);
2943 };
2944
2945 return_op.inv_Tvmult = [first_op, second_op](Range &tril_dst,
2946 const Domain &tril_src) {
2947 // Duplicated from LinearOperator::operator*
2948 // TODO: Template the constructor on GrowingVectorMemory vector type?
2950 VectorMemory<GVMVectorType>::Pointer i(vector_memory);
2951
2952 // These operators may themselves be transposed or not, so we let them
2953 // decide what the intended outcome is
2954 // We must first transpose the operators to get the right IndexSets
2955 // for the input, intermediate and result vectors
2956 const_cast<TrilinosPayload &>(first_op).transpose();
2957 const_cast<TrilinosPayload &>(second_op).transpose();
2958
2959 // Initialize intermediate vector
2960 const Epetra_Map &first_op_init_map = first_op.OperatorDomainMap();
2961 i->reinit(IndexSet(first_op_init_map),
2962 first_op.get_mpi_communicator(),
2963 /*bool omit_zeroing_entries =*/true);
2964
2965 // Duplicated from TrilinosWrappers::SparseMatrix::vmult
2966 const size_type i_local_size = i->end() - i->begin();
2967 AssertDimension(i_local_size, first_op_init_map.NumMyPoints());
2968 const Epetra_Map &second_op_init_map = second_op.OperatorRangeMap();
2969 AssertDimension(i_local_size, second_op_init_map.NumMyPoints());
2970 Intermediate tril_int(View,
2971 first_op_init_map,
2972 const_cast<TrilinosScalar *>(i->begin()),
2973 i_local_size,
2974 1);
2975
2976 // These operators may themselves be transposed or not, so we let them
2977 // decide what the intended outcome is
2978 // Apply the operators in the reverse order to Tvmult
2979 // and the same order as vmult
2980 second_op.ApplyInverse(tril_src, tril_int);
2981 first_op.ApplyInverse(tril_int, tril_dst);
2982
2983 // Reset transpose flag
2984 const_cast<TrilinosPayload &>(first_op).transpose();
2985 const_cast<TrilinosPayload &>(second_op).transpose();
2986 };
2987
2988 return return_op;
2989 }
2990
2991 } // namespace LinearOperatorImplementation
2992 } /* namespace internal */
2993} /* namespace TrilinosWrappers */
2994
2995
2996
2997// explicit instantiations
2998# include "lac/trilinos_sparse_matrix.inst"
2999
3000# ifndef DOXYGEN
3001// TODO: put these instantiations into generic file
3002namespace TrilinosWrappers
3003{
3004 template void
3005 SparseMatrix::reinit(const ::SparsityPattern &);
3006
3007 template void
3009
3010 template void
3012 const IndexSet &,
3013 const ::SparsityPattern &,
3014 const MPI_Comm,
3015 const bool);
3016
3017 template void
3019 const IndexSet &,
3020 const DynamicSparsityPattern &,
3021 const MPI_Comm,
3022 const bool);
3023
3024 template void
3025 SparseMatrix::vmult(MPI::Vector &, const MPI::Vector &) const;
3026
3027 template void
3029 const ::Vector<double> &) const;
3030
3031 template void
3034 const ::LinearAlgebra::distributed::Vector<double, MemorySpace::Host>
3035 &) const;
3036
3037 template void
3040 const ::LinearAlgebra::distributed::Vector<float, MemorySpace::Host>
3041 &) const;
3042
3043 template void
3046 const ::LinearAlgebra::EpetraWrappers::Vector &) const;
3047
3048 template void
3049 SparseMatrix::Tvmult(MPI::Vector &, const MPI::Vector &) const;
3050
3051 template void
3053 const ::Vector<double> &) const;
3054
3055 template void
3058 const ::LinearAlgebra::distributed::Vector<double, MemorySpace::Host>
3059 &) const;
3060
3061 template void
3064 const ::LinearAlgebra::EpetraWrappers::Vector &) const;
3065
3066 template void
3067 SparseMatrix::vmult_add(MPI::Vector &, const MPI::Vector &) const;
3068
3069 template void
3071 const ::Vector<double> &) const;
3072
3073 template void
3076 const ::LinearAlgebra::distributed::Vector<double, MemorySpace::Host>
3077 &) const;
3078
3079 template void
3082 const ::LinearAlgebra::EpetraWrappers::Vector &) const;
3083
3084 template void
3085 SparseMatrix::Tvmult_add(MPI::Vector &, const MPI::Vector &) const;
3086
3087 template void
3089 const ::Vector<double> &) const;
3090
3091 template void
3094 const ::LinearAlgebra::distributed::Vector<double, MemorySpace::Host>
3095 &) const;
3096
3097 template void
3100 const ::LinearAlgebra::distributed::Vector<float, MemorySpace::Host>
3101 &) const;
3102
3103 template void
3106 const ::LinearAlgebra::EpetraWrappers::Vector &) const;
3107} // namespace TrilinosWrappers
3108# endif // DOXYGEN
3109
3110
3111#endif // DEAL_II_WITH_TRILINOS
*  iterator end()
*  *  iterator begin()
*  *  reference operator*() const
const IndexSet & row_index_set() const
size_type row_length(const size_type row) const
size_type column_number(const size_type row, const size_type index) const
size_type size() const
Definition index_set.h:1759
bool is_element(const size_type index) const
Definition index_set.h:1877
Epetra_Map make_trilinos_map(const MPI_Comm communicator=MPI_COMM_WORLD, const bool overlapping=false) const
size_type n_rows() const
size_type n_cols() const
void reinit(const size_type m, const size_type n, const ArrayView< const unsigned int > &row_lengths)
void reinit(const Vector &v, const bool omit_zeroing_entries=false)
const Epetra_BlockMap & trilinos_partitioner() const
size_type size() const override
std::shared_ptr< std::vector< TrilinosScalar > > value_cache
std::shared_ptr< std::vector< size_type > > colnum_cache
void set(const size_type i, const size_type j, const TrilinosScalar value)
std::unique_ptr< Epetra_Map > column_space_map
SparseMatrix & operator*=(const TrilinosScalar factor)
void mmult(SparseMatrix &C, const SparseMatrix &B, const MPI::Vector &V=MPI::Vector()) const
std::unique_ptr< Epetra_Export > nonlocal_matrix_exporter
void compress(VectorOperation::values operation)
std::unique_ptr< Epetra_FECrsMatrix > matrix
void vmult(VectorType &dst, const VectorType &src) const
const Epetra_CrsMatrix & trilinos_matrix() const
TrilinosScalar matrix_norm_square(const MPI::Vector &v) const
IndexSet locally_owned_range_indices() const
void print(std::ostream &out, const bool write_extended_trilinos_info=false) const
void Tmmult(SparseMatrix &C, const SparseMatrix &B, const MPI::Vector &V=MPI::Vector()) const
void clear_row(const size_type row, const TrilinosScalar new_diag_value=0)
void clear_rows(const ArrayView< const size_type > &rows, const TrilinosScalar new_diag_value=0)
void reinit(const SparsityPatternType &sparsity_pattern)
void vmult_add(VectorType &dst, const VectorType &src) const
SparseMatrix & operator=(const SparseMatrix &)=delete
SparseMatrix & operator/=(const TrilinosScalar factor)
void Tvmult_add(VectorType &dst, const VectorType &src) const
TrilinosScalar el(const size_type i, const size_type j) const
IndexSet locally_owned_domain_indices() const
bool in_local_range(const size_type index) const
void copy_from(const SparseMatrix &source)
unsigned int row_length(const size_type row) const
void Tvmult(VectorType &dst, const VectorType &src) const
std::uint64_t n_nonzero_elements() const
const Epetra_CrsGraph & trilinos_sparsity_pattern() const
TrilinosScalar diag_element(const size_type i) const
void add(const size_type i, const size_type j, const TrilinosScalar value)
unsigned int local_size() const
TrilinosScalar operator()(const size_type i, const size_type j) const
TrilinosScalar matrix_scalar_product(const MPI::Vector &u, const MPI::Vector &v) const
std::pair< size_type, size_type > local_range() const
std::unique_ptr< Epetra_CrsMatrix > nonlocal_matrix
std::unique_ptr< Epetra_CrsGraph > nonlocal_graph
const Epetra_FECrsGraph & trilinos_sparsity_pattern() const
::types::global_dof_index size_type
std::function< void(VectorType &, const VectorType &)> inv_Tvmult
virtual int ApplyInverse(const VectorType &Y, VectorType &X) const override
virtual int Apply(const VectorType &X, VectorType &Y) const override
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_DISABLE_EXTRA_DIAGNOSTICS
Definition config.h:636
constexpr bool running_in_debug_mode()
Definition config.h:76
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_ENABLE_EXTRA_DIAGNOSTICS
Definition config.h:680
DerivativeForm< 1, spacedim, dim, Number > transpose(const DerivativeForm< 1, dim, spacedim, Number > &DF)
#define DEAL_II_NOT_IMPLEMENTED()
Point< 2 > second
Definition grid_out.cc:4640
Point< 2 > first
Definition grid_out.cc:4639
static ::ExceptionBase & ExcIO()
static ::ExceptionBase & ExcNotImplemented()
static ::ExceptionBase & ExcScalarAssignmentOnlyForZeroValue()
static ::ExceptionBase & ExcInvalidIndex(size_type arg1, size_type arg2)
#define Assert(cond, exc)
static ::ExceptionBase & ExcAccessToNonPresentElement(size_type arg1, size_type arg2)
#define AssertIsFinite(number)
static ::ExceptionBase & ExcAccessToNonlocalRow(std::size_t arg1)
#define AssertDimension(dim1, dim2)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDivideByZero()
static ::ExceptionBase & ExcSourceEqualsDestination()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcNotQuadratic()
static ::ExceptionBase & ExcMatrixNotCompressed()
static ::ExceptionBase & ExcTrilinosError(int arg1)
static ::ExceptionBase & ExcAccessToNonLocalElement(size_type arg1, size_type arg2, size_type arg3, size_type arg4)
static ::ExceptionBase & ExcMessage(std::string arg1)
static ::ExceptionBase & ExcTrilinosError(int arg1)
#define AssertThrow(cond, exc)
IndexSet complete_index_set(const IndexSet::size_type N)
Definition index_set.h:1187
std::vector< index_type > data
Definition mpi.cc:734
bool use_vector
Definition mpi.cc:732
@ matrix
Contents is actually a matrix.
*  *  *  *  std::vector< Number > ThermoPlasticMaterial< dim, ViscoplasticYieldLaw, Number >::get_state_parameters   const
TrilinosPayload operator+(const TrilinosPayload &first_op, const TrilinosPayload &second_op)
void check_vector_map_equality(const Epetra_CrsMatrix &, const VectorType &, const VectorType &)
VectorType::value_type * end(VectorType &V)
VectorType::value_type * begin(VectorType &V)
void perform_mmult(const SparseMatrix &inputleft, const SparseMatrix &inputright, SparseMatrix &result, const MPI::Vector &V, const bool transpose_left)
TrilinosWrappers::types::int_type min_my_gid(const Epetra_BlockMap &map)
TrilinosWrappers::types::int64_type n_global_elements(const Epetra_BlockMap &map)
TrilinosWrappers::types::int_type global_column_index(const Epetra_CrsMatrix &matrix, const ::types::global_dof_index i)
TrilinosWrappers::types::int_type max_my_gid(const Epetra_BlockMap &map)
TrilinosWrappers::types::int_type global_row_index(const Epetra_CrsMatrix &matrix, const ::types::global_dof_index i)
TrilinosWrappers::types::int_type n_global_cols(const Epetra_CrsGraph &graph)
const Epetra_Comm & comm_self()
Iterator lower_bound(Iterator first, Iterator last, const T &val)
Definition utilities.h:1003
Definition types.h:30
double TrilinosScalar
Definition types.h:188