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 ) ); }
void PETSC_STDCALL kspdefaultconvergedsetuirnorm_(KSP ksp, int *__ierr ){ *__ierr = KSPDefaultConvergedSetUIRNorm( (KSP)PetscToPointer((ksp) )); }