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 2 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 Consult the COPYING file in the top-level source directory of this
22 module for the precise wording of the license and the list of
23 copyright holders.
24*/
25#ifndef OPM_TPSA_MATRIX_HPP
26#define OPM_TPSA_MATRIX_HPP
27
28#include <opm/common/ErrorMacros.hpp>
31
32#include <array>
33#include <cstddef>
34#include <numeric>
35#include <ranges>
36#include <tuple>
37#include <utility>
38#include <vector>
39
40namespace Opm::Linear
41{
42
43template <class Scalar>
44class TpsaMatrix;
45
54template <class Scalar>
56{
57public:
59
61 TpsaBlockRef() = default;
62
70 TpsaBlockRef(const TpsaMatrix<Scalar>& matrix, std::size_t flatIdx)
71 : matrix_(&matrix)
72 , k_(flatIdx)
73 {
74 }
75
83 {
84 return *this;
85 }
86
95
104
112 TpsaBlockRef& operator=(Scalar value);
113
119 void gather(MatrixBlock& b) const;
120
121private:
135 template <class Op, class Block>
136 void apply_(Op op, Block& b) const;
137
138 const TpsaMatrix<Scalar>* matrix_{nullptr};
139 std::size_t k_{0};
140};
141
161template <class Scalar>
163{
164 friend class TpsaBlockRef<Scalar>;
165
166public:
169
172
175
177 using field_type = Scalar;
178
187 TpsaMatrix(std::size_t rows, std::size_t columns)
188 : rows_(rows)
189 , columns_(columns)
190 {
191 }
192
201 template <class Simulator>
202 explicit TpsaMatrix(const Simulator& simulator)
203 : TpsaMatrix(simulator.model().numTotalDof(), simulator.model().numTotalDof())
204 {
205 }
206
207 // The cached value-array base pointers and the sub-matrix view point into
208 // this object, so it must not be copied or moved.
209 TpsaMatrix(const TpsaMatrix&) = delete;
210
212
213 TpsaMatrix& operator=(const TpsaMatrix&) = delete;
214
216
228 template <class Set>
229 void reserve(const std::vector<Set>& sparsityPattern)
230 {
231 if (sparsityPattern.size() != rows_) {
232 OPM_THROW(std::logic_error,
233 "TPSA: sparsity pattern does not match the number of matrix rows");
234 }
235
236 // Flatten the pattern once; the column indices of a std::set are
237 // already ascending, which is the order BCRSMatrix stores them in.
238 rowStart_.resize(rows_ + 1);
239 rowStart_[0] = 0;
240 const auto sizes = sparsityPattern
241 | std::views::transform([](const auto& a) { return a.size(); });
242 std::partial_sum(sizes.begin(), sizes.end(), rowStart_.begin() + 1);
243 nnz_ = rowStart_[rows_];
244
245 colIdx_.clear();
246 colIdx_.reserve(nnz_);
247 for (std::size_t row = 0; row < rows_; ++row) {
248 colIdx_.insert(colIdx_.end(),
249 sparsityPattern[row].begin(),
250 sparsityPattern[row].end());
251 }
252
253 forEachSubMatrix_([&](auto& subMatrix) {
254 reserveSubMatrix_(subMatrix, sparsityPattern);
255 });
256
257 // Initialize base_ pointer to sub-matrices and set up TpsaMatrixView
258 cacheValueArrays_();
259 setMatrixView_();
260 }
261
275 BlockAddress blockAddress(const std::size_t rowIdx, const std::size_t colIdx) const
276 {
277 return BlockAddress(*this, flatIndex_(rowIdx, colIdx));
278 }
279
285 void clear();
286
298 void clearRow(const std::size_t row, const Scalar diag = 1.0);
299
305 void makeOverlapRowsInvalid(const std::vector<int>& overlapRows);
306
320 void scaleFields(const std::array<Scalar, numTpsaFields>& rowFac,
321 const std::array<Scalar, numTpsaFields>& colFac);
322
332 void block(const std::size_t rowIdx, const std::size_t colIdx, MatrixBlock& value) const
333 {
334 blockAddress(rowIdx, colIdx).gather(value);
335 }
336
345 void setBlock(const std::size_t rowIdx, const std::size_t colIdx, const MatrixBlock& value)
346 {
347 blockAddress(rowIdx, colIdx) = value;
348 }
349
358 void addToBlock(const std::size_t rowIdx, const std::size_t colIdx, const MatrixBlock& value)
359 {
360 blockAddress(rowIdx, colIdx) += value;
361 }
362
364 void commit()
365 {
366 }
367
369 void finalize()
370 {
371 }
372
381 {
382 return view_;
383 }
384
386 const IstlMatrix& istlMatrix() const
387 {
388 return view_;
389 }
390
396 std::size_t rows() const
397 {
398 return rows_;
399 }
400
406 std::size_t cols() const
407 {
408 return columns_;
409 }
410
412 std::size_t N() const
413 {
414 return rows_;
415 }
416
418 std::size_t M() const
419 {
420 return columns_;
421 }
422
428 std::size_t nonzeroes() const
429 {
430 return nnz_;
431 }
432
433 // Sub-matrix accessors. dd00/dd11/dd22 and spsp are the scalar blocks Hypre
434 // can precondition.
435
442 {
443 return dd00_;
444 }
445
452 {
453 return dd11_;
454 }
455
462 {
463 return dd22_;
464 }
465
472 {
473 return rr_;
474 }
475
482 {
483 return spsp_;
484 }
485
488 {
489 return dd00_;
490 }
491
494 {
495 return dd11_;
496 }
497
500 {
501 return dd22_;
502 }
503
506 {
507 return rr_;
508 }
509
512 {
513 return spsp_;
514 }
515
516private:
522 enum SubMatrixIdx : std::size_t
523 {
524 DD00 = 0, DD11, DD22,
525 DR0, DR1, DR2,
526 DSP0, DSP1, DSP2,
527 RD0, RD1, RD2,
528 RR, RSP,
529 SPD0, SPD1, SPD2,
530 SPR, SPSP,
531 numSubMatrices
532 };
533
540 static constexpr std::array<std::pair<std::size_t, std::size_t>, numSubMatrices>
541 subMatrixFields_ {{
542 {0, 0}, {1, 1}, {2, 2}, // DD00, DD11, DD22
543 {0, 3}, {1, 3}, {2, 3}, // DR0, DR1, DR2
544 {0, 4}, {1, 4}, {2, 4}, // DSP0, DSP1, DSP2
545 {3, 0}, {3, 1}, {3, 2}, // RD0, RD1, RD2
546 {3, 3}, {3, 4}, // RR, RSP
547 {4, 0}, {4, 1}, {4, 2}, // SPD0, SPD1, SPD2
548 {4, 3}, {4, 4} // SPR, SPSP
549 }};
550
564 template <class SubMatrix>
565 static constexpr std::size_t blockScalars_(const SubMatrix&)
566 {
567 using Block = typename SubMatrix::block_type;
568
569 return static_cast<std::size_t>(Block::rows) * static_cast<std::size_t>(Block::cols);
570 }
571
577 auto subMatrices_()
578 {
579 return std::tie(dd00_,
580 dd11_,
581 dd22_,
582 dr0_,
583 dr1_,
584 dr2_,
585 dsp0_,
586 dsp1_,
587 dsp2_,
588 rd0_,
589 rd1_,
590 rd2_,
591 rr_,
592 rsp_,
593 spd0_,
594 spd1_,
595 spd2_,
596 spr_,
597 spsp_);
598 }
599
607 template <class Op>
608 void forEachSubMatrix_(Op op)
609 {
610 std::apply([&op](auto&... subMatrix) {
611 (op(subMatrix), ...);
612 },
613 subMatrices_());
614 }
615
624 template <class Op>
625 void forEachSubMatrixWithIndex_(Op op)
626 {
627 std::apply([&op, subIdx = std::size_t{0}](auto&... subMatrix) mutable {
628 (op(subMatrix, subIdx++), ...);
629 },
630 subMatrices_());
631 }
632
645 template <class SubMatrix, class Set>
646 void reserveSubMatrix_(SubMatrix& subMatrix, const std::vector<Set>& sparsityPattern)
647 {
648 subMatrix.setBuildMode(SubMatrix::random);
649 subMatrix.setSize(rows_, columns_);
650
651 for (std::size_t row = 0; row < rows_; ++row) {
652 subMatrix.setrowsize(row, sparsityPattern[row].size());
653 }
654 subMatrix.endrowsizes();
655
656 for (std::size_t row = 0; row < rows_; ++row) {
657 for (const auto& col : sparsityPattern[row]) {
658 subMatrix.addindex(row, col);
659 }
660 }
661 // Note: all entries in subMatrix are Scalar(0.0) by default construction in endindices()
662 subMatrix.endindices();
663 }
664
672 void cacheValueArrays_();
673
675 void setMatrixView_();
676
685 std::size_t flatIndex_(std::size_t rowIdx, std::size_t colIdx) const;
686
687 std::size_t rows_{0};
688 std::size_t columns_{0};
689 std::size_t nnz_{0};
690
691 // Flattened sparsity pattern, shared by all sub-matrices.
692 std::vector<std::size_t> rowStart_{};
693 std::vector<unsigned> colIdx_{};
694
695 // Base pointers into the sub-matrices' contiguous value arrays.
696 std::array<Scalar*, numSubMatrices> base_{};
697
698 DispDispMatrix00T<Scalar> dd00_{};
699 DispDispMatrix11T<Scalar> dd11_{};
700 DispDispMatrix22T<Scalar> dd22_{};
701
702 DispRotMatrix0T<Scalar> dr0_{};
703 DispRotMatrix1T<Scalar> dr1_{};
704 DispRotMatrix2T<Scalar> dr2_{};
705
706 DispSPresMatrix0T<Scalar> dsp0_{};
707 DispSPresMatrix1T<Scalar> dsp1_{};
708 DispSPresMatrix2T<Scalar> dsp2_{};
709
710 RotDispMatrix0T<Scalar> rd0_{};
711 RotDispMatrix1T<Scalar> rd1_{};
712 RotDispMatrix2T<Scalar> rd2_{};
713
714 RotRotMatrixT<Scalar> rr_{};
715 RotSPresMatrixT<Scalar> rsp_{};
716
717 SPresDispMatrix0T<Scalar> spd0_{};
718 SPresDispMatrix1T<Scalar> spd1_{};
719 SPresDispMatrix2T<Scalar> spd2_{};
720
721 SPresRotMatrixT<Scalar> spr_{};
722
723 SPresSPresMatrixT<Scalar> spsp_{};
724
725 IstlMatrix view_{};
726};
727
728//
729// TpsaBlockRef implementation
730//
731template <class Scalar>
732template <class Op, class Block>
733void
734TpsaBlockRef<Scalar>::apply_(Op op, Block& b) const
735{
736 using Matrix = TpsaMatrix<Scalar>;
737 const auto& base = matrix_->base_;
738 const std::size_t k = k_;
739
740 // Displacement-displacement (diagonal components only)
741 op(base[Matrix::DD00][k], b[0][0]);
742 op(base[Matrix::DD11][k], b[1][1]);
743 op(base[Matrix::DD22][k], b[2][2]);
744
745 // Displacement-rotation: three 1x3 blocks
746 for (int j = 0; j < numRotDofs; ++j) {
747 op(base[Matrix::DR0][3 * k + j], b[0][3 + j]);
748 op(base[Matrix::DR1][3 * k + j], b[1][3 + j]);
749 op(base[Matrix::DR2][3 * k + j], b[2][3 + j]);
750 }
751
752 // Displacement-solid pressure: three 1x1 blocks
753 op(base[Matrix::DSP0][k], b[0][6]);
754 op(base[Matrix::DSP1][k], b[1][6]);
755 op(base[Matrix::DSP2][k], b[2][6]);
756
757 // Rotation-displacement: three 3x1 blocks
758 for (int i = 0; i < numRotDofs; ++i) {
759 op(base[Matrix::RD0][3 * k + i], b[3 + i][0]);
760 op(base[Matrix::RD1][3 * k + i], b[3 + i][1]);
761 op(base[Matrix::RD2][3 * k + i], b[3 + i][2]);
762 }
763
764 // Rotation-rotation: one 3x3 block
765 for (int i = 0; i < numRotDofs; ++i) {
766 for (int j = 0; j < numRotDofs; ++j) {
767 op(base[Matrix::RR][9 * k + 3 * i + j], b[3 + i][3 + j]);
768 }
769 }
770
771 // Rotation-solid pressure: one 3x1 block
772 for (int i = 0; i < numRotDofs; ++i) {
773 op(base[Matrix::RSP][3 * k + i], b[3 + i][6]);
774 }
775
776 // Solid pressure-displacement: three 1x1 blocks
777 op(base[Matrix::SPD0][k], b[6][0]);
778 op(base[Matrix::SPD1][k], b[6][1]);
779 op(base[Matrix::SPD2][k], b[6][2]);
780
781 // Solid pressure-rotation: one 1x3 block
782 for (int j = 0; j < numRotDofs; ++j) {
783 op(base[Matrix::SPR][3 * k + j], b[6][3 + j]);
784 }
785
786 // Solid pressure-solid pressure: one 1x1 block
787 op(base[Matrix::SPSP][k], b[6][6]);
788}
789
790} // namespace Opm::Linear
791
792#endif // OPM_TPSA_MATRIX_HPP
Handle on one block of the TPSA matrix.
Definition: TpsaMatrix.hpp:56
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:70
TpsaBlockRef & operator*()
Dereference the handle, so that it can be used where a pointer to a block is expected.
Definition: TpsaMatrix.hpp:82
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:163
IstlMatrix & istlMatrix()
The sub-matrix view the linear solver operates on.
Definition: TpsaMatrix.hpp:380
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:471
std::size_t rows() const
Number of block rows.
Definition: TpsaMatrix.hpp:396
std::size_t cols() const
Number of block columns.
Definition: TpsaMatrix.hpp:406
TpsaMatrix(std::size_t rows, std::size_t columns)
Construct a matrix of the given block dimensions.
Definition: TpsaMatrix.hpp:187
DispDispMatrix00T< Scalar > & dd00()
Access the u_x-u_x sub-matrix.
Definition: TpsaMatrix.hpp:441
void finalize()
The structure is already solver-ready after reserve().
Definition: TpsaMatrix.hpp:369
const RotRotMatrixT< Scalar > & rr() const
Access the rotation-rotation sub-matrix.
Definition: TpsaMatrix.hpp:505
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:358
std::size_t N() const
Number of block rows.
Definition: TpsaMatrix.hpp:412
std::size_t nonzeroes() const
Number of nonzero blocks in the shared sparsity pattern.
Definition: TpsaMatrix.hpp:428
DispDispMatrix11T< Scalar > & dd11()
Access the u_y-u_y sub-matrix.
Definition: TpsaMatrix.hpp:451
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:487
BlockAddress blockAddress(const std::size_t rowIdx, const std::size_t colIdx) const
Handle on the block at (rowIdx, colIdx).
Definition: TpsaMatrix.hpp:275
TpsaBlockRef< Scalar > BlockAddress
What blockAddress() returns.
Definition: TpsaMatrix.hpp:174
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:332
void commit()
No local caching, so nothing to commit.
Definition: TpsaMatrix.hpp:364
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:511
std::size_t M() const
Number of block columns.
Definition: TpsaMatrix.hpp:418
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:345
DispDispMatrix22T< Scalar > & dd22()
Access the u_z-u_z sub-matrix.
Definition: TpsaMatrix.hpp:461
TpsaMatrix(const Simulator &simulator)
Construct a square matrix sized from a simulator's degrees of freedom.
Definition: TpsaMatrix.hpp:202
const DispDispMatrix22T< Scalar > & dd22() const
Access the u_z-u_z sub-matrix.
Definition: TpsaMatrix.hpp:499
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:177
void clear()
Set all matrix entries to zero.
const IstlMatrix & istlMatrix() const
The sub-matrix view the linear solver operates on.
Definition: TpsaMatrix.hpp:386
TpsaMatrixView< Scalar > IstlMatrix
What the linear solver operates on.
Definition: TpsaMatrix.hpp:168
void reserve(const std::vector< Set > &sparsityPattern)
Allocate all sub-matrices from a common sparsity pattern.
Definition: TpsaMatrix.hpp:229
const DispDispMatrix11T< Scalar > & dd11() const
Access the u_y-u_y sub-matrix.
Definition: TpsaMatrix.hpp:493
SPresSPresMatrixT< Scalar > & spsp()
Access the solid pressure-solid pressure sub-matrix.
Definition: TpsaMatrix.hpp:481
Lightweight, non-owning 5x5 view over the sub-matrices owned by TpsaMatrix. Provides the operator int...
Definition: TpsaTypes.hpp:136
Definition: matrixblock.hh:256
Manages the initializing and running of time dependent problems.
Definition: simulator.hh:84
Definition: bicgstabsolver.hh:42
Dune::BCRSMatrix< MatrixBlock< Scalar, numRotDofs, numRotDofs > > RotRotMatrixT
Definition: TpsaTypes.hpp:62
Dune::BCRSMatrix< MatrixBlock< Scalar, numSolidPresDofs, numSolidPresDofs > > SPresSPresMatrixT
Definition: TpsaTypes.hpp:64
Dune::BCRSMatrix< MatrixBlock< Scalar, numDispDofs, numDispDofs > > DispDispMatrix11T
Definition: TpsaTypes.hpp:58
Dune::BCRSMatrix< MatrixBlock< Scalar, numDispDofs, numDispDofs > > DispDispMatrix22T
Definition: TpsaTypes.hpp:60
Dune::BCRSMatrix< MatrixBlock< Scalar, numDispDofs, numDispDofs > > DispDispMatrix00T
Definition: TpsaTypes.hpp:56
constexpr int numRotDofs
Definition: TpsaTypes.hpp:42