Example #1
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;
		}
	}

};
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);
};