TpsaMatrix.hpp
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3/*
4 Copyright 2025 NORCE AS
5
6 This file is part of the Open Porous Media project (OPM).
7
8 OPM is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 OPM is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with OPM. If not, see <http://www.gnu.org/licenses/>.
20*/
21#ifndef OPM_TPSA_MATRIX_HPP
22#define OPM_TPSA_MATRIX_HPP
23
24#include <opm/common/ErrorMacros.hpp>
27
28#include <array>
29#include <cstddef>
30#include <numeric>
31#include <ranges>
32#include <tuple>
33#include <utility>
34#include <vector>
35
36namespace Opm::Linear
37{
38
39template <class Scalar>
40class TpsaMatrix;
41
50template <class Scalar>
52{
53public:
55
57 TpsaBlockRef() = default;
58
66 TpsaBlockRef(const TpsaMatrix<Scalar>& matrix, std::size_t flatIdx)
67 : matrix_(&matrix)
68 , k_(flatIdx)
69 {
70 }
71
79 {
80 return *this;
81 }
82
91
100
108 TpsaBlockRef& operator=(Scalar value);
109
115 void gather(MatrixBlock& b) const;
116
117private:
131 template <class Op, class Block>
132 void apply_(Op op, Block& b) const;
133
134 const TpsaMatrix<Scalar>* matrix_{nullptr};
135 std::size_t k_{0};
136};
137
157template <class Scalar>
159{
160 friend class TpsaBlockRef<Scalar>;
161
162public:
165
168
171
173 using field_type = Scalar;
174
183 TpsaMatrix(std::size_t rows, std::size_t columns)
184 : rows_(rows)
185 , columns_(columns)
186 {
187 }
188
197 template <class Simulator>
198 explicit TpsaMatrix(const Simulator& simulator)
199 : TpsaMatrix(simulator.model().numTotalDof(), simulator.model().numTotalDof())
200 {
201 }
202
203 // The cached value-array base pointers and the sub-matrix view point into
204 // this object, so it must not be copied or moved.
205 TpsaMatrix(const TpsaMatrix&) = delete;
206
208
209 TpsaMatrix& operator=(const TpsaMatrix&) = delete;
210
212
224 template <class Set>
225 void reserve(const std::vector<Set>& sparsityPattern)
226 {
227 if (sparsityPattern.size() != rows_) {
228 OPM_THROW(std::logic_error,
229 "TPSA: sparsity pattern does not match the number of matrix rows");
230 }
231
232 // Flatten the pattern once; the column indices of a std::set are
233 // already ascending, which is the order BCRSMatrix stores them in.
234 rowStart_.resize(rows_ + 1);
235 rowStart_[0] = 0;
236 const auto sizes = sparsityPattern
237 | std::views::transform([](const auto& a) { return a.size(); });
238 std::partial_sum(sizes.begin(), sizes.end(), rowStart_.begin() + 1);
239 nnz_ = rowStart_[rows_];
240
241 colIdx_.clear();
242 colIdx_.reserve(nnz_);
243 for (std::size_t row = 0; row < rows_; ++row) {
244 colIdx_.insert(colIdx_.end(),
245 sparsityPattern[row].begin(),
246 sparsityPattern[row].end());
247 }
248
249 forEachSubMatrix_([&](auto& subMatrix) {
250 reserveSubMatrix_(subMatrix, sparsityPattern);
251 });
252
253 // Initialize base_ pointer to sub-matrices and set up TpsaMatrixView
254 cacheValueArrays_();
255 setMatrixView_();
256 }
257
271 BlockAddress blockAddress(const std::size_t rowIdx, const std::size_t colIdx) const
272 {
273 return BlockAddress(*this, flatIndex_(rowIdx, colIdx));
274 }
275
281 void clear();
282
294 void clearRow(const std::size_t row, const Scalar diag = 1.0);
295
301 void makeOverlapRowsInvalid(const std::vector<int>& overlapRows);
302
316 void scaleFields(const std::array<Scalar, numTpsaFields>& rowFac,
317 const std::array<Scalar, numTpsaFields>& colFac);
318
328 void block(const std::size_t rowIdx, const std::size_t colIdx, MatrixBlock& value) const
329 {
330 blockAddress(rowIdx, colIdx).gather(value);
331 }
332
341 void setBlock(const std::size_t rowIdx, const std::size_t colIdx, const MatrixBlock& value)
342 {
343 blockAddress(rowIdx, colIdx) = value;
344 }
345
354 void addToBlock(const std::size_t rowIdx, const std::size_t colIdx, const MatrixBlock& value)
355 {
356 blockAddress(rowIdx, colIdx) += value;
357 }
358
360 void commit()
361 {
362 }
363
365 void finalize()
366 {
367 }
368
377 {
378 return view_;
379 }
380
382 const IstlMatrix& istlMatrix() const
383 {
384 return view_;
385 }
386
392 std::size_t rows() const
393 {
394 return rows_;
395 }
396
402 std::size_t cols() const
403 {
404 return columns_;
405 }
406
408 std::size_t N() const
409 {
410 return rows_;
411 }
412
414 std::size_t M() const
415 {
416 return columns_;
417 }
418
424 std::size_t nonzeroes() const
425 {
426 return nnz_;
427 }
428
429 // Sub-matrix accessors. dd00/dd11/dd22 and spsp are the scalar blocks Hypre
430 // can precondition.
431
438 {
439 return dd00_;
440 }
441
448 {
449 return dd11_;
450 }
451
458 {
459 return dd22_;
460 }
461
468 {
469 return rr_;
470 }
471
478 {
479 return spsp_;
480 }
481
484 {
485 return dd00_;
486 }
487
490 {
491 return dd11_;
492 }
493
496 {
497 return dd22_;
498 }
499
502 {
503 return rr_;
504 }
505
508 {
509 return spsp_;
510 }
511
512private:
518 enum SubMatrixIdx : std::size_t
519 {
520 DD00 = 0, DD11, DD22,
521 DR0, DR1, DR2,
522 DSP0, DSP1, DSP2,
523 RD0, RD1, RD2,
524 RR, RSP,
525 SPD0, SPD1, SPD2,
526 SPR, SPSP,
527 numSubMatrices
528 };
529
536 static constexpr std::array<std::pair<std::size_t, std::size_t>, numSubMatrices>
537 subMatrixFields_ {{
538 {0, 0}, {1, 1}, {2, 2}, // DD00, DD11, DD22
539 {0, 3}, {1, 3}, {2, 3}, // DR0, DR1, DR2
540 {0, 4}, {1, 4}, {2, 4}, // DSP0, DSP1, DSP2
541 {3, 0}, {3, 1}, {3, 2}, // RD0, RD1, RD2
542 {3, 3}, {3, 4}, // RR, RSP
543 {4, 0}, {4, 1}, {4, 2}, // SPD0, SPD1, SPD2
544 {4, 3}, {4, 4} // SPR, SPSP
545 }};
546
560 template <class SubMatrix>
561 static constexpr std::size_t blockScalars_(const SubMatrix&)
562 {
563 using Block = typename SubMatrix::block_type;
564
565 return static_cast<std::size_t>(Block::rows) * static_cast<std::size_t>(Block::cols);
566 }
567
573 auto subMatrices_()
574 {
575 return std::tie(dd00_,
576 dd11_,
577 dd22_,
578 dr0_,
579 dr1_,
580 dr2_,
581 dsp0_,
582 dsp1_,
583 dsp2_,
584 rd0_,
585 rd1_,
586 rd2_,
587 rr_,
588 rsp_,
589 spd0_,
590 spd1_,
591 spd2_,
592 spr_,
593 spsp_);
594 }
595
603 template <class Op>
604 void forEachSubMatrix_(Op op)
605 {
606 std::apply([&op](auto&... subMatrix) {
607 (op(subMatrix), ...);
608 },
609 subMatrices_());
610 }
611
620 template <class Op>
621 void forEachSubMatrixWithIndex_(Op op)
622 {
623 std::apply([&op, subIdx = std::size_t{0}](auto&... subMatrix) mutable {
624 (op(subMatrix, subIdx++), ...);
625 },
626 subMatrices_());
627 }
628
641 template <class SubMatrix, class Set>
642 void reserveSubMatrix_(SubMatrix& subMatrix, const std::vector<Set>& sparsityPattern)
643 {
644 subMatrix.setBuildMode(SubMatrix::random);
645 subMatrix.setSize(rows_, columns_);
646
647 for (std::size_t row = 0; row < rows_; ++row) {
648 subMatrix.setrowsize(row, sparsityPattern[row].size());
649 }
650 subMatrix.endrowsizes();
651
652 for (std::size_t row = 0; row < rows_; ++row) {
653 for (const auto& col : sparsityPattern[row]) {
654 subMatrix.addindex(row, col);
655 }
656 }
657 // Note: all entries in subMatrix are Scalar(0.0) by default construction in endindices()
658 subMatrix.endindices();
659 }
660
668 void cacheValueArrays_();
669
671 void setMatrixView_();
672
681 std::size_t flatIndex_(std::size_t rowIdx, std::size_t colIdx) const;
682
683 std::size_t rows_{0};
684 std::size_t columns_{0};
685 std::size_t nnz_{0};
686
687 // Flattened sparsity pattern, shared by all sub-matrices.
688 std::vector<std::size_t> rowStart_{};
689 std::vector<unsigned> colIdx_{};
690
691 // Base pointers into the sub-matrices' contiguous value arrays.
692 std::array<Scalar*, numSubMatrices> base_{};
693
694 DispDispMatrix00T<Scalar> dd00_{};
695 DispDispMatrix11T<Scalar> dd11_{};
696 DispDispMatrix22T<Scalar> dd22_{};
697
698 DispRotMatrix0T<Scalar> dr0_{};
699 DispRotMatrix1T<Scalar> dr1_{};
700 DispRotMatrix2T<Scalar> dr2_{};
701
702 DispSPresMatrix0T<Scalar> dsp0_{};
703 DispSPresMatrix1T<Scalar> dsp1_{};
704 DispSPresMatrix2T<Scalar> dsp2_{};
705
706 RotDispMatrix0T<Scalar> rd0_{};
707 RotDispMatrix1T<Scalar> rd1_{};
708 RotDispMatrix2T<Scalar> rd2_{};
709
710 RotRotMatrixT<Scalar> rr_{};
711 RotSPresMatrixT<Scalar> rsp_{};
712
713 SPresDispMatrix0T<Scalar> spd0_{};
714 SPresDispMatrix1T<Scalar> spd1_{};
715 SPresDispMatrix2T<Scalar> spd2_{};
716
717 SPresRotMatrixT<Scalar> spr_{};
718
719 SPresSPresMatrixT<Scalar> spsp_{};
720
721 IstlMatrix view_{};
722};
723
724//
725// TpsaBlockRef implementation
726//
727template <class Scalar>
728template <class Op, class Block>
729void
730TpsaBlockRef<Scalar>::apply_(Op op, Block& b) const
731{
732 using Matrix = TpsaMatrix<Scalar>;
733 const auto& base = matrix_->base_;
734 const std::size_t k = k_;
735
736 // Displacement-displacement (diagonal components only)
737 op(base[Matrix::DD00][k], b[0][0]);
738 op(base[Matrix::DD11][k], b[1][1]);
739 op(base[Matrix::DD22][k], b[2][2]);
740
741 // Displacement-rotation: three 1x3 blocks
742 for (int j = 0; j < numRotDofs; ++j) {
743 op(base[Matrix::DR0][3 * k + j], b[0][3 + j]);
744 op(base[Matrix::DR1][3 * k + j], b[1][3 + j]);
745 op(base[Matrix::DR2][3 * k + j], b[2][3 + j]);
746 }
747
748 // Displacement-solid pressure: three 1x1 blocks
749 op(base[Matrix::DSP0][k], b[0][6]);
750 op(base[Matrix::DSP1][k], b[1][6]);
751 op(base[Matrix::DSP2][k], b[2][6]);
752
753 // Rotation-displacement: three 3x1 blocks
754 for (int i = 0; i < numRotDofs; ++i) {
755 op(base[Matrix::RD0][3 * k + i], b[3 + i][0]);
756 op(base[Matrix::RD1][3 * k + i], b[3 + i][1]);
757 op(base[Matrix::RD2][3 * k + i], b[3 + i][2]);
758 }
759
760 // Rotation-rotation: one 3x3 block
761 for (int i = 0; i < numRotDofs; ++i) {
762 for (int j = 0; j < numRotDofs; ++j) {
763 op(base[Matrix::RR][9 * k + 3 * i + j], b[3 + i][3 + j]);
764 }
765 }
766
767 // Rotation-solid pressure: one 3x1 block
768 for (int i = 0; i < numRotDofs; ++i) {
769 op(base[Matrix::RSP][3 * k + i], b[3 + i][6]);
770 }
771
772 // Solid pressure-displacement: three 1x1 blocks
773 op(base[Matrix::SPD0][k], b[6][0]);
774 op(base[Matrix::SPD1][k], b[6][1]);
775 op(base[Matrix::SPD2][k], b[6][2]);
776
777 // Solid pressure-rotation: one 1x3 block
778 for (int j = 0; j < numRotDofs; ++j) {
779 op(base[Matrix::SPR][3 * k + j], b[6][3 + j]);
780 }
781
782 // Solid pressure-solid pressure: one 1x1 block
783 op(base[Matrix::SPSP][k], b[6][6]);
784}
785
786} // namespace Opm::Linear
787
788#endif // OPM_TPSA_MATRIX_HPP
Handle on one block of the TPSA matrix.
Definition: TpsaMatrix.hpp:52
void gather(MatrixBlock &b) const
Gather the stored entries into a dense 7x7 block.
TpsaBlockRef & operator=(Scalar value)
Set every stored entry of this block to a scalar.
TpsaBlockRef(const TpsaMatrix< Scalar > &matrix, std::size_t flatIdx)
Construct a handle on one block of a TPSA matrix.
Definition: TpsaMatrix.hpp:66
TpsaBlockRef & operator*()
Dereference the handle, so that it can be used where a pointer to a block is expected.
Definition: TpsaMatrix.hpp:78
TpsaBlockRef()=default
Construct a handle that does not refer to any block.
TpsaBlockRef & operator=(const MatrixBlock &b)
Overwrite the stored entries with a dense 7x7 block.
TpsaBlockRef & operator+=(const MatrixBlock &b)
Scatter a dense 7x7 contribution into the sub-matrices.
TPSA matrix for linear elasticity.
Definition: TpsaMatrix.hpp:159
IstlMatrix & istlMatrix()
The sub-matrix view the linear solver operates on.
Definition: TpsaMatrix.hpp:376
void scaleFields(const std::array< Scalar, numTpsaFields > &rowFac, const std::array< Scalar, numTpsaFields > &colFac)
Scale the system by one factor per field: A <- D_row * A * D_col.
RotRotMatrixT< Scalar > & rr()
Access the rotation-rotation sub-matrix.
Definition: TpsaMatrix.hpp:467
std::size_t rows() const
Number of block rows.
Definition: TpsaMatrix.hpp:392
std::size_t cols() const
Number of block columns.
Definition: TpsaMatrix.hpp:402
TpsaMatrix(std::size_t rows, std::size_t columns)
Construct a matrix of the given block dimensions.
Definition: TpsaMatrix.hpp:183
DispDispMatrix00T< Scalar > & dd00()
Access the u_x-u_x sub-matrix.
Definition: TpsaMatrix.hpp:437
void finalize()
The structure is already solver-ready after reserve().
Definition: TpsaMatrix.hpp:365
const RotRotMatrixT< Scalar > & rr() const
Access the rotation-rotation sub-matrix.
Definition: TpsaMatrix.hpp:501
TpsaMatrix(TpsaMatrix &&)=delete
TpsaMatrix & operator=(TpsaMatrix &&)=delete
void addToBlock(const std::size_t rowIdx, const std::size_t colIdx, const MatrixBlock &value)
Add a dense 7x7 block to the given block.
Definition: TpsaMatrix.hpp:354
std::size_t N() const
Number of block rows.
Definition: TpsaMatrix.hpp:408
std::size_t nonzeroes() const
Number of nonzero blocks in the shared sparsity pattern.
Definition: TpsaMatrix.hpp:424
DispDispMatrix11T< Scalar > & dd11()
Access the u_y-u_y sub-matrix.
Definition: TpsaMatrix.hpp:447
TpsaMatrix & operator=(const TpsaMatrix &)=delete
TpsaMatrix(const TpsaMatrix &)=delete
const DispDispMatrix00T< Scalar > & dd00() const
Access the u_x-u_x sub-matrix.
Definition: TpsaMatrix.hpp:483
BlockAddress blockAddress(const std::size_t rowIdx, const std::size_t colIdx) const
Handle on the block at (rowIdx, colIdx).
Definition: TpsaMatrix.hpp:271
TpsaBlockRef< Scalar > BlockAddress
What blockAddress() returns.
Definition: TpsaMatrix.hpp:170
void block(const std::size_t rowIdx, const std::size_t colIdx, MatrixBlock &value) const
Fill value with the stored entries of the given block.
Definition: TpsaMatrix.hpp:328
void commit()
No local caching, so nothing to commit.
Definition: TpsaMatrix.hpp:360
void clearRow(const std::size_t row, const Scalar diag=1.0)
Set the given row to zero, except for the main diagonal.
const SPresSPresMatrixT< Scalar > & spsp() const
Access the solid pressure-solid pressure sub-matrix.
Definition: TpsaMatrix.hpp:507
std::size_t M() const
Number of block columns.
Definition: TpsaMatrix.hpp:414
void setBlock(const std::size_t rowIdx, const std::size_t colIdx, const MatrixBlock &value)
Overwrite the given block with a dense 7x7 block.
Definition: TpsaMatrix.hpp:341
DispDispMatrix22T< Scalar > & dd22()
Access the u_z-u_z sub-matrix.
Definition: TpsaMatrix.hpp:457
TpsaMatrix(const Simulator &simulator)
Construct a square matrix sized from a simulator's degrees of freedom.
Definition: TpsaMatrix.hpp:198
const DispDispMatrix22T< Scalar > & dd22() const
Access the u_z-u_z sub-matrix.
Definition: TpsaMatrix.hpp:495
void makeOverlapRowsInvalid(const std::vector< int > &overlapRows)
Zero out the overlap rows and put the identity on their diagonal.
Scalar field_type
Field type of the matrix entries.
Definition: TpsaMatrix.hpp:173
void clear()
Set all matrix entries to zero.
const IstlMatrix & istlMatrix() const
The sub-matrix view the linear solver operates on.
Definition: TpsaMatrix.hpp:382
TpsaMatrixView< Scalar > IstlMatrix
What the linear solver operates on.
Definition: TpsaMatrix.hpp:164
void reserve(const std::vector< Set > &sparsityPattern)
Allocate all sub-matrices from a common sparsity pattern.
Definition: TpsaMatrix.hpp:225
const DispDispMatrix11T< Scalar > & dd11() const
Access the u_y-u_y sub-matrix.
Definition: TpsaMatrix.hpp:489
SPresSPresMatrixT< Scalar > & spsp()
Access the solid pressure-solid pressure sub-matrix.
Definition: TpsaMatrix.hpp:477
Lightweight, non-owning 5x5 view over the sub-matrices owned by TpsaMatrix. Provides the operator int...
Definition: TpsaTypes.hpp:132
Definition: matrixblock.hh:256
Manages the initializing and running of time dependent problems.
Definition: simulator.hh:87
Definition: bicgstabsolver.hh:42
Dune::BCRSMatrix< MatrixBlock< Scalar, numRotDofs, numRotDofs > > RotRotMatrixT
Definition: TpsaTypes.hpp:58
Dune::BCRSMatrix< MatrixBlock< Scalar, numSolidPresDofs, numSolidPresDofs > > SPresSPresMatrixT
Definition: TpsaTypes.hpp:60
Dune::BCRSMatrix< MatrixBlock< Scalar, numDispDofs, numDispDofs > > DispDispMatrix11T
Definition: TpsaTypes.hpp:54
Dune::BCRSMatrix< MatrixBlock< Scalar, numDispDofs, numDispDofs > > DispDispMatrix22T
Definition: TpsaTypes.hpp:56
Dune::BCRSMatrix< MatrixBlock< Scalar, numDispDofs, numDispDofs > > DispDispMatrix00T
Definition: TpsaTypes.hpp:52
constexpr int numRotDofs
Definition: TpsaTypes.hpp:38