deal.II version GIT relicensing-6816-g8d70a4508a 2026-09-28 16:30: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
block_sparsity_pattern.h
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2000 - 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
13#ifndef dealii_block_sparsity_pattern_h
14#define dealii_block_sparsity_pattern_h
15
16
17#include <deal.II/base/config.h>
18
22#include <deal.II/base/table.h>
23
29
31
32// Forward declarations
33#ifndef DOXYGEN
34template <typename number>
37#endif
38
76template <typename SparsityPatternType>
78{
79public:
84
94
101
108 const size_type n_block_columns);
109
117
131 void
132 reinit(const size_type n_block_rows, const size_type n_block_columns);
133
141
148 void
150
154 SparsityPatternType &
155 block(const size_type row, const size_type column);
156
161 const SparsityPatternType &
162 block(const size_type row, const size_type column) const;
163
168 const BlockIndices &
170
175 const BlockIndices &
177
182 void
183 compress();
184
190
196
203 bool
204 empty() const;
205
212 max_entries_per_row() const;
213
223 void
224 add(const size_type i, const size_type j);
225
239 template <typename ForwardIterator>
240 void
242 ForwardIterator begin,
243 ForwardIterator end,
244 const bool indices_are_sorted = false);
245
254 virtual void
256 const ArrayView<const size_type> &columns,
257 const bool indices_are_sorted = false) override;
258
260
266
273
277 bool
278 exists(const size_type i, const size_type j) const;
279
284 unsigned int
285 row_length(const size_type row) const;
286
299 n_nonzero_elements() const;
300
306 void
307 print(std::ostream &out) const;
308
316 void
317 print_gnuplot(std::ostream &out) const;
318
324 void
325 print_svg(std::ostream &out) const;
326
331 std::size_t
332 memory_consumption() const;
333
344 "The number of rows and columns (returned by n_rows() and n_cols()) does "
345 "not match their directly computed values. This typically means that a "
346 "call to collect_sizes() is missing.");
347
352 int,
353 int,
354 int,
355 int,
356 << "The blocks [" << arg1 << ',' << arg2 << "] and [" << arg3
357 << ',' << arg4 << "] have differing row numbers.");
362 int,
363 int,
364 int,
365 int,
366 << "The blocks [" << arg1 << ',' << arg2 << "] and [" << arg3
367 << ',' << arg4 << "] have differing column numbers.");
370protected:
375
380
385
391
397
398private:
403 compute_n_rows() const;
404
409 compute_n_cols() const;
410
415 std::vector<size_type> counter_within_block;
416
421 std::vector<std::vector<size_type>> block_column_indices;
422
423 // Make the block sparse matrix a friend, so that it can use our
424 // #row_indices and #column_indices objects.
425 template <typename number>
426 friend class BlockSparseMatrix;
427};
428
429
430
440class BlockSparsityPattern : public BlockSparsityPatternBase<SparsityPattern>
441{
442public:
449
455 BlockSparsityPattern(const size_type n_rows, const size_type n_columns);
456
460 void
461 reinit(const size_type n_block_rows, const size_type n_block_columns);
462
475 void
477 const BlockIndices &col_indices,
478 const std::vector<std::vector<unsigned int>> &row_lengths);
479
480
485 bool
486 is_compressed() const;
487
493 void
495};
496
497
498
552 : public BlockSparsityPatternBase<DynamicSparsityPattern>
553{
554public:
561
568 const size_type n_columns);
569
576 BlockDynamicSparsityPattern(const std::vector<size_type> &row_block_sizes,
577 const std::vector<size_type> &col_block_sizes);
578
587 BlockDynamicSparsityPattern(const std::vector<IndexSet> &partitioning);
588
594 const BlockIndices &col_indices);
595
596
605 void
606 reinit(const std::vector<size_type> &row_block_sizes,
607 const std::vector<size_type> &col_block_sizes);
608
613 void
614 reinit(const std::vector<IndexSet> &partitioning);
615
621 void
622 reinit(const BlockIndices &row_indices, const BlockIndices &col_indices);
623
629 column_number(const size_type row, const unsigned int index) const;
630
635};
636
640#ifdef DEAL_II_WITH_TRILINOS
641
642
643namespace TrilinosWrappers
644{
668 : public ::BlockSparsityPatternBase<SparsityPattern>
669 {
670 public:
677
683 BlockSparsityPattern(const size_type n_rows, const size_type n_columns);
684
691 BlockSparsityPattern(const std::vector<size_type> &row_block_sizes,
692 const std::vector<size_type> &col_block_sizes);
693
701 BlockSparsityPattern(const std::vector<IndexSet> &parallel_partitioning,
702 const MPI_Comm communicator = MPI_COMM_WORLD);
703
716 const std::vector<IndexSet> &row_parallel_partitioning,
717 const std::vector<IndexSet> &column_parallel_partitioning,
718 const std::vector<IndexSet> &writable_rows,
719 const MPI_Comm communicator = MPI_COMM_WORLD);
720
730 void
731 reinit(const std::vector<size_type> &row_block_sizes,
732 const std::vector<size_type> &col_block_sizes);
733
738 void
739 reinit(const std::vector<IndexSet> &parallel_partitioning,
740 const MPI_Comm communicator = MPI_COMM_WORLD);
741
747 void
748 reinit(const std::vector<IndexSet> &row_parallel_partitioning,
749 const std::vector<IndexSet> &column_parallel_partitioning,
750 const MPI_Comm communicator = MPI_COMM_WORLD);
751
760 void
761 reinit(const std::vector<IndexSet> &row_parallel_partitioning,
762 const std::vector<IndexSet> &column_parallel_partitioning,
763 const std::vector<IndexSet> &writable_rows,
764 const MPI_Comm communicator = MPI_COMM_WORLD);
765
770 };
771
774} /* namespace TrilinosWrappers */
775
776#endif
777
778/*--------------------- Template functions ----------------------------------*/
779
780
781
782template <typename SparsityPatternType>
783inline SparsityPatternType &
785 const size_type column)
786{
787 AssertIndexRange(row, n_block_rows());
788 AssertIndexRange(column, n_block_cols());
789 return *sub_objects(row, column);
790}
791
792
793
794template <typename SparsityPatternType>
795inline const SparsityPatternType &
797 const size_type row,
798 const size_type column) const
799{
800 AssertIndexRange(row, n_block_rows());
801 AssertIndexRange(column, n_block_cols());
802 return *sub_objects(row, column);
803}
804
805
806
807template <typename SparsityPatternType>
808inline const BlockIndices &
813
814
815
816template <typename SparsityPatternType>
817inline const BlockIndices &
819{
820 return column_indices;
821}
822
823
824
825template <typename SparsityPatternType>
826inline void
828 const size_type j)
829{
830 // if you get an error here, are
831 // you sure you called
832 // <tt>collect_sizes()</tt> before?
833 const std::pair<size_type, size_type> row_index =
834 row_indices.global_to_local(i),
835 col_index =
836 column_indices.global_to_local(j);
837 sub_objects[row_index.first][col_index.first]->add(row_index.second,
838 col_index.second);
839}
840
841
842
843template <typename SparsityPatternType>
844template <typename ForwardIterator>
845void
847 const size_type row,
848 ForwardIterator begin,
849 ForwardIterator end,
850 const bool indices_are_sorted)
851{
852 // In debug mode, verify that collect_sizes() was called by redoing the
853 // calculation
854 Assert(n_rows() == compute_n_rows(), ExcNeedsCollectSizes());
855 Assert(n_cols() == compute_n_cols(), ExcNeedsCollectSizes());
856
857 const size_type n_cols = static_cast<size_type>(end - begin);
858
859 if (indices_are_sorted && n_cols > 0)
860 {
861 block_column_indices[0].resize(0);
862 Assert(std::is_sorted(begin, end), ExcInternalError());
863 Assert(std::adjacent_find(begin, end) == end, ExcInternalError());
864
865 const std::pair<size_type, size_type> row_index =
866 this->row_indices.global_to_local(row);
867 const auto n_blocks = column_indices.size();
868
869 // Assume we start with the first block: since we assemble sparsity
870 // patterns one cell at a time this should always be true
871 size_type current_block = 0;
872 size_type current_start_index = column_indices.block_start(current_block);
873 size_type next_start_index =
874 current_block == n_blocks - 1 ?
876 column_indices.block_start(current_block + 1);
877
878 for (auto it = begin; it < end; ++it)
879 {
880 // BlockIndices::global_to_local() is a bit slow so instead we just
881 // keep track of which block we are in - as the indices are sorted we
882 // know that the block number can only increase.
883 if (*it >= next_start_index)
884 {
885 // we found a column outside the present block: write the present
886 // block entries and continue to the next block
887 sub_objects[row_index.first][current_block]->add_entries(
888 row_index.second,
889 block_column_indices[0].begin(),
890 block_column_indices[0].end(),
891 true);
892 block_column_indices[0].clear();
893
894 auto block_and_col = column_indices.global_to_local(*it);
895 current_block = block_and_col.first;
896 current_start_index = column_indices.block_start(current_block);
897 next_start_index =
898 current_block == n_blocks - 1 ?
900 column_indices.block_start(current_block + 1);
901 }
902 const size_type local_index = *it - current_start_index;
903 block_column_indices[0].push_back(local_index);
904
905 // Check that calculation:
906 if constexpr (running_in_debug_mode())
907 {
908 {
909 auto check_block_and_col = column_indices.global_to_local(*it);
910 Assert(current_block == check_block_and_col.first,
912 Assert(local_index == check_block_and_col.second,
914 }
915 }
916 }
917 // add whatever is left over:
918 sub_objects[row_index.first][current_block]->add_entries(
919 row_index.second,
920 block_column_indices[0].begin(),
921 block_column_indices[0].end(),
922 true);
923
924 return;
925 }
926 else
927 {
928 // Resize sub-arrays to n_cols. This
929 // is a bit wasteful, but we resize
930 // only a few times (then the maximum
931 // row length won't increase that
932 // much any more). At least we know
933 // that all arrays are going to be of
934 // the same size, so we can check
935 // whether the size of one is large
936 // enough before actually going
937 // through all of them.
938 if (block_column_indices[0].size() < n_cols)
939 for (size_type i = 0; i < this->n_block_cols(); ++i)
940 block_column_indices[i].resize(n_cols);
941
942 // Reset the number of added elements
943 // in each block to zero.
944 for (size_type i = 0; i < this->n_block_cols(); ++i)
945 counter_within_block[i] = 0;
946
947 // Go through the column indices to
948 // find out which portions of the
949 // values should be set in which
950 // block of the matrix. We need to
951 // touch all the data, since we can't
952 // be sure that the data of one block
953 // is stored contiguously (in fact,
954 // indices will be intermixed when it
955 // comes from an element matrix).
956 for (ForwardIterator it = begin; it != end; ++it)
957 {
958 const size_type col = *it;
959
960 const std::pair<size_type, size_type> col_index =
961 this->column_indices.global_to_local(col);
962
963 const size_type local_index = counter_within_block[col_index.first]++;
964
965 block_column_indices[col_index.first][local_index] = col_index.second;
966 }
967
968 // Now we found out about where the
969 // individual columns should start and
970 // where we should start reading out
971 // data. Now let's write the data into
972 // the individual blocks!
973 const std::pair<size_type, size_type> row_index =
974 this->row_indices.global_to_local(row);
975 for (size_type block_col = 0; block_col < n_block_cols(); ++block_col)
976 {
977 if (counter_within_block[block_col] == 0)
978 continue;
979 sub_objects[row_index.first][block_col]->add_entries(
980 row_index.second,
981 block_column_indices[block_col].begin(),
982 block_column_indices[block_col].begin() +
983 counter_within_block[block_col],
984 indices_are_sorted);
985 }
986 }
987}
988
989
990
991template <typename SparsityPatternType>
992void
994 const size_type &row,
995 const ArrayView<const size_type> &columns,
996 const bool indices_are_sorted)
997{
998 add_entries(row, columns.begin(), columns.end(), indices_are_sorted);
999}
1000
1001
1002
1003template <typename SparsityPatternType>
1004inline bool
1006 const size_type j) const
1007{
1008 // if you get an error here, are
1009 // you sure you called
1010 // <tt>collect_sizes()</tt> before?
1011 const std::pair<size_type, size_type> row_index =
1012 row_indices.global_to_local(i),
1013 col_index =
1014 column_indices.global_to_local(j);
1015 return sub_objects[row_index.first][col_index.first]->exists(
1016 row_index.second, col_index.second);
1017}
1018
1019
1020
1021template <typename SparsityPatternType>
1022inline unsigned int
1024 const size_type row) const
1025{
1026 const std::pair<size_type, size_type> row_index =
1027 row_indices.global_to_local(row);
1028
1029 unsigned int c = 0;
1030
1031 for (size_type b = 0; b < n_block_rows(); ++b)
1032 c += sub_objects[row_index.first][b]->row_length(row_index.second);
1033
1034 return c;
1035}
1036
1037
1038
1039template <typename SparsityPatternType>
1042{
1043 return block_columns;
1044}
1045
1046
1047
1048template <typename SparsityPatternType>
1051{
1052 return block_rows;
1053}
1054
1055
1058 const unsigned int index) const
1059{
1060 // .first= ith block, .second = jth row in that block
1061 const std::pair<size_type, size_type> row_index =
1063
1064 AssertIndexRange(index, row_length(row));
1065
1066 size_type c = 0;
1067 size_type block_columns = 0; // sum of n_cols for all blocks to the left
1068 for (unsigned int b = 0; b < this->n_block_cols(); ++b)
1069 {
1070 unsigned int rowlen =
1071 sub_objects[row_index.first][b]->row_length(row_index.second);
1072 if (index < c + rowlen)
1073 return block_columns +
1074 sub_objects[row_index.first][b]->column_number(row_index.second,
1075 index - c);
1076 c += rowlen;
1077 block_columns += sub_objects[row_index.first][b]->n_cols();
1078 }
1079
1081 return 0;
1082}
1083
1084
1085inline void
1087 const size_type new_block_columns)
1088{
1090 new_block_columns);
1091}
1092
1093
1095
1096#endif
*  iterator end()
*  *  iterator begin()
iterator begin() const
Definition array_view.h:755
iterator end() const
Definition array_view.h:764
void reinit(const std::vector< size_type > &row_block_sizes, const std::vector< size_type > &col_block_sizes)
size_type column_number(const size_type row, const unsigned int index) const
std::pair< unsigned int, size_type > global_to_local(const size_type i) const
void print_gnuplot(std::ostream &out) const
static const size_type invalid_entry
const SparsityPatternType & block(const size_type row, const size_type column) const
std::vector< size_type > counter_within_block
Table< 2, std::unique_ptr< SparsityPatternType > > sub_objects
SparsityPatternType & block(const size_type row, const size_type column)
std::vector< std::vector< size_type > > block_column_indices
void add_entries(const size_type row, ForwardIterator begin, ForwardIterator end, const bool indices_are_sorted=false)
const BlockIndices & get_column_indices() const
void print(std::ostream &out) const
std::size_t memory_consumption() const
void print_svg(std::ostream &out) const
void reinit(const size_type n_block_rows, const size_type n_block_columns)
const BlockIndices & get_row_indices() const
unsigned int row_length(const size_type row) const
virtual void add_row_entries(const size_type &row, const ArrayView< const size_type > &columns, const bool indices_are_sorted=false) override
void add(const size_type i, const size_type j)
bool exists(const size_type i, const size_type j) const
BlockSparsityPatternBase & operator=(const BlockSparsityPatternBase &)
void copy_from(const BlockDynamicSparsityPattern &dsp)
void reinit(const size_type n_block_rows, const size_type n_block_columns)
BlockSparsityPattern()=default
size_type n_rows() const
virtual void add_entries(const ArrayView< const std::pair< size_type, size_type > > &entries)
size_type n_cols() const
static constexpr size_type invalid_entry
void reinit(const std::vector< size_type > &row_block_sizes, const std::vector< size_type > &col_block_sizes)
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
constexpr bool running_in_debug_mode()
Definition config.h:76
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_ASSERT_UNREACHABLE()
static ::ExceptionBase & ExcNeedsCollectSizes()
#define DeclException4(Exception4, type1, type2, type3, type4, outsequence)
static ::ExceptionBase & ExcIncompatibleColNumbers(int arg1, int arg2, int arg3, int arg4)
static ::ExceptionBase & ExcIncompatibleRowNumbers(int arg1, int arg2, int arg3, int arg4)
#define Assert(cond, exc)
#define AssertIndexRange(index, range)
#define DeclExceptionMsg(Exception, defaulttext)
static ::ExceptionBase & ExcInternalError()
std::size_t size
Definition mpi.cc:733
constexpr types::global_dof_index invalid_dof_index
Definition types.h:259
unsigned int global_dof_index
Definition types.h:92