Exemplo n.º 1
0
typename SolverLinearPetsc<T>::solve_return_type
SolverLinearPetsc<T>::solve ( MatrixSparse<T> const&  matrix_in,
                              MatrixSparse<T> const&  precond_in,
                              Vector<T> & solution_in,
                              Vector<T> const& rhs_in,
                              const double tol,
                              const unsigned int m_its,
                              bool transpose )
{
    this->setWorldComm( matrix_in.comm() );
    this->init ();

    MatrixPetsc<T> * matrix   = const_cast<MatrixPetsc<T> *>( dynamic_cast<MatrixPetsc<T> const*>( &matrix_in ) );
    MatrixPetsc<T> * precond  = const_cast<MatrixPetsc<T> *>( dynamic_cast<MatrixPetsc<T> const*>( &precond_in ) );
    VectorPetsc<T> * solution = dynamic_cast<VectorPetsc<T>*>( &solution_in );
    VectorPetsc<T> * rhs      = const_cast<VectorPetsc<T> *>( dynamic_cast<VectorPetsc<T> const*>( &rhs_in ) );

    // We cast to pointers so we can be sure that they succeeded
    // by comparing the result against NULL.
    FEELPP_ASSERT( matrix   != NULL ).error( "non petsc matrix structure" );
    FEELPP_ASSERT( precond  != NULL ).error( "non petsc matrix structure" );
    FEELPP_ASSERT( solution != NULL ).error( "non petsc vector structure" );
    FEELPP_ASSERT( rhs      != NULL ).error( "non petsc vector structure" );

    int ierr=0;
    int its=0;
    PetscReal final_resid=0.;

    // Close the matrices and vectors in case this wasn't already done.
    matrix->close ();
    precond->close ();
    solution->close ();
    rhs->close ();


    if ( !this->M_preconditioner && this->preconditionerType() == FIELDSPLIT_PRECOND )
        matrix->updatePCFieldSplit( M_pc );

    //   // If matrix != precond, then this means we have specified a
    //   // special preconditioner, so reset preconditioner type to PCMAT.
    //   if (matrix != precond)
    //     {
    //       this->_preconditioner_type = USER_PRECOND;
    //       this->set_petsc_preconditioner_type ();
    //     }

    // 2.1.x & earlier style
#if (PETSC_VERSION_MAJOR == 2) && (PETSC_VERSION_MINOR <= 1)

    // Set operators. The input matrix works as the preconditioning matrix
    ierr = SLESSetOperators( M_sles, matrix->mat(), precond->mat(),
                             SAME_NONZERO_PATTERN );
    CHKERRABORT( this->worldComm().globalComm(),ierr );


    // Set the tolerances for the iterative solver.  Use the user-supplied
    // tolerance for the relative residual & leave the others at default values.
    ierr = KSPSetTolerances ( M_ksp,
                              this->rTolerance(),
                              this->aTolerance(),
                              this->dTolerance(),
                              this->maxIterations() );
    CHKERRABORT( this->worldComm().globalComm(),ierr );

    // makes the default convergence test use || B*(b - A*(initial guess))||
    // instead of || B*b ||. In the case of right preconditioner or if
    // KSPSetNormType(ksp,KSP_NORM_UNPRECONDIITONED) is used there is no B in
    // the above formula. UIRNorm is short for Use Initial Residual Norm.
#if PETSC_VERSION_GREATER_OR_EQUAL_THAN(3,4,4)
    KSPConvergedDefaultSetUIRNorm( M_ksp );
#else
    KSPDefaultConvergedSetUIRNorm( M_ksp );
#endif


    // Solve the linear system
    ierr = SLESSolve ( M_sles, rhs->vec(), solution->vec(), &its );
    CHKERRABORT( this->worldComm().globalComm(),ierr );


    // Get the norm of the final residual to return to the user.
    ierr = KSPGetResidualNorm ( M_ksp, &final_resid );
    CHKERRABORT( this->worldComm().globalComm(),ierr );

    // 2.2.0
#elif (PETSC_VERSION_MAJOR == 2) && (PETSC_VERSION_MINOR == 2) && (PETSC_VERSION_SUBMINOR == 0)

    // Set operators. The input matrix works as the preconditioning matrix
    ierr = KSPSetOperators( M_ksp, matrix->mat(), precond->mat(),
                            MatStructure::SAME_NONZERO_PATTERN );
    CHKERRABORT( this->worldComm().globalComm(),ierr );


    // Set the tolerances for the iterative solver.  Use the user-supplied
    // tolerance for the relative residual & leave the others at default values.
    // Convergence is detected at iteration k if
    // ||r_k||_2 < max(rtol*||b||_2 , abstol)
    // where r_k is the residual vector and b is the right-hand side.  Note that
    // it is the *maximum* of the two values, the larger of which will almost
    // always be rtol*||b||_2.
    ierr = KSPSetTolerances ( M_ksp,
                              this->rTolerance(),
                              this->aTolerance(),
                              this->dTolerance(),
                              this->maxIterations() );
    CHKERRABORT( this->worldComm().globalComm(),ierr );


    // Set the solution vector to use
    ierr = KSPSetSolution ( M_ksp, solution->vec() );
    CHKERRABORT( this->worldComm().globalComm(),ierr );

    // Set the RHS vector to use
    ierr = KSPSetRhs ( M_ksp, rhs->vec() );
    CHKERRABORT( this->worldComm().globalComm(),ierr );

    // makes the default convergence test use || B*(b - A*(initial guess))||
    // instead of || B*b ||. In the case of right preconditioner or if
    // KSPSetNormType(ksp,KSP_NORM_UNPRECONDIITONED) is used there is no B in
    // the above formula. UIRNorm is short for Use Initial Residual Norm.
#if PETSC_VERSION_GREATER_OR_EQUAL_THAN(3,4,4)
    KSPConvergedDefaultSetUIRNorm( M_ksp );
#else
    KSPDefaultConvergedSetUIRNorm( M_ksp );
#endif

    // Solve the linear system
    if ( transpose )
        ierr = KSPSolveTranspose ( M_ksp );

    else
        ierr = KSPSolve ( M_ksp );

    CHKERRABORT( this->worldComm().globalComm(),ierr );

    // Get the number of iterations required for convergence
    ierr = KSPGetIterationNumber ( M_ksp, &its );
    CHKERRABORT( this->worldComm().globalComm(),ierr );

    // Get the norm of the final residual to return to the user.
    ierr = KSPGetResidualNorm ( M_ksp, &final_resid );
    CHKERRABORT( this->worldComm().globalComm(),ierr );

    // 2.2.1 & newer style
#else
    //std::cout << "sles: " << this->precMatrixStructure() << "\n";
    // Set operators. The input matrix works as the preconditioning matrix
#if PETSC_VERSION_LESS_THAN(3,5,0)
    ierr = KSPSetOperators( M_ksp, matrix->mat(), precond->mat(),
                            PetscGetMatStructureEnum(this->precMatrixStructure()) );
#else
    ierr = KSPSetReusePreconditioner( M_ksp, (this->precMatrixStructure() == Feel::SAME_PRECONDITIONER)? PETSC_TRUE : PETSC_FALSE );
    CHKERRABORT( this->worldComm().globalComm(),ierr );
    ierr = KSPSetOperators( M_ksp, matrix->mat(), precond->mat() );
#endif
    CHKERRABORT( this->worldComm().globalComm(),ierr );

    // Set the tolerances for the iterative solver.  Use the user-supplied
    // tolerance for the relative residual & leave the others at default values.
    ierr = KSPSetTolerances ( M_ksp,
                              this->rTolerance(),
                              //1e-15,
                              this->aTolerance(),
                              this->dTolerance(),
                              this->maxIterations() );
    CHKERRABORT( this->worldComm().globalComm(),ierr );

    //PreconditionerPetsc<T>::setPetscPreconditionerType( this->preconditionerType(),this->matSolverPackageType(),M_pc, this->worldComm() );


    // makes the default convergence test use || B*(b - A*(initial guess))||
    // instead of || B*b ||. In the case of right preconditioner or if
    // KSPSetNormType(ksp,KSP_NORM_UNPRECONDIITONED) is used there is no B in
    // the above formula. UIRNorm is short for Use Initial Residual Norm.
#if PETSC_VERSION_LESS_THAN(3,5,0)
    KSPDefaultConvergedSetUIRNorm( M_ksp );
#else
    KSPConvergedDefaultSetUIRNorm( M_ksp );
#endif

    // Solve the linear system
    if ( transpose )
        ierr = KSPSolveTranspose ( M_ksp, rhs->vec(), solution->vec() );

    else
        ierr = KSPSolve ( M_ksp, rhs->vec(), solution->vec() );

    CHKERRABORT( this->worldComm().globalComm(),ierr );

    // Get the number of iterations required for convergence
    ierr = KSPGetIterationNumber ( M_ksp, &its );
    CHKERRABORT( this->worldComm().globalComm(),ierr );

    // Get the norm of the final residual to return to the user.
    ierr = KSPGetResidualNorm ( M_ksp, &final_resid );
    //std::cout << "final residual = " << final_resid << "\n";
    CHKERRABORT( this->worldComm().globalComm(),ierr );


    KSPConvergedReason reason;
    KSPGetConvergedReason( M_ksp,&reason );

    if ( option( _prefix=this->prefix(), _name="ksp-view" ).template as<bool>() )
        check( KSPView( M_ksp, PETSC_VIEWER_STDOUT_WORLD ) );

    if ( reason==KSP_DIVERGED_INDEFINITE_PC )
    {
        LOG(INFO) << "[solverlinearpetsc] Divergence because of indefinite preconditioner;\n";
        LOG(INFO) << "[solverlinearpetsc] Run the executable again but with '-pc_factor_shift_type POSITIVE_DEFINITE' option.\n";
    }

    else if ( reason<0 )
    {
        LOG(INFO) <<"[solverlinearpetsc] Other kind of divergence: this should not happen.\n";
    }

    bool hasConverged;

    if ( reason> 0 )
        {
            hasConverged=true;
            if (this->showKSPConvergedReason() && this->worldComm().globalRank() == this->worldComm().masterRank() )
                std::cout<< "Linear solve converged due to " << PetscConvertKSPReasonToString(reason)
                         << " iterations " << its << std::endl;
        }
    else
        {
            hasConverged=false;
            if (this->showKSPConvergedReason() && this->worldComm().globalRank() == this->worldComm().masterRank() )
                std::cout<< "Linear solve did not converge due to " << PetscConvertKSPReasonToString(reason)
                         << " iterations " << its << std::endl;
        }

#endif
    // return the # of its. and the final residual norm.
    //return std::make_pair(its, final_resid);
    return solve_return_type( boost::make_tuple( hasConverged, its, final_resid ) );


}
Exemplo n.º 2
0
void PETSC_STDCALL  kspdefaultconvergedsetuirnorm_(KSP ksp, int *__ierr ){
*__ierr = KSPDefaultConvergedSetUIRNorm(
	(KSP)PetscToPointer((ksp) ));
}