Beispiel #1
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;
};
std::tuple<bool, CMatrix2D const, std::vector<double> >
LinearSolver::GaussElim(CMatrix2D const & A, std::vector<double> const & f) {
    // Solve the equation A x = f using Gauss' elimination method with
    // row pivoting.
    // Description of algorithm: First, search for the largest element
    // in all following row and use it as the pivot element. This is to
    // reduce round-off errors. The matrix ACopy will be transformed
    // into the identity matrix, while the identity matrix, AInv, will
    // be transformed into the inverse.
    // A x =  Id y is successively transformed into A^{-1} A x = A^{-1} Id f,
    // where ACopy = Id and A^{-1} = AInv.
    boost::uint64_t max_col = A.getCols();
    boost::uint64_t max_row = A.getRows();
    bool success = false;
    CMatrix2D ACopy(A);
    CMatrix2D AInv(CMatrix2D::identity(max_col));
    std::vector<double> rhs(f);

    bool assert_cond = max_col == max_row;
    BOOST_ASSERT_MSG(assert_cond, "LinearSolver::GaussElim: Matrix must be quadratic");
    if (!assert_cond)
        throw std::out_of_range("LinearSolver::GaussElim: Matrix must be quadratic");

    // Create row-row map (because of pivoting)
    std::vector<int> row_row_map(max_row);
    for (int i = 0; i < max_row; ++i)
        row_row_map[i] = i;

    for (int col = 0; col < max_col; ++col) {
        // Find pivot element row index
        int pivot_index = findPivotIndex(ACopy, col, row_row_map);

        // Arrange rows due to row pivoting
        if (col != row_row_map[pivot_index]) {
            row_row_map[pivot_index] = col;
            row_row_map[row_row_map[col]] = pivot_index;
        }

        BOOST_ASSERT_MSG(row_row_map[pivot_index] == col, "LinearSolver::GaussElim: Pivoting error");
        double pivot_element = ACopy(pivot_index, col);

        // Matrix is singular
        if (pivot_element == 0.0)
            return std::make_tuple(false, AInv, rhs);

        // Divide pivot row by pivot element to set element to 1
        for (int i = 0; i < max_col; ++i) {
            // ACopy(pivot_index, i) = 0 for i < col
            if (i >= col) {
                double& val1 = ACopy(pivot_index, i);
                val1 /= pivot_element;
            }

            double& val2 = AInv(pivot_index, i);
            val2 /= pivot_element;
        }

        // Do same transformation on the rhs
        rhs[pivot_index] /= pivot_element;

        // Add pivot row to all other rows to reduce column col
        // to the corresponding identity matrix column.
        for (int current_row = 0; current_row < max_row; ++current_row) {
            if (current_row == pivot_index)
                continue;

            double val = - ACopy(current_row, col) / ACopy(pivot_index, col);

            for (int j = 0; j < max_col; ++j) {
                ACopy(current_row, j) += val * ACopy(pivot_index, j);
                AInv(current_row, j) += val * AInv(pivot_index, j);
            }

            // Do same transformation on the rhs
            rhs[current_row] += val * rhs[pivot_index];
        }
    }

    // Rearrange the rows in AInv due to pivoting
    for (int i = 0; i < max_row; ++i) {
        int row = row_row_map[i];

        if (row == i)
            continue;

        // Swap rows
        for (int j = 0; j < max_col; ++j) {
            double tmp = AInv(i, j);
            AInv(i, j) = AInv(row, j);
            AInv(row, j) = tmp;

            tmp = ACopy(i, j);
            ACopy(i, j) = ACopy(row, j);
            ACopy(row, j) = tmp;
        }

        // Swap rows on the rhs
        double tmp = rhs[i];
        rhs[i] = rhs[row];
        rhs[row] = tmp;

        row_row_map[i] = row_row_map[row];
        row_row_map[row] = row;
    }

    return std::make_tuple(success, AInv, rhs);
}
Beispiel #3
0
void magnet::math::Spline::generate()
{
    if (size() < 2)
        throw std::runtime_error("Spline requires at least 2 points");

    // If any spline points are at the same x location, we have to
    // just slightly seperate them
    {
        bool testPassed(false);
        while (!testPassed) {
            testPassed = true;
            std::sort(base::begin(), base::end());

            for (auto iPtr = base::begin(); iPtr != base::end() - 1; ++iPtr)
                if (iPtr->first == (iPtr + 1)->first) {
                    if ((iPtr + 1)->first != 0)
                        (iPtr + 1)->first += (iPtr + 1)->first
                                             * std::numeric_limits
                                             <double>::epsilon() * 10;
                    else
                        (iPtr + 1)->first = std::numeric_limits
                                            <double>::epsilon() * 10;
                    testPassed = false;
                    break;
                }
        }
    }

    const size_t e = size() - 1;

    switch (_type) {
    case LINEAR: {
        _data.resize(e);
        for (size_t i(0); i < e; ++i) {
            _data[i].x = x(i);
            _data[i].a = 0;
            _data[i].b = 0;
            _data[i].c = (y(i + 1) - y(i)) / (x(i + 1) - x(i));
            _data[i].d = y(i);
        }
        break;
    }
    case CUBIC: {
        ublas::matrix<double> A(size(), size());
        for (size_t yv(0); yv <= e; ++yv)
            for (size_t xv(0); xv <= e; ++xv)
                A(xv, yv) = 0;

        for (size_t i(1); i < e; ++i) {
            A(i - 1, i) = h(i - 1);
            A(i, i) = 2 * (h(i - 1) + h(i));
            A(i + 1, i) = h(i);
        }

        ublas::vector<double> C(size());
        for (size_t xv(0); xv <= e; ++xv)
            C(xv) = 0;

        for (size_t i(1); i < e; ++i)
            C(i) = 6
                   * ((y(i + 1) - y(i)) / h(i) - (y(i) - y(i - 1)) / h(i - 1));

        // Boundary conditions
        switch (_BCLow) {
        case FIXED_1ST_DERIV_BC:
            C(0) = 6 * ((y(1) - y(0)) / h(0) - _BCLowVal);
            A(0, 0) = 2 * h(0);
            A(1, 0) = h(0);
            break;
        case FIXED_2ND_DERIV_BC:
            C(0) = _BCLowVal;
            A(0, 0) = 1;
            break;
        case PARABOLIC_RUNOUT_BC:
            C(0) = 0;
            A(0, 0) = 1;
            A(1, 0) = -1;
            break;
        }

        switch (_BCHigh) {
        case FIXED_1ST_DERIV_BC:
            C(e) = 6 * (_BCHighVal - (y(e) - y(e - 1)) / h(e - 1));
            A(e, e) = 2 * h(e - 1);
            A(e - 1, e) = h(e - 1);
            break;
        case FIXED_2ND_DERIV_BC:
            C(e) = _BCHighVal;
            A(e, e) = 1;
            break;
        case PARABOLIC_RUNOUT_BC:
            C(e) = 0;
            A(e, e) = 1;
            A(e - 1, e) = -1;
            break;
        }

        ublas::matrix<double> AInv(size(), size());
        InvertMatrix(A, AInv);

        _ddy = ublas::prod(C, AInv);

        _data.resize(size() - 1);
        for (size_t i(0); i < e; ++i) {
            _data[i].x = x(i);
            _data[i].a = (_ddy(i + 1) - _ddy(i)) / (6 * h(i));
            _data[i].b = _ddy(i) / 2;
            _data[i].c = (y(i + 1) - y(i)) / h(i) - _ddy(i + 1) * h(i) / 6
                         - _ddy(i) * h(i) / 3;
            _data[i].d = y(i);
        }
    }
    }
    _valid = true;
}