OGS
EigenTools.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#include "EigenTools.h"
5
6#include <range/v3/view/zip.hpp>
7
8#include "EigenVector.h"
9
10namespace
11{
14 const std::vector<MathLib::EigenMatrix::IndexType>& row_ids)
15{
17
18 // A_eigen(k, j) = 0.
19 // set row to zero
20 for (auto row_id : row_ids)
21 {
22 for (SpMat::InnerIterator it(A_eigen, row_id); it; ++it)
23 {
24 if (it.col() != decltype(it.col())(row_id))
25 {
26 it.valueRef() = 0.0;
27 }
28 }
29 }
30}
31
35 const std::vector<MathLib::EigenMatrix::IndexType>& vec_knownX_id,
36 const std::vector<double>& vec_knownX_x)
37{
38 setRowsToZeroOffDiagonal(A_eigen, vec_knownX_id);
39
41 SpMat AT = A_eigen.transpose();
42
43 // Reserve space for at least one value (on the diagonal). For
44 // deactivated subdomains some rows and columns might end empty (in the
45 // A matrix) and so no space is reserved for the Dirichlet conditions in
46 // the transposed matrix. Then the coeffRef call will do costly
47 // reallocations.
48 AT.reserve(Eigen::VectorXi::Constant(A_eigen.rows(), 1));
49
50 for (std::size_t ix = 0; ix < vec_knownX_id.size(); ix++)
51 {
52 SpMat::Index const row_id = vec_knownX_id[ix];
53 auto const x = vec_knownX_x[ix];
54
55 // b_i -= A_eigen(i,k)*val, i!=k
56 // set column to zero, subtract from rhs
57 for (SpMat::InnerIterator it(AT, row_id); it; ++it)
58 {
59 if (it.col() == row_id)
60 {
61 continue;
62 }
63
64 b_eigen[it.col()] -= it.value() * x;
65 it.valueRef() = 0.0;
66 }
67
68 auto& c = AT.coeffRef(row_id, row_id);
69 if (c != 0.0)
70 {
71 b_eigen[row_id] = x * c;
72 }
73 else
74 {
75 b_eigen[row_id] = x;
76 c = 1.0;
77 }
78 }
79
80 A_eigen = AT.transpose();
81}
82
86 const std::vector<MathLib::EigenMatrix::IndexType>& vec_knownX_id,
87 const std::vector<double>& vec_knownX_x)
88{
89 INFO("partial Dirichlet BC application (rhs only).");
90
91 setRowsToZeroOffDiagonal(A_eigen, vec_knownX_id);
92
93 Eigen::VectorXd x_known{A_eigen.rows()};
94 x_known.setZero();
95
96 for (auto const& [row_id, x] :
97 ranges::views::zip(vec_knownX_id, vec_knownX_x))
98 {
99 x_known[row_id] = x;
100
101 // set rhs to Dirichlet value
102 auto const c = A_eigen.coeff(row_id, row_id);
103 if (c != 0)
104 {
105 b_eigen[row_id] = x * c;
106
107 // exclude diagonal (A_eigen(i,i)) from multiplication below
108 // (A_eigen * x_known)
109 A_eigen.coeffRef(row_id, row_id) = 0;
110 }
111 else
112 {
113 b_eigen[row_id] = x;
114 }
115 }
116
117 b_eigen -= A_eigen * x_known;
118}
119} // namespace
120
121namespace MathLib
122{
124 EigenMatrix& A, EigenVector& b, EigenVector& /*x*/,
125 const std::vector<EigenMatrix::IndexType>& vec_knownX_id,
126 const std::vector<double>& vec_knownX_x,
128{
129 using SpMat = EigenMatrix::RawMatrixType;
130 static_assert(SpMat::IsRowMajor, "matrix is assumed to be row major!");
131
132 auto& A_eigen = A.getRawMatrix();
133 auto& b_eigen = b.getRawVector();
134
136 switch (mode)
137 {
139 ::applyKnownSolutionComplete(A_eigen, b_eigen, vec_knownX_id,
140 vec_knownX_x);
141 return;
143 ::applyKnownSolutionIncomplete(A_eigen, b_eigen, vec_knownX_id,
144 vec_knownX_x);
145 return;
146 }
147
148 OGS_FATAL("Unhandled DirichletBCApplicationMode with integer value {}.",
149 std::to_underlying(mode));
150}
151
152} // namespace MathLib
#define OGS_FATAL(...)
Definition Error.h:19
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28
Eigen::SparseMatrix< double, Eigen::RowMajor > RawMatrixType
Definition EigenMatrix.h:24
RawMatrixType & getRawMatrix()
Global vector based on Eigen vector.
Definition EigenVector.h:19
Eigen::VectorXd RawVectorType
Definition EigenVector.h:21
RawVectorType & getRawVector()
return a raw Eigen vector object
DirichletBCApplicationMode
Definition LinAlgEnums.h:33
@ COMPLETE_MATRIX_UPDATE
Both A and b fully updated.
Definition LinAlgEnums.h:34
@ FAST_INCOMPLETE_MATRIX_UPDATE
A partially updated, b fully updated.
Definition LinAlgEnums.h:35
void applyKnownSolution(EigenMatrix &A, EigenVector &b, EigenVector &, const std::vector< EigenMatrix::IndexType > &vec_knownX_id, const std::vector< double > &vec_knownX_x, DirichletBCApplicationMode const mode)
void setRowsToZeroOffDiagonal(MathLib::EigenMatrix::RawMatrixType &A_eigen, const std::vector< MathLib::EigenMatrix::IndexType > &row_ids)
void applyKnownSolutionIncomplete(MathLib::EigenMatrix::RawMatrixType &A_eigen, MathLib::EigenVector::RawVectorType &b_eigen, const std::vector< MathLib::EigenMatrix::IndexType > &vec_knownX_id, const std::vector< double > &vec_knownX_x)
void applyKnownSolutionComplete(MathLib::EigenMatrix::RawMatrixType &A_eigen, MathLib::EigenVector::RawVectorType &b_eigen, const std::vector< MathLib::EigenMatrix::IndexType > &vec_knownX_id, const std::vector< double > &vec_knownX_x)