void ISOP2P1::solveStokes() { buildStokesSys(); std::cout << "Stokes system builded." << std::endl; 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; /// 构建系数矩阵和右端项. /// 这个存放整体的数值解. 没有分割成 u_h[0], u_h[1] 和 p_h. Vector<double> x(n_total_dof); /// 将数值解合并一个向量便于边界处理. for (int i = 0; i < n_dof_v; ++i) { x(i) = v_h[0](i); x(n_dof_v + i) = v_h[1](i); } for (int i = 0; i < n_dof_p; ++i) x(2 * n_dof_v + i) = p_h(i); rhs.reinit(n_total_dof); /// 边界条件一起处理了. 修改了matrix, rhs和x. boundaryValueStokes(x, t); std::cout << "Stokes boundary applied." << std::endl; // /// 矩阵求解. // dealii::SolverControl solver_control (400000, l_tol * rhs.l2_norm(), 1); // /// 不完全LU分解. // dealii::SparseILU<double> preconditioner; // preconditioner.initialize(matrix); // /// 求解Stokes方程, MinRes要比GMRES求解器要快很多, // /// 当矩阵规模稍微大点的时候,GMRES会出现不收敛的情况. // SolverMinRes<Vector<double> > minres (solver_control); // SolverGMRES<Vector<double> >::AdditionalData para(1000, false, true); // /// 不用para算不动, 但是均匀网格下可以不用para,算其它的例子也不用para,是不是跟计算区域有关系? // SolverGMRES<Vector<double> > gmres(solver_control, para); // // /// 移动网格和时间发展中,这个预处理失效. // // StokesPreconditioner preconditioner; // // /// 预处理矩阵. // // SparseMatrix<double> matrix_vxvx(sp_vxvx); // // SparseMatrix<double> matrix_vyvy(sp_vyvy); // // /// 这里从 Stokes 取是因为加了边界条件. // // for (int i = 0; i < sp_vxvx.n_nonzero_elements(); ++i) // // matrix_vxvx.global_entry(i) = matrix.global_entry(index_vxvx[i]); // // for (int i = 0; i < sp_vyvy.n_nonzero_elements(); ++i) // // matrix_vyvy.global_entry(i) = matrix.global_entry(index_vyvy[i]); // // preconditioner.initialize(mat_v_stiff, mat_v_stiff, mat_p_mass); // clock_t t_cost = clock(); // minres.solve (matrix, x, rhs, PreconditionIdentity()); // // gmres.solve(matrix, x, rhs, preconditioner); // 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); // /// 计算误差, t为时间参数. // computeError(t); // /// debug, 计算惨量的L2 norm。 // Vector<double> res(n_total_dof); // matrix.vmult(res, x); // res *= -1; // res += rhs; // std::cout << "res_l2norm =" << res.l2_norm() << std::endl; /// 矩阵求解. SparseMatrix<double> mat_BTx(sp_pvx); SparseMatrix<double> mat_BTy(sp_pvy); SparseMatrix<double> mat_Bx(sp_vxp); SparseMatrix<double> mat_By(sp_vyp); SparseMatrix<double> mat_Ax(sp_vxvx); SparseMatrix<double> mat_Ay(sp_vyvy); for (int i = 0; i < sp_vxvx.n_nonzero_elements(); ++i) mat_Ax.global_entry(i) = matrix.global_entry(index_vxvx[i]); for (int i = 0; i < sp_vyvy.n_nonzero_elements(); ++i) mat_Ay.global_entry(i) = matrix.global_entry(index_vyvy[i]); for (int i = 0; i < sp_pvx.n_nonzero_elements(); ++i) mat_BTx.global_entry(i) = matrix.global_entry(index_pvx[i]); for (int i = 0; i < sp_pvy.n_nonzero_elements(); ++i) mat_BTy.global_entry(i) = matrix.global_entry(index_pvy[i]); for (int i = 0; i < sp_vxp.n_nonzero_elements(); ++i) mat_Bx.global_entry(i) = matrix.global_entry(index_vxp[i]); for (int i = 0; i < sp_vyp.n_nonzero_elements(); ++i) mat_By.global_entry(i) = matrix.global_entry(index_vyp[i]); /// alp对AMGSolver的初始化影响比较大, 如果取得很小,初始化很快. double alp = dt * viscosity; AMGSolver solverQ(mat_Ax, 1.0e-12, 3, 100, 0.382, alp); // AMGSolver solverQ(mat_Ax); InverseMatrix AInv(mat_Ax, solverQ); /// 这里没有对速度质量阵进行边界条件处理. InverseMatrix QInv(mat_v_mass, solverQ); SchurComplement schur_complement(mat_BTx, mat_BTy, mat_Bx, mat_By, mat_v_mass, QInv, QInv); AMGSolver solverP(mat_p_mass); ApproxSchurComplement asc(mat_p_mass, solverQ); LSCPreconditioner lsc_preconditioner(mat_BTx, mat_BTy, mat_Bx, mat_By, mat_Ax, mat_Ax, mat_v_mass, schur_complement, asc, QInv, AInv, AInv); /// 矩阵求解. dealii::SolverControl solver_control (400000, l_Euler_tol * rhs.l2_norm(), 0); SolverMinRes<Vector<double> > minres(solver_control); minres.solve(matrix, x, rhs, lsc_preconditioner); /// 将整体数值解分割成速度和压力. 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); /// 计算误差, t为时间参数. computeError(t); // /// 矩阵求解. // SparseMatrix<double> mat_BTx(sp_pvx); // SparseMatrix<double> mat_BTy(sp_pvy); // SparseMatrix<double> mat_Bx(sp_vxp); // SparseMatrix<double> mat_By(sp_vyp); // SparseMatrix<double> mat_Ax(sp_vxvx); // SparseMatrix<double> mat_Ay(sp_vyvy); // for (int i = 0; i < sp_vxvx.n_nonzero_elements(); ++i) // mat_Ax.global_entry(i) = matrix.global_entry(index_vxvx[i]); // for (int i = 0; i < sp_vyvy.n_nonzero_elements(); ++i) // mat_Ay.global_entry(i) = matrix.global_entry(index_vyvy[i]); // for (int i = 0; i < sp_pvx.n_nonzero_elements(); ++i) // mat_BTx.global_entry(i) = matrix.global_entry(index_pvx[i]); // for (int i = 0; i < sp_pvy.n_nonzero_elements(); ++i) // mat_BTy.global_entry(i) = matrix.global_entry(index_pvy[i]); // for (int i = 0; i < sp_vxp.n_nonzero_elements(); ++i) // mat_Bx.global_entry(i) = matrix.global_entry(index_vxp[i]); // for (int i = 0; i < sp_vyp.n_nonzero_elements(); ++i) // mat_By.global_entry(i) = matrix.global_entry(index_vyp[i]); // Vector<double> tmp1(n_dof_v); // Vector<double> tmp2(n_dof_v); // Vector<double> rhs_vx(n_dof_v); // Vector<double> rhs_vy(n_dof_v); // Vector<double> rhs_p(n_dof_p); // for (int i = 0; i < n_dof_v; ++i) // { // rhs_vx(i) = rhs(i); // v_h[0](i) = x(i); // rhs_vy(i) = rhs(n_dof_v + i); // v_h[1](i) = x(n_dof_v + i); // } // for (int i = 0; i < n_dof_p; ++i) // { // rhs_p(i) = rhs(2 * n_dof_v + i); // p_h(i) = x(2 * n_dof_v + i); // } // Vector<double> schur_rhs (n_dof_p); // AMGSolver solverQ(mat_Ax); // InverseMatrix M(mat_Ax, solverQ); // M.vmult (tmp1, rhs_vx); // M.vmult (tmp2, rhs_vy); // mat_Bx.vmult(schur_rhs, tmp1); // mat_By.vmult_add(schur_rhs, tmp2); // schur_rhs -= rhs_p; // SchurComplement schur_complement(mat_BTx, mat_BTy, mat_Bx, mat_By, mat_v_mass, M, M, dt); // SolverControl solver_control_cg (n_dof_p * 2, // 1e-12*schur_rhs.l2_norm()); // SolverCG<> cg (solver_control_cg); // AMGSolver AQ(mat_p_mass); // ApproxSchurComplement asc(mat_p_mass, AQ); // cg.solve (schur_complement, p_h, schur_rhs, asc); // // cg.solve (schur_complement, p_h, schur_rhs, PreconditionIdentity()); // std::cout << solver_control_cg.last_step() // << " CG Schur complement iterations to obtain convergence." // << std::endl; // mat_BTx.vmult(tmp1, *dynamic_cast<const Vector<double>* >(&p_h)); // mat_BTy.vmult(tmp2, *dynamic_cast<const Vector<double>* >(&p_h)); // tmp1 *= -1; // tmp2 *= -1; // tmp1 += rhs_vx; // tmp2 += rhs_vy; // M.vmult(v_h[0], tmp1); // M.vmult(v_h[1], tmp2); // std::cout << "Stokes system solved." << std::endl; // /// 计算误差, t为时间参数. // computeError(t); // /// debug, 计算惨量的L2 norm。 // Vector<double> res(n_total_dof); // matrix.vmult(res, x); // res *= -1; // res += rhs; // std::cout << "res_l2norm =" << res.l2_norm() << std::endl; };
void ISOP2P1::solveStokes() { buildStokesSys(); 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; /// 构建系数矩阵和右端项. /// 这个存放整体的数值解. 没有分割成 u_h[0], u_h[1] 和 p_h. Vector<double> x(n_total_dof); /// 将数值解合并一个向量便于边界处理. for (int i = 0; i < n_dof_v; ++i) { x(i) = v_h[0](i); x(n_dof_v + i) = v_h[1](i); } for (int i = 0; i < n_dof_p; ++i) x(2 * n_dof_v + i) = p_h(i); rhs.reinit(n_total_dof); /// 边界条件一起处理了. boundaryValueStokes(); /// 矩阵求解. dealii::SolverControl solver_control (4000000, 1e-14, 1); SolverMinRes<Vector<double> > minres (solver_control); StokesPreconditioner preconditioner; /// 预处理矩阵. SparseMatrix<double> matrix_vxvx(sp_vxvx); SparseMatrix<double> matrix_vyvy(sp_vyvy); /// 这里从 Stokes 取是因为加了边界条件. for (int i = 0; i < sp_vxvx.n_nonzero_elements(); ++i) matrix_vxvx.global_entry(i) = matrix.global_entry(index_vxvx[i]); for (int i = 0; i < sp_vyvy.n_nonzero_elements(); ++i) matrix_vyvy.global_entry(i) = matrix.global_entry(index_vyvy[i]); preconditioner.initialize(matrix_vxvx, matrix_vyvy, mat_p_mass); clock_t t_cost = clock(); minres.solve (matrix, x, rhs, preconditioner); // 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); /* /// 矩阵求解. SparseMatrix<double> mat_BTx(sp_pvx); SparseMatrix<double> mat_BTy(sp_pvy); SparseMatrix<double> mat_Bx(sp_vxp); SparseMatrix<double> mat_By(sp_vyp); SparseMatrix<double> mat_Ax(sp_vxvx); SparseMatrix<double> mat_Ay(sp_vyvy); for (int i = 0; i < sp_vxvx.n_nonzero_elements(); ++i) mat_Ax.global_entry(i) = matrix.global_entry(index_vxvx[i]); for (int i = 0; i < sp_vyvy.n_nonzero_elements(); ++i) mat_Ay.global_entry(i) = matrix.global_entry(index_vyvy[i]); for (int i = 0; i < sp_pvx.n_nonzero_elements(); ++i) mat_BTx.global_entry(i) = matrix.global_entry(index_pvx[i]); for (int i = 0; i < sp_pvy.n_nonzero_elements(); ++i) mat_BTy.global_entry(i) = matrix.global_entry(index_pvy[i]); for (int i = 0; i < sp_vxp.n_nonzero_elements(); ++i) mat_Bx.global_entry(i) = matrix.global_entry(index_vxp[i]); for (int i = 0; i < sp_vyp.n_nonzero_elements(); ++i) mat_By.global_entry(i) = matrix.global_entry(index_vyp[i]); Vector<double> tmp1(n_dof_v); Vector<double> tmp2(n_dof_v); Vector<double> rhs_vx(n_dof_v); Vector<double> rhs_vy(n_dof_v); Vector<double> rhs_p(n_dof_p); for (int i = 0; i < n_dof_v; ++i) { rhs_vx(i) = rhs(i); v_h[0](i) = x(i); rhs_vy(i) = rhs(n_dof_v + i); v_h[1](i) = x(n_dof_v + i); } for (int i = 0; i < n_dof_p; ++i) { rhs_p(i) = rhs(2 * n_dof_v + i); p_h(i) = x(2 * n_dof_v + i); } Vector<double> schur_rhs (n_dof_p); // AMGSolver solverQ(mat_Ax, 1.0e-12, 3, 50, 0.382, 0.25); AMGSolver solverQ(mat_Ax); InverseMatrix M(mat_Ax, solverQ); M.vmult (tmp1, rhs_vx); M.vmult (tmp2, rhs_vy); mat_Bx.vmult(schur_rhs, tmp1); mat_By.vmult_add(schur_rhs, tmp2); schur_rhs -= rhs_p; SchurComplement schur_complement(mat_BTx, mat_BTy, mat_Bx, mat_By, M, M); // SolverControl solver_control_cg (n_dof_p * 2, // 1e-12*schur_rhs.l2_norm()); SolverControl solver_control_cg (n_dof_p * 20, 1e-15); // SolverCG<> cg (solver_control_cg); SolverMinRes<> minres (solver_control_cg); AMGSolver AQ(mat_p_mass); ApproxSchurComplement asc(mat_p_mass, AQ); minres.solve (schur_complement, p_h, schur_rhs, asc); // cg.solve (schur_complement, p_h, schur_rhs, PreconditionIdentity()); std::cout << solver_control_cg.last_step() << " CG Schur complement iterations to obtain convergence." << std::endl; mat_BTx.vmult(tmp1, *dynamic_cast<const Vector<double>* >(&p_h)); mat_BTy.vmult(tmp2, *dynamic_cast<const Vector<double>* >(&p_h)); tmp1 *= -1; tmp2 *= -1; tmp1 += rhs_vx; tmp2 += rhs_vy; M.vmult(v_h[0], tmp1); M.vmult(v_h[1], tmp2); */ double error; RealVx accuracy_vx; error = Functional::L2Error(v_h[0], accuracy_vx, 2); std::cout << "|| u - u_h ||_L2 = " << error << std::endl; error = Functional::H1SemiError(v_h[0], accuracy_vx, 1); std::cout << "|| u - u_h ||_H1 = " << error << std::endl; RealVy accuracy_vy; error = Functional::L2Error(v_h[1], accuracy_vy, 2); std::cout << "|| v - v_h ||_L2 = " << error << std::endl; error = Functional::H1SemiError(v_h[1], accuracy_vy, 1); std::cout << "|| v - v_h ||_H1 = " << error << std::endl; double p_avg = Functional::meanValue(p_h, 2); RealP accuracy_p(p_avg); error = Functional::L2Error(p_h, accuracy_p, 2); std::cout << "|| p - p_h ||_0 = " << error << std::endl; };
void ISOP2P1::run() { /// 初始化. initialize(); /// 构建 Stokes 系统. buildStokesSys(); /// 边界条件处理. boundaryValueStokes(); /// 准备预处理. StokesPreconditioner preconditioner; /// 预处理矩阵. SparseMatrix<double> matrix_vxvx(sp_vxvx); SparseMatrix<double> matrix_vyvy(sp_vyvy); /// 这里从 Stokes 取是因为加了边界条件. for (int i = 0; i < sp_vxvx.n_nonzero_elements(); ++i) matrix_vxvx.global_entry(i) = matrix.global_entry(index_vxvx[i]); for (int i = 0; i < sp_vyvy.n_nonzero_elements(); ++i) matrix_vyvy.global_entry(i) = matrix.global_entry(index_vyvy[i]); preconditioner.initialize(matrix_vxvx, matrix_vyvy, mat_p_mass); /// 矩阵求解. dealii::SolverControl solver_control (4000000, 1e-14, 1); SolverMinRes<Vector<double> > minres (solver_control); clock_t t_cost = clock(); minres.solve (matrix, x, rhs, preconditioner); // minres.solve (matrix, x, rhs, PreconditionIdentity()); t_cost = clock() - t_cost; std::cout << "time cost: " << (((float)t_cost) / CLOCKS_PER_SEC) << std::endl; /// 将整体数值解分割成速度和压力. 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; 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); /// 数据输出. outputTecplotP("P0"); outputTecplot("V0"); /// 误差比较. double error; RealVx accuracy_vx; error = Functional::L2Error(v_h[0], accuracy_vx, 2); std::cout << "|| u - u_h ||_L2 = " << error << std::endl; error = Functional::H1SemiError(v_h[0], accuracy_vx, 1); std::cout << "|| u - u_h ||_H1 = " << error << std::endl; RealVy accuracy_vy; error = Functional::L2Error(v_h[1], accuracy_vy, 2); std::cout << "|| v - v_h ||_L2 = " << error << std::endl; error = Functional::H1SemiError(v_h[1], accuracy_vy, 1); std::cout << "|| v - v_h ||_H1 = " << error << std::endl; double p_avg = Functional::meanValue(p_h, 2); RealP accuracy_p(p_avg); error = Functional::L2Error(p_h, accuracy_p, 2); std::cout << "|| p - p_h ||_0 = " << error << std::endl; };