deal.II version GIT relicensing-6839-g338455934c 2026-10-02 12:10: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_sparsity_pattern.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
18# include <deal.II/base/mpi.h>
20
23
25# include <Epetra_Export.h>
27
28# include <limits>
29
30
31#endif // DEAL_II_WITH_TRILINOS
32
34
35#ifdef DEAL_II_WITH_TRILINOS
36
37namespace TrilinosWrappers
38{
40 {
41 void
43 {
44 // if we are asked to visit the past-the-end line, then simply
45 // release all our caches and go on with life
46 if (this->a_row == sparsity_pattern->n_rows() ||
47 (sparsity_pattern->in_local_range(this->a_row) == false))
48 {
49 colnum_cache.reset();
50 return;
51 }
52
53 // otherwise first flush Trilinos caches if necessary
56
57 colnum_cache = std::make_shared<std::vector<size_type>>(
59
60 if (colnum_cache->size() > 0)
61 {
62 // get a representation of the present row
63 int ncols;
64 const int ierr = sparsity_pattern->graph->ExtractGlobalRowCopy(
65 this->a_row,
66 colnum_cache->size(),
67 ncols,
68 reinterpret_cast<TrilinosWrappers::types::int_type *>(
69 const_cast<size_type *>(colnum_cache->data())));
70 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
71 AssertThrow(static_cast<std::vector<size_type>::size_type>(ncols) ==
72 colnum_cache->size(),
74 }
75 }
76 } // namespace SparsityPatternIterators
77
78
79 // The constructor is actually the
80 // only point where we have to check
81 // whether we build a serial or a
82 // parallel Trilinos matrix.
83 // Actually, it does not even matter
84 // how many threads there are, but
85 // only if we use an MPI compiler or
86 // a standard compiler. So, even one
87 // thread on a configuration with
88 // MPI will still get a parallel
89 // interface.
91 {
93 std::make_unique<Epetra_Map>(TrilinosWrappers::types::int_type(0),
96 graph = std::make_unique<Epetra_FECrsGraph>(View,
99 0);
100 graph->FillComplete();
101 }
102
103
104
106 const size_type n,
107 const size_type n_entries_per_row)
108 {
109 reinit(m, n, n_entries_per_row);
110 }
111
112
113
117
118
119
121 const size_type m,
122 const size_type n,
123 const std::vector<size_type> &n_entries_per_row)
124 {
125 reinit(m, n, n_entries_per_row);
126 }
127
128
129
131 : SparsityPatternBase(std::move(other))
132 , column_space_map(std::move(other.column_space_map))
133 , graph(std::move(other.graph))
134 , nonlocal_graph(std::move(other.nonlocal_graph))
135 {}
136
137
138
139 // Copy function only works if the
140 // sparsity pattern is empty.
142 : SparsityPatternBase(input_sparsity)
143 , column_space_map(new Epetra_Map(TrilinosWrappers::types::int_type(0),
144 TrilinosWrappers::types::int_type(0),
145 Utilities::Trilinos::comm_self()))
146 , graph(
147 new Epetra_FECrsGraph(View, *column_space_map, *column_space_map, 0))
148 {
149 Assert(input_sparsity.n_rows() == 0,
151 "Copy constructor only works for empty sparsity patterns."));
152 }
153
154
155
156 SparsityPattern::SparsityPattern(const IndexSet &parallel_partitioning,
157 const MPI_Comm communicator,
158 const size_type n_entries_per_row)
159 {
160 reinit(parallel_partitioning,
161 parallel_partitioning,
162 communicator,
163 n_entries_per_row);
164 }
165
166
167
168 SparsityPattern::SparsityPattern(const IndexSet &parallel_partitioning,
169 const MPI_Comm communicator)
170 : SparsityPattern(parallel_partitioning, communicator, 0)
171 {}
172
173
174
175 SparsityPattern::SparsityPattern(const IndexSet &parallel_partitioning)
176 : SparsityPattern(parallel_partitioning, MPI_COMM_WORLD, 0)
177 {}
178
179
180
182 const IndexSet &parallel_partitioning,
183 const MPI_Comm communicator,
184 const std::vector<size_type> &n_entries_per_row)
185 {
186 reinit(parallel_partitioning,
187 parallel_partitioning,
188 communicator,
189 n_entries_per_row);
190 }
191
192
193
194 SparsityPattern::SparsityPattern(const IndexSet &row_parallel_partitioning,
195 const IndexSet &col_parallel_partitioning,
196 const MPI_Comm communicator,
197 const size_type n_entries_per_row)
198 {
199 reinit(row_parallel_partitioning,
200 col_parallel_partitioning,
201 communicator,
202 n_entries_per_row);
203 }
204
205
206
207 SparsityPattern::SparsityPattern(const IndexSet &row_parallel_partitioning,
208 const IndexSet &col_parallel_partitioning,
209 const MPI_Comm communicator)
210 : SparsityPattern(row_parallel_partitioning,
211 col_parallel_partitioning,
212 communicator,
213 0)
214 {}
215
216
217
218 SparsityPattern::SparsityPattern(const IndexSet &row_parallel_partitioning,
219 const IndexSet &col_parallel_partitioning)
220 : SparsityPattern(row_parallel_partitioning,
221 col_parallel_partitioning,
222 MPI_COMM_WORLD,
223 0)
224 {}
225
226
227
229 const IndexSet &row_parallel_partitioning,
230 const IndexSet &col_parallel_partitioning,
231 const MPI_Comm communicator,
232 const std::vector<size_type> &n_entries_per_row)
233 {
234 reinit(row_parallel_partitioning,
235 col_parallel_partitioning,
236 communicator,
237 n_entries_per_row);
238 }
239
240
241
242 SparsityPattern::SparsityPattern(const IndexSet &row_parallel_partitioning,
243 const IndexSet &col_parallel_partitioning,
244 const IndexSet &writable_rows,
245 const MPI_Comm communicator)
246 : SparsityPattern(row_parallel_partitioning,
247 col_parallel_partitioning,
248 writable_rows,
249 communicator,
250 0)
251 {}
252
253
254
255 SparsityPattern::SparsityPattern(const IndexSet &row_parallel_partitioning,
256 const IndexSet &col_parallel_partitioning,
257 const IndexSet &writable_rows,
258 const MPI_Comm communicator,
259 const size_type n_max_entries_per_row)
260 {
261 reinit(row_parallel_partitioning,
262 col_parallel_partitioning,
263 writable_rows,
264 communicator,
265 n_max_entries_per_row);
266 }
267
268
269
270 void
272 const size_type n,
273 const size_type n_entries_per_row)
274 {
277 MPI_COMM_SELF,
278 n_entries_per_row);
279 }
280
281
282
283 void
285 {
286 reinit(m, n, 0);
287 }
288
289
290
291 void
293 const size_type n,
294 const std::vector<size_type> &n_entries_per_row)
295 {
298 MPI_COMM_SELF,
299 n_entries_per_row);
300 }
301
302
303
304 namespace
305 {
306 using size_type = SparsityPattern::size_type;
307
308 void
309 reinit_sp(const Epetra_Map &row_map,
310 const Epetra_Map &col_map,
311 const size_type n_entries_per_row,
312 std::unique_ptr<Epetra_Map> &column_space_map,
313 std::unique_ptr<Epetra_FECrsGraph> &graph,
314 std::unique_ptr<Epetra_CrsGraph> &nonlocal_graph)
315 {
316 Assert(row_map.IsOneToOne(),
317 ExcMessage("Row map must be 1-to-1, i.e., no overlap between "
318 "the maps of different processors."));
319 Assert(col_map.IsOneToOne(),
320 ExcMessage("Column map must be 1-to-1, i.e., no overlap between "
321 "the maps of different processors."));
322
323 nonlocal_graph.reset();
324 graph.reset();
325 column_space_map = std::make_unique<Epetra_Map>(col_map);
326
327 // for empty ranges the maximum index might be lower than the minimum
328 // index
329 auto max_local_elements =
333 std::uint64_t(n_entries_per_row);
334 AssertThrow(max_local_elements <
335 static_cast<std::uint64_t>(std::numeric_limits<int>::max()),
336 ExcMessage("The TrilinosWrappers use Epetra internally which "
337 "uses 'signed int' to represent local indices. "
338 "Therefore, only 2,147,483,647 nonzero matrix "
339 "entries can be stored on a single process, "
340 "but you are requesting more than that. "
341 "If possible, use more MPI processes."));
342
343
344 // for more than one processor, need to specify only row map first and
345 // let the matrix entries decide about the column map (which says which
346 // columns are present in the matrix, not to be confused with the
347 // col_map that tells how the domain dofs of the matrix will be
348 // distributed). for only one processor, we can directly assign the
349 // columns as well. If we use a recent Trilinos version, we can also
350 // require building a non-local graph which gives us thread-safe
351 // initialization.
352 if (row_map.Comm().NumProc() > 1)
353 graph = std::make_unique<Epetra_FECrsGraph>(
354 Copy, row_map, n_entries_per_row, false
355 // TODO: Check which new Trilinos version supports this...
356 // Remember to change tests/trilinos/assemble_matrix_parallel_07, too.
357 // #if DEAL_II_TRILINOS_VERSION_GTE(11,14,0)
358 // , true
359 // #endif
360 );
361 else
362 graph = std::make_unique<Epetra_FECrsGraph>(
363 Copy, row_map, col_map, n_entries_per_row, false);
364 }
365
366
367
368 void
369 reinit_sp(const Epetra_Map &row_map,
370 const Epetra_Map &col_map,
371 const std::vector<size_type> &n_entries_per_row,
372 std::unique_ptr<Epetra_Map> &column_space_map,
373 std::unique_ptr<Epetra_FECrsGraph> &graph,
374 std::unique_ptr<Epetra_CrsGraph> &nonlocal_graph)
375 {
376 Assert(row_map.IsOneToOne(),
377 ExcMessage("Row map must be 1-to-1, i.e., no overlap between "
378 "the maps of different processors."));
379 Assert(col_map.IsOneToOne(),
380 ExcMessage("Column map must be 1-to-1, i.e., no overlap between "
381 "the maps of different processors."));
382
383 // release memory before reallocation
384 nonlocal_graph.reset();
385 graph.reset();
386 AssertDimension(n_entries_per_row.size(),
388
389 column_space_map = std::make_unique<Epetra_Map>(col_map);
390
391 // Translate the vector of row lengths into one that only stores
392 // those entries that related to the locally stored rows of the matrix:
393 std::vector<int> local_entries_per_row(
396 for (unsigned int i = 0; i < local_entries_per_row.size(); ++i)
397 local_entries_per_row[i] =
398 n_entries_per_row[TrilinosWrappers::min_my_gid(row_map) + i];
399
400 AssertThrow(std::accumulate(local_entries_per_row.begin(),
401 local_entries_per_row.end(),
402 std::uint64_t(0)) <
403 static_cast<std::uint64_t>(std::numeric_limits<int>::max()),
404 ExcMessage("The TrilinosWrappers use Epetra internally which "
405 "uses 'signed int' to represent local indices. "
406 "Therefore, only 2,147,483,647 nonzero matrix "
407 "entries can be stored on a single process, "
408 "but you are requesting more than that. "
409 "If possible, use more MPI processes."));
410
411 if (row_map.Comm().NumProc() > 1)
412 graph = std::make_unique<Epetra_FECrsGraph>(
413 Copy, row_map, local_entries_per_row.data(), false
414 // TODO: Check which new Trilinos version supports this...
415 // Remember to change tests/trilinos/assemble_matrix_parallel_07, too.
416 // #if DEAL_II_TRILINOS_VERSION_GTE(11,14,0)
417 // , true
418 // #endif
419 );
420 else
421 graph = std::make_unique<Epetra_FECrsGraph>(
422 Copy, row_map, col_map, local_entries_per_row.data(), false);
423 }
424
425
426
427 template <typename SparsityPatternType>
428 void
429 reinit_sp(const Epetra_Map &row_map,
430 const Epetra_Map &col_map,
431 const SparsityPatternType &sp,
432 const bool exchange_data,
433 std::unique_ptr<Epetra_Map> &column_space_map,
434 std::unique_ptr<Epetra_FECrsGraph> &graph,
435 std::unique_ptr<Epetra_CrsGraph> &nonlocal_graph)
436 {
437 nonlocal_graph.reset();
438 graph.reset();
439
440 AssertDimension(sp.n_rows(),
442 AssertDimension(sp.n_cols(),
444
445 column_space_map = std::make_unique<Epetra_Map>(col_map);
446
447 Assert(row_map.LinearMap() == true,
449 "This function only works if the row map is contiguous."));
450
451 const size_type first_row = TrilinosWrappers::min_my_gid(row_map),
452 last_row = TrilinosWrappers::max_my_gid(row_map) + 1;
453 std::vector<int> n_entries_per_row(last_row - first_row);
454
455 // Trilinos wants the row length as an int this is hopefully never going
456 // to be a problem.
457 for (size_type row = first_row; row < last_row; ++row)
458 n_entries_per_row[row - first_row] =
459 static_cast<int>(sp.row_length(row));
460
461 AssertThrow(std::accumulate(n_entries_per_row.begin(),
462 n_entries_per_row.end(),
463 std::uint64_t(0)) <
464 static_cast<std::uint64_t>(std::numeric_limits<int>::max()),
465 ExcMessage("The TrilinosWrappers use Epetra internally which "
466 "uses 'signed int' to represent local indices. "
467 "Therefore, only 2,147,483,647 nonzero matrix "
468 "entries can be stored on a single process, "
469 "but you are requesting more than that. "
470 "If possible, use more MPI processes."));
471
472 if (row_map.Comm().NumProc() > 1)
473 graph = std::make_unique<Epetra_FECrsGraph>(Copy,
474 row_map,
475 n_entries_per_row.data(),
476 false);
477 else
478 graph = std::make_unique<Epetra_FECrsGraph>(
479 Copy, row_map, col_map, n_entries_per_row.data(), false);
480
481 AssertDimension(sp.n_rows(), n_global_rows(*graph));
482
483 std::vector<TrilinosWrappers::types::int_type> row_indices;
484
485 for (size_type row = first_row; row < last_row; ++row)
486 {
487 const TrilinosWrappers::types::int_type row_length =
488 sp.row_length(row);
489 if (row_length == 0)
490 continue;
491
492 row_indices.resize(row_length, -1);
493 {
494 typename SparsityPatternType::iterator p = sp.begin(row);
495 // avoid incrementing p over the end of the current row because
496 // it is slow for DynamicSparsityPattern in parallel
497 for (int col = 0; col < row_length;)
498 {
499 row_indices[col++] = p->column();
500 if (col < row_length)
501 ++p;
502 }
503 }
504 if (exchange_data == false)
505 graph->Epetra_CrsGraph::InsertGlobalIndices(row,
506 row_length,
507 row_indices.data());
508 else
509 {
510 // Include possibility to exchange data since
511 // DynamicSparsityPattern is able to do so
512 const TrilinosWrappers::types::int_type trilinos_row = row;
513 graph->InsertGlobalIndices(1,
514 &trilinos_row,
515 row_length,
516 row_indices.data());
517 }
518 }
519
520 // TODO A dynamic_cast fails here, this is suspicious.
521 const auto &range_map =
522 static_cast<const Epetra_Map &>(graph->RangeMap()); // NOLINT
523 int ierr = graph->GlobalAssemble(*column_space_map, range_map, true);
524 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
525
526 ierr = graph->OptimizeStorage();
527 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
528 }
529 } // namespace
530
531
532
533 void
534 SparsityPattern::reinit(const IndexSet &parallel_partitioning,
535 const MPI_Comm communicator,
536 const size_type n_entries_per_row)
537 {
538 SparsityPatternBase::resize(parallel_partitioning.size(),
539 parallel_partitioning.size());
540 Epetra_Map map =
541 parallel_partitioning.make_trilinos_map(communicator, false);
542 reinit_sp(
543 map, map, n_entries_per_row, column_space_map, graph, nonlocal_graph);
544 }
545
546
547
548 void
549 SparsityPattern::reinit(const IndexSet &parallel_partitioning,
550 const MPI_Comm communicator)
551 {
552 reinit(parallel_partitioning, communicator, 0);
553 }
554
555
556
557 void
558 SparsityPattern::reinit(const IndexSet &parallel_partitioning)
559 {
560 reinit(parallel_partitioning, MPI_COMM_WORLD, 0);
561 }
562
563
564
565 void
566 SparsityPattern::reinit(const IndexSet &parallel_partitioning,
567 const MPI_Comm communicator,
568 const std::vector<size_type> &n_entries_per_row)
569 {
570 SparsityPatternBase::resize(parallel_partitioning.size(),
571 parallel_partitioning.size());
572 Epetra_Map map =
573 parallel_partitioning.make_trilinos_map(communicator, false);
574 reinit_sp(
575 map, map, n_entries_per_row, column_space_map, graph, nonlocal_graph);
576 }
577
578
579
580 void
581 SparsityPattern::reinit(const IndexSet &row_parallel_partitioning,
582 const IndexSet &col_parallel_partitioning,
583 const MPI_Comm communicator,
584 const size_type n_entries_per_row)
585 {
586 SparsityPatternBase::resize(row_parallel_partitioning.size(),
587 col_parallel_partitioning.size());
588 Epetra_Map row_map =
589 row_parallel_partitioning.make_trilinos_map(communicator, false);
590 Epetra_Map col_map =
591 col_parallel_partitioning.make_trilinos_map(communicator, false);
592 reinit_sp(row_map,
593 col_map,
594 n_entries_per_row,
596 graph,
598 }
599
600
601
602 void
603 SparsityPattern::reinit(const IndexSet &row_parallel_partitioning,
604 const IndexSet &col_parallel_partitioning,
605 const MPI_Comm communicator)
606 {
607 reinit(row_parallel_partitioning,
608 col_parallel_partitioning,
609 communicator,
610 0);
611 }
612
613
614
615 void
616 SparsityPattern::reinit(const IndexSet &row_parallel_partitioning,
617 const IndexSet &col_parallel_partitioning)
618 {
619 reinit(row_parallel_partitioning,
620 col_parallel_partitioning,
621 MPI_COMM_WORLD,
622 0);
623 }
624
625
626
627 void
628 SparsityPattern::reinit(const IndexSet &row_parallel_partitioning,
629 const IndexSet &col_parallel_partitioning,
630 const MPI_Comm communicator,
631 const std::vector<size_type> &n_entries_per_row)
632 {
633 SparsityPatternBase::resize(row_parallel_partitioning.size(),
634 col_parallel_partitioning.size());
635 Epetra_Map row_map =
636 row_parallel_partitioning.make_trilinos_map(communicator, false);
637 Epetra_Map col_map =
638 col_parallel_partitioning.make_trilinos_map(communicator, false);
639 reinit_sp(row_map,
640 col_map,
641 n_entries_per_row,
643 graph,
645 }
646
647
648
649 void
650 SparsityPattern::reinit(const IndexSet &row_parallel_partitioning,
651 const IndexSet &col_parallel_partitioning,
652 const IndexSet &writable_rows,
653 const MPI_Comm communicator,
654 const size_type n_entries_per_row)
655 {
656 SparsityPatternBase::resize(row_parallel_partitioning.size(),
657 col_parallel_partitioning.size());
658 Epetra_Map row_map =
659 row_parallel_partitioning.make_trilinos_map(communicator, false);
660 Epetra_Map col_map =
661 col_parallel_partitioning.make_trilinos_map(communicator, false);
662 reinit_sp(row_map,
663 col_map,
664 n_entries_per_row,
666 graph,
668
669 IndexSet nonlocal_partitioner = writable_rows;
670 AssertDimension(nonlocal_partitioner.size(),
671 row_parallel_partitioning.size());
672 if constexpr (running_in_debug_mode())
673 {
674 {
675 IndexSet tmp = writable_rows & row_parallel_partitioning;
676 Assert(tmp == row_parallel_partitioning,
678 "The set of writable rows passed to this method does not "
679 "contain the locally owned rows, which is not allowed."));
680 }
681 }
682 nonlocal_partitioner.subtract_set(row_parallel_partitioning);
683 if (Utilities::MPI::n_mpi_processes(communicator) > 1)
684 {
685 Epetra_Map nonlocal_map =
686 nonlocal_partitioner.make_trilinos_map(communicator, true);
688 std::make_unique<Epetra_CrsGraph>(Copy, nonlocal_map, 0);
689 }
690 else
691 Assert(nonlocal_partitioner.n_elements() == 0, ExcInternalError());
692 }
693
694
695
696 void
697 SparsityPattern::reinit(const IndexSet &row_parallel_partitioning,
698 const IndexSet &col_parallel_partitioning,
699 const IndexSet &writable_rows,
700 const MPI_Comm communicator)
701 {
702 reinit(row_parallel_partitioning,
703 col_parallel_partitioning,
704 writable_rows,
705 communicator,
706 0);
707 }
708
709
710
711 void
712 SparsityPattern::reinit(const IndexSet &row_parallel_partitioning,
713 const IndexSet &col_parallel_partitioning,
714 const IndexSet &writable_rows)
715 {
716 reinit(row_parallel_partitioning,
717 col_parallel_partitioning,
718 writable_rows,
719 MPI_COMM_WORLD,
720 0);
721 }
722
723
724
725 template <typename SparsityPatternType, typename>
726 void
728 const IndexSet &row_parallel_partitioning,
729 const IndexSet &col_parallel_partitioning,
730 const SparsityPatternType &nontrilinos_sparsity_pattern,
731 const MPI_Comm communicator,
732 const bool exchange_data)
733 {
734 SparsityPatternBase::resize(row_parallel_partitioning.size(),
735 col_parallel_partitioning.size());
736 Epetra_Map row_map =
737 row_parallel_partitioning.make_trilinos_map(communicator, false);
738 Epetra_Map col_map =
739 col_parallel_partitioning.make_trilinos_map(communicator, false);
740 reinit_sp(row_map,
741 col_map,
742 nontrilinos_sparsity_pattern,
743 exchange_data,
745 graph,
747 }
748
749
750
751 template <typename SparsityPatternType, typename>
752 void
754 const IndexSet &parallel_partitioning,
755 const SparsityPatternType &nontrilinos_sparsity_pattern,
756 const MPI_Comm communicator,
757 const bool exchange_data)
758 {
759 AssertDimension(nontrilinos_sparsity_pattern.n_rows(),
760 parallel_partitioning.size());
761 AssertDimension(nontrilinos_sparsity_pattern.n_cols(),
762 parallel_partitioning.size());
763 SparsityPatternBase::resize(parallel_partitioning.size(),
764 parallel_partitioning.size());
765 Epetra_Map map =
766 parallel_partitioning.make_trilinos_map(communicator, false);
767 reinit_sp(map,
768 map,
769 nontrilinos_sparsity_pattern,
770 exchange_data,
772 graph,
774 }
775
776
777
780 {
782 return *this;
783 }
784
785
786
787 void
789 {
791 column_space_map = std::make_unique<Epetra_Map>(*sp.column_space_map);
792 graph = std::make_unique<Epetra_FECrsGraph>(*sp.graph);
793
794 if (sp.nonlocal_graph.get() != nullptr)
795 nonlocal_graph = std::make_unique<Epetra_CrsGraph>(*sp.nonlocal_graph);
796 else
797 nonlocal_graph.reset();
798 }
799
800
801
802 template <typename SparsityPatternType>
803 void
804 SparsityPattern::copy_from(const SparsityPatternType &sp)
805 {
806 SparsityPatternBase::resize(sp.n_rows(), sp.n_cols());
807 const Epetra_Map rows(TrilinosWrappers::types::int_type(sp.n_rows()),
808 0,
810 const Epetra_Map columns(TrilinosWrappers::types::int_type(sp.n_cols()),
811 0,
813
814 reinit_sp(
815 rows, columns, sp, false, column_space_map, graph, nonlocal_graph);
816 }
817
818
819
820 void
822 {
824 // When we clear the matrix, reset
825 // the pointer and generate an
826 // empty sparsity pattern.
828 std::make_unique<Epetra_Map>(TrilinosWrappers::types::int_type(0),
831 graph = std::make_unique<Epetra_FECrsGraph>(View,
834 0);
835 graph->FillComplete();
836
837 nonlocal_graph.reset();
838 }
839
840
841
842 void
844 {
845 int ierr;
847 if (nonlocal_graph.get() != nullptr)
848 {
849 if (nonlocal_graph->IndicesAreGlobal() == false &&
850 nonlocal_graph->RowMap().NumMyElements() > 0 &&
852 {
853 // Insert dummy element at (row, column) that corresponds to row 0
854 // in local index counting.
858
859 // in case we have a square sparsity pattern, add the entry on the
860 // diagonal
863 column = row;
864 // if not, take a column index that we have ourselves since we
865 // know for sure it is there (and it will not create spurious
866 // messages to many ranks like putting index 0 on many processors)
867 else if (column_space_map->NumMyElements() > 0)
869 ierr = nonlocal_graph->InsertGlobalIndices(row, 1, &column);
870 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
871 }
872 Assert(nonlocal_graph->RowMap().NumMyElements() == 0 ||
874 nonlocal_graph->IndicesAreGlobal() == true,
876
877 ierr =
878 nonlocal_graph->FillComplete(*column_space_map, graph->RangeMap());
879 AssertThrow(ierr >= 0, ExcTrilinosError(ierr));
880 ierr = nonlocal_graph->OptimizeStorage();
881 AssertThrow(ierr >= 0, ExcTrilinosError(ierr));
882 Epetra_Export exporter(nonlocal_graph->RowMap(), graph->RowMap());
883 ierr = graph->Export(*nonlocal_graph, exporter, Add);
884 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
885 ierr = graph->FillComplete(*column_space_map, graph->RangeMap());
886 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
887 }
888 else
889 {
890 // TODO A dynamic_cast fails here, this is suspicious.
891 const auto &range_map =
892 static_cast<const Epetra_Map &>(graph->RangeMap()); // NOLINT
893 ierr = graph->GlobalAssemble(*column_space_map, range_map, true);
894 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
895 }
896
897 try
898 {
899 ierr = graph->OptimizeStorage();
900 }
901 catch (const int error_code)
902 {
904 false,
906 "The Epetra_CrsGraph::OptimizeStorage() function "
907 "has thrown an error with code " +
908 std::to_string(error_code) +
909 ". You will have to look up the exact meaning of this error "
910 "in the Trilinos source code, but oftentimes, this function "
911 "throwing an error indicates that you are trying to allocate "
912 "more than 2,147,483,647 nonzero entries in the sparsity "
913 "pattern on the local process; this will not work because "
914 "Epetra indexes entries with a simple 'signed int'."));
915 }
916 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
917
918 // Check consistency between the sizes set at the beginning and what
919 // Trilinos stores:
920 using namespace deal_II_exceptions::internals;
921 Assert(compare_for_equality(n_rows(), n_global_rows(*graph)),
923 Assert(compare_for_equality(n_cols(), n_global_cols(*graph)),
925 }
926
927
928
929 bool
931 {
932 return graph->RowMap().LID(
933 static_cast<TrilinosWrappers::types::int_type>(i)) != -1;
934 }
935
936
937
938 bool
940 {
941 if (!row_is_stored_locally(i))
942 {
943 return false;
944 }
945 else
946 {
947 // Extract local indices in
948 // the matrix.
949 int trilinos_i =
950 graph->LRID(static_cast<TrilinosWrappers::types::int_type>(i)),
951 trilinos_j =
952 graph->LCID(static_cast<TrilinosWrappers::types::int_type>(j));
953
954 // Check whether the matrix
955 // already is transformed to
956 // local indices.
957 if (graph->Filled() == false)
958 {
959 int nnz_present = graph->NumGlobalIndices(i);
960 int nnz_extracted;
962
963 // Generate the view and make
964 // sure that we have not generated
965 // an error.
966 // TODO: trilinos_i is the local row index -> it is an int but
967 // ExtractGlobalRowView requires trilinos_i to be the global row
968 // index and thus it should be a long long int
969 int ierr = graph->ExtractGlobalRowView(trilinos_i,
970 nnz_extracted,
971 col_indices);
972 Assert(ierr == 0, ExcTrilinosError(ierr));
973 Assert(nnz_present == nnz_extracted,
974 ExcDimensionMismatch(nnz_present, nnz_extracted));
975
976 // Search the index
977 const std::ptrdiff_t local_col_index =
978 std::find(col_indices, col_indices + nnz_present, trilinos_j) -
979 col_indices;
980
981 if (local_col_index == nnz_present)
982 return false;
983 }
984 else
985 {
986 // Prepare pointers for extraction
987 // of a view of the row.
988 int nnz_present = graph->NumGlobalIndices(i);
989 int nnz_extracted;
990 int *col_indices;
991
992 // Generate the view and make
993 // sure that we have not generated
994 // an error.
995 int ierr =
996 graph->ExtractMyRowView(trilinos_i, nnz_extracted, col_indices);
997 Assert(ierr == 0, ExcTrilinosError(ierr));
998
999 Assert(nnz_present == nnz_extracted,
1000 ExcDimensionMismatch(nnz_present, nnz_extracted));
1001
1002 // Search the index
1003 const std::ptrdiff_t local_col_index =
1004 std::find(col_indices, col_indices + nnz_present, trilinos_j) -
1005 col_indices;
1006
1007 if (local_col_index == nnz_present)
1008 return false;
1009 }
1010 }
1011
1012 return true;
1013 }
1014
1015
1016
1019 {
1020 size_type local_b = 0;
1021 for (int i = 0; i < static_cast<int>(local_size()); ++i)
1022 {
1023 int *indices;
1024 int num_entries;
1025 graph->ExtractMyRowView(i, num_entries, indices);
1026 for (unsigned int j = 0; j < static_cast<unsigned int>(num_entries);
1027 ++j)
1028 {
1029 if (static_cast<size_type>(std::abs(i - indices[j])) > local_b)
1030 local_b = std::abs(i - indices[j]);
1031 }
1032 }
1033
1035 graph->Comm().MaxAll(reinterpret_cast<TrilinosWrappers::types::int_type *>(
1036 &local_b),
1037 &global_b,
1038 1);
1039 return static_cast<size_type>(global_b);
1040 }
1041
1042
1043
1044 unsigned int
1046 {
1047 return graph->NumMyRows();
1048 }
1049
1050
1051
1052 std::pair<SparsityPattern::size_type, SparsityPattern::size_type>
1054 {
1056 const size_type end = TrilinosWrappers::max_my_gid(graph->RowMap()) + 1;
1057
1058 return {begin, end};
1059 }
1060
1061
1062
1063 std::uint64_t
1065 {
1066 return n_global_entries(*graph);
1067 }
1068
1069
1070
1071 unsigned int
1073 {
1074 return graph->MaxNumIndices();
1075 }
1076
1077
1078
1081 {
1082 Assert(row < n_rows(), ExcInternalError());
1083
1084 // Get a representation of the where the present row is located on
1085 // the current processor
1087 graph->LRID(static_cast<TrilinosWrappers::types::int_type>(row));
1088
1089 // On the processor who owns this row, we'll have a non-negative
1090 // value for `local_row` and can ask for the length of the row.
1091 if (local_row >= 0)
1092 return graph->NumMyIndices(local_row);
1093 else
1094 return static_cast<size_type>(-1);
1095 }
1096
1097
1098
1099 void
1101 const ArrayView<const size_type> &columns,
1102 const bool indices_are_sorted)
1103 {
1104 add_entries(row, columns.begin(), columns.end(), indices_are_sorted);
1105 }
1106
1107
1108
1109 const Epetra_Map &
1111 {
1112 // TODO A dynamic_cast fails here, this is suspicious.
1113 const auto &domain_map =
1114 static_cast<const Epetra_Map &>(graph->DomainMap()); // NOLINT
1115 return domain_map;
1116 }
1117
1118
1119
1120 const Epetra_Map &
1122 {
1123 // TODO A dynamic_cast fails here, this is suspicious.
1124 const auto &range_map =
1125 static_cast<const Epetra_Map &>(graph->RangeMap()); // NOLINT
1126 return range_map;
1127 }
1128
1129
1130
1131 MPI_Comm
1133 {
1134 const Epetra_MpiComm *mpi_comm =
1135 dynamic_cast<const Epetra_MpiComm *>(&graph->RangeMap().Comm());
1136 Assert(mpi_comm != nullptr, ExcInternalError());
1137 return mpi_comm->Comm();
1138 }
1139
1140
1141
1142 void
1147
1148
1149
1150 // As of now, no particularly neat
1151 // output is generated in case of
1152 // multiple processors.
1153 void
1154 SparsityPattern::print(std::ostream &out,
1155 const bool write_extended_trilinos_info) const
1156 {
1157 if (write_extended_trilinos_info)
1158 out << *graph;
1159 else
1160 {
1161 int *indices;
1162 int num_entries;
1163
1164 for (int i = 0; i < graph->NumMyRows(); ++i)
1165 {
1166 graph->ExtractMyRowView(i, num_entries, indices);
1167 for (int j = 0; j < num_entries; ++j)
1168 out << "(" << TrilinosWrappers::global_index(graph->RowMap(), i)
1169 << ","
1170 << TrilinosWrappers::global_index(graph->ColMap(), indices[j])
1171 << ") " << std::endl;
1172 }
1173 }
1174
1175 AssertThrow(out.fail() == false, ExcIO());
1176 }
1177
1178
1179
1180 void
1181 SparsityPattern::print_gnuplot(std::ostream &out) const
1182 {
1183 Assert(graph->Filled(), ExcInternalError());
1184 for (::types::global_dof_index row = 0; row < local_size(); ++row)
1185 {
1186 int *indices;
1187 int num_entries;
1188 graph->ExtractMyRowView(row, num_entries, indices);
1189
1190 Assert(num_entries >= 0, ExcInternalError());
1191 // avoid sign comparison warning
1192 const ::types::global_dof_index num_entries_ = num_entries;
1193 for (::types::global_dof_index j = 0; j < num_entries_; ++j)
1194 // while matrix entries are usually
1195 // written (i,j), with i vertical and
1196 // j horizontal, gnuplot output is
1197 // x-y, that is we have to exchange
1198 // the order of output
1199 out << static_cast<int>(
1200 TrilinosWrappers::global_index(graph->ColMap(), indices[j]))
1201 << " "
1202 << -static_cast<int>(
1203 TrilinosWrappers::global_index(graph->RowMap(), row))
1204 << std::endl;
1205 }
1206
1207 AssertThrow(out.fail() == false, ExcIO());
1208 }
1209
1210 // TODO: Implement!
1211 std::size_t
1213 {
1215 return 0;
1216 }
1217
1218
1219# ifndef DOXYGEN
1220 // explicit instantiations
1221 //
1222 template void
1223 SparsityPattern::copy_from(const ::SparsityPattern &);
1224 template void
1225 SparsityPattern::copy_from(const ::DynamicSparsityPattern &);
1226
1227 template void
1229 const ::SparsityPattern &,
1230 const MPI_Comm,
1231 bool);
1232 template void
1234 const ::DynamicSparsityPattern &,
1235 const MPI_Comm,
1236 bool);
1237
1238
1239 template void
1241 const IndexSet &,
1242 const ::SparsityPattern &,
1243 const MPI_Comm,
1244 bool);
1245 template void
1247 const IndexSet &,
1248 const ::DynamicSparsityPattern &,
1249 const MPI_Comm,
1250 bool);
1251# endif
1252
1253} // namespace TrilinosWrappers
1254
1255
1256#endif // DEAL_II_WITH_TRILINOS
iterator begin() const
Definition array_view.h:755
iterator end() const
Definition array_view.h:764
size_type size() const
Definition index_set.h:1759
size_type n_elements() const
Definition index_set.h:1917
Epetra_Map make_trilinos_map(const MPI_Comm communicator=MPI_COMM_WORLD, const bool overlapping=false) const
void subtract_set(const IndexSet &other)
Definition index_set.cc:496
virtual void resize(const size_type rows, const size_type cols)
size_type n_rows() const
size_type n_cols() const
std::shared_ptr< const std::vector< size_type > > colnum_cache
size_type row_length(const size_type row) const
std::unique_ptr< Epetra_FECrsGraph > graph
void print(std::ostream &out, const bool write_extended_trilinos_info=false) const
void print_gnuplot(std::ostream &out) const
const_iterator end() const
virtual void add_row_entries(const size_type &row, const ArrayView< const size_type > &columns, const bool indices_are_sorted=false) override
std::unique_ptr< Epetra_CrsGraph > nonlocal_graph
bool exists(const size_type i, const size_type j) const
std::pair< size_type, size_type > local_range() const
void add_entries(const size_type row, ForwardIterator begin, ForwardIterator end, const bool indices_are_sorted=false)
void reinit(const size_type m, const size_type n, const size_type n_entries_per_row)
void copy_from(const SparsityPattern &input_sparsity_pattern)
std::unique_ptr< Epetra_Map > column_space_map
const_iterator begin() const
bool in_local_range(const size_type index) const
SparsityPattern & operator=(const SparsityPattern &input_sparsity_pattern)
bool row_is_stored_locally(const size_type i) const
#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
#define DEAL_II_NOT_IMPLEMENTED()
static ::ExceptionBase & ExcIO()
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcTrilinosError(int arg1)
static ::ExceptionBase & ExcTrilinosError(int arg1)
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
IndexSet complete_index_set(const IndexSet::size_type N)
Definition index_set.h:1187
void reinit_sp(const Teuchos::RCP< TpetraTypes::MapType< MemorySpace > > &row_map, const Teuchos::RCP< TpetraTypes::MapType< MemorySpace > > &col_map, const size_type< MemorySpace > n_entries_per_row, Teuchos::RCP< TpetraTypes::MapType< MemorySpace > > &column_space_map, Teuchos::RCP< TpetraTypes::GraphType< MemorySpace > > &graph, Teuchos::RCP< TpetraTypes::GraphType< MemorySpace > > &nonlocal_graph)
TrilinosWrappers::types::int_type global_index(const Epetra_BlockMap &map, const ::types::global_dof_index i)
TrilinosWrappers::types::int_type n_global_rows(const Epetra_CrsGraph &graph)
TrilinosWrappers::types::int_type min_my_gid(const Epetra_BlockMap &map)
TrilinosWrappers::types::int64_type n_global_entries(const Epetra_CrsGraph &graph)
TrilinosWrappers::types::int64_type n_global_elements(const Epetra_BlockMap &map)
TrilinosWrappers::types::int_type max_my_gid(const Epetra_BlockMap &map)
TrilinosWrappers::types::int_type n_global_cols(const Epetra_CrsGraph &graph)
unsigned int n_mpi_processes(const MPI_Comm mpi_communicator)
Definition mpi.cc:103
const Epetra_Comm & comm_self()
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
Definition types.h:30