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
block_matrix_base.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) 2004 - 2025 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13#ifndef dealii_block_matrix_base_h
14#define dealii_block_matrix_base_h
15
16
17#include <deal.II/base/config.h>
18
20#include <deal.II/base/mutex.h>
22#include <deal.II/base/table.h>
24
29#include <deal.II/lac/vector.h>
31
32#include <cmath>
33#include <mutex>
34
36
37
38// Forward declaration
39#ifndef DOXYGEN
40template <typename>
41class MatrixIterator;
42#endif
43
44
54{
59 template <typename BlockMatrixType>
61 {
62 public:
67
71 using value_type = typename BlockMatrixType::value_type;
72
77
81 unsigned int
82 block_row() const;
83
87 unsigned int
88 block_column() const;
89
90 protected:
94 unsigned int row_block;
95
99 unsigned int col_block;
100 };
101
102
103
107 template <typename BlockMatrixType, bool Constness>
108 class Accessor;
109
110
114 template <typename BlockMatrixType>
115 class Accessor<BlockMatrixType, false> : public AccessorBase<BlockMatrixType>
116 {
117 public:
122
126 using MatrixType = BlockMatrixType;
127
131 using value_type = typename BlockMatrixType::value_type;
132
141 Accessor(BlockMatrixType *m, const size_type row, const size_type col);
142
147 row() const;
148
153 column() const;
154
159 value() const;
160
164 void
165 set_value(value_type newval) const;
166
167 protected:
171 BlockMatrixType *matrix;
172
176 typename BlockMatrixType::BlockType::iterator base_iterator;
177
181 void
183
187 bool
188 operator==(const Accessor &a) const;
189
190 template <typename>
191 friend class ::MatrixIterator;
192
193 friend class Accessor<BlockMatrixType, true>;
194 };
195
196
197
202 template <typename BlockMatrixType>
203 class Accessor<BlockMatrixType, true> : public AccessorBase<BlockMatrixType>
204 {
205 public:
210
214 using MatrixType = const BlockMatrixType;
215
219 using value_type = typename BlockMatrixType::value_type;
220
229 Accessor(const BlockMatrixType *m,
230 const size_type row,
231 const size_type col);
232
237
242 row() const;
243
248 column() const;
249
254 value() const;
255
256 protected:
260 const BlockMatrixType *matrix;
261
265 typename BlockMatrixType::BlockType::const_iterator base_iterator;
266
270 void
272
276 bool
277 operator==(const Accessor &a) const;
278
279 // Let the iterator class be a friend.
280 template <typename>
281 friend class ::MatrixIterator;
282 };
283} // namespace BlockMatrixIterators
284
285
286
346template <typename MatrixType>
348{
349public:
353 using BlockType = MatrixType;
354
359 using value_type = typename BlockType::value_type;
362 using const_pointer = const value_type *;
366
367 using iterator =
369
372
373
377 BlockMatrixBase() = default;
378
383
400 template <typename BlockMatrixType>
402 copy_from(const BlockMatrixType &source);
403
407 BlockType &
408 block(const unsigned int row, const unsigned int column);
409
410
415 const BlockType &
416 block(const unsigned int row, const unsigned int column) const;
417
423 m() const;
424
430 n() const;
431
432
437 unsigned int
439
444 unsigned int
446
452 void
453 set(const size_type i, const size_type j, const value_type value);
454
470 template <typename number>
471 void
472 set(const std::vector<size_type> &indices,
473 const FullMatrix<number> &full_matrix,
474 const bool elide_zero_values = false);
475
481 template <typename number>
482 void
483 set(const std::vector<size_type> &row_indices,
484 const std::vector<size_type> &col_indices,
485 const FullMatrix<number> &full_matrix,
486 const bool elide_zero_values = false);
487
498 template <typename number>
499 void
500 set(const size_type row,
501 const std::vector<size_type> &col_indices,
502 const std::vector<number> &values,
503 const bool elide_zero_values = false);
504
514 template <typename number>
515 void
516 set(const size_type row,
517 const size_type n_cols,
518 const size_type *col_indices,
519 const number *values,
520 const bool elide_zero_values = false);
521
527 void
528 add(const size_type i, const size_type j, const value_type value);
529
544 template <typename number>
545 void
546 add(const std::vector<size_type> &indices,
547 const FullMatrix<number> &full_matrix,
548 const bool elide_zero_values = true);
549
555 template <typename number>
556 void
557 add(const std::vector<size_type> &row_indices,
558 const std::vector<size_type> &col_indices,
559 const FullMatrix<number> &full_matrix,
560 const bool elide_zero_values = true);
561
571 template <typename number>
572 void
573 add(const size_type row,
574 const std::vector<size_type> &col_indices,
575 const std::vector<number> &values,
576 const bool elide_zero_values = true);
577
587 template <typename number>
588 void
589 add(const size_type row,
590 const size_type n_cols,
591 const size_type *col_indices,
592 const number *values,
593 const bool elide_zero_values = true,
594 const bool col_indices_are_sorted = false);
595
607 void
608 add(const value_type factor, const BlockMatrixBase<MatrixType> &matrix);
609
617 operator()(const size_type i, const size_type j) const;
618
628 el(const size_type i, const size_type j) const;
629
641 diag_element(const size_type i) const;
642
651 void
653
658 operator*=(const value_type factor);
659
664 operator/=(const value_type factor);
665
670 template <typename BlockVectorType>
671 void
672 vmult_add(BlockVectorType &dst, const BlockVectorType &src) const;
673
679 template <typename BlockVectorType>
680 void
681 Tvmult_add(BlockVectorType &dst, const BlockVectorType &src) const;
682
695 template <typename BlockVectorType>
697 matrix_norm_square(const BlockVectorType &v) const;
698
705
709 template <typename BlockVectorType>
711 matrix_scalar_product(const BlockVectorType &u,
712 const BlockVectorType &v) const;
713
717 template <typename BlockVectorType>
719 residual(BlockVectorType &dst,
720 const BlockVectorType &x,
721 const BlockVectorType &b) const;
722
729 void
730 print(std::ostream &out, const bool alternative_output = false) const;
731
737
743
748 begin(const size_type r);
749
754 end(const size_type r);
759 begin() const;
760
765 end() const;
766
771 begin(const size_type r) const;
772
777 end(const size_type r) const;
778
782 const BlockIndices &
784
788 const BlockIndices &
790
796 std::size_t
798
808 int,
809 int,
810 int,
811 int,
812 << "The blocks [" << arg1 << ',' << arg2 << "] and [" << arg3
813 << ',' << arg4 << "] have differing row numbers.");
818 int,
819 int,
820 int,
821 int,
822 << "The blocks [" << arg1 << ',' << arg2 << "] and [" << arg3
823 << ',' << arg4 << "] have differing column numbers.");
825protected:
838 void
840
846
851
870 void
872
883 template <typename BlockVectorType>
884 void
885 vmult_block_block(BlockVectorType &dst, const BlockVectorType &src) const;
886
897 template <typename BlockVectorType, typename VectorType>
898 void
899 vmult_block_nonblock(BlockVectorType &dst, const VectorType &src) const;
900
911 template <typename BlockVectorType, typename VectorType>
912 void
913 vmult_nonblock_block(VectorType &dst, const BlockVectorType &src) const;
914
925 template <typename VectorType>
926 void
927 vmult_nonblock_nonblock(VectorType &dst, const VectorType &src) const;
928
940 template <typename BlockVectorType>
941 void
942 Tvmult_block_block(BlockVectorType &dst, const BlockVectorType &src) const;
943
954 template <typename BlockVectorType, typename VectorType>
955 void
956 Tvmult_block_nonblock(BlockVectorType &dst, const VectorType &src) const;
957
968 template <typename BlockVectorType, typename VectorType>
969 void
970 Tvmult_nonblock_block(VectorType &dst, const BlockVectorType &src) const;
971
982 template <typename VectorType>
983 void
984 Tvmult_nonblock_nonblock(VectorType &dst, const VectorType &src) const;
985
986
987protected:
994 void
996
1001 void
1003
1004
1005private:
1015 {
1020 std::vector<size_type> counter_within_block;
1021
1026 std::vector<std::vector<size_type>> column_indices;
1027
1032 std::vector<std::vector<value_type>> column_values;
1033
1039
1051 {
1052 return *this;
1053 }
1054 };
1055
1063
1064 // Make the iterator class a friend. We have to work around a compiler bug
1065 // here again.
1066 template <typename, bool>
1068
1069 template <typename>
1070 friend class MatrixIterator;
1071};
1072
1073
1076#ifndef DOXYGEN
1077/* ------------------------- Template functions ---------------------- */
1078
1079
1080namespace BlockMatrixIterators
1081{
1082 template <typename BlockMatrixType>
1084 : row_block(0)
1085 , col_block(0)
1086 {}
1087
1088
1089 template <typename BlockMatrixType>
1090 inline unsigned int
1091 AccessorBase<BlockMatrixType>::block_row() const
1092 {
1094
1095 return row_block;
1096 }
1097
1098
1099 template <typename BlockMatrixType>
1100 inline unsigned int
1101 AccessorBase<BlockMatrixType>::block_column() const
1102 {
1104
1105 return col_block;
1106 }
1107
1108
1109 template <typename BlockMatrixType>
1110 inline Accessor<BlockMatrixType, true>::Accessor(
1111 const BlockMatrixType *matrix,
1112 const size_type row,
1113 const size_type col)
1114 : matrix(matrix)
1115 , base_iterator(matrix->block(0, 0).begin())
1116 {
1117 Assert(col == 0, ExcNotImplemented());
1118
1119 // check if this is a regular row or
1120 // the end of the matrix
1121 if (row < matrix->m())
1122 {
1123 const std::pair<unsigned int, size_type> indices =
1124 matrix->row_block_indices.global_to_local(row);
1125
1126 // find the first block that does
1127 // have an entry in this row
1128 for (unsigned int bc = 0; bc < matrix->n_block_cols(); ++bc)
1129 {
1130 base_iterator =
1131 matrix->block(indices.first, bc).begin(indices.second);
1132 if (base_iterator !=
1133 matrix->block(indices.first, bc).end(indices.second))
1134 {
1135 this->row_block = indices.first;
1136 this->col_block = bc;
1137 return;
1138 }
1139 }
1140
1141 // hm, there is no block that has
1142 // an entry in this column. we need
1143 // to take the next entry then,
1144 // which may be the first entry of
1145 // the next row, or recursively the
1146 // next row, or so on
1147 *this = Accessor(matrix, row + 1, 0);
1148 }
1149 else
1150 {
1151 // we were asked to create the end
1152 // iterator for this matrix
1153 this->row_block = numbers::invalid_unsigned_int;
1154 this->col_block = numbers::invalid_unsigned_int;
1155 }
1156 }
1157
1158
1159 // template <typename BlockMatrixType>
1160 // inline
1161 // Accessor<BlockMatrixType, true>::Accessor (const
1162 // Accessor<BlockMatrixType, true>& other)
1163 // :
1164 // matrix(other.matrix),
1165 // base_iterator(other.base_iterator)
1166 // {
1167 // this->row_block = other.row_block;
1168 // this->col_block = other.col_block;
1169 // }
1170
1171
1172 template <typename BlockMatrixType>
1173 inline Accessor<BlockMatrixType, true>::Accessor(
1174 const Accessor<BlockMatrixType, false> &other)
1175 : matrix(other.matrix)
1176 , base_iterator(other.base_iterator)
1177 {
1178 this->row_block = other.row_block;
1179 this->col_block = other.col_block;
1180 }
1181
1182
1183 template <typename BlockMatrixType>
1184 inline typename Accessor<BlockMatrixType, true>::size_type
1185 Accessor<BlockMatrixType, true>::row() const
1186 {
1187 Assert(this->row_block != numbers::invalid_unsigned_int,
1189
1190 return (matrix->row_block_indices.local_to_global(this->row_block, 0) +
1191 base_iterator->row());
1192 }
1193
1194
1195 template <typename BlockMatrixType>
1196 inline typename Accessor<BlockMatrixType, true>::size_type
1197 Accessor<BlockMatrixType, true>::column() const
1198 {
1199 Assert(this->col_block != numbers::invalid_unsigned_int,
1201
1202 return (matrix->column_block_indices.local_to_global(this->col_block, 0) +
1203 base_iterator->column());
1204 }
1205
1206
1207 template <typename BlockMatrixType>
1208 inline typename Accessor<BlockMatrixType, true>::value_type
1209 Accessor<BlockMatrixType, true>::value() const
1210 {
1211 Assert(this->row_block != numbers::invalid_unsigned_int,
1213 Assert(this->col_block != numbers::invalid_unsigned_int,
1215
1216 return base_iterator->value();
1217 }
1218
1219
1220
1221 template <typename BlockMatrixType>
1222 inline void
1223 Accessor<BlockMatrixType, true>::advance()
1224 {
1225 Assert(this->row_block != numbers::invalid_unsigned_int,
1227 Assert(this->col_block != numbers::invalid_unsigned_int,
1229
1230 // Remember current row inside block
1231 size_type local_row = base_iterator->row();
1232
1233 // Advance one element inside the
1234 // current block
1235 ++base_iterator;
1236
1237 // while we hit the end of the row of a
1238 // block (which may happen multiple
1239 // times if rows inside a block are
1240 // empty), we have to jump to the next
1241 // block and take the
1242 while (base_iterator ==
1243 matrix->block(this->row_block, this->col_block).end(local_row))
1244 {
1245 // jump to next block in this block
1246 // row, if possible, otherwise go
1247 // to next row
1248 if (this->col_block < matrix->n_block_cols() - 1)
1249 {
1250 ++this->col_block;
1251 base_iterator =
1252 matrix->block(this->row_block, this->col_block).begin(local_row);
1253 }
1254 else
1255 {
1256 // jump back to next row in
1257 // first block column
1258 this->col_block = 0;
1259 ++local_row;
1260
1261 // see if this has brought us
1262 // past the number of rows in
1263 // this block. if so see
1264 // whether we've just fallen
1265 // off the end of the whole
1266 // matrix
1267 if (local_row ==
1268 matrix->block(this->row_block, this->col_block).m())
1269 {
1270 local_row = 0;
1271 ++this->row_block;
1272 if (this->row_block == matrix->n_block_rows())
1273 {
1274 this->row_block = numbers::invalid_unsigned_int;
1275 this->col_block = numbers::invalid_unsigned_int;
1276 return;
1277 }
1278 }
1279
1280 base_iterator =
1281 matrix->block(this->row_block, this->col_block).begin(local_row);
1282 }
1283 }
1284 }
1285
1286
1287 template <typename BlockMatrixType>
1288 inline bool
1289 Accessor<BlockMatrixType, true>::operator==(const Accessor &a) const
1290 {
1291 if (matrix != a.matrix)
1292 return false;
1293
1294 if (this->row_block == a.row_block && this->col_block == a.col_block)
1295 // end iterators do not necessarily
1296 // have to have the same
1297 // base_iterator representation, but
1298 // valid iterators have to
1299 return (((this->row_block == numbers::invalid_unsigned_int) &&
1300 (this->col_block == numbers::invalid_unsigned_int)) ||
1301 (base_iterator == a.base_iterator));
1302
1303 return false;
1304 }
1305
1306 //----------------------------------------------------------------------//
1307
1308
1309 template <typename BlockMatrixType>
1310 inline Accessor<BlockMatrixType, false>::Accessor(BlockMatrixType *matrix,
1311 const size_type row,
1312 const size_type col)
1313 : matrix(matrix)
1314 , base_iterator(matrix->block(0, 0).begin())
1315 {
1316 Assert(col == 0, ExcNotImplemented());
1317 // check if this is a regular row or
1318 // the end of the matrix
1319 if (row < matrix->m())
1320 {
1321 const std::pair<unsigned int, size_type> indices =
1322 matrix->row_block_indices.global_to_local(row);
1323
1324 // find the first block that does
1325 // have an entry in this row
1326 for (size_type bc = 0; bc < matrix->n_block_cols(); ++bc)
1327 {
1328 base_iterator =
1329 matrix->block(indices.first, bc).begin(indices.second);
1330 if (base_iterator !=
1331 matrix->block(indices.first, bc).end(indices.second))
1332 {
1333 this->row_block = indices.first;
1334 this->col_block = bc;
1335 return;
1336 }
1337 }
1338
1339 // hm, there is no block that has
1340 // an entry in this column. we need
1341 // to take the next entry then,
1342 // which may be the first entry of
1343 // the next row, or recursively the
1344 // next row, or so on
1345 *this = Accessor(matrix, row + 1, 0);
1346 }
1347 else
1348 {
1349 // we were asked to create the end
1350 // iterator for this matrix
1351 this->row_block = numbers::invalid_unsigned_int;
1352 this->col_block = numbers::invalid_unsigned_int;
1353 }
1354 }
1355
1356
1357 template <typename BlockMatrixType>
1358 inline typename Accessor<BlockMatrixType, false>::size_type
1359 Accessor<BlockMatrixType, false>::row() const
1360 {
1361 Assert(this->row_block != numbers::invalid_unsigned_int,
1363
1364 return (matrix->row_block_indices.local_to_global(this->row_block, 0) +
1365 base_iterator->row());
1366 }
1367
1368
1369 template <typename BlockMatrixType>
1370 inline typename Accessor<BlockMatrixType, false>::size_type
1371 Accessor<BlockMatrixType, false>::column() const
1372 {
1373 Assert(this->col_block != numbers::invalid_unsigned_int,
1375
1376 return (matrix->column_block_indices.local_to_global(this->col_block, 0) +
1377 base_iterator->column());
1378 }
1379
1380
1381 template <typename BlockMatrixType>
1382 inline typename Accessor<BlockMatrixType, false>::value_type
1383 Accessor<BlockMatrixType, false>::value() const
1384 {
1385 Assert(this->row_block != numbers::invalid_unsigned_int,
1387 Assert(this->col_block != numbers::invalid_unsigned_int,
1389
1390 return base_iterator->value();
1391 }
1392
1393
1394
1395 template <typename BlockMatrixType>
1396 inline void
1397 Accessor<BlockMatrixType, false>::set_value(
1398 typename Accessor<BlockMatrixType, false>::value_type newval) const
1399 {
1400 Assert(this->row_block != numbers::invalid_unsigned_int,
1402 Assert(this->col_block != numbers::invalid_unsigned_int,
1404
1405 base_iterator->value() = newval;
1406 }
1407
1408
1409
1410 template <typename BlockMatrixType>
1411 inline void
1412 Accessor<BlockMatrixType, false>::advance()
1413 {
1414 Assert(this->row_block != numbers::invalid_unsigned_int,
1416 Assert(this->col_block != numbers::invalid_unsigned_int,
1418
1419 // Remember current row inside block
1420 size_type local_row = base_iterator->row();
1421
1422 // Advance one element inside the
1423 // current block
1424 ++base_iterator;
1425
1426 // while we hit the end of the row of a
1427 // block (which may happen multiple
1428 // times if rows inside a block are
1429 // empty), we have to jump to the next
1430 // block and take the
1431 while (base_iterator ==
1432 matrix->block(this->row_block, this->col_block).end(local_row))
1433 {
1434 // jump to next block in this block
1435 // row, if possible, otherwise go
1436 // to next row
1437 if (this->col_block < matrix->n_block_cols() - 1)
1438 {
1439 ++this->col_block;
1440 base_iterator =
1441 matrix->block(this->row_block, this->col_block).begin(local_row);
1442 }
1443 else
1444 {
1445 // jump back to next row in
1446 // first block column
1447 this->col_block = 0;
1448 ++local_row;
1449
1450 // see if this has brought us
1451 // past the number of rows in
1452 // this block. if so see
1453 // whether we've just fallen
1454 // off the end of the whole
1455 // matrix
1456 if (local_row ==
1457 matrix->block(this->row_block, this->col_block).m())
1458 {
1459 local_row = 0;
1460 ++this->row_block;
1461 if (this->row_block == matrix->n_block_rows())
1462 {
1463 this->row_block = numbers::invalid_unsigned_int;
1464 this->col_block = numbers::invalid_unsigned_int;
1465 return;
1466 }
1467 }
1468
1469 base_iterator =
1470 matrix->block(this->row_block, this->col_block).begin(local_row);
1471 }
1472 }
1473 }
1474
1475
1476
1477 template <typename BlockMatrixType>
1478 inline bool
1479 Accessor<BlockMatrixType, false>::operator==(const Accessor &a) const
1480 {
1481 if (matrix != a.matrix)
1482 return false;
1483
1484 if (this->row_block == a.row_block && this->col_block == a.col_block)
1485 // end iterators do not necessarily
1486 // have to have the same
1487 // base_iterator representation, but
1488 // valid iterators have to
1489 return (((this->row_block == numbers::invalid_unsigned_int) &&
1490 (this->col_block == numbers::invalid_unsigned_int)) ||
1491 (base_iterator == a.base_iterator));
1492
1493 return false;
1494 }
1495} // namespace BlockMatrixIterators
1496
1497
1498//---------------------------------------------------------------------------
1499
1500template <typename MatrixType>
1502{
1503 try
1504 {
1505 clear();
1506 }
1507 catch (...)
1508 {}
1509}
1510
1511
1512template <typename MatrixType>
1513template <typename BlockMatrixType>
1515BlockMatrixBase<MatrixType>::copy_from(const BlockMatrixType &source)
1516{
1517 for (unsigned int r = 0; r < n_block_rows(); ++r)
1518 for (unsigned int c = 0; c < n_block_cols(); ++c)
1519 block(r, c).copy_from(source.block(r, c));
1520
1521 return *this;
1522}
1523
1524
1525template <typename MatrixType>
1526std::size_t
1528{
1529 std::size_t mem =
1530 MemoryConsumption::memory_consumption(row_block_indices) +
1531 MemoryConsumption::memory_consumption(column_block_indices) +
1533 MemoryConsumption::memory_consumption(temporary_data.counter_within_block) +
1534 MemoryConsumption::memory_consumption(temporary_data.column_indices) +
1535 MemoryConsumption::memory_consumption(temporary_data.column_values) +
1536 sizeof(temporary_data.mutex);
1537
1538 for (unsigned int r = 0; r < n_block_rows(); ++r)
1539 for (unsigned int c = 0; c < n_block_cols(); ++c)
1540 {
1541 MatrixType *p = this->sub_objects[r][c];
1543 }
1544
1545 return mem;
1546}
1547
1548
1549
1550template <typename MatrixType>
1551inline void
1553{
1554 for (unsigned int r = 0; r < n_block_rows(); ++r)
1555 for (unsigned int c = 0; c < n_block_cols(); ++c)
1556 {
1557 MatrixType *p = this->sub_objects[r][c];
1558 this->sub_objects[r][c] = nullptr;
1559 delete p;
1560 }
1561 sub_objects.reinit(0, 0);
1562
1563 // reset block indices to empty
1564 row_block_indices = column_block_indices = BlockIndices();
1565}
1566
1567
1568
1569template <typename MatrixType>
1571BlockMatrixBase<MatrixType>::block(const unsigned int row,
1572 const unsigned int column)
1573{
1574 AssertIndexRange(row, n_block_rows());
1575 AssertIndexRange(column, n_block_cols());
1576
1577 return *sub_objects[row][column];
1578}
1579
1580
1581
1582template <typename MatrixType>
1583inline const typename BlockMatrixBase<MatrixType>::BlockType &
1584BlockMatrixBase<MatrixType>::block(const unsigned int row,
1585 const unsigned int column) const
1586{
1587 AssertIndexRange(row, n_block_rows());
1588 AssertIndexRange(column, n_block_cols());
1589
1590 return *sub_objects[row][column];
1591}
1592
1593
1594template <typename MatrixType>
1597{
1598 return row_block_indices.total_size();
1599}
1600
1601
1602
1603template <typename MatrixType>
1606{
1607 return column_block_indices.total_size();
1608}
1609
1610
1611
1612template <typename MatrixType>
1613inline unsigned int
1615{
1616 return column_block_indices.size();
1617}
1618
1619
1620
1621template <typename MatrixType>
1622inline unsigned int
1624{
1625 return row_block_indices.size();
1626}
1627
1628
1629
1630// Write the single set manually,
1631// since the other function has a lot
1632// of overhead in that case.
1633template <typename MatrixType>
1634inline void
1635BlockMatrixBase<MatrixType>::set(const size_type i,
1636 const size_type j,
1637 const value_type value)
1638{
1639 prepare_set_operation();
1640
1641 AssertIsFinite(value);
1642
1643 const std::pair<unsigned int, size_type>
1644 row_index = row_block_indices.global_to_local(i),
1645 col_index = column_block_indices.global_to_local(j);
1646 block(row_index.first, col_index.first)
1647 .set(row_index.second, col_index.second, value);
1648}
1649
1650
1651
1652template <typename MatrixType>
1653template <typename number>
1654inline void
1655BlockMatrixBase<MatrixType>::set(const std::vector<size_type> &row_indices,
1656 const std::vector<size_type> &col_indices,
1657 const FullMatrix<number> &values,
1658 const bool elide_zero_values)
1659{
1660 Assert(row_indices.size() == values.m(),
1661 ExcDimensionMismatch(row_indices.size(), values.m()));
1662 Assert(col_indices.size() == values.n(),
1663 ExcDimensionMismatch(col_indices.size(), values.n()));
1664
1665 for (size_type i = 0; i < row_indices.size(); ++i)
1666 set(row_indices[i],
1667 col_indices.size(),
1668 col_indices.data(),
1669 &values(i, 0),
1670 elide_zero_values);
1671}
1672
1673
1674
1675template <typename MatrixType>
1676template <typename number>
1677inline void
1678BlockMatrixBase<MatrixType>::set(const std::vector<size_type> &indices,
1679 const FullMatrix<number> &values,
1680 const bool elide_zero_values)
1681{
1682 Assert(indices.size() == values.m(),
1683 ExcDimensionMismatch(indices.size(), values.m()));
1684 Assert(values.n() == values.m(), ExcNotQuadratic());
1685
1686 for (size_type i = 0; i < indices.size(); ++i)
1687 set(indices[i],
1688 indices.size(),
1689 indices.data(),
1690 &values(i, 0),
1691 elide_zero_values);
1692}
1693
1694
1695
1696template <typename MatrixType>
1697template <typename number>
1698inline void
1699BlockMatrixBase<MatrixType>::set(const size_type row,
1700 const std::vector<size_type> &col_indices,
1701 const std::vector<number> &values,
1702 const bool elide_zero_values)
1703{
1704 Assert(col_indices.size() == values.size(),
1705 ExcDimensionMismatch(col_indices.size(), values.size()));
1706
1707 set(row,
1708 col_indices.size(),
1709 col_indices.data(),
1710 values.data(),
1711 elide_zero_values);
1712}
1713
1714
1715
1716// This is a very messy function, since
1717// we need to calculate to each position
1718// the location in the global array.
1719template <typename MatrixType>
1720template <typename number>
1721inline void
1722BlockMatrixBase<MatrixType>::set(const size_type row,
1723 const size_type n_cols,
1724 const size_type *col_indices,
1725 const number *values,
1726 const bool elide_zero_values)
1727{
1728 prepare_set_operation();
1729
1730 // lock access to the temporary data structure to
1731 // allow multiple threads to call this function concurrently
1732 std::scoped_lock lock(temporary_data.mutex);
1733
1734 // Resize scratch arrays
1735 if (temporary_data.column_indices.size() < this->n_block_cols())
1736 {
1737 temporary_data.column_indices.resize(this->n_block_cols());
1738 temporary_data.column_values.resize(this->n_block_cols());
1739 temporary_data.counter_within_block.resize(this->n_block_cols());
1740 }
1741
1742 // Resize sub-arrays to n_cols. This
1743 // is a bit wasteful, but we resize
1744 // only a few times (then the maximum
1745 // row length won't increase that
1746 // much any more). At least we know
1747 // that all arrays are going to be of
1748 // the same size, so we can check
1749 // whether the size of one is large
1750 // enough before actually going
1751 // through all of them.
1752 if (temporary_data.column_indices[0].size() < n_cols)
1753 {
1754 for (unsigned int i = 0; i < this->n_block_cols(); ++i)
1755 {
1756 temporary_data.column_indices[i].resize(n_cols);
1757 temporary_data.column_values[i].resize(n_cols);
1758 }
1759 }
1760
1761 // Reset the number of added elements
1762 // in each block to zero.
1763 for (unsigned int i = 0; i < this->n_block_cols(); ++i)
1764 temporary_data.counter_within_block[i] = 0;
1765
1766 // Go through the column indices to
1767 // find out which portions of the
1768 // values should be set in which
1769 // block of the matrix. We need to
1770 // touch all the data, since we can't
1771 // be sure that the data of one block
1772 // is stored contiguously (in fact,
1773 // indices will be intermixed when it
1774 // comes from an element matrix).
1775 for (size_type j = 0; j < n_cols; ++j)
1776 {
1777 number value = values[j];
1778
1779 if (value == number() && elide_zero_values == true)
1780 continue;
1781
1782 const std::pair<unsigned int, size_type> col_index =
1783 this->column_block_indices.global_to_local(col_indices[j]);
1784
1785 const size_type local_index =
1786 temporary_data.counter_within_block[col_index.first]++;
1787
1788 temporary_data.column_indices[col_index.first][local_index] =
1789 col_index.second;
1790 temporary_data.column_values[col_index.first][local_index] = value;
1791 }
1792
1793 if constexpr (running_in_debug_mode())
1794 {
1795 // If in debug mode, do a check whether
1796 // the right length has been obtained.
1797 size_type length = 0;
1798 for (unsigned int i = 0; i < this->n_block_cols(); ++i)
1799 length += temporary_data.counter_within_block[i];
1800 Assert(length <= n_cols, ExcInternalError());
1801 }
1802
1803 // Now we found out about where the
1804 // individual columns should start and
1805 // where we should start reading out
1806 // data. Now let's write the data into
1807 // the individual blocks!
1808 const std::pair<unsigned int, size_type> row_index =
1809 this->row_block_indices.global_to_local(row);
1810 for (unsigned int block_col = 0; block_col < n_block_cols(); ++block_col)
1811 {
1812 if (temporary_data.counter_within_block[block_col] == 0)
1813 continue;
1814
1815 block(row_index.first, block_col)
1816 .set(row_index.second,
1817 temporary_data.counter_within_block[block_col],
1818 temporary_data.column_indices[block_col].data(),
1819 temporary_data.column_values[block_col].data(),
1820 false);
1821 }
1822}
1823
1824
1825
1826template <typename MatrixType>
1827inline void
1828BlockMatrixBase<MatrixType>::add(const size_type i,
1829 const size_type j,
1830 const value_type value)
1831{
1832 AssertIsFinite(value);
1833
1834 prepare_add_operation();
1835
1836 // save some cycles for zero additions, but
1837 // only if it is safe for the matrix we are
1838 // working with
1839 using MatrixTraits = typename MatrixType::Traits;
1840 if ((MatrixTraits::zero_addition_can_be_elided == true) &&
1841 (value == value_type()))
1842 return;
1843
1844 const std::pair<unsigned int, size_type>
1845 row_index = row_block_indices.global_to_local(i),
1846 col_index = column_block_indices.global_to_local(j);
1847 block(row_index.first, col_index.first)
1848 .add(row_index.second, col_index.second, value);
1849}
1850
1851
1852
1853template <typename MatrixType>
1854template <typename number>
1855inline void
1856BlockMatrixBase<MatrixType>::add(const std::vector<size_type> &row_indices,
1857 const std::vector<size_type> &col_indices,
1858 const FullMatrix<number> &values,
1859 const bool elide_zero_values)
1860{
1861 Assert(row_indices.size() == values.m(),
1862 ExcDimensionMismatch(row_indices.size(), values.m()));
1863 Assert(col_indices.size() == values.n(),
1864 ExcDimensionMismatch(col_indices.size(), values.n()));
1865
1866 for (size_type i = 0; i < row_indices.size(); ++i)
1867 add(row_indices[i],
1868 col_indices.size(),
1869 col_indices.data(),
1870 &values(i, 0),
1871 elide_zero_values);
1872}
1873
1874
1875
1876template <typename MatrixType>
1877template <typename number>
1878inline void
1879BlockMatrixBase<MatrixType>::add(const std::vector<size_type> &indices,
1880 const FullMatrix<number> &values,
1881 const bool elide_zero_values)
1882{
1883 Assert(indices.size() == values.m(),
1884 ExcDimensionMismatch(indices.size(), values.m()));
1885 Assert(values.n() == values.m(), ExcNotQuadratic());
1886
1887 for (size_type i = 0; i < indices.size(); ++i)
1888 add(indices[i],
1889 indices.size(),
1890 indices.data(),
1891 &values(i, 0),
1892 elide_zero_values);
1893}
1894
1895
1896
1897template <typename MatrixType>
1898template <typename number>
1899inline void
1900BlockMatrixBase<MatrixType>::add(const size_type row,
1901 const std::vector<size_type> &col_indices,
1902 const std::vector<number> &values,
1903 const bool elide_zero_values)
1904{
1905 Assert(col_indices.size() == values.size(),
1906 ExcDimensionMismatch(col_indices.size(), values.size()));
1907
1908 add(row,
1909 col_indices.size(),
1910 col_indices.data(),
1911 values.data(),
1912 elide_zero_values);
1913}
1914
1915
1916
1917// This is a very messy function, since
1918// we need to calculate to each position
1919// the location in the global array.
1920template <typename MatrixType>
1921template <typename number>
1922inline void
1923BlockMatrixBase<MatrixType>::add(const size_type row,
1924 const size_type n_cols,
1925 const size_type *col_indices,
1926 const number *values,
1927 const bool elide_zero_values,
1928 const bool col_indices_are_sorted)
1929{
1930 prepare_add_operation();
1931
1932 // TODO: Look over this to find out
1933 // whether we can do that more
1934 // efficiently.
1935 if (col_indices_are_sorted == true)
1936 {
1937 if constexpr (running_in_debug_mode())
1938 {
1939 // check whether indices really are
1940 // sorted.
1941 size_type before = col_indices[0];
1942 for (size_type i = 1; i < n_cols; ++i)
1943 if (col_indices[i] <= before)
1944 {
1945 Assert(false,
1946 ExcMessage("Flag col_indices_are_sorted is set, but "
1947 "indices appear to not be sorted."));
1948 }
1949 else
1950 before = col_indices[i];
1951 }
1952 const std::pair<unsigned int, size_type> row_index =
1953 this->row_block_indices.global_to_local(row);
1954
1955 if (this->n_block_cols() > 1)
1956 {
1957 const size_type *first_block =
1958 Utilities::lower_bound(col_indices,
1959 col_indices + n_cols,
1960 this->column_block_indices.block_start(1));
1961
1962 const size_type n_zero_block_indices = first_block - col_indices;
1963 block(row_index.first, 0)
1964 .add(row_index.second,
1965 n_zero_block_indices,
1966 col_indices,
1967 values,
1968 elide_zero_values,
1969 col_indices_are_sorted);
1970
1971 if (n_zero_block_indices < n_cols)
1972 this->add(row,
1973 n_cols - n_zero_block_indices,
1974 first_block,
1975 values + n_zero_block_indices,
1976 elide_zero_values,
1977 false);
1978 }
1979 else
1980 {
1981 block(row_index.first, 0)
1982 .add(row_index.second,
1983 n_cols,
1984 col_indices,
1985 values,
1986 elide_zero_values,
1987 col_indices_are_sorted);
1988 }
1989
1990 return;
1991 }
1992
1993 // Lock scratch arrays, then resize them
1994 std::scoped_lock lock(temporary_data.mutex);
1995
1996 if (temporary_data.column_indices.size() < this->n_block_cols())
1997 {
1998 temporary_data.column_indices.resize(this->n_block_cols());
1999 temporary_data.column_values.resize(this->n_block_cols());
2000 temporary_data.counter_within_block.resize(this->n_block_cols());
2001 }
2002
2003 // Resize sub-arrays to n_cols. This
2004 // is a bit wasteful, but we resize
2005 // only a few times (then the maximum
2006 // row length won't increase that
2007 // much any more). At least we know
2008 // that all arrays are going to be of
2009 // the same size, so we can check
2010 // whether the size of one is large
2011 // enough before actually going
2012 // through all of them.
2013 if (temporary_data.column_indices[0].size() < n_cols)
2014 {
2015 for (unsigned int i = 0; i < this->n_block_cols(); ++i)
2016 {
2017 temporary_data.column_indices[i].resize(n_cols);
2018 temporary_data.column_values[i].resize(n_cols);
2019 }
2020 }
2021
2022 // Reset the number of added elements
2023 // in each block to zero.
2024 for (unsigned int i = 0; i < this->n_block_cols(); ++i)
2025 temporary_data.counter_within_block[i] = 0;
2026
2027 // Go through the column indices to
2028 // find out which portions of the
2029 // values should be written into
2030 // which block of the matrix. We need
2031 // to touch all the data, since we
2032 // can't be sure that the data of one
2033 // block is stored contiguously (in
2034 // fact, data will be intermixed when
2035 // it comes from an element matrix).
2036 for (size_type j = 0; j < n_cols; ++j)
2037 {
2038 number value = values[j];
2039
2040 if (value == number() && elide_zero_values == true)
2041 continue;
2042
2043 const std::pair<unsigned int, size_type> col_index =
2044 this->column_block_indices.global_to_local(col_indices[j]);
2045
2046 const size_type local_index =
2047 temporary_data.counter_within_block[col_index.first]++;
2048
2049 temporary_data.column_indices[col_index.first][local_index] =
2050 col_index.second;
2051 temporary_data.column_values[col_index.first][local_index] = value;
2052 }
2053
2054 if constexpr (running_in_debug_mode())
2055 {
2056 // If in debug mode, do a check whether
2057 // the right length has been obtained.
2058 size_type length = 0;
2059 for (unsigned int i = 0; i < this->n_block_cols(); ++i)
2060 length += temporary_data.counter_within_block[i];
2061 Assert(length <= n_cols, ExcInternalError());
2062 }
2063
2064 // Now we found out about where the
2065 // individual columns should start and
2066 // where we should start reading out
2067 // data. Now let's write the data into
2068 // the individual blocks!
2069 const std::pair<unsigned int, size_type> row_index =
2070 this->row_block_indices.global_to_local(row);
2071 for (unsigned int block_col = 0; block_col < n_block_cols(); ++block_col)
2072 {
2073 if (temporary_data.counter_within_block[block_col] == 0)
2074 continue;
2075
2076 block(row_index.first, block_col)
2077 .add(row_index.second,
2078 temporary_data.counter_within_block[block_col],
2079 temporary_data.column_indices[block_col].data(),
2080 temporary_data.column_values[block_col].data(),
2081 false,
2082 col_indices_are_sorted);
2083 }
2084}
2085
2086
2087
2088template <typename MatrixType>
2089inline void
2091 const BlockMatrixBase<MatrixType> &matrix)
2092{
2093 AssertIsFinite(factor);
2094
2095 prepare_add_operation();
2096
2097 // save some cycles for zero additions, but
2098 // only if it is safe for the matrix we are
2099 // working with
2100 using MatrixTraits = typename MatrixType::Traits;
2101 if ((MatrixTraits::zero_addition_can_be_elided == true) && (factor == 0))
2102 return;
2103
2104 for (unsigned int row = 0; row < n_block_rows(); ++row)
2105 for (unsigned int col = 0; col < n_block_cols(); ++col)
2106 // This function should throw if the sparsity
2107 // patterns of the two blocks differ
2108 block(row, col).add(factor, matrix.block(row, col));
2109}
2110
2111
2112
2113template <typename MatrixType>
2116 const size_type j) const
2117{
2118 const std::pair<unsigned int, size_type>
2119 row_index = row_block_indices.global_to_local(i),
2120 col_index = column_block_indices.global_to_local(j);
2121 return block(row_index.first, col_index.first)(row_index.second,
2122 col_index.second);
2123}
2124
2125
2126
2127template <typename MatrixType>
2129BlockMatrixBase<MatrixType>::el(const size_type i, const size_type j) const
2130{
2131 const std::pair<unsigned int, size_type>
2132 row_index = row_block_indices.global_to_local(i),
2133 col_index = column_block_indices.global_to_local(j);
2134 return block(row_index.first, col_index.first)
2135 .el(row_index.second, col_index.second);
2136}
2137
2138
2139
2140template <typename MatrixType>
2142BlockMatrixBase<MatrixType>::diag_element(const size_type i) const
2143{
2144 Assert(n_block_rows() == n_block_cols(), ExcNotQuadratic());
2145
2146 const std::pair<unsigned int, size_type> index =
2147 row_block_indices.global_to_local(i);
2148 return block(index.first, index.first).diag_element(index.second);
2149}
2150
2151
2152
2153template <typename MatrixType>
2154inline void
2156{
2157 for (unsigned int r = 0; r < n_block_rows(); ++r)
2158 for (unsigned int c = 0; c < n_block_cols(); ++c)
2159 block(r, c).compress(operation);
2160}
2161
2162
2163
2164template <typename MatrixType>
2167{
2168 Assert(n_block_cols() != 0, ExcNotInitialized());
2169 Assert(n_block_rows() != 0, ExcNotInitialized());
2170
2171 for (unsigned int r = 0; r < n_block_rows(); ++r)
2172 for (unsigned int c = 0; c < n_block_cols(); ++c)
2173 block(r, c) *= factor;
2174
2175 return *this;
2176}
2177
2178
2179
2180template <typename MatrixType>
2183{
2184 Assert(n_block_cols() != 0, ExcNotInitialized());
2185 Assert(n_block_rows() != 0, ExcNotInitialized());
2186 Assert(factor != 0, ExcDivideByZero());
2187
2188 const value_type factor_inv = 1. / factor;
2189
2190 for (unsigned int r = 0; r < n_block_rows(); ++r)
2191 for (unsigned int c = 0; c < n_block_cols(); ++c)
2192 block(r, c) *= factor_inv;
2193
2194 return *this;
2195}
2196
2197
2198
2199template <typename MatrixType>
2200const BlockIndices &
2202{
2203 return this->row_block_indices;
2204}
2205
2206
2207
2208template <typename MatrixType>
2209const BlockIndices &
2211{
2212 return this->column_block_indices;
2213}
2214
2215
2216
2217template <typename MatrixType>
2218template <typename BlockVectorType>
2219void
2221 const BlockVectorType &src) const
2222{
2223 Assert(dst.n_blocks() == n_block_rows(),
2224 ExcDimensionMismatch(dst.n_blocks(), n_block_rows()));
2225 Assert(src.n_blocks() == n_block_cols(),
2226 ExcDimensionMismatch(src.n_blocks(), n_block_cols()));
2227
2228 for (size_type row = 0; row < n_block_rows(); ++row)
2229 {
2230 block(row, 0).vmult(dst.block(row), src.block(0));
2231 for (size_type col = 1; col < n_block_cols(); ++col)
2232 block(row, col).vmult_add(dst.block(row), src.block(col));
2233 };
2234}
2235
2236
2237
2238template <typename MatrixType>
2239template <typename BlockVectorType, typename VectorType>
2240void
2242 VectorType &dst,
2243 const BlockVectorType &src) const
2244{
2245 Assert(n_block_rows() == 1, ExcDimensionMismatch(1, n_block_rows()));
2246 Assert(src.n_blocks() == n_block_cols(),
2247 ExcDimensionMismatch(src.n_blocks(), n_block_cols()));
2248
2249 block(0, 0).vmult(dst, src.block(0));
2250 for (size_type col = 1; col < n_block_cols(); ++col)
2251 block(0, col).vmult_add(dst, src.block(col));
2252}
2253
2254
2255
2256template <typename MatrixType>
2257template <typename BlockVectorType, typename VectorType>
2258void
2260 const VectorType &src) const
2261{
2262 Assert(dst.n_blocks() == n_block_rows(),
2263 ExcDimensionMismatch(dst.n_blocks(), n_block_rows()));
2264 Assert(1 == n_block_cols(), ExcDimensionMismatch(1, n_block_cols()));
2265
2266 for (size_type row = 0; row < n_block_rows(); ++row)
2267 block(row, 0).vmult(dst.block(row), src);
2268}
2269
2270
2271
2272template <typename MatrixType>
2273template <typename VectorType>
2274void
2276 VectorType &dst,
2277 const VectorType &src) const
2278{
2279 Assert(1 == n_block_rows(), ExcDimensionMismatch(1, n_block_rows()));
2280 Assert(1 == n_block_cols(), ExcDimensionMismatch(1, n_block_cols()));
2281
2282 block(0, 0).vmult(dst, src);
2283}
2284
2285
2286
2287template <typename MatrixType>
2288template <typename BlockVectorType>
2289void
2290BlockMatrixBase<MatrixType>::vmult_add(BlockVectorType &dst,
2291 const BlockVectorType &src) const
2292{
2293 Assert(dst.n_blocks() == n_block_rows(),
2294 ExcDimensionMismatch(dst.n_blocks(), n_block_rows()));
2295 Assert(src.n_blocks() == n_block_cols(),
2296 ExcDimensionMismatch(src.n_blocks(), n_block_cols()));
2297
2298 for (unsigned int row = 0; row < n_block_rows(); ++row)
2299 for (unsigned int col = 0; col < n_block_cols(); ++col)
2300 block(row, col).vmult_add(dst.block(row), src.block(col));
2301}
2302
2303
2304
2305template <typename MatrixType>
2306template <typename BlockVectorType>
2307void
2309 BlockVectorType &dst,
2310 const BlockVectorType &src) const
2311{
2312 Assert(dst.n_blocks() == n_block_cols(),
2313 ExcDimensionMismatch(dst.n_blocks(), n_block_cols()));
2314 Assert(src.n_blocks() == n_block_rows(),
2315 ExcDimensionMismatch(src.n_blocks(), n_block_rows()));
2316
2317 dst = 0.;
2318
2319 for (unsigned int row = 0; row < n_block_rows(); ++row)
2320 {
2321 for (unsigned int col = 0; col < n_block_cols(); ++col)
2322 block(row, col).Tvmult_add(dst.block(col), src.block(row));
2323 };
2324}
2325
2326
2327
2328template <typename MatrixType>
2329template <typename BlockVectorType, typename VectorType>
2330void
2332 const VectorType &src) const
2333{
2334 Assert(dst.n_blocks() == n_block_cols(),
2335 ExcDimensionMismatch(dst.n_blocks(), n_block_cols()));
2336 Assert(1 == n_block_rows(), ExcDimensionMismatch(1, n_block_rows()));
2337
2338 dst = 0.;
2339
2340 for (unsigned int col = 0; col < n_block_cols(); ++col)
2341 block(0, col).Tvmult_add(dst.block(col), src);
2342}
2343
2344
2345
2346template <typename MatrixType>
2347template <typename BlockVectorType, typename VectorType>
2348void
2350 VectorType &dst,
2351 const BlockVectorType &src) const
2352{
2353 Assert(1 == n_block_cols(), ExcDimensionMismatch(1, n_block_cols()));
2354 Assert(src.n_blocks() == n_block_rows(),
2355 ExcDimensionMismatch(src.n_blocks(), n_block_rows()));
2356
2357 block(0, 0).Tvmult(dst, src.block(0));
2358
2359 for (size_type row = 1; row < n_block_rows(); ++row)
2360 block(row, 0).Tvmult_add(dst, src.block(row));
2361}
2362
2363
2364
2365template <typename MatrixType>
2366template <typename VectorType>
2367void
2369 VectorType &dst,
2370 const VectorType &src) const
2371{
2372 Assert(1 == n_block_cols(), ExcDimensionMismatch(1, n_block_cols()));
2373 Assert(1 == n_block_rows(), ExcDimensionMismatch(1, n_block_rows()));
2374
2375 block(0, 0).Tvmult(dst, src);
2376}
2377
2378
2379
2380template <typename MatrixType>
2381template <typename BlockVectorType>
2382void
2383BlockMatrixBase<MatrixType>::Tvmult_add(BlockVectorType &dst,
2384 const BlockVectorType &src) const
2385{
2386 Assert(dst.n_blocks() == n_block_cols(),
2387 ExcDimensionMismatch(dst.n_blocks(), n_block_cols()));
2388 Assert(src.n_blocks() == n_block_rows(),
2389 ExcDimensionMismatch(src.n_blocks(), n_block_rows()));
2390
2391 for (unsigned int row = 0; row < n_block_rows(); ++row)
2392 for (unsigned int col = 0; col < n_block_cols(); ++col)
2393 block(row, col).Tvmult_add(dst.block(col), src.block(row));
2394}
2395
2396
2397
2398template <typename MatrixType>
2399template <typename BlockVectorType>
2401BlockMatrixBase<MatrixType>::matrix_norm_square(const BlockVectorType &v) const
2402{
2403 Assert(n_block_rows() == n_block_cols(), ExcNotQuadratic());
2404 Assert(v.n_blocks() == n_block_rows(),
2405 ExcDimensionMismatch(v.n_blocks(), n_block_rows()));
2406
2407 value_type norm_sqr = 0;
2408 for (unsigned int row = 0; row < n_block_rows(); ++row)
2409 for (unsigned int col = 0; col < n_block_cols(); ++col)
2410 if (row == col)
2411 norm_sqr += block(row, col).matrix_norm_square(v.block(row));
2412 else
2413 norm_sqr +=
2414 block(row, col).matrix_scalar_product(v.block(row), v.block(col));
2415 return norm_sqr;
2416}
2417
2418
2419
2420template <typename MatrixType>
2423{
2424 value_type norm_sqr = 0;
2425
2426 // For each block, get the Frobenius norm, and add the square to the
2427 // accumulator for the full matrix
2428 for (unsigned int row = 0; row < n_block_rows(); ++row)
2429 {
2430 for (unsigned int col = 0; col < n_block_cols(); ++col)
2431 {
2432 const value_type block_norm = block(row, col).frobenius_norm();
2433 norm_sqr += block_norm * block_norm;
2434 }
2435 }
2436
2437 return std::sqrt(norm_sqr);
2438}
2439
2440
2441
2442template <typename MatrixType>
2443template <typename BlockVectorType>
2446 const BlockVectorType &u,
2447 const BlockVectorType &v) const
2448{
2449 Assert(u.n_blocks() == n_block_rows(),
2450 ExcDimensionMismatch(u.n_blocks(), n_block_rows()));
2451 Assert(v.n_blocks() == n_block_cols(),
2452 ExcDimensionMismatch(v.n_blocks(), n_block_cols()));
2453
2454 value_type result = 0;
2455 for (unsigned int row = 0; row < n_block_rows(); ++row)
2456 for (unsigned int col = 0; col < n_block_cols(); ++col)
2457 result +=
2458 block(row, col).matrix_scalar_product(u.block(row), v.block(col));
2459 return result;
2460}
2461
2462
2463
2464template <typename MatrixType>
2465template <typename BlockVectorType>
2467BlockMatrixBase<MatrixType>::residual(BlockVectorType &dst,
2468 const BlockVectorType &x,
2469 const BlockVectorType &b) const
2470{
2471 Assert(dst.n_blocks() == n_block_rows(),
2472 ExcDimensionMismatch(dst.n_blocks(), n_block_rows()));
2473 Assert(b.n_blocks() == n_block_rows(),
2474 ExcDimensionMismatch(b.n_blocks(), n_block_rows()));
2475 Assert(x.n_blocks() == n_block_cols(),
2476 ExcDimensionMismatch(x.n_blocks(), n_block_cols()));
2477 // in block notation, the residual is
2478 // r_i = b_i - \sum_j A_ij x_j.
2479 // this can be written as
2480 // r_i = b_i - A_i0 x_0 - \sum_{j>0} A_ij x_j.
2481 //
2482 // for the first two terms, we can
2483 // call the residual function of
2484 // A_i0. for the other terms, we
2485 // use vmult_add. however, we want
2486 // to subtract, so in order to
2487 // avoid a temporary vector, we
2488 // perform a sign change of the
2489 // first two term before, and after
2490 // adding up
2491 for (unsigned int row = 0; row < n_block_rows(); ++row)
2492 {
2493 block(row, 0).residual(dst.block(row), x.block(0), b.block(row));
2494
2495 for (size_type i = 0; i < dst.block(row).size(); ++i)
2496 dst.block(row)(i) = -dst.block(row)(i);
2497
2498 for (unsigned int col = 1; col < n_block_cols(); ++col)
2499 block(row, col).vmult_add(dst.block(row), x.block(col));
2500
2501 for (size_type i = 0; i < dst.block(row).size(); ++i)
2502 dst.block(row)(i) = -dst.block(row)(i);
2503 };
2504
2505 value_type res = 0;
2506 for (size_type row = 0; row < n_block_rows(); ++row)
2507 res += dst.block(row).norm_sqr();
2508 return std::sqrt(res);
2509}
2510
2511
2512
2513template <typename MatrixType>
2514inline void
2515BlockMatrixBase<MatrixType>::print(std::ostream &out,
2516 const bool alternative_output) const
2517{
2518 for (unsigned int row = 0; row < n_block_rows(); ++row)
2519 for (unsigned int col = 0; col < n_block_cols(); ++col)
2520 {
2521 if (!alternative_output)
2522 out << "Block (" << row << ", " << col << ')' << std::endl;
2523
2524 block(row, col).print(out, alternative_output);
2525 }
2526}
2527
2528
2529
2530template <typename MatrixType>
2533{
2534 return const_iterator(this, 0);
2535}
2536
2537
2538
2539template <typename MatrixType>
2542{
2543 return const_iterator(this, m());
2544}
2545
2546
2547
2548template <typename MatrixType>
2550BlockMatrixBase<MatrixType>::begin(const size_type r) const
2551{
2552 AssertIndexRange(r, m());
2553 return const_iterator(this, r);
2554}
2555
2556
2557
2558template <typename MatrixType>
2560BlockMatrixBase<MatrixType>::end(const size_type r) const
2561{
2562 AssertIndexRange(r, m());
2563 return const_iterator(this, r + 1);
2564}
2565
2566
2567
2568template <typename MatrixType>
2571{
2572 return iterator(this, 0);
2573}
2574
2575
2576
2577template <typename MatrixType>
2580{
2581 return iterator(this, m());
2582}
2583
2584
2585
2586template <typename MatrixType>
2588BlockMatrixBase<MatrixType>::begin(const size_type r)
2589{
2590 AssertIndexRange(r, m());
2591 return iterator(this, r);
2592}
2593
2594
2595
2596template <typename MatrixType>
2598BlockMatrixBase<MatrixType>::end(const size_type r)
2599{
2600 AssertIndexRange(r, m());
2601 return iterator(this, r + 1);
2602}
2603
2604
2605
2606template <typename MatrixType>
2607void
2609{
2610 std::vector<size_type> row_sizes(this->n_block_rows());
2611 std::vector<size_type> col_sizes(this->n_block_cols());
2612
2613 // first find out the row sizes
2614 // from the first block column
2615 for (unsigned int r = 0; r < this->n_block_rows(); ++r)
2616 row_sizes[r] = sub_objects[r][0]->m();
2617 // then check that the following
2618 // block columns have the same
2619 // sizes
2620 for (unsigned int c = 1; c < this->n_block_cols(); ++c)
2621 for (unsigned int r = 0; r < this->n_block_rows(); ++r)
2622 Assert(row_sizes[r] == sub_objects[r][c]->m(),
2623 ExcIncompatibleRowNumbers(r, 0, r, c));
2624
2625 // finally initialize the row
2626 // indices with this array
2627 this->row_block_indices.reinit(row_sizes);
2628
2629
2630 // then do the same with the columns
2631 for (unsigned int c = 0; c < this->n_block_cols(); ++c)
2632 col_sizes[c] = sub_objects[0][c]->n();
2633 for (unsigned int r = 1; r < this->n_block_rows(); ++r)
2634 for (unsigned int c = 0; c < this->n_block_cols(); ++c)
2635 Assert(col_sizes[c] == sub_objects[r][c]->n(),
2636 ExcIncompatibleRowNumbers(0, c, r, c));
2637
2638 // finally initialize the row
2639 // indices with this array
2640 this->column_block_indices.reinit(col_sizes);
2641}
2642
2643
2644
2645template <typename MatrixType>
2646void
2648{
2649 for (unsigned int row = 0; row < n_block_rows(); ++row)
2650 for (unsigned int col = 0; col < n_block_cols(); ++col)
2651 block(row, col).prepare_add();
2652}
2653
2654
2655
2656template <typename MatrixType>
2657void
2659{
2660 for (unsigned int row = 0; row < n_block_rows(); ++row)
2661 for (unsigned int col = 0; col < n_block_cols(); ++col)
2662 block(row, col).prepare_set();
2663}
2664
2665#endif // DOXYGEN
2666
2667
2669
2670#endif // dealii_block_matrix_base_h
*  *  iterator begin()
*  x_component_mask set(0, true)
*  *  const_iterator()=default
*  *  iterator()=default
void Tvmult_nonblock_nonblock(VectorType &dst, const VectorType &src) const
void vmult_nonblock_nonblock(VectorType &dst, const VectorType &src) const
void add(const size_type row, const std::vector< size_type > &col_indices, const std::vector< number > &values, const bool elide_zero_values=true)
void add(const std::vector< size_type > &row_indices, const std::vector< size_type > &col_indices, const FullMatrix< number > &full_matrix, const bool elide_zero_values=true)
value_type & reference
void add(const size_type row, const size_type n_cols, const size_type *col_indices, const number *values, const bool elide_zero_values=true, const bool col_indices_are_sorted=false)
void print(std::ostream &out, const bool alternative_output=false) const
friend class BlockMatrixIterators::Accessor
const_iterator end() const
BlockIndices column_block_indices
BlockMatrixBase & operator*=(const value_type factor)
value_type matrix_norm_square(const BlockVectorType &v) const
void Tvmult_block_block(BlockVectorType &dst, const BlockVectorType &src) const
const value_type & const_reference
void Tvmult_nonblock_block(VectorType &dst, const BlockVectorType &src) const
unsigned int n_block_rows() const
value_type operator()(const size_type i, const size_type j) const
value_type el(const size_type i, const size_type j) const
const_iterator begin() const
real_type frobenius_norm() const
void vmult_block_block(BlockVectorType &dst, const BlockVectorType &src) const
void compress(VectorOperation::values operation)
void vmult_add(BlockVectorType &dst, const BlockVectorType &src) const
types::global_dof_index size_type
void Tvmult_add(BlockVectorType &dst, const BlockVectorType &src) const
typename BlockType::value_type value_type
void collect_sizes()
void prepare_add_operation()
void vmult_nonblock_block(VectorType &dst, const BlockVectorType &src) const
value_type residual(BlockVectorType &dst, const BlockVectorType &x, const BlockVectorType &b) const
BlockMatrixBase()=default
void set(const size_type row, const size_type n_cols, const size_type *col_indices, const number *values, const bool elide_zero_values=false)
size_type n() const
void prepare_set_operation()
unsigned int n_block_cols() const
const value_type * const_pointer
iterator begin()
TemporaryData temporary_data
const BlockIndices & get_row_indices() const
iterator end()
void set(const size_type i, const size_type j, const value_type value)
BlockMatrixBase & copy_from(const BlockMatrixType &source)
std::size_t memory_consumption() const
void add(const value_type factor, const BlockMatrixBase< MatrixType > &matrix)
const BlockType & block(const unsigned int row, const unsigned int column) const
typename numbers::NumberTraits< value_type >::real_type real_type
BlockIndices row_block_indices
~BlockMatrixBase() override
BlockType & block(const unsigned int row, const unsigned int column)
size_type m() const
value_type matrix_scalar_product(const BlockVectorType &u, const BlockVectorType &v) const
const BlockIndices & get_column_indices() const
void set(const std::vector< size_type > &indices, const FullMatrix< number > &full_matrix, const bool elide_zero_values=false)
void add(const std::vector< size_type > &indices, const FullMatrix< number > &full_matrix, const bool elide_zero_values=true)
void add(const size_type i, const size_type j, const value_type value)
void set(const size_type row, const std::vector< size_type > &col_indices, const std::vector< number > &values, const bool elide_zero_values=false)
value_type diag_element(const size_type i) const
void vmult_block_nonblock(BlockVectorType &dst, const VectorType &src) const
Table< 2, ObserverPointer< BlockType, BlockMatrixBase< MatrixType > > > sub_objects
iterator begin(const size_type r)
const_iterator begin(const size_type r) const
BlockMatrixBase & operator/=(const value_type factor)
void Tvmult_block_nonblock(BlockVectorType &dst, const VectorType &src) const
iterator end(const size_type r)
const_iterator end(const size_type r) const
void set(const std::vector< size_type > &row_indices, const std::vector< size_type > &col_indices, const FullMatrix< number > &full_matrix, const bool elide_zero_values=false)
unsigned int block_row() const
unsigned int block_column() const
typename BlockMatrixType::value_type value_type
Accessor(BlockMatrixType *m, const size_type row, const size_type col)
Accessor(const Accessor< BlockMatrixType, false > &)
BlockMatrixType::BlockType::const_iterator base_iterator
Accessor(const BlockMatrixType *m, const size_type row, const size_type col)
#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 DeclException4(Exception4, type1, type2, type3, type4, outsequence)
static ::ExceptionBase & ExcIncompatibleColNumbers(int arg1, int arg2, int arg3, int arg4)
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
static ::ExceptionBase & ExcIncompatibleRowNumbers(int arg1, int arg2, int arg3, int arg4)
static ::ExceptionBase & ExcIteratorPastEnd()
#define AssertIsFinite(number)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDivideByZero()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcNotInitialized()
static ::ExceptionBase & ExcNotQuadratic()
static ::ExceptionBase & ExcMessage(std::string arg1)
std::size_t size
Definition mpi.cc:733
@ matrix
Contents is actually a matrix.
Tpetra::CrsMatrix< Number, LO, GO, NodeType< MemorySpace > > MatrixType
std::enable_if_t< std::is_fundamental_v< T >, std::size_t > memory_consumption(const T &t)
SymmetricTensor< 2, dim, Number > b(const Tensor< 2, dim, Number > &F)
Iterator lower_bound(Iterator first, Iterator last, const T &val)
Definition utilities.h:1003
constexpr unsigned int invalid_unsigned_int
Definition types.h:228
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
unsigned int global_dof_index
Definition types.h:92
std::vector< std::vector< size_type > > column_indices
std::vector< std::vector< value_type > > column_values
TemporaryData & operator=(const TemporaryData &)
std::vector< size_type > counter_within_block