forked from yinweijie/CFD-Eigen-Solver
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMatrixCoeff.h
200 lines (155 loc) · 4.92 KB
/
MatrixCoeff.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#ifndef __MATRIX_COEFF_H__
#define __MATRIX_COEFF_H__
#include <iostream>
#include <Eigen/Sparse>
#include <Eigen/IterativeLinearSolvers>
#include "Inputs.h"
#include "Mesh.h"
#include "MatrixWrapper.h"
using Eigen::SparseMatrix;
using Eigen::BiCGSTAB;
using namespace std;
template <typename T>
class MatrixCoeff
{
private:
const Mesh* mesh;
// 网格数量
int N;
VectorXd aW, aE, aS, aN, aO, SO, SE, SW, SN, SS, Su;
VectorXd b_m;
VectorXd x;
/**
* MatrixXd和SparseMatrix的封装类,封装后的Wrapper类共同继承接口MatrixInterface,
* 并实现接口函数MatrixInterface::setNum,这个函数用来往矩阵中插入元素
*/
DenseMatrixWrapper dense_matrix_wrapper;
SparseMatrixWrapper sparse_matrix_wrapper;
double m_res;
double epsilon;
friend T;
public:
MatrixCoeff(const Mesh* mesh)
: mesh(mesh), N(mesh->get_N())
{
aW = VectorXd::Zero(N);
aE = VectorXd::Zero(N);
aS = VectorXd::Zero(N);
aN = VectorXd::Zero(N);
aO = VectorXd::Zero(N);
SO = VectorXd::Zero(N);
SE = VectorXd::Zero(N);
SW = VectorXd::Zero(N);
SN = VectorXd::Zero(N);
SS = VectorXd::Zero(N);
Su = VectorXd::Zero(N);
b_m = VectorXd::Zero(N);
x = VectorXd::Zero(N);
m_res = 0.0;
epsilon = 1.e-10;
}
VectorXd& get_b_m() { return b_m; }
VectorXd& get_x() { return x; }
VectorXd& get_aO() { return aO; }
// MatrixXd系数初始化
void initDenseMatrix();
// SparseMatrix系数初始化
void initSparseMatrix();
void init(MatrixInterface* matrix);
// 系数矩阵存在非稀疏矩阵MatrixXd中,方便打印输出
void DebugSolve(VectorXd& field_var);
// 系数矩阵存在稀疏矩阵SparseMatrix中,用于迭代求解
void Solve(VectorXd& field_var, double& res, double tolerance = 1.e-10);
};
template <typename T>
void MatrixCoeff<T>::initDenseMatrix()
{
dense_matrix_wrapper = DenseMatrixWrapper(N, N);
init(&dense_matrix_wrapper);
b_m = Su;
}
template <typename T>
void MatrixCoeff<T>::initSparseMatrix()
{
sparse_matrix_wrapper = SparseMatrixWrapper(N, N);
SparseMatrix<double>& A_m = sparse_matrix_wrapper.getMatrix();
// 每列预留5个元素的空间,用于插入
// ref. http://eigen.tuxfamily.org/dox/group__TutorialSparse.html - Filling a sparse matrix
A_m.reserve(VectorXi::Constant(N, 5));
init(&sparse_matrix_wrapper);
A_m.makeCompressed(); // optional
b_m = Su;
}
template <typename T>
void MatrixCoeff<T>::init(MatrixInterface* matrix)
{
for(int i = 0; i < N; i++)
{
int i_l = mesh->left_of(i);
int i_r = mesh->right_of(i);
int i_t = mesh->top_of(i);
int i_b = mesh->bottom_of(i);
matrix->setNum(i, i, aO[i]);
if(!mesh->is_at_left_boundary(i))
{
matrix->setNum(i, i_l, -(aW[i] - SW[i]));
}
if(!mesh->is_at_right_boundary(i))
{
matrix->setNum(i, i_r, -(aE[i] - SE[i]));
}
if(!mesh->is_at_bottom_boundary(i))
{
matrix->setNum(i, i_b, -(aS[i] - SS[i]));
}
if(!mesh->is_at_top_boundary(i))
{
matrix->setNum(i, i_t, -(aN[i] - SN[i]));
}
}
}
template <typename T>
void MatrixCoeff<T>::DebugSolve(VectorXd& field_var)
{
initDenseMatrix();
MatrixXd& A_m = dense_matrix_wrapper.getMatrix();
// 输出结果
cout << "A_m: " << endl;
// for(int i = 0; i < A_m.rows(); i++)
// {
// for(int j = 0; j < A_m.cols(); j++)
// {
// cout << A_m(i, j) << ", ";
// }
// cout << endl;
// }
cout << A_m << endl;
cout << endl;
// 求解矩阵
field_var = A_m.fullPivLu().solve(b_m);
cout << "b_m: " << endl << b_m << endl;
cout << endl;
cout << "Solution: " << endl << field_var << endl;
}
template <typename T>
void MatrixCoeff<T>::Solve(VectorXd& field_var, double& res, double tolerance)
{
initSparseMatrix();
SparseMatrix<double>& A_m = sparse_matrix_wrapper.getMatrix();
VectorXd& x = field_var;
// 计算残差
m_res = (b_m - A_m * x).norm();
res = m_res;
if(res < epsilon) return;
// ref. http://eigen.tuxfamily.org/dox/classEigen_1_1BiCGSTAB.html
// ref. http://eigen.tuxfamily.org/dox/group__TopicSparseSystems.html#TutorialSparseSolverConcept
// ref. http://eigen.tuxfamily.org/dox/group__MatrixfreeSolverExample.html
// BiCGSTAB<SparseMatrix<double>, Eigen::IdentityPreconditioner> solver;
BiCGSTAB<SparseMatrix<double>, Eigen::IncompleteLUT<double>> solver;
solver.compute(A_m).setTolerance(tolerance);
x = solver.solve(b_m);
std::cout << "# inner iterations: " << solver.iterations() << std::endl;
std::cout << "estimated error: " << solver.error() << std::endl;
// std::cout << "Solution: " << std::endl << x << std::endl;
}
#endif