deal.II version 9.7.0
\(\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: 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// Part of the source code is dual licensed under Apache-2.0 WITH
9// LLVM-exception OR LGPL-2.1-or-later. Detailed license information
10// governing the source code and code contributions can be found in
11// LICENSE.md and CONTRIBUTING.md at the top level directory of deal.II.
12//
13// ------------------------------------------------------------------------
14
15#ifndef dealii_block_matrix_base_h
16#define dealii_block_matrix_base_h
17
18
19#include <deal.II/base/config.h>
20
22#include <deal.II/base/mutex.h>
24#include <deal.II/base/table.h>
26
31#include <deal.II/lac/vector.h>
33
34#include <cmath>
35#include <mutex>
36
38
39
40// Forward declaration
41#ifndef DOXYGEN
42template <typename>
43class MatrixIterator;
44#endif
45
46
51
56{
61 template <typename BlockMatrixType>
63 {
64 public:
69
73 using value_type = typename BlockMatrixType::value_type;
74
79
83 unsigned int
84 block_row() const;
85
89 unsigned int
90 block_column() const;
91
92 protected:
96 unsigned int row_block;
97
101 unsigned int col_block;
102 };
103
104
105
109 template <typename BlockMatrixType, bool Constness>
110 class Accessor;
111
112
116 template <typename BlockMatrixType>
117 class Accessor<BlockMatrixType, false> : public AccessorBase<BlockMatrixType>
118 {
119 public:
124
128 using MatrixType = BlockMatrixType;
129
133 using value_type = typename BlockMatrixType::value_type;
134
143 Accessor(BlockMatrixType *m, const size_type row, const size_type col);
144
149 row() const;
150
155 column() const;
156
161 value() const;
162
166 void
167 set_value(value_type newval) const;
168
169 protected:
173 BlockMatrixType *matrix;
174
178 typename BlockMatrixType::BlockType::iterator base_iterator;
179
183 void
185
189 bool
190 operator==(const Accessor &a) const;
191
192 template <typename>
193 friend class ::MatrixIterator;
194
195 friend class Accessor<BlockMatrixType, true>;
196 };
197
198
199
204 template <typename BlockMatrixType>
205 class Accessor<BlockMatrixType, true> : public AccessorBase<BlockMatrixType>
206 {
207 public:
212
216 using MatrixType = const BlockMatrixType;
217
221 using value_type = typename BlockMatrixType::value_type;
222
231 Accessor(const BlockMatrixType *m,
232 const size_type row,
233 const size_type col);
234
239
244 row() const;
245
250 column() const;
251
256 value() const;
257
258 protected:
262 const BlockMatrixType *matrix;
263
267 typename BlockMatrixType::BlockType::const_iterator base_iterator;
268
272 void
274
278 bool
279 operator==(const Accessor &a) const;
280
281 // Let the iterator class be a friend.
282 template <typename>
283 friend class ::MatrixIterator;
284 };
285} // namespace BlockMatrixIterators
286
287
288
348template <typename MatrixType>
350{
351public:
355 using BlockType = MatrixType;
356
361 using value_type = typename BlockType::value_type;
364 using const_pointer = const value_type *;
368
369 using iterator =
371
374
375
379 BlockMatrixBase() = default;
380
385
402 template <typename BlockMatrixType>
404 copy_from(const BlockMatrixType &source);
405
409 BlockType &
410 block(const unsigned int row, const unsigned int column);
411
412
417 const BlockType &
418 block(const unsigned int row, const unsigned int column) const;
419
425 m() const;
426
432 n() const;
433
434
439 unsigned int
441
446 unsigned int
448
454 void
455 set(const size_type i, const size_type j, const value_type value);
456
472 template <typename number>
473 void
474 set(const std::vector<size_type> &indices,
475 const FullMatrix<number> &full_matrix,
476 const bool elide_zero_values = false);
477
483 template <typename number>
484 void
485 set(const std::vector<size_type> &row_indices,
486 const std::vector<size_type> &col_indices,
487 const FullMatrix<number> &full_matrix,
488 const bool elide_zero_values = false);
489
500 template <typename number>
501 void
502 set(const size_type row,
503 const std::vector<size_type> &col_indices,
504 const std::vector<number> &values,
505 const bool elide_zero_values = false);
506
516 template <typename number>
517 void
518 set(const size_type row,
519 const size_type n_cols,
520 const size_type *col_indices,
521 const number *values,
522 const bool elide_zero_values = false);
523
529 void
530 add(const size_type i, const size_type j, const value_type value);
531
546 template <typename number>
547 void
548 add(const std::vector<size_type> &indices,
549 const FullMatrix<number> &full_matrix,
550 const bool elide_zero_values = true);
551
557 template <typename number>
558 void
559 add(const std::vector<size_type> &row_indices,
560 const std::vector<size_type> &col_indices,
561 const FullMatrix<number> &full_matrix,
562 const bool elide_zero_values = true);
563
573 template <typename number>
574 void
575 add(const size_type row,
576 const std::vector<size_type> &col_indices,
577 const std::vector<number> &values,
578 const bool elide_zero_values = true);
579
589 template <typename number>
590 void
591 add(const size_type row,
592 const size_type n_cols,
593 const size_type *col_indices,
594 const number *values,
595 const bool elide_zero_values = true,
596 const bool col_indices_are_sorted = false);
597
609 void
610 add(const value_type factor, const BlockMatrixBase<MatrixType> &matrix);
611
619 operator()(const size_type i, const size_type j) const;
620
630 el(const size_type i, const size_type j) const;
631
643 diag_element(const size_type i) const;
644
653 void
655
660 operator*=(const value_type factor);
661
666 operator/=(const value_type factor);
667
672 template <typename BlockVectorType>
673 void
674 vmult_add(BlockVectorType &dst, const BlockVectorType &src) const;
675
681 template <typename BlockVectorType>
682 void
683 Tvmult_add(BlockVectorType &dst, const BlockVectorType &src) const;
684
697 template <typename BlockVectorType>
699 matrix_norm_square(const BlockVectorType &v) const;
700
707
711 template <typename BlockVectorType>
713 matrix_scalar_product(const BlockVectorType &u,
714 const BlockVectorType &v) const;
715
719 template <typename BlockVectorType>
721 residual(BlockVectorType &dst,
722 const BlockVectorType &x,
723 const BlockVectorType &b) const;
724
731 void
732 print(std::ostream &out, const bool alternative_output = false) const;
733
739
745
750 begin(const size_type r);
751
756 end(const size_type r);
761 begin() const;
762
767 end() const;
768
773 begin(const size_type r) const;
774
779 end(const size_type r) const;
780
784 const BlockIndices &
786
790 const BlockIndices &
792
798 std::size_t
800
805
810 int,
811 int,
812 int,
813 int,
814 << "The blocks [" << arg1 << ',' << arg2 << "] and [" << arg3
815 << ',' << arg4 << "] have differing row numbers.");
820 int,
821 int,
822 int,
823 int,
824 << "The blocks [" << arg1 << ',' << arg2 << "] and [" << arg3
825 << ',' << arg4 << "] have differing column numbers.");
827protected:
840 void
842
848
853
872 void
874
885 template <typename BlockVectorType>
886 void
887 vmult_block_block(BlockVectorType &dst, const BlockVectorType &src) const;
888
899 template <typename BlockVectorType, typename VectorType>
900 void
901 vmult_block_nonblock(BlockVectorType &dst, const VectorType &src) const;
902
913 template <typename BlockVectorType, typename VectorType>
914 void
915 vmult_nonblock_block(VectorType &dst, const BlockVectorType &src) const;
916
927 template <typename VectorType>
928 void
929 vmult_nonblock_nonblock(VectorType &dst, const VectorType &src) const;
930
942 template <typename BlockVectorType>
943 void
944 Tvmult_block_block(BlockVectorType &dst, const BlockVectorType &src) const;
945
956 template <typename BlockVectorType, typename VectorType>
957 void
958 Tvmult_block_nonblock(BlockVectorType &dst, const VectorType &src) const;
959
970 template <typename BlockVectorType, typename VectorType>
971 void
972 Tvmult_nonblock_block(VectorType &dst, const BlockVectorType &src) const;
973
984 template <typename VectorType>
985 void
986 Tvmult_nonblock_nonblock(VectorType &dst, const VectorType &src) const;
987
988
989protected:
996 void
998
1003 void
1005
1006
1007private:
1017 {
1022 std::vector<size_type> counter_within_block;
1023
1028 std::vector<std::vector<size_type>> column_indices;
1029
1034 std::vector<std::vector<value_type>> column_values;
1035
1041
1053 {
1054 return *this;
1055 }
1056 };
1057
1064 TemporaryData temporary_data;
1065
1066 // Make the iterator class a friend. We have to work around a compiler bug
1067 // here again.
1068 template <typename, bool>
1070
1071 template <typename>
1072 friend class MatrixIterator;
1073};
1074
1075
1077
1078#ifndef DOXYGEN
1079/* ------------------------- Template functions ---------------------- */
1080
1081
1082namespace BlockMatrixIterators
1083{
1084 template <typename BlockMatrixType>
1086 : row_block(0)
1087 , col_block(0)
1088 {}
1089
1090
1091 template <typename BlockMatrixType>
1092 inline unsigned int
1093 AccessorBase<BlockMatrixType>::block_row() const
1094 {
1096
1097 return row_block;
1098 }
1099
1100
1101 template <typename BlockMatrixType>
1102 inline unsigned int
1103 AccessorBase<BlockMatrixType>::block_column() const
1104 {
1106
1107 return col_block;
1108 }
1109
1110
1111 template <typename BlockMatrixType>
1112 inline Accessor<BlockMatrixType, true>::Accessor(
1113 const BlockMatrixType *matrix,
1114 const size_type row,
1115 const size_type col)
1116 : matrix(matrix)
1117 , base_iterator(matrix->block(0, 0).begin())
1118 {
1119 Assert(col == 0, ExcNotImplemented());
1120
1121 // check if this is a regular row or
1122 // the end of the matrix
1123 if (row < matrix->m())
1124 {
1125 const std::pair<unsigned int, size_type> indices =
1126 matrix->row_block_indices.global_to_local(row);
1127
1128 // find the first block that does
1129 // have an entry in this row
1130 for (unsigned int bc = 0; bc < matrix->n_block_cols(); ++bc)
1131 {
1132 base_iterator =
1133 matrix->block(indices.first, bc).begin(indices.second);
1134 if (base_iterator !=
1135 matrix->block(indices.first, bc).end(indices.second))
1136 {
1137 this->row_block = indices.first;
1138 this->col_block = bc;
1139 return;
1140 }
1141 }
1142
1143 // hm, there is no block that has
1144 // an entry in this column. we need
1145 // to take the next entry then,
1146 // which may be the first entry of
1147 // the next row, or recursively the
1148 // next row, or so on
1149 *this = Accessor(matrix, row + 1, 0);
1150 }
1151 else
1152 {
1153 // we were asked to create the end
1154 // iterator for this matrix
1155 this->row_block = numbers::invalid_unsigned_int;
1156 this->col_block = numbers::invalid_unsigned_int;
1157 }
1158 }
1159
1160
1161 // template <typename BlockMatrixType>
1162 // inline
1163 // Accessor<BlockMatrixType, true>::Accessor (const
1164 // Accessor<BlockMatrixType, true>& other)
1165 // :
1166 // matrix(other.matrix),
1167 // base_iterator(other.base_iterator)
1168 // {
1169 // this->row_block = other.row_block;
1170 // this->col_block = other.col_block;
1171 // }
1172
1173
1174 template <typename BlockMatrixType>
1175 inline Accessor<BlockMatrixType, true>::Accessor(
1176 const Accessor<BlockMatrixType, false> &other)
1177 : matrix(other.matrix)
1178 , base_iterator(other.base_iterator)
1179 {
1180 this->row_block = other.row_block;
1181 this->col_block = other.col_block;
1182 }
1183
1184
1185 template <typename BlockMatrixType>
1186 inline typename Accessor<BlockMatrixType, true>::size_type
1187 Accessor<BlockMatrixType, true>::row() const
1188 {
1189 Assert(this->row_block != numbers::invalid_unsigned_int,
1191
1192 return (matrix->row_block_indices.local_to_global(this->row_block, 0) +
1193 base_iterator->row());
1194 }
1195
1196
1197 template <typename BlockMatrixType>
1198 inline typename Accessor<BlockMatrixType, true>::size_type
1199 Accessor<BlockMatrixType, true>::column() const
1200 {
1201 Assert(this->col_block != numbers::invalid_unsigned_int,
1203
1204 return (matrix->column_block_indices.local_to_global(this->col_block, 0) +
1205 base_iterator->column());
1206 }
1207
1208
1209 template <typename BlockMatrixType>
1210 inline typename Accessor<BlockMatrixType, true>::value_type
1211 Accessor<BlockMatrixType, true>::value() const
1212 {
1213 Assert(this->row_block != numbers::invalid_unsigned_int,
1215 Assert(this->col_block != numbers::invalid_unsigned_int,
1217
1218 return base_iterator->value();
1219 }
1220
1221
1222
1223 template <typename BlockMatrixType>
1224 inline void
1225 Accessor<BlockMatrixType, true>::advance()
1226 {
1227 Assert(this->row_block != numbers::invalid_unsigned_int,
1229 Assert(this->col_block != numbers::invalid_unsigned_int,
1231
1232 // Remember current row inside block
1233 size_type local_row = base_iterator->row();
1234
1235 // Advance one element inside the
1236 // current block
1237 ++base_iterator;
1238
1239 // while we hit the end of the row of a
1240 // block (which may happen multiple
1241 // times if rows inside a block are
1242 // empty), we have to jump to the next
1243 // block and take the
1244 while (base_iterator ==
1245 matrix->block(this->row_block, this->col_block).end(local_row))
1246 {
1247 // jump to next block in this block
1248 // row, if possible, otherwise go
1249 // to next row
1250 if (this->col_block < matrix->n_block_cols() - 1)
1251 {
1252 ++this->col_block;
1253 base_iterator =
1254 matrix->block(this->row_block, this->col_block).begin(local_row);
1255 }
1256 else
1257 {
1258 // jump back to next row in
1259 // first block column
1260 this->col_block = 0;
1261 ++local_row;
1262
1263 // see if this has brought us
1264 // past the number of rows in
1265 // this block. if so see
1266 // whether we've just fallen
1267 // off the end of the whole
1268 // matrix
1269 if (local_row ==
1270 matrix->block(this->row_block, this->col_block).m())
1271 {
1272 local_row = 0;
1273 ++this->row_block;
1274 if (this->row_block == matrix->n_block_rows())
1275 {
1276 this->row_block = numbers::invalid_unsigned_int;
1277 this->col_block = numbers::invalid_unsigned_int;
1278 return;
1279 }
1280 }
1281
1282 base_iterator =
1283 matrix->block(this->row_block, this->col_block).begin(local_row);
1284 }
1285 }
1286 }
1287
1288
1289 template <typename BlockMatrixType>
1290 inline bool
1291 Accessor<BlockMatrixType, true>::operator==(const Accessor &a) const
1292 {
1293 if (matrix != a.matrix)
1294 return false;
1295
1296 if (this->row_block == a.row_block && this->col_block == a.col_block)
1297 // end iterators do not necessarily
1298 // have to have the same
1299 // base_iterator representation, but
1300 // valid iterators have to
1301 return (((this->row_block == numbers::invalid_unsigned_int) &&
1302 (this->col_block == numbers::invalid_unsigned_int)) ||
1303 (base_iterator == a.base_iterator));
1304
1305 return false;
1306 }
1307
1308 //----------------------------------------------------------------------//
1309
1310
1311 template <typename BlockMatrixType>
1312 inline Accessor<BlockMatrixType, false>::Accessor(BlockMatrixType *matrix,
1313 const size_type row,
1314 const size_type col)
1315 : matrix(matrix)
1316 , base_iterator(matrix->block(0, 0).begin())
1317 {
1318 Assert(col == 0, ExcNotImplemented());
1319 // check if this is a regular row or
1320 // the end of the matrix
1321 if (row < matrix->m())
1322 {
1323 const std::pair<unsigned int, size_type> indices =
1324 matrix->row_block_indices.global_to_local(row);
1325
1326 // find the first block that does
1327 // have an entry in this row
1328 for (size_type bc = 0; bc < matrix->n_block_cols(); ++bc)
1329 {
1330 base_iterator =
1331 matrix->block(indices.first, bc).begin(indices.second);
1332 if (base_iterator !=
1333 matrix->block(indices.first, bc).end(indices.second))
1334 {
1335 this->row_block = indices.first;
1336 this->col_block = bc;
1337 return;
1338 }
1339 }
1340
1341 // hm, there is no block that has
1342 // an entry in this column. we need
1343 // to take the next entry then,
1344 // which may be the first entry of
1345 // the next row, or recursively the
1346 // next row, or so on
1347 *this = Accessor(matrix, row + 1, 0);
1348 }
1349 else
1350 {
1351 // we were asked to create the end
1352 // iterator for this matrix
1353 this->row_block = numbers::invalid_size_type;
1354 this->col_block = numbers::invalid_size_type;
1355 }
1356 }
1357
1358
1359 template <typename BlockMatrixType>
1360 inline typename Accessor<BlockMatrixType, false>::size_type
1361 Accessor<BlockMatrixType, false>::row() const
1362 {
1364
1365 return (matrix->row_block_indices.local_to_global(this->row_block, 0) +
1366 base_iterator->row());
1367 }
1368
1369
1370 template <typename BlockMatrixType>
1371 inline typename Accessor<BlockMatrixType, false>::size_type
1372 Accessor<BlockMatrixType, false>::column() const
1373 {
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 {
1387
1388 return base_iterator->value();
1389 }
1390
1391
1392
1393 template <typename BlockMatrixType>
1394 inline void
1395 Accessor<BlockMatrixType, false>::set_value(
1396 typename Accessor<BlockMatrixType, false>::value_type newval) const
1397 {
1400
1401 base_iterator->value() = newval;
1402 }
1403
1404
1405
1406 template <typename BlockMatrixType>
1407 inline void
1408 Accessor<BlockMatrixType, false>::advance()
1409 {
1412
1413 // Remember current row inside block
1414 size_type local_row = base_iterator->row();
1415
1416 // Advance one element inside the
1417 // current block
1418 ++base_iterator;
1419
1420 // while we hit the end of the row of a
1421 // block (which may happen multiple
1422 // times if rows inside a block are
1423 // empty), we have to jump to the next
1424 // block and take the
1425 while (base_iterator ==
1426 matrix->block(this->row_block, this->col_block).end(local_row))
1427 {
1428 // jump to next block in this block
1429 // row, if possible, otherwise go
1430 // to next row
1431 if (this->col_block < matrix->n_block_cols() - 1)
1432 {
1433 ++this->col_block;
1434 base_iterator =
1435 matrix->block(this->row_block, this->col_block).begin(local_row);
1436 }
1437 else
1438 {
1439 // jump back to next row in
1440 // first block column
1441 this->col_block = 0;
1442 ++local_row;
1443
1444 // see if this has brought us
1445 // past the number of rows in
1446 // this block. if so see
1447 // whether we've just fallen
1448 // off the end of the whole
1449 // matrix
1450 if (local_row ==
1451 matrix->block(this->row_block, this->col_block).m())
1452 {
1453 local_row = 0;
1454 ++this->row_block;
1455 if (this->row_block == matrix->n_block_rows())
1456 {
1457 this->row_block = numbers::invalid_size_type;
1458 this->col_block = numbers::invalid_size_type;
1459 return;
1460 }
1461 }
1462
1463 base_iterator =
1464 matrix->block(this->row_block, this->col_block).begin(local_row);
1465 }
1466 }
1467 }
1468
1469
1470
1471 template <typename BlockMatrixType>
1472 inline bool
1473 Accessor<BlockMatrixType, false>::operator==(const Accessor &a) const
1474 {
1475 if (matrix != a.matrix)
1476 return false;
1477
1478 if (this->row_block == a.row_block && this->col_block == a.col_block)
1479 // end iterators do not necessarily
1480 // have to have the same
1481 // base_iterator representation, but
1482 // valid iterators have to
1483 return (((this->row_block == numbers::invalid_size_type) &&
1484 (this->col_block == numbers::invalid_size_type)) ||
1485 (base_iterator == a.base_iterator));
1486
1487 return false;
1488 }
1489} // namespace BlockMatrixIterators
1490
1491
1492//---------------------------------------------------------------------------
1493
1494template <typename MatrixType>
1496{
1497 try
1498 {
1499 clear();
1500 }
1501 catch (...)
1502 {}
1503}
1504
1505
1506template <typename MatrixType>
1507template <typename BlockMatrixType>
1509BlockMatrixBase<MatrixType>::copy_from(const BlockMatrixType &source)
1510{
1511 for (unsigned int r = 0; r < n_block_rows(); ++r)
1512 for (unsigned int c = 0; c < n_block_cols(); ++c)
1513 block(r, c).copy_from(source.block(r, c));
1514
1515 return *this;
1516}
1517
1518
1519template <typename MatrixType>
1520std::size_t
1522{
1523 std::size_t mem =
1524 MemoryConsumption::memory_consumption(row_block_indices) +
1525 MemoryConsumption::memory_consumption(column_block_indices) +
1527 MemoryConsumption::memory_consumption(temporary_data.counter_within_block) +
1528 MemoryConsumption::memory_consumption(temporary_data.column_indices) +
1529 MemoryConsumption::memory_consumption(temporary_data.column_values) +
1530 sizeof(temporary_data.mutex);
1531
1532 for (unsigned int r = 0; r < n_block_rows(); ++r)
1533 for (unsigned int c = 0; c < n_block_cols(); ++c)
1534 {
1535 MatrixType *p = this->sub_objects[r][c];
1537 }
1538
1539 return mem;
1540}
1541
1542
1543
1544template <typename MatrixType>
1545inline void
1547{
1548 for (unsigned int r = 0; r < n_block_rows(); ++r)
1549 for (unsigned int c = 0; c < n_block_cols(); ++c)
1550 {
1551 MatrixType *p = this->sub_objects[r][c];
1552 this->sub_objects[r][c] = nullptr;
1553 delete p;
1554 }
1555 sub_objects.reinit(0, 0);
1556
1557 // reset block indices to empty
1558 row_block_indices = column_block_indices = BlockIndices();
1559}
1560
1561
1562
1563template <typename MatrixType>
1565BlockMatrixBase<MatrixType>::block(const unsigned int row,
1566 const unsigned int column)
1567{
1568 AssertIndexRange(row, n_block_rows());
1569 AssertIndexRange(column, n_block_cols());
1570
1571 return *sub_objects[row][column];
1572}
1573
1574
1575
1576template <typename MatrixType>
1577inline const typename BlockMatrixBase<MatrixType>::BlockType &
1578BlockMatrixBase<MatrixType>::block(const unsigned int row,
1579 const unsigned int column) const
1580{
1581 AssertIndexRange(row, n_block_rows());
1582 AssertIndexRange(column, n_block_cols());
1583
1584 return *sub_objects[row][column];
1585}
1586
1587
1588template <typename MatrixType>
1591{
1592 return row_block_indices.total_size();
1593}
1594
1595
1596
1597template <typename MatrixType>
1600{
1601 return column_block_indices.total_size();
1602}
1603
1604
1605
1606template <typename MatrixType>
1607inline unsigned int
1609{
1610 return column_block_indices.size();
1611}
1612
1613
1614
1615template <typename MatrixType>
1616inline unsigned int
1618{
1619 return row_block_indices.size();
1620}
1621
1622
1623
1624// Write the single set manually,
1625// since the other function has a lot
1626// of overhead in that case.
1627template <typename MatrixType>
1628inline void
1629BlockMatrixBase<MatrixType>::set(const size_type i,
1630 const size_type j,
1631 const value_type value)
1632{
1633 prepare_set_operation();
1634
1636
1637 const std::pair<unsigned int, size_type>
1638 row_index = row_block_indices.global_to_local(i),
1639 col_index = column_block_indices.global_to_local(j);
1640 block(row_index.first, col_index.first)
1641 .set(row_index.second, col_index.second, value);
1642}
1643
1644
1645
1646template <typename MatrixType>
1647template <typename number>
1648inline void
1649BlockMatrixBase<MatrixType>::set(const std::vector<size_type> &row_indices,
1650 const std::vector<size_type> &col_indices,
1651 const FullMatrix<number> &values,
1652 const bool elide_zero_values)
1653{
1654 Assert(row_indices.size() == values.m(),
1655 ExcDimensionMismatch(row_indices.size(), values.m()));
1656 Assert(col_indices.size() == values.n(),
1657 ExcDimensionMismatch(col_indices.size(), values.n()));
1658
1659 for (size_type i = 0; i < row_indices.size(); ++i)
1660 set(row_indices[i],
1661 col_indices.size(),
1662 col_indices.data(),
1663 &values(i, 0),
1664 elide_zero_values);
1665}
1666
1667
1668
1669template <typename MatrixType>
1670template <typename number>
1671inline void
1672BlockMatrixBase<MatrixType>::set(const std::vector<size_type> &indices,
1673 const FullMatrix<number> &values,
1674 const bool elide_zero_values)
1675{
1676 Assert(indices.size() == values.m(),
1677 ExcDimensionMismatch(indices.size(), values.m()));
1678 Assert(values.n() == values.m(), ExcNotQuadratic());
1679
1680 for (size_type i = 0; i < indices.size(); ++i)
1681 set(indices[i],
1682 indices.size(),
1683 indices.data(),
1684 &values(i, 0),
1685 elide_zero_values);
1686}
1687
1688
1689
1690template <typename MatrixType>
1691template <typename number>
1692inline void
1693BlockMatrixBase<MatrixType>::set(const size_type row,
1694 const std::vector<size_type> &col_indices,
1695 const std::vector<number> &values,
1696 const bool elide_zero_values)
1697{
1698 Assert(col_indices.size() == values.size(),
1699 ExcDimensionMismatch(col_indices.size(), values.size()));
1700
1701 set(row,
1702 col_indices.size(),
1703 col_indices.data(),
1704 values.data(),
1705 elide_zero_values);
1706}
1707
1708
1709
1710// This is a very messy function, since
1711// we need to calculate to each position
1712// the location in the global array.
1713template <typename MatrixType>
1714template <typename number>
1715inline void
1716BlockMatrixBase<MatrixType>::set(const size_type row,
1717 const size_type n_cols,
1718 const size_type *col_indices,
1719 const number *values,
1720 const bool elide_zero_values)
1721{
1722 prepare_set_operation();
1723
1724 // lock access to the temporary data structure to
1725 // allow multiple threads to call this function concurrently
1726 std::lock_guard<std::mutex> lock(temporary_data.mutex);
1727
1728 // Resize scratch arrays
1729 if (temporary_data.column_indices.size() < this->n_block_cols())
1730 {
1731 temporary_data.column_indices.resize(this->n_block_cols());
1732 temporary_data.column_values.resize(this->n_block_cols());
1733 temporary_data.counter_within_block.resize(this->n_block_cols());
1734 }
1735
1736 // Resize sub-arrays to n_cols. This
1737 // is a bit wasteful, but we resize
1738 // only a few times (then the maximum
1739 // row length won't increase that
1740 // much any more). At least we know
1741 // that all arrays are going to be of
1742 // the same size, so we can check
1743 // whether the size of one is large
1744 // enough before actually going
1745 // through all of them.
1746 if (temporary_data.column_indices[0].size() < n_cols)
1747 {
1748 for (unsigned int i = 0; i < this->n_block_cols(); ++i)
1749 {
1750 temporary_data.column_indices[i].resize(n_cols);
1751 temporary_data.column_values[i].resize(n_cols);
1752 }
1753 }
1754
1755 // Reset the number of added elements
1756 // in each block to zero.
1757 for (unsigned int i = 0; i < this->n_block_cols(); ++i)
1758 temporary_data.counter_within_block[i] = 0;
1759
1760 // Go through the column indices to
1761 // find out which portions of the
1762 // values should be set in which
1763 // block of the matrix. We need to
1764 // touch all the data, since we can't
1765 // be sure that the data of one block
1766 // is stored contiguously (in fact,
1767 // indices will be intermixed when it
1768 // comes from an element matrix).
1769 for (size_type j = 0; j < n_cols; ++j)
1770 {
1771 number value = values[j];
1772
1773 if (value == number() && elide_zero_values == true)
1774 continue;
1775
1776 const std::pair<unsigned int, size_type> col_index =
1777 this->column_block_indices.global_to_local(col_indices[j]);
1778
1779 const size_type local_index =
1780 temporary_data.counter_within_block[col_index.first]++;
1781
1782 temporary_data.column_indices[col_index.first][local_index] =
1783 col_index.second;
1784 temporary_data.column_values[col_index.first][local_index] = value;
1785 }
1786
1787 if constexpr (running_in_debug_mode())
1788 {
1789 // If in debug mode, do a check whether
1790 // the right length has been obtained.
1791 size_type length = 0;
1792 for (unsigned int i = 0; i < this->n_block_cols(); ++i)
1793 length += temporary_data.counter_within_block[i];
1794 Assert(length <= n_cols, ExcInternalError());
1795 }
1796
1797 // Now we found out about where the
1798 // individual columns should start and
1799 // where we should start reading out
1800 // data. Now let's write the data into
1801 // the individual blocks!
1802 const std::pair<unsigned int, size_type> row_index =
1803 this->row_block_indices.global_to_local(row);
1804 for (unsigned int block_col = 0; block_col < n_block_cols(); ++block_col)
1805 {
1806 if (temporary_data.counter_within_block[block_col] == 0)
1807 continue;
1808
1809 block(row_index.first, block_col)
1810 .set(row_index.second,
1811 temporary_data.counter_within_block[block_col],
1812 temporary_data.column_indices[block_col].data(),
1813 temporary_data.column_values[block_col].data(),
1814 false);
1815 }
1816}
1817
1818
1819
1820template <typename MatrixType>
1821inline void
1822BlockMatrixBase<MatrixType>::add(const size_type i,
1823 const size_type j,
1824 const value_type value)
1825{
1827
1828 prepare_add_operation();
1829
1830 // save some cycles for zero additions, but
1831 // only if it is safe for the matrix we are
1832 // working with
1833 using MatrixTraits = typename MatrixType::Traits;
1834 if ((MatrixTraits::zero_addition_can_be_elided == true) &&
1835 (value == value_type()))
1836 return;
1837
1838 const std::pair<unsigned int, size_type>
1839 row_index = row_block_indices.global_to_local(i),
1840 col_index = column_block_indices.global_to_local(j);
1841 block(row_index.first, col_index.first)
1842 .add(row_index.second, col_index.second, value);
1843}
1844
1845
1846
1847template <typename MatrixType>
1848template <typename number>
1849inline void
1850BlockMatrixBase<MatrixType>::add(const std::vector<size_type> &row_indices,
1851 const std::vector<size_type> &col_indices,
1852 const FullMatrix<number> &values,
1853 const bool elide_zero_values)
1854{
1855 Assert(row_indices.size() == values.m(),
1856 ExcDimensionMismatch(row_indices.size(), values.m()));
1857 Assert(col_indices.size() == values.n(),
1858 ExcDimensionMismatch(col_indices.size(), values.n()));
1859
1860 for (size_type i = 0; i < row_indices.size(); ++i)
1861 add(row_indices[i],
1862 col_indices.size(),
1863 col_indices.data(),
1864 &values(i, 0),
1865 elide_zero_values);
1866}
1867
1868
1869
1870template <typename MatrixType>
1871template <typename number>
1872inline void
1873BlockMatrixBase<MatrixType>::add(const std::vector<size_type> &indices,
1874 const FullMatrix<number> &values,
1875 const bool elide_zero_values)
1876{
1877 Assert(indices.size() == values.m(),
1878 ExcDimensionMismatch(indices.size(), values.m()));
1879 Assert(values.n() == values.m(), ExcNotQuadratic());
1880
1881 for (size_type i = 0; i < indices.size(); ++i)
1882 add(indices[i],
1883 indices.size(),
1884 indices.data(),
1885 &values(i, 0),
1886 elide_zero_values);
1887}
1888
1889
1890
1891template <typename MatrixType>
1892template <typename number>
1893inline void
1894BlockMatrixBase<MatrixType>::add(const size_type row,
1895 const std::vector<size_type> &col_indices,
1896 const std::vector<number> &values,
1897 const bool elide_zero_values)
1898{
1899 Assert(col_indices.size() == values.size(),
1900 ExcDimensionMismatch(col_indices.size(), values.size()));
1901
1902 add(row,
1903 col_indices.size(),
1904 col_indices.data(),
1905 values.data(),
1906 elide_zero_values);
1907}
1908
1909
1910
1911// This is a very messy function, since
1912// we need to calculate to each position
1913// the location in the global array.
1914template <typename MatrixType>
1915template <typename number>
1916inline void
1917BlockMatrixBase<MatrixType>::add(const size_type row,
1918 const size_type n_cols,
1919 const size_type *col_indices,
1920 const number *values,
1921 const bool elide_zero_values,
1922 const bool col_indices_are_sorted)
1923{
1924 prepare_add_operation();
1925
1926 // TODO: Look over this to find out
1927 // whether we can do that more
1928 // efficiently.
1929 if (col_indices_are_sorted == true)
1930 {
1931 if constexpr (running_in_debug_mode())
1932 {
1933 // check whether indices really are
1934 // sorted.
1935 size_type before = col_indices[0];
1936 for (size_type i = 1; i < n_cols; ++i)
1937 if (col_indices[i] <= before)
1938 {
1939 Assert(false,
1940 ExcMessage("Flag col_indices_are_sorted is set, but "
1941 "indices appear to not be sorted."));
1942 }
1943 else
1944 before = col_indices[i];
1945 }
1946 const std::pair<unsigned int, size_type> row_index =
1947 this->row_block_indices.global_to_local(row);
1948
1949 if (this->n_block_cols() > 1)
1950 {
1951 const size_type *first_block =
1952 Utilities::lower_bound(col_indices,
1953 col_indices + n_cols,
1954 this->column_block_indices.block_start(1));
1955
1956 const size_type n_zero_block_indices = first_block - col_indices;
1957 block(row_index.first, 0)
1958 .add(row_index.second,
1959 n_zero_block_indices,
1960 col_indices,
1961 values,
1962 elide_zero_values,
1963 col_indices_are_sorted);
1964
1965 if (n_zero_block_indices < n_cols)
1966 this->add(row,
1967 n_cols - n_zero_block_indices,
1968 first_block,
1969 values + n_zero_block_indices,
1970 elide_zero_values,
1971 false);
1972 }
1973 else
1974 {
1975 block(row_index.first, 0)
1976 .add(row_index.second,
1977 n_cols,
1978 col_indices,
1979 values,
1980 elide_zero_values,
1981 col_indices_are_sorted);
1982 }
1983
1984 return;
1985 }
1986
1987 // Lock scratch arrays, then resize them
1988 std::lock_guard<std::mutex> lock(temporary_data.mutex);
1989
1990 if (temporary_data.column_indices.size() < this->n_block_cols())
1991 {
1992 temporary_data.column_indices.resize(this->n_block_cols());
1993 temporary_data.column_values.resize(this->n_block_cols());
1994 temporary_data.counter_within_block.resize(this->n_block_cols());
1995 }
1996
1997 // Resize sub-arrays to n_cols. This
1998 // is a bit wasteful, but we resize
1999 // only a few times (then the maximum
2000 // row length won't increase that
2001 // much any more). At least we know
2002 // that all arrays are going to be of
2003 // the same size, so we can check
2004 // whether the size of one is large
2005 // enough before actually going
2006 // through all of them.
2007 if (temporary_data.column_indices[0].size() < n_cols)
2008 {
2009 for (unsigned int i = 0; i < this->n_block_cols(); ++i)
2010 {
2011 temporary_data.column_indices[i].resize(n_cols);
2012 temporary_data.column_values[i].resize(n_cols);
2013 }
2014 }
2015
2016 // Reset the number of added elements
2017 // in each block to zero.
2018 for (unsigned int i = 0; i < this->n_block_cols(); ++i)
2019 temporary_data.counter_within_block[i] = 0;
2020
2021 // Go through the column indices to
2022 // find out which portions of the
2023 // values should be written into
2024 // which block of the matrix. We need
2025 // to touch all the data, since we
2026 // can't be sure that the data of one
2027 // block is stored contiguously (in
2028 // fact, data will be intermixed when
2029 // it comes from an element matrix).
2030 for (size_type j = 0; j < n_cols; ++j)
2031 {
2032 number value = values[j];
2033
2034 if (value == number() && elide_zero_values == true)
2035 continue;
2036
2037 const std::pair<unsigned int, size_type> col_index =
2038 this->column_block_indices.global_to_local(col_indices[j]);
2039
2040 const size_type local_index =
2041 temporary_data.counter_within_block[col_index.first]++;
2042
2043 temporary_data.column_indices[col_index.first][local_index] =
2044 col_index.second;
2045 temporary_data.column_values[col_index.first][local_index] = value;
2046 }
2047
2048 if constexpr (running_in_debug_mode())
2049 {
2050 // If in debug mode, do a check whether
2051 // the right length has been obtained.
2052 size_type length = 0;
2053 for (unsigned int i = 0; i < this->n_block_cols(); ++i)
2054 length += temporary_data.counter_within_block[i];
2055 Assert(length <= n_cols, ExcInternalError());
2056 }
2057
2058 // Now we found out about where the
2059 // individual columns should start and
2060 // where we should start reading out
2061 // data. Now let's write the data into
2062 // the individual blocks!
2063 const std::pair<unsigned int, size_type> row_index =
2064 this->row_block_indices.global_to_local(row);
2065 for (unsigned int block_col = 0; block_col < n_block_cols(); ++block_col)
2066 {
2067 if (temporary_data.counter_within_block[block_col] == 0)
2068 continue;
2069
2070 block(row_index.first, block_col)
2071 .add(row_index.second,
2072 temporary_data.counter_within_block[block_col],
2073 temporary_data.column_indices[block_col].data(),
2074 temporary_data.column_values[block_col].data(),
2075 false,
2076 col_indices_are_sorted);
2077 }
2078}
2079
2080
2081
2082template <typename MatrixType>
2083inline void
2084BlockMatrixBase<MatrixType>::add(const value_type factor,
2085 const BlockMatrixBase<MatrixType> &matrix)
2086{
2087 AssertIsFinite(factor);
2088
2089 prepare_add_operation();
2090
2091 // save some cycles for zero additions, but
2092 // only if it is safe for the matrix we are
2093 // working with
2094 using MatrixTraits = typename MatrixType::Traits;
2095 if ((MatrixTraits::zero_addition_can_be_elided == true) && (factor == 0))
2096 return;
2097
2098 for (unsigned int row = 0; row < n_block_rows(); ++row)
2099 for (unsigned int col = 0; col < n_block_cols(); ++col)
2100 // This function should throw if the sparsity
2101 // patterns of the two blocks differ
2102 block(row, col).add(factor, matrix.block(row, col));
2103}
2104
2105
2106
2107template <typename MatrixType>
2110 const size_type j) const
2111{
2112 const std::pair<unsigned int, size_type>
2113 row_index = row_block_indices.global_to_local(i),
2114 col_index = column_block_indices.global_to_local(j);
2115 return block(row_index.first, col_index.first)(row_index.second,
2116 col_index.second);
2117}
2118
2119
2120
2121template <typename MatrixType>
2123BlockMatrixBase<MatrixType>::el(const size_type i, const size_type j) const
2124{
2125 const std::pair<unsigned int, size_type>
2126 row_index = row_block_indices.global_to_local(i),
2127 col_index = column_block_indices.global_to_local(j);
2128 return block(row_index.first, col_index.first)
2129 .el(row_index.second, col_index.second);
2130}
2131
2132
2133
2134template <typename MatrixType>
2136BlockMatrixBase<MatrixType>::diag_element(const size_type i) const
2137{
2138 Assert(n_block_rows() == n_block_cols(), ExcNotQuadratic());
2139
2140 const std::pair<unsigned int, size_type> index =
2141 row_block_indices.global_to_local(i);
2142 return block(index.first, index.first).diag_element(index.second);
2143}
2144
2145
2146
2147template <typename MatrixType>
2148inline void
2150{
2151 for (unsigned int r = 0; r < n_block_rows(); ++r)
2152 for (unsigned int c = 0; c < n_block_cols(); ++c)
2153 block(r, c).compress(operation);
2154}
2155
2156
2157
2158template <typename MatrixType>
2160BlockMatrixBase<MatrixType>::operator*=(const value_type factor)
2161{
2162 Assert(n_block_cols() != 0, ExcNotInitialized());
2163 Assert(n_block_rows() != 0, ExcNotInitialized());
2164
2165 for (unsigned int r = 0; r < n_block_rows(); ++r)
2166 for (unsigned int c = 0; c < n_block_cols(); ++c)
2167 block(r, c) *= factor;
2168
2169 return *this;
2170}
2171
2172
2173
2174template <typename MatrixType>
2176BlockMatrixBase<MatrixType>::operator/=(const value_type factor)
2177{
2178 Assert(n_block_cols() != 0, ExcNotInitialized());
2179 Assert(n_block_rows() != 0, ExcNotInitialized());
2180 Assert(factor != 0, ExcDivideByZero());
2181
2182 const value_type factor_inv = 1. / factor;
2183
2184 for (unsigned int r = 0; r < n_block_rows(); ++r)
2185 for (unsigned int c = 0; c < n_block_cols(); ++c)
2186 block(r, c) *= factor_inv;
2187
2188 return *this;
2189}
2190
2191
2192
2193template <typename MatrixType>
2194const BlockIndices &
2196{
2197 return this->row_block_indices;
2198}
2199
2200
2201
2202template <typename MatrixType>
2203const BlockIndices &
2205{
2206 return this->column_block_indices;
2207}
2208
2209
2210
2211template <typename MatrixType>
2212template <typename BlockVectorType>
2213void
2215 const BlockVectorType &src) const
2216{
2217 Assert(dst.n_blocks() == n_block_rows(),
2218 ExcDimensionMismatch(dst.n_blocks(), n_block_rows()));
2219 Assert(src.n_blocks() == n_block_cols(),
2220 ExcDimensionMismatch(src.n_blocks(), n_block_cols()));
2221
2222 for (size_type row = 0; row < n_block_rows(); ++row)
2223 {
2224 block(row, 0).vmult(dst.block(row), src.block(0));
2225 for (size_type col = 1; col < n_block_cols(); ++col)
2226 block(row, col).vmult_add(dst.block(row), src.block(col));
2227 };
2228}
2229
2230
2231
2232template <typename MatrixType>
2233template <typename BlockVectorType, typename VectorType>
2234void
2236 VectorType &dst,
2237 const BlockVectorType &src) const
2238{
2239 Assert(n_block_rows() == 1, ExcDimensionMismatch(1, n_block_rows()));
2240 Assert(src.n_blocks() == n_block_cols(),
2241 ExcDimensionMismatch(src.n_blocks(), n_block_cols()));
2242
2243 block(0, 0).vmult(dst, src.block(0));
2244 for (size_type col = 1; col < n_block_cols(); ++col)
2245 block(0, col).vmult_add(dst, src.block(col));
2246}
2247
2248
2249
2250template <typename MatrixType>
2251template <typename BlockVectorType, typename VectorType>
2252void
2254 const VectorType &src) const
2255{
2256 Assert(dst.n_blocks() == n_block_rows(),
2257 ExcDimensionMismatch(dst.n_blocks(), n_block_rows()));
2258 Assert(1 == n_block_cols(), ExcDimensionMismatch(1, n_block_cols()));
2259
2260 for (size_type row = 0; row < n_block_rows(); ++row)
2261 block(row, 0).vmult(dst.block(row), src);
2262}
2263
2264
2265
2266template <typename MatrixType>
2267template <typename VectorType>
2268void
2270 VectorType &dst,
2271 const VectorType &src) const
2272{
2273 Assert(1 == n_block_rows(), ExcDimensionMismatch(1, n_block_rows()));
2274 Assert(1 == n_block_cols(), ExcDimensionMismatch(1, n_block_cols()));
2275
2276 block(0, 0).vmult(dst, src);
2277}
2278
2279
2280
2281template <typename MatrixType>
2282template <typename BlockVectorType>
2283void
2284BlockMatrixBase<MatrixType>::vmult_add(BlockVectorType &dst,
2285 const BlockVectorType &src) const
2286{
2287 Assert(dst.n_blocks() == n_block_rows(),
2288 ExcDimensionMismatch(dst.n_blocks(), n_block_rows()));
2289 Assert(src.n_blocks() == n_block_cols(),
2290 ExcDimensionMismatch(src.n_blocks(), n_block_cols()));
2291
2292 for (unsigned int row = 0; row < n_block_rows(); ++row)
2293 for (unsigned int col = 0; col < n_block_cols(); ++col)
2294 block(row, col).vmult_add(dst.block(row), src.block(col));
2295}
2296
2297
2298
2299template <typename MatrixType>
2300template <typename BlockVectorType>
2301void
2303 BlockVectorType &dst,
2304 const BlockVectorType &src) const
2305{
2306 Assert(dst.n_blocks() == n_block_cols(),
2307 ExcDimensionMismatch(dst.n_blocks(), n_block_cols()));
2308 Assert(src.n_blocks() == n_block_rows(),
2309 ExcDimensionMismatch(src.n_blocks(), n_block_rows()));
2310
2311 dst = 0.;
2312
2313 for (unsigned int row = 0; row < n_block_rows(); ++row)
2314 {
2315 for (unsigned int col = 0; col < n_block_cols(); ++col)
2316 block(row, col).Tvmult_add(dst.block(col), src.block(row));
2317 };
2318}
2319
2320
2321
2322template <typename MatrixType>
2323template <typename BlockVectorType, typename VectorType>
2324void
2326 const VectorType &src) const
2327{
2328 Assert(dst.n_blocks() == n_block_cols(),
2329 ExcDimensionMismatch(dst.n_blocks(), n_block_cols()));
2330 Assert(1 == n_block_rows(), ExcDimensionMismatch(1, n_block_rows()));
2331
2332 dst = 0.;
2333
2334 for (unsigned int col = 0; col < n_block_cols(); ++col)
2335 block(0, col).Tvmult_add(dst.block(col), src);
2336}
2337
2338
2339
2340template <typename MatrixType>
2341template <typename BlockVectorType, typename VectorType>
2342void
2344 VectorType &dst,
2345 const BlockVectorType &src) const
2346{
2347 Assert(1 == n_block_cols(), ExcDimensionMismatch(1, n_block_cols()));
2348 Assert(src.n_blocks() == n_block_rows(),
2349 ExcDimensionMismatch(src.n_blocks(), n_block_rows()));
2350
2351 block(0, 0).Tvmult(dst, src.block(0));
2352
2353 for (size_type row = 1; row < n_block_rows(); ++row)
2354 block(row, 0).Tvmult_add(dst, src.block(row));
2355}
2356
2357
2358
2359template <typename MatrixType>
2360template <typename VectorType>
2361void
2363 VectorType &dst,
2364 const VectorType &src) const
2365{
2366 Assert(1 == n_block_cols(), ExcDimensionMismatch(1, n_block_cols()));
2367 Assert(1 == n_block_rows(), ExcDimensionMismatch(1, n_block_rows()));
2368
2369 block(0, 0).Tvmult(dst, src);
2370}
2371
2372
2373
2374template <typename MatrixType>
2375template <typename BlockVectorType>
2376void
2377BlockMatrixBase<MatrixType>::Tvmult_add(BlockVectorType &dst,
2378 const BlockVectorType &src) const
2379{
2380 Assert(dst.n_blocks() == n_block_cols(),
2381 ExcDimensionMismatch(dst.n_blocks(), n_block_cols()));
2382 Assert(src.n_blocks() == n_block_rows(),
2383 ExcDimensionMismatch(src.n_blocks(), n_block_rows()));
2384
2385 for (unsigned int row = 0; row < n_block_rows(); ++row)
2386 for (unsigned int col = 0; col < n_block_cols(); ++col)
2387 block(row, col).Tvmult_add(dst.block(col), src.block(row));
2388}
2389
2390
2391
2392template <typename MatrixType>
2393template <typename BlockVectorType>
2395BlockMatrixBase<MatrixType>::matrix_norm_square(const BlockVectorType &v) const
2396{
2397 Assert(n_block_rows() == n_block_cols(), ExcNotQuadratic());
2398 Assert(v.n_blocks() == n_block_rows(),
2399 ExcDimensionMismatch(v.n_blocks(), n_block_rows()));
2400
2401 value_type norm_sqr = 0;
2402 for (unsigned int row = 0; row < n_block_rows(); ++row)
2403 for (unsigned int col = 0; col < n_block_cols(); ++col)
2404 if (row == col)
2405 norm_sqr += block(row, col).matrix_norm_square(v.block(row));
2406 else
2407 norm_sqr +=
2408 block(row, col).matrix_scalar_product(v.block(row), v.block(col));
2409 return norm_sqr;
2410}
2411
2412
2413
2414template <typename MatrixType>
2417{
2418 value_type norm_sqr = 0;
2419
2420 // For each block, get the Frobenius norm, and add the square to the
2421 // accumulator for the full matrix
2422 for (unsigned int row = 0; row < n_block_rows(); ++row)
2423 {
2424 for (unsigned int col = 0; col < n_block_cols(); ++col)
2425 {
2426 const value_type block_norm = block(row, col).frobenius_norm();
2427 norm_sqr += block_norm * block_norm;
2428 }
2429 }
2430
2431 return std::sqrt(norm_sqr);
2432}
2433
2434
2435
2436template <typename MatrixType>
2437template <typename BlockVectorType>
2440 const BlockVectorType &u,
2441 const BlockVectorType &v) const
2442{
2443 Assert(u.n_blocks() == n_block_rows(),
2444 ExcDimensionMismatch(u.n_blocks(), n_block_rows()));
2445 Assert(v.n_blocks() == n_block_cols(),
2446 ExcDimensionMismatch(v.n_blocks(), n_block_cols()));
2447
2448 value_type result = 0;
2449 for (unsigned int row = 0; row < n_block_rows(); ++row)
2450 for (unsigned int col = 0; col < n_block_cols(); ++col)
2451 result +=
2452 block(row, col).matrix_scalar_product(u.block(row), v.block(col));
2453 return result;
2454}
2455
2456
2457
2458template <typename MatrixType>
2459template <typename BlockVectorType>
2461BlockMatrixBase<MatrixType>::residual(BlockVectorType &dst,
2462 const BlockVectorType &x,
2463 const BlockVectorType &b) const
2464{
2465 Assert(dst.n_blocks() == n_block_rows(),
2466 ExcDimensionMismatch(dst.n_blocks(), n_block_rows()));
2467 Assert(b.n_blocks() == n_block_rows(),
2468 ExcDimensionMismatch(b.n_blocks(), n_block_rows()));
2469 Assert(x.n_blocks() == n_block_cols(),
2470 ExcDimensionMismatch(x.n_blocks(), n_block_cols()));
2471 // in block notation, the residual is
2472 // r_i = b_i - \sum_j A_ij x_j.
2473 // this can be written as
2474 // r_i = b_i - A_i0 x_0 - \sum_{j>0} A_ij x_j.
2475 //
2476 // for the first two terms, we can
2477 // call the residual function of
2478 // A_i0. for the other terms, we
2479 // use vmult_add. however, we want
2480 // to subtract, so in order to
2481 // avoid a temporary vector, we
2482 // perform a sign change of the
2483 // first two term before, and after
2484 // adding up
2485 for (unsigned int row = 0; row < n_block_rows(); ++row)
2486 {
2487 block(row, 0).residual(dst.block(row), x.block(0), b.block(row));
2488
2489 for (size_type i = 0; i < dst.block(row).size(); ++i)
2490 dst.block(row)(i) = -dst.block(row)(i);
2491
2492 for (unsigned int col = 1; col < n_block_cols(); ++col)
2493 block(row, col).vmult_add(dst.block(row), x.block(col));
2494
2495 for (size_type i = 0; i < dst.block(row).size(); ++i)
2496 dst.block(row)(i) = -dst.block(row)(i);
2497 };
2498
2499 value_type res = 0;
2500 for (size_type row = 0; row < n_block_rows(); ++row)
2501 res += dst.block(row).norm_sqr();
2502 return std::sqrt(res);
2503}
2504
2505
2506
2507template <typename MatrixType>
2508inline void
2509BlockMatrixBase<MatrixType>::print(std::ostream &out,
2510 const bool alternative_output) const
2511{
2512 for (unsigned int row = 0; row < n_block_rows(); ++row)
2513 for (unsigned int col = 0; col < n_block_cols(); ++col)
2514 {
2515 if (!alternative_output)
2516 out << "Block (" << row << ", " << col << ')' << std::endl;
2517
2518 block(row, col).print(out, alternative_output);
2519 }
2520}
2521
2522
2523
2524template <typename MatrixType>
2527{
2528 return const_iterator(this, 0);
2529}
2530
2531
2532
2533template <typename MatrixType>
2536{
2537 return const_iterator(this, m());
2538}
2539
2540
2541
2542template <typename MatrixType>
2544BlockMatrixBase<MatrixType>::begin(const size_type r) const
2545{
2546 AssertIndexRange(r, m());
2547 return const_iterator(this, r);
2548}
2549
2550
2551
2552template <typename MatrixType>
2554BlockMatrixBase<MatrixType>::end(const size_type r) const
2555{
2556 AssertIndexRange(r, m());
2557 return const_iterator(this, r + 1);
2558}
2559
2560
2561
2562template <typename MatrixType>
2565{
2566 return iterator(this, 0);
2567}
2568
2569
2570
2571template <typename MatrixType>
2574{
2575 return iterator(this, m());
2576}
2577
2578
2579
2580template <typename MatrixType>
2582BlockMatrixBase<MatrixType>::begin(const size_type r)
2583{
2584 AssertIndexRange(r, m());
2585 return iterator(this, r);
2586}
2587
2588
2589
2590template <typename MatrixType>
2592BlockMatrixBase<MatrixType>::end(const size_type r)
2593{
2594 AssertIndexRange(r, m());
2595 return iterator(this, r + 1);
2596}
2597
2598
2599
2600template <typename MatrixType>
2601void
2603{
2604 std::vector<size_type> row_sizes(this->n_block_rows());
2605 std::vector<size_type> col_sizes(this->n_block_cols());
2606
2607 // first find out the row sizes
2608 // from the first block column
2609 for (unsigned int r = 0; r < this->n_block_rows(); ++r)
2610 row_sizes[r] = sub_objects[r][0]->m();
2611 // then check that the following
2612 // block columns have the same
2613 // sizes
2614 for (unsigned int c = 1; c < this->n_block_cols(); ++c)
2615 for (unsigned int r = 0; r < this->n_block_rows(); ++r)
2616 Assert(row_sizes[r] == sub_objects[r][c]->m(),
2617 ExcIncompatibleRowNumbers(r, 0, r, c));
2618
2619 // finally initialize the row
2620 // indices with this array
2621 this->row_block_indices.reinit(row_sizes);
2622
2623
2624 // then do the same with the columns
2625 for (unsigned int c = 0; c < this->n_block_cols(); ++c)
2626 col_sizes[c] = sub_objects[0][c]->n();
2627 for (unsigned int r = 1; r < this->n_block_rows(); ++r)
2628 for (unsigned int c = 0; c < this->n_block_cols(); ++c)
2629 Assert(col_sizes[c] == sub_objects[r][c]->n(),
2630 ExcIncompatibleRowNumbers(0, c, r, c));
2631
2632 // finally initialize the row
2633 // indices with this array
2634 this->column_block_indices.reinit(col_sizes);
2635}
2636
2637
2638
2639template <typename MatrixType>
2640void
2642{
2643 for (unsigned int row = 0; row < n_block_rows(); ++row)
2644 for (unsigned int col = 0; col < n_block_cols(); ++col)
2645 block(row, col).prepare_add();
2646}
2647
2648
2649
2650template <typename MatrixType>
2651void
2653{
2654 for (unsigned int row = 0; row < n_block_rows(); ++row)
2655 for (unsigned int col = 0; col < n_block_cols(); ++col)
2656 block(row, col).prepare_set();
2657}
2658
2659#endif // DOXYGEN
2660
2661
2663
2664#endif // dealii_block_matrix_base_h
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
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
MatrixIterator< BlockMatrixIterators::Accessor< BlockMatrixBase, true > > const_iterator
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()
const BlockIndices & get_row_indices() const
iterator end()
void set(const size_type i, const size_type j, const value_type value)
friend class MatrixIterator
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
~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
MatrixIterator< BlockMatrixIterators::Accessor< BlockMatrixBase, false > > iterator
Table< 2, ObserverPointer< BlockType, BlockMatrixBase< SparseMatrix< number > > > > 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:40
constexpr bool running_in_debug_mode()
Definition config.h:78
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:41
#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)
const bool IsBlockVector< VectorType >::value
@ matrix
Contents is actually a matrix.
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)
VectorType::value_type * begin(VectorType &V)
Iterator lower_bound(Iterator first, Iterator last, const T &val)
Definition utilities.h:1033
constexpr types::global_dof_index invalid_size_type
Definition types.h:250
constexpr unsigned int invalid_unsigned_int
Definition types.h:238
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
unsigned int global_dof_index
Definition types.h:94
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