-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmoving.cpp_bak
More file actions
306 lines (275 loc) · 12.3 KB
/
Copy pathmoving.cpp_bak
File metadata and controls
306 lines (275 loc) · 12.3 KB
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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
#include "ISOP2P1.h"
#include "preconditioner.h"
#include "functions.h"
#define DIM 2
void ISOP2P1::syncMesh()
{
// RegularMesh<DIM> &mesh_v = irregular_mesh_v->regularMesh();
// RegularMesh<DIM> &mesh_p = irregular_mesh_p->regularMesh();
// for (int i = 0; i < mesh_p.n_geometry(0); ++i)
// {
// (*mesh_p.h_geometry<0>(i))[0] = point(i)[0];
// (*mesh_p.h_geometry<0>(i))[1] = point(i)[1];
// }
// /// 更新p网格的中点. 学习这个过程, 似乎可以去掉单元对应?
// for (int j = 0; j < mesh_p.n_geometry(1); ++j)
// {
// GeometryBM &bnd = mesh_p.geometry(1, j);
// (*mesh_p.h_geometry<1>(bnd.index())->child[1]->vertex[0])[0]
// = 0.5 * ((*mesh_p.h_geometry<0>(bnd.vertex(0)))[0] +
// (*mesh_p.h_geometry<0>(bnd.vertex(1)))[0]);
// (*mesh_p.h_geometry<1>(bnd.index())->child[1]->vertex[0])[1]
// = 0.5 * ((*mesh_p.h_geometry<0>(bnd.vertex(0)))[1] +
// (*mesh_p.h_geometry<0>(bnd.vertex(1)))[1]);
// }
// irregular_mesh_p->semiregularize();
// irregular_mesh_p->regularize(false);
// irregular_mesh_v->semiregularize();
// irregular_mesh_v->regularize(false);
};
void ISOP2P1::getMonitor()
{
RegularMesh<DIM> ®ular_mesh = irregular_mesh_p->regularMesh();
FEMFunction<double, DIM> u_h_p(fem_space_p);
FEMFunction<double, DIM> v_h_p(fem_space_p);
/// 将速度插值到压力单元上.
Operator::L2Interpolate(v_h[0], u_h_p);
Operator::L2Interpolate(v_h[1], v_h_p);
FEMSpace<double, DIM>::ElementIterator the_element = fem_space_p.beginElement();
FEMSpace<double, DIM>::ElementIterator end_element = fem_space_p.endElement();
for (int i = 0; the_element != end_element; ++the_element)
{
int idx_p = the_element->index();
/// 几何信息.
double volume = the_element->templateElement().volume();
const QuadratureInfo<DIM>& quad_info = the_element->findQuadratureInfo(2);
std::vector<double> jacobian = the_element->local_to_global_jacobian(quad_info.quadraturePoint());
int n_quadrature_point = quad_info.n_quadraturePoint();
std::vector<Point<DIM> > q_point = the_element->local_to_global(quad_info.quadraturePoint());
std::vector<std::vector<double> > vx_gradient = u_h_p.gradient(q_point, *the_element);
std::vector<std::vector<double> > vy_gradient = v_h_p.gradient(q_point, *the_element);
std::vector<double> vx_value = u_h_p.value(q_point, *the_element);
std::vector<double> vy_value = v_h_p.value(q_point, *the_element);
double d = 0, area = 0, vh_L2norm = 0.0;
for (int l = 0; l < n_quadrature_point; ++l)
{
double Jxw = quad_info.weight(l) * jacobian[l] * volume;
area += Jxw;
vh_L2norm += vx_value[l] * vx_value[l] + vy_value[l] * vy_value[l] + eps;
d += Jxw * (innerProduct(vx_gradient[l], vx_gradient[l]) + innerProduct(vy_gradient[l], vy_gradient[l]));
}
monitor(i) = d / area;
}
double max_monitor = *std::max_element(monitor().begin(), monitor().end());
std::cerr << "max monitor=" << *std::max_element(monitor().begin(), monitor().end())
<< "\tmin monitor=" << *std::min_element(monitor().begin(), monitor().end())
<< std::endl;
smoothMonitor(5);
for (int i = 0; i < n_geometry(DIM); ++i)
{
monitor(i) = 1. / sqrt(1. + alpha * pow((monitor(i)), beta));
}
};
void ISOP2P1::updateSolution()
{
/// 在MovingMesh2D的moveMesh()中,实际上是先做的updateSolution,然后再更新网格,
/// 压力网格移动步长.
double msl = moveStepLength();
/// 网格移动后,更新速度和压力,按照邸亚娜老师文章上的方法,
/// 保证在update的过程中保证质量守恒条件. 实际上是求解
/// 类似时间发展的对流方程.
/// 先更新插值点.
fem_space_p.updateDofInterpPoint();
fem_space_v.updateDofInterpPoint();
/// 因为网格移动了, 插值点变化, 矩阵需要重新构造.
/// 是不是可以不用重新更改稀疏矩阵结构?
// buildMatrixStruct();
buildMatrix();
int n_dof_v = fem_space_v.n_dof();
int n_dof_p = fem_space_p.n_dof();
int n_total_dof = 2 * n_dof_v + n_dof_p;
/// 备份数值解.
FEMFunction<double, DIM> _u_h(v_h[0]);
FEMFunction<double, DIM> _v_h(v_h[1]);
FEMFunction<double, DIM> _p_h(p_h);
/// 虚拟时间, dt 可以取到1.
double _dt = 1.0;
/// 为了稳定性考虑, m至少取3, 少于3的话, 数值解会不稳定.
/// 三阶显示Rugue-Kutta方法.
for (int m = 3; m > 0; --m)
{
/// 系数矩阵直接使用 Stokes 矩阵结构.
matrix.reinit(sp_stokes);
/// (0, 0)
for (int i = 0; i < sp_vxvx.n_nonzero_elements(); ++i)
matrix.global_entry(index_vxvx[i]) = mat_v_mass.global_entry(i);
/// (1, 1) 这两个对角块对应质量算子.
for (int i = 0; i < sp_vyvy.n_nonzero_elements(); ++i)
matrix.global_entry(index_vyvy[i]) = mat_v_mass.global_entry(i);
/// (0, 2) 这个不是方阵. 在矩阵结构定义的时候已经直接排除了对角元优
/// 先.
for (int i = 0; i < sp_pvx.n_nonzero_elements(); ++i)
matrix.global_entry(index_pvx[i]) = (_dt / m) * mat_pvx_divT.global_entry(i);
/// (1, 2)
for (int i = 0; i < sp_pvy.n_nonzero_elements(); ++i)
matrix.global_entry(index_pvy[i]) = (_dt / m) * mat_pvy_divT.global_entry(i);
/// (2, 0)
for (int i = 0; i < sp_vxp.n_nonzero_elements(); ++i)
matrix.global_entry(index_vxp[i]) = (_dt / m) * mat_vxp_div.global_entry(i);
/// (2, 1) 这四块直接复制散度矩阵.
for (int i = 0; i < sp_vyp.n_nonzero_elements(); ++i)
matrix.global_entry(index_vyp[i]) = (_dt / m) * mat_vyp_div.global_entry(i);
/// 问题右端项.
rhs.reinit(n_total_dof);
/// debug
const std::size_t * rowstart = sp_stokes.get_rowstart_indices();
const unsigned int * colnum = sp_stokes.get_column_numbers();
std::ofstream mat_deb;
mat_deb.open("mat.m", std::ofstream::out);
mat_deb.setf(std::ios::fixed);
mat_deb.precision(20);
mat_deb << "A = sparse(" << n_total_dof << ", " << n_total_dof << ");" << std::endl;
for (int i = 0; i < n_total_dof; ++i)
{
for (int j = rowstart[i]; j < rowstart[i + 1]; ++j)
{
mat_deb << "A(" << i + 1 << ", " << colnum[j] + 1 << ")="
<< matrix.global_entry(j) << ";" << std::endl;
}
}
mat_deb.close();
std::cout << "mat output" << std::endl;
getchar();
/// debug
FEMSpace<double, DIM>::ElementIterator the_element_v = fem_space_v.beginElement();
FEMSpace<double, DIM>::ElementIterator end_element_v = fem_space_v.endElement();
/// 遍历速度单元, 拼装相关系数矩阵和右端项.
for (the_element_v = fem_space_v.beginElement();
the_element_v != end_element_v; ++the_element_v)
{
/// 当前单元信息.
double volume = the_element_v->templateElement().volume();
/// 积分精度, u 和 p 都是 1 次, 梯度和散度 u 都是常数. 因此矩阵拼
/// 装时积分精度不用超过 1 次.
const QuadratureInfo<DIM>& quad_info = the_element_v->findQuadratureInfo(1);
std::vector<double> jacobian = the_element_v->local_to_global_jacobian(quad_info.quadraturePoint());
int n_quadrature_point = quad_info.n_quadraturePoint();
std::vector<Point<DIM> > q_point = the_element_v->local_to_global(quad_info.quadraturePoint());
/// 速度单元信息.
std::vector<std::vector<double> > basis_value_v = the_element_v->basis_function_value(q_point);
std::vector<std::vector<std::vector<double> > > basis_gradient_v = the_element_v->basis_function_gradient(q_point);
std::vector<double> vx_value = _u_h.value(q_point, *the_element_v);
std::vector<double> vy_value = _v_h.value(q_point, *the_element_v);
std::vector<double> fx_value = source_v[0].value(q_point, *the_element_v);
std::vector<double> fy_value = source_v[1].value(q_point, *the_element_v);
std::vector<std::vector<double> > vx_gradient = v_h[0].gradient(q_point, *the_element_v);
std::vector<std::vector<double> > vy_gradient = v_h[1].gradient(q_point, *the_element_v);
const std::vector<int>& element_dof_v = the_element_v->dof();
int n_element_dof_v = the_element_v->n_dof();
/// 对应压力单元信息,可能用不到,先放在这里.
Element<double, DIM> &p_element = fem_space_p.element(index_v2p[the_element_v->index()]);
const std::vector<int>& element_dof_p = p_element.dof();
std::vector<std::vector<std::vector<double> > > basis_gradient_p = p_element.basis_function_gradient(q_point);
std::vector<std::vector<double> > basis_value_p = p_element.basis_function_value(q_point);
int n_element_dof_p = p_element.n_dof();
std::vector<double> p_value = _p_h.value(q_point, p_element);
/// 注意这里的moveDirection实际上是速度网格上积分点的移动, 因为速度单元是在压力单元的一部分, 位置有重合.
/// 因此可以直接掉用 MovingMesh2D中内置计算点移动方向的函数moveDirection().
std::vector<std::vector<double> > move_vector = moveDirection(q_point, p_element.index());
for (int l = 0; l < n_quadrature_point; ++l)
{
double Jxw = quad_info.weight(l) * jacobian[l] * volume;
for (int j = 0; j < n_element_dof_v; ++j)
{
double rhs_cont = Jxw * basis_value_v[j][l] * (vx_value[l]); // + (_dt / m) * msl * innerProduct(move_vector[l], vx_gradient[l]));
rhs(element_dof_v[j]) += rhs_cont;
rhs_cont = Jxw * basis_value_v[j][l] * (vy_value[l]); // + (_dt / m) * msl * innerProduct(move_vector[l], vy_gradient[l]));
rhs(n_dof_v + element_dof_v[j]) += rhs_cont;
}
}
}
/// 构建系数矩阵和右端项.
Vector<double> x(n_total_dof);
for (int i = 0; i < n_dof_v; ++i)
{
x(i) = v_h[0](i);
x(i + n_dof_v) = v_h[1](i);
}
for (int i = 0; i < n_dof_p; ++i)
x(i + 2 * n_dof_v) = p_h(i);
/// 处理边界.
boundaryValueUpdateSolution(x);
clock_t t_cost = clock();
dealii::SolverControl solver_control (4000000, l_Euler_tol, check);
/// AMG 预处理不行,试一下ILU预处理.
/// 不完全LU分解.
dealii::SparseILU <double> preconditioner;
preconditioner.initialize(matrix);
SolverMinRes<Vector<double> > minres(solver_control);
minres.solve (matrix, x, rhs, PreconditionIdentity());
t_cost = clock() - t_cost;
std::cout << "time cost: " << (((float)t_cost) / CLOCKS_PER_SEC) << std::endl;
///速度数值解和压力数值解.
for (int i = 0; i < n_dof_v; ++i)
{
v_h[0](i) = x(i);
v_h[1](i) = x(i + n_dof_v);
}
for (int i = 0; i < n_dof_p; ++i)
p_h(i) = x(i + 2 * n_dof_v);
}
outputTecplot("NS_Euler");
outputSolution();
};
void ISOP2P1::updateMesh()
{
for (int i = 0; i < n_geometry(0); ++i)
{
point(i)[0] += moveStepLength() * moveDirection(i)[0];
point(i)[1] += moveStepLength() * moveDirection(i)[1];
}
/// 移动irregular_mesh_p树上的网格点.
RegularMesh<DIM> &mesh_p = irregular_mesh_p->regularMesh();
for (int i = 0; i < mesh_p.n_geometry(0); ++i)
{
(*mesh_p.h_geometry<0>(i))[0] = point(i)[0];
(*mesh_p.h_geometry<0>(i))[1] = point(i)[1];
}
/// 更新p网格的中点.
for (int j = 0; j < mesh_p.n_geometry(1); ++j)
{
GeometryBM &bnd = mesh_p.geometry(1, j);
(*mesh_p.h_geometry<1>(bnd.index())->child[1]->vertex[0])[0]
= 0.5 * ((*mesh_p.h_geometry<0>(bnd.vertex(0)))[0] +
(*mesh_p.h_geometry<0>(bnd.vertex(1)))[0]);
(*mesh_p.h_geometry<1>(bnd.index())->child[1]->vertex[0])[1]
= 0.5 * ((*mesh_p.h_geometry<0>(bnd.vertex(0)))[1] +
(*mesh_p.h_geometry<0>(bnd.vertex(1)))[1]);
}
// /// irregular_mesh_p 和 irregular_mesh_v 在同一棵树上, 因此, 移动了 irregular_mesh_v,
/// irregular_mesh_p上的网格点也移动了, 不能重复移动两次.
irregular_mesh_p->semiregularize();
irregular_mesh_p->regularize(false);
irregular_mesh_v->semiregularize();
irregular_mesh_v->regularize(false);
/// 更新一下插值点.
fem_space_v.updateDofInterpPoint();
fem_space_p.updateDofInterpPoint();
}
void ISOP2P1::outputSolution()
{
p_h.writeOpenDXData("p_h.dx");
outputPhysicalMesh("E");
};
void ISOP2P1::movingMesh()
{
// /// 修改最大移动次数.
// maxStep() = max_step;
// /// 设置容忍量.
// tolerence() = 0.01;
// moveMesh();
// /// 在一步网格移动之后, 同步一下速度和压力网格.
// syncMesh();
// fem_space_p.updateDofInterpPoint();
// fem_space_v.updateDofInterpPoint();
};