Beispiel #1
0
TEST(solver, sparse_direct_umfpack)
{
	// Test CG solver on the system
	//
	// ( 1 1 ) ( x ) = ( 5 )
	// ( 1 0 ) ( y ) = ( 2 )
	//
	// with the solution x = 2, y = 3.

	dealii::SparsityPattern pattern(2, 2);
	dealii::SparseMatrix<double> mat;
	dealii::Vector<double> rhs(2), sol(2);
	
	


	pattern.add(0, 1);
	pattern.add(1, 0);
	pattern.compress();
	mat.reinit(pattern);

	mat.set(0, 0, 1);
	mat.set(0, 1, 1);
	mat.set(1, 0, 1);

	rhs(0) = 5;
	rhs(1) = 2;
	
	dealii::SolverControl solver_control (10, 1e-12);
	dealii::SolverCG<> solver (solver_control);
	solver.solve (mat, sol, rhs, dealii::PreconditionIdentity());
	
	EXPECT_DOUBLE_EQ( 2, sol(0) );
	EXPECT_DOUBLE_EQ( 3, sol(1) );
}
Beispiel #2
0
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;

};
Beispiel #3
0
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;
};
Beispiel #4
0
void ISOP2P1::solveNS(int method)
{
	int n_dof_v = fem_space_v.n_dof();
	int n_dof_p = fem_space_p.n_dof();
	int n_total_dof = n_dof_v * 2 + n_dof_p;

	/// 开始迭代.
	double error_N = 1.0;
	int iteration_times = 0;
	while (error_N > n_tol)
	{
		/// Newton 迭代或 Picard 迭代.
		/// 先更新和速度场有关的矩阵块.
		updateNonlinearMatrix();
		/// 构建迭代矩阵.
		if (method == 1)
			buildNewtonSys4NS();
		else if (method == 2)
			buildPicardSys4NS();
		else if (method == 3)
			if (iteration_times < 2)
				buildPicardSys4NS();
			else
				buildNewtonSys4NS();
		else
		{
			std::cout << "Newton: 1, Picard: 2, Hybrid: 3." << std::endl;
			exit(1);
		}

		/// 建立右端项.
		rhs.reinit(n_total_dof);

		FEMSpace<double, DIM>::ElementIterator the_element_v = fem_space_v.beginElement();
		FEMSpace<double, DIM>::ElementIterator end_element_v = fem_space_v.endElement();
		FEMSpace<double, DIM>::ElementIterator the_element_p = fem_space_p.beginElement();
		FEMSpace<double, DIM>::ElementIterator end_element_p = fem_space_p.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(4);
			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<std::vector<double> > > basis_gradient_v
				= the_element_v->basis_function_gradient(q_point);
			std::vector<std::vector<double> >  basis_value_v
				= the_element_v->basis_function_value(q_point);
			const std::vector<int>& element_dof_v = the_element_v->dof();
			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);
			int n_element_dof_v = the_element_v->n_dof();
			std::vector<double> vx_value = v_h[0].value(q_point, *the_element_v);
			std::vector<double> vy_value = v_h[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);
			/// 压力单元信息.
			Element<double, DIM> &p_element = fem_space_p.element(index_ele_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);
			std::vector<double> p_value = p_h.value(q_point, p_element);
			int n_element_dof_p = p_element.n_dof();
			/// 实际拼装.
			for (int l = 0; l < n_quadrature_point; ++l)
			{
				double Jxw = quad_info.weight(l) * jacobian[l] * volume;
				for (int i = 0; i < n_element_dof_v; ++i)
				{
					double rhs_cont = fx_value[l] * basis_value_v[i][l];
					rhs_cont -= (vx_value[l] * vx_gradient[l][0] +
						     vy_value[l] * vx_gradient[l][1]) * basis_value_v[i][l];
					rhs_cont -= viscosity * innerProduct(basis_gradient_v[i][l], vx_gradient[l]);
					rhs_cont += p_value[l] * basis_gradient_v[i][l][0];
					rhs_cont *= Jxw;
					rhs(element_dof_v[i]) += rhs_cont;

					rhs_cont = fy_value[l] * basis_value_v[i][l];
					rhs_cont -= (vx_value[l] * vy_gradient[l][0] +
						     vy_value[l] * vy_gradient[l][1]) * basis_value_v[i][l];
					rhs_cont -= viscosity * innerProduct(basis_gradient_v[i][l], vy_gradient[l]);
					rhs_cont += p_value[l] * basis_gradient_v[i][l][1];
					rhs_cont *= Jxw;
					rhs(n_dof_v + element_dof_v[i]) += rhs_cont;
				}
			}
		}

		/// 遍历压力单元. 拼装矩阵和右端项.
		for (the_element_p = fem_space_p.beginElement();
		     the_element_p != end_element_p; ++the_element_p)
		{
			const std::vector<int>& element_dof_p = the_element_p->dof();
			int n_element_dof_p = the_element_p->n_dof();
			for (int i = 0; i < n_element_dof_p; ++i)
			{
				int idx_p = the_element_p->index();
				int n_chi = index_ele_p2v[idx_p].size();
				for (int k = 0; k < n_chi; k++)
				{
					/// 速度单元信息.
					Element<double, DIM> &v_element = fem_space_v.element(index_ele_p2v[idx_p][k]);
					/// 几何信息.
					double volume = v_element.templateElement().volume();
					const QuadratureInfo<DIM>& quad_info = v_element.findQuadratureInfo(4);
					std::vector<double> jacobian
						= v_element.local_to_global_jacobian(quad_info.quadraturePoint());
					int n_quadrature_point = quad_info.n_quadraturePoint();
					std::vector<Point<DIM> > q_point
						= v_element.local_to_global(quad_info.quadraturePoint());
					std::vector<std::vector<double> > vx_gradient
						= v_h[0].gradient(q_point, v_element);
					std::vector<std::vector<double> > vy_gradient
						= v_h[1].gradient(q_point, v_element);
					std::vector<double> vx_value = v_h[0].value(q_point, v_element);
					std::vector<double> vy_value = v_h[1].value(q_point, v_element);
					/// 压力单元信息.
					std::vector<std::vector<double> >  basis_value_p
						= the_element_p->basis_function_value(q_point);
					/// 具体拼装.
					for (int l = 0; l < n_quadrature_point; ++l)
					{
						double Jxw = quad_info.weight(l) * jacobian[l] * volume;

						/// 右端项还是零. 源项和 Neumann 条件.
						double rhs_cont = Jxw * basis_value_p[i][l]
							* (vx_gradient[l][0] + vy_gradient[l][1]);
						rhs(2 * n_dof_v + element_dof_p[i]) += rhs_cont;
					}
				}
			}

		}

		/// 初始化未知量.
		Vector<double> x(n_total_dof);

		/// 边界条件处理.
		boundaryValueNS(x);

		std::cout << "nonlinear res:" << std::endl;
		double revx = 0.0;
		for (int i = 0; i < n_dof_v; ++i)
			revx += rhs(i) * rhs(i);
		std::cout << "vx re: " << sqrt(revx) << std::endl;
		double revy = 0.0;
		for (int i = 0; i < n_dof_v; ++i)
			revy += rhs(i + n_dof_v) * rhs(i + n_dof_v);
		std::cout << "vy re: " << sqrt(revy) << std::endl;
		double rep = 0.0;
		for (int i = 0; i < n_dof_p; ++i)
			rep += rhs(i + 2 * n_dof_v) * rhs(i + 2 * n_dof_v);
		std::cout << "p re: " << sqrt(rep) << std::endl;

		double re = revx + revy +rep;
		std::cout << "total re: " << sqrt(re) << std::endl;
		std::cout << "pause ..." << std::endl;
		getchar();
		if (sqrt(re) < n_tol)
		{
			std::cout << "Covergence with residual: " << sqrt(re)
		    		  << " in step " << iteration_times << std::endl;
			break;
		}

		std::cout << "Building precondition matrix ..." << std::endl;

		/// 矩阵求解.
		SparseMatrix<double> mat_Axx(sp_vxvx);
		SparseMatrix<double> mat_Ayy(sp_vyvy);
		SparseMatrix<double> mat_Wxy(sp_vyvx);
		SparseMatrix<double> mat_Wyx(sp_vxvy);
		SparseMatrix<double> mat_BTx(sp_pvx);
		SparseMatrix<double> mat_BTy(sp_pvy);

		for (int i = 0; i < sp_vxvx.n_nonzero_elements(); ++i)
			mat_Axx.global_entry(i) = matrix.global_entry(index_vxvx[i]);
		for (int i = 0; i < sp_vyvy.n_nonzero_elements(); ++i)
			mat_Ayy.global_entry(i) = matrix.global_entry(index_vyvy[i]);
		for (int i = 0; i < sp_vyvx.n_nonzero_elements(); ++i)
			mat_Wxy.global_entry(i) = matrix.global_entry(index_vyvx[i]);
		for (int i = 0; i < sp_vxvy.n_nonzero_elements(); ++i)
			mat_Wyx.global_entry(i) = matrix.global_entry(index_vxvy[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]);
		std::cout << "Precondition matrix builded!" << std::endl;

		/// 矩阵求解.
		dealii::SolverControl solver_control (4000000, l_tol);

		SolverGMRES<Vector<double> >::AdditionalData para(2000, false, true);
		SolverGMRES<Vector<double> > gmres (solver_control, para);
		std::cout << "Begin to solve linear system ..." << std::endl;
		//	gmres.solve (matrix, x, rhs, navierstokes_preconditioner);
		gmres.solve (matrix, x, rhs, PreconditionIdentity());

		/// 调试块: 直接观测真实残量.
		//	Vector<double> tmp(n_total_dof);
		//	matrix.vmult(tmp, x);
		//	tmp -= rhs;
		//	std::cout << "linear residual: " << tmp.l2_norm() << std::endl;
		//	getchar();

		FEMFunction<double, DIM> res_vx(fem_space_v);
		FEMFunction<double, DIM> res_vy(fem_space_v);
		FEMFunction<double, DIM> res_p(fem_space_p);

		/// 更新数值解.
		for (int i = 0; i < n_dof_v; ++i)
		{
			v_h[0](i) += x(i);
			res_vx(i) = x(i);
			v_h[1](i) += x(i + n_dof_v);
			res_vy(i) = x(i+ n_dof_v);
		}
		for (int i = 0; i < n_dof_p; ++i)
		{
			p_h(i) += x(i + 2 * n_dof_v);
			res_p(i) = x(i + 2 * n_dof_v);
		}

		double r_vx = Functional::L2Norm(res_vx, 1);
		double r_vy = Functional::L2Norm(res_vy, 1);
		double r_p = Functional::L2Norm(res_p, 1);
		/// 这个其实是更新...
		error_N = r_vx + r_vy + r_p;

		std::cout.setf(std::ios::fixed);
		std::cout.precision(20);
		std::cout << "updated vx: " << r_vx << std::endl;
		std::cout << "updated vy: " << r_vy << std::endl;
		std::cout << "updated p: " << r_p << std::endl;
		std::cout << "total updated: " << error_N << std::endl;
		std::cout << "step " << iteration_times << ", total updated: " << error_N
			  << ", GMRES stpes: " << solver_control.last_step() << std::endl;

		iteration_times++;
		if (iteration_times > 10)
		{
			std::cout << "Disconvergence at step 10." << std::endl;
			break;
		}
	}

};
Beispiel #5
0
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;

};
void ISOP2P1::updateSolution()
{
	/// 更新插值点.
	fem_space_p.updateDofInterpPoint();
	fem_space_v.updateDofInterpPoint();
	
	/// 备份数值解.
	FEMFunction<double, DIM> _u_h(v_h[0]);
	FEMFunction<double, DIM> _v_h(v_h[1]);
	FEMFunction<double, DIM> _p_h(p_h);
	const double& msl = moveStepLength();
	/// 因为有限元空间插值点变化, 重新构造矩阵.
	buildMatrixStruct();
	buildMatrix();
	/// 因为网格移动量为小量, 因此时间步长可以相对取的大些.
	double _dt = 0.1;
    
	int n_dof_v = fem_space_v.n_dof();
	int n_dof_p = fem_space_p.n_dof();
	int n_total_dof = DIM * n_dof_v + n_dof_p;
	int n_total_dof_v = DIM * n_dof_v;
	
	/// 一步Euler.
	for (int m = 1; m > 0; --m)
	{
		/// 系数矩阵直接使用 Stokes 矩阵结构.
		SparseMatrix<double> mat_moving;
		mat_moving.reinit(sp_stokes);
		/// (0, 0) 
		for (int i = 0; i < sp_vxvx.n_nonzero_elements(); ++i)
			mat_moving.global_entry(index_vxvx[i]) = mat_v_mass.global_entry(i); 
		/// (1, 1) 这两个对角块仅有质量块.
		for (int i = 0; i < sp_vyvy.n_nonzero_elements(); ++i)
			mat_moving.global_entry(index_vyvy[i]) = mat_v_mass.global_entry(i);
		/// (0, 2) 这个不是方阵. 在矩阵结构定义的时候已经直接排除了对角元优
		/// 先.
		for (int i = 0; i < sp_pvx.n_nonzero_elements(); ++i)
			mat_moving.global_entry(index_pvx[i]) = (1.0 / m) * mat_pvx_divT.global_entry(i);

		/// (1, 2)
		for (int i = 0; i < sp_pvy.n_nonzero_elements(); ++i)
			mat_moving.global_entry(index_pvy[i]) = (1.0 / m) * mat_pvy_divT.global_entry(i);

		/// (2, 0)
		for (int i = 0; i < sp_vxp.n_nonzero_elements(); ++i)
			mat_moving.global_entry(index_vxp[i]) = (1.0 / m) * mat_vxp_div.global_entry(i);
	
		/// (2, 1) 这四块直接复制散度矩阵. 
		for (int i = 0; i < sp_vyp.n_nonzero_elements(); ++i)
			mat_moving.global_entry(index_vyp[i]) = (1.0 / m) * mat_vyp_div.global_entry(i);

		/// 问题的右端项.
		Vector<double> rhs_loc(n_total_dof);
//		rhs.reinit(n_total_dof);
		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();
			/// 积分精度至少为2.
			const QuadratureInfo<DIM>& quad_info = the_element_v->findQuadratureInfo(4);
			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<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<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();
			/// 速度积分点上的移动方向, 注意是速度单元的积分点, 在压力单元上的移动方向.
			/// 所以下面一行程序, 仔细算过, 没有问题.
			std::vector<std::vector<double> > move_vector = moveDirection(q_point, index_v2p[the_element_v->index()]);
			for (int l = 0; l < n_quadrature_point; ++l)
			{
				double Jxw = quad_info.weight(l) * jacobian[l] * volume;
				for (int i = 0; i < n_element_dof_v; ++i)
				{
					double rhs_cont = (vx_value[l] + (1.0 / m) * msl * innerProduct(move_vector[l], vx_gradient[l])) * basis_value_v[i][l];
					rhs_cont *= Jxw;
					rhs_loc(element_dof_v[i]) += rhs_cont;

					rhs_cont = (vy_value[l] + (1.0 / m) * msl * innerProduct(move_vector[l], vy_gradient[l])) * basis_value_v[i][l];
					rhs_cont *= Jxw;
					rhs_loc(n_dof_v + element_dof_v[i]) += rhs_cont;
				}
			}
		}

		/// 构建系数矩阵和右端项.
		Vector<double> x(n_total_dof);
//		PoiseuilleVx real_vx (-1.0, 1.0);
//		PoiseuilleVy real_vy;
		// Operator::L2Project(real_vx, v_h[0], Operator::LOCAL_LEAST_SQUARE, 3);
		// Operator::L2Project(real_vy, v_h[1], Operator::LOCAL_LEAST_SQUARE, 3);
		
		// /// 边界处理.
		const std::size_t * rowstart = sp_stokes.get_rowstart_indices();
		const unsigned int * colnum = sp_stokes.get_column_numbers();

		/// 遍历全部维度的速度节点.
		for (unsigned int i = 0; i < n_total_dof_v; ++i)
		{
			/// 边界标志.
			int bm = -1;
			/// 判断一下是 x 方向还是 y 方向. 分别读取标志.
			if (i < n_dof_v)
				bm = fem_space_v.dofInfo(i).boundary_mark;
			else
				bm = fem_space_v.dofInfo(i - n_dof_v).boundary_mark;

			if (bm == 0)
				continue;
			/// 方腔流边界条件.
			if (bm == 1 || bm == 2 || bm == 4 || bm == 5)
				x(i) = 0.0;
			if (bm == 3)
				if (i < n_dof_v)
				{
					/// 不包括顶端的两个端点,称为watertight cavity.
					// x(i) = scale * 1.0;
					Regularized regularize;
					x(i) = scale * regularize.value(fem_space_v.dofInfo(i).interp_point);
				}
				else
					x(i) = 0.0;
			// /// poiseuille flow边界条件.
			// if (bm == 1 || bm == 2 || bm == 4 || bm == 5)
			// 	if (i < n_dof_v)
			// 		x(i) = scale * real_vx.value(fem_space_v.dofInfo(i).interp_point);
			// 	else
			// 		x(i) = scale * real_vy.value(fem_space_v.dofInfo(i - n_dof_v).interp_point);
			/// 右端项这样改, 如果该行和列其余元素均为零, 则在迭代中确
			/// 保该数值解和边界一致.
			if (bm == 1 || bm == 2 || bm == 3 || bm == 4 || bm == 5)
				// if (bm == 1 || bm == 2 || bm == 4 || bm == 5)
			{
				rhs_loc(i) = mat_moving.diag_element(i) * x(i);
				/// 遍历 i 行.
				for (unsigned int j = rowstart[i] + 1; j < rowstart[i + 1]; ++j)
				{
					/// 第 j 个元素消成零(不是第 j 列!). 注意避开了对角元.
					mat_moving.global_entry(j) -= mat_moving.global_entry(j);
					/// 第 j 个元素是第 k 列.
					unsigned int k = colnum[j];
					/// 看看第 k 行的 i 列是否为零元.
					const unsigned int *p = std::find(&colnum[rowstart[k] + 1],
									  &colnum[rowstart[k + 1]],
									  i);
					/// 如果是非零元. 则需要将这一项移动到右端项. 因为第 i 个未知量已知.
					if (p != &colnum[rowstart[k + 1]])
					{
						/// 计算 k 行 i 列的存储位置.
						unsigned int l = p - &colnum[rowstart[0]];
						/// 移动到右端项. 等价于 r(k) = r(k) - x(i) * A(k, i).
						rhs_loc(k) -= mat_moving.global_entry(l) * x(i);
						/// 移完此项自然是零.
						mat_moving.global_entry(l) -= mat_moving.global_entry(l);
					}
				}
			}
		}
		std::cout << "boundary values for updateSolution OK!" << std::endl;
		
		// /// debug 边界条件处理部分,已经测试过, 边界处理正确.
		// RegularMesh<DIM> &mesh_v = irregular_mesh_v->regularMesh();
		// for (int i = 0; i < mesh_v.n_geometry(0); ++i)
		// {
		// 	Point<DIM> &p= mesh_v.point(i);
		// 	if (fabs(1 - p[1]) < eps || fabs(1 - p[0]) < eps || fabs(-1 - p[1]) < eps || fabs(-1 - p[0]) < eps)
		// 	{
		// 		std::cout << "point(" << i << ") = (" << p[0] << "," << p[1] << ");" << std::endl;
		// 		std::cout << "uh(" << i << ") = " << v_h[0](i) << std::endl;
		// 		std::cout << "vh(" << i << ") = " << v_h[1](i) << std::endl;
		// 	}
		// }
		// getchar();
		// /// debug

		clock_t t_cost = clock();
		/// 预处理矩阵.
		/// 不完全LU分解.     
		dealii::SparseILU <double> preconditioner;
		preconditioner.initialize(mat_moving);	
		/// 矩阵求解. 
		dealii::SolverControl solver_control (4000000, l_tol, check);

		SolverMinRes<Vector<double> > minres (solver_control);
		minres.solve (mat_moving, x, rhs_loc, 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);
	
		/// debug
		std::ofstream mat_deb;
		// rowstart = sp_pvx.get_rowstart_indices();
		// colnum = sp_pvx.get_column_numbers();
		mat_deb.open("mat.m", std::ofstream::out);
		mat_deb.setf(std::ios::fixed);
		mat_deb.precision(20);
	    
		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 << ")=" 
					<< mat_moving.global_entry(j) << ";" << std::endl;
			}
			mat_deb << "x(" << i + 1<< ") = " << x(i) << ";" << std::endl;
			mat_deb << "rhs(" << i + 1 << ") = " << rhs_loc(i) << ";" << std::endl;
		}
		// for(int i = 0; i < n_dof_p; ++i)
		// 	mat_deb << "x(" << i + 1<< ") = " << p_h(i) << ";" << std::endl;
		mat_deb.close();
		std::cout << "mat output" << std::endl;
		Vector<double> res(n_total_dof);
		mat_moving.vmult(res, x);
		res *= -1;
		res += rhs_loc;
		std::cout << "res_l2norm =" << res.l2_norm() << std::endl;
		// double error;
		// error = Functional::L2Error(v_h[0], real_vx, 3);
		// std::cout << "|| u - u_h ||_L2 = " << error << std::endl;

		// error = Functional::H1SemiError(v_h[0], real_vx, 3);
		// std::cout << "|| u - u_h ||_H1 = " << error << std::endl;

        /// debug
		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] += moveDirection(i)[0];
			(*mesh_p.h_geometry<0>(i))[1] += moveDirection(i)[1];
		}
		
		/// 输出一下.
		outputTecplotP("NS_Euler");
		getchar();
	}
}; 
Beispiel #7
0
void RBEC::stepForward()
{
    int i, j, k, l;
    int n_dof = fem_space.n_dof();
    int n_total_dof = 2 * n_dof;

    mat_RBEC.reinit(sp_RBEC);
    mat_rere.reinit(sp_rere);
    mat_reim.reinit(sp_reim);
    mat_imre.reinit(sp_imre);
    mat_imim.reinit(sp_imim);

    Vector<double> phi(n_total_dof);
    FEMFunction <double, DIM> phi_star(fem_space);
    Vector<double> rhs(n_total_dof);
    Potential V(gamma_x, gamma_y);

/// 准备一个遍历全部单元的迭代器.
    FEMSpace<double, DIM>::ElementIterator the_element = fem_space.beginElement();
    FEMSpace<double, DIM>::ElementIterator end_element = fem_space.endElement();

/// 循环遍历全部单元, 只是为了统计每一行的非零元个数.
    for (; the_element != end_element; ++the_element)
    {
/// 当前单元信息.
	double volume = the_element->templateElement().volume();
	const QuadratureInfo<DIM>& quad_info = the_element->findQuadratureInfo(6);
	std::vector<double> jacobian = the_element->local_to_global_jacobian(quad_info.quadraturePoint());
	int n_quadrature_point = quad_info.n_quadraturePoint();
	std::vector<AFEPack::Point<DIM> > q_point = the_element->local_to_global(quad_info.quadraturePoint());
/// 单元信息.
	std::vector<std::vector<std::vector<double> > > basis_gradient = the_element->basis_function_gradient(q_point);
	std::vector<std::vector<double> >  basis_value = the_element->basis_function_value(q_point);
	std::vector<double> phi_re_value = phi_re.value(q_point, *the_element);
	std::vector<double> phi_im_value = phi_im.value(q_point, *the_element);
	const std::vector<int>& element_dof = the_element->dof();
	int n_element_dof = the_element->n_dof();
/// 实际拼装.
	for (l = 0; l < n_quadrature_point; ++l)
	{
	    double Jxw = quad_info.weight(l) * jacobian[l] * volume;
	    for (j = 0; j < n_element_dof; ++j)
	    {
		for (k = 0; k < n_element_dof; ++k)
		{

		    double cont = Jxw * ((1 / dt) * basis_value[j][l] * basis_value[k][l]
					 + 0.5 * innerProduct(basis_gradient[j][l], basis_gradient[k][l])
					 + V.value(q_point[l]) * basis_value[j][l] * basis_value[k][l]
					 + beta * (phi_re_value[l] * phi_re_value[l]  + phi_im_value[l] * phi_im_value[l]) * basis_value[j][l] * basis_value[k][l]);

		    mat_RBEC.add(element_dof[j], element_dof[k], cont);
		    mat_RBEC.add(element_dof[j] + n_dof, element_dof[k] + n_dof, cont);
		}
		rhs(element_dof[j]) += Jxw * phi_re_value[l] * basis_value[j][l] / dt;
		rhs(element_dof[j] + n_dof) += Jxw * phi_im_value[l] * basis_value[j][l] / dt;
	    }
	}
    }

    FEMFunction<double, DIM> _phi_re(phi_re);
    FEMFunction<double, DIM> _phi_im(phi_im);

    boundaryValue(phi, rhs, mat_RBEC);

//    AMGSolver solver(mat_RBEC);
//    solver.solve(phi, rhs);

    dealii::SolverControl solver_control(4000, 1e-15);
    SolverGMRES<Vector<double> >::AdditionalData para(500, false, true);
    SolverGMRES<Vector<double> > gmres(solver_control, para);
    gmres.solve(mat_RBEC, phi, rhs, PreconditionIdentity());

    for (int i = 0; i < n_dof; ++i)
    {
         phi_re(i) = phi(i);
         phi_im(i) = phi(n_dof + i);
    }
	
    for (int i = 0; i < n_dof; ++i)
        phi_star(i) = sqrt(phi_re(i) * phi_re(i) + phi_im(i) * phi_im(i));

    double L2Phi = Functional::L2Norm(phi_re, 6);

    std::cout << "L2 norm = " << L2Phi << std::endl;
       
    for (int i = 0; i < n_dof; ++i)
    {
	phi_re(i) /= L2Phi;
	phi_im(i) /= L2Phi;
    }

    double e = energy(phi_re, phi_im, 6);
    std::cout << "Energy = " << e << std::endl;

    
    t += dt;
};
void ISOP2P1::stepForwardLinearizedEuler()
{
    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;

    matrix.reinit(sp_stokes);
    /// (0, 0)
    for (int i = 0; i < sp_vxvx.n_nonzero_elements(); ++i)
	matrix.global_entry(index_vxvx[i]) = viscosity * mat_v_stiff.global_entry(i)
	    + (1.0 / dt) * 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]) = viscosity * mat_v_stiff.global_entry(i)
	    + (1.0 / dt) * 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]) = 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]) = 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]) = 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]) = mat_vyp_div.global_entry(i);

    rhs.reinit(n_total_dof);

    FEMSpace<double,2>::ElementIterator the_element_v = fem_space_v.beginElement();
    FEMSpace<double,2>::ElementIterator end_element_v = fem_space_v.endElement();
    FEMSpace<double,2>::ElementIterator the_element_p = fem_space_p.beginElement();
    FEMSpace<double,2>::ElementIterator end_element_p = fem_space_p.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<2>& quad_info = the_element_v->findQuadratureInfo(4);
	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<2> > 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 = v_h[0].value(q_point, *the_element_v);
	std::vector<double> vy_value = v_h[1].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, 2> &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);
	for (int l = 0; l < n_quadrature_point; ++l)
	{
	    double Jxw = quad_info.weight(l) * jacobian[l] * volume;
	    for (int i = 0; i < n_element_dof_v; ++i)
	    {
		for (int j = 0; j < n_element_dof_v; ++j)
		{
		    double cont = Jxw * (vx_value[l] * basis_gradient_v[j][l][0] +
					 vy_value[l] * basis_gradient_v[j][l][1]) * basis_value_v[i][l];
		    matrix.add(element_dof_v[i], element_dof_v[j], cont);
		    matrix.add(n_dof_v + element_dof_v[i], n_dof_v + element_dof_v[j], cont);
		}
		/// 右端项. 这里可施加源项和 Neumann 条件.
		double rhs_cont = fx_value[l] * basis_value_v[i][l] + (1.0 / dt) * vx_value[l] * basis_value_v[i][l];
		rhs_cont *= Jxw;
		rhs(element_dof_v[i]) += rhs_cont;
		rhs_cont = fy_value[l] * basis_value_v[i][l] + (1.0 / dt ) * vy_value[l] * basis_value_v[i][l];
		rhs_cont *= Jxw;
		rhs(n_dof_v + element_dof_v[i]) += rhs_cont;

	    }
	}
    }

    /// 构建系数矩阵和右端项.
    /// 这个存放整体的数值解. 没有分割成 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(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);

    boundaryValueStokes(x);

    /// 矩阵求解. 
    SparseMatrix<double> mat_Axx(sp_vxvx);
    SparseMatrix<double> mat_Ayy(sp_vyvy);
    SparseMatrix<double> mat_BTx(sp_pvx);
    SparseMatrix<double> mat_BTy(sp_pvy);

    for (int i = 0; i < sp_vxvx.n_nonzero_elements(); ++i)
	mat_Axx.global_entry(i) = matrix.global_entry(index_vxvx[i]); 
    for (int i = 0; i < sp_vyvy.n_nonzero_elements(); ++i)
	mat_Ayy.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]);
    std::cout << "Precondition matrix builded!" << std::endl;
	
    // NSPreconditioner preconditioner_ns;
    // preconditioner_ns.initialize(mat_Axx, 
    // 				 mat_Ayy,
    // 				 mat_BTx,
    // 				 mat_BTy,
    // 				 mat_p_mass);

    clock_t t_cost = clock();
    dealii::SolverControl solver_control (4000000, l_tol, check);

    SolverGMRES<Vector<double> >::AdditionalData para(2000, false, true);
    SolverGMRES<Vector<double> > gmres (solver_control, para);
    gmres.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);
};