void TimeIterationPolicyLinear<mesh_Type, AssemblyPolicy, SolverPolicy>:: iterate ( vectorPtr_Type solution, bcContainerPtr_Type bchandler, const Real& currentTime ) { Real rhsIterNorm ( 0.0 ); // // STEP 1: Updating the system // displayer().leaderPrint ( "Updating the system... " ); *M_rhs = 0.0; M_systemMatrix.reset ( new matrix_Type ( *M_solutionMap ) ); AssemblyPolicy::assembleSystem ( M_systemMatrix, M_rhs, solution, SolverPolicy::preconditioner() ); displayer().leaderPrint ( "done\n" ); // // STEP 2: Applying the boundary conditions // displayer().leaderPrint ( "Applying BC... " ); bcManage ( *M_systemMatrix, *M_rhs, *uFESpace()->mesh(), uFESpace()->dof(), *bchandler, uFESpace()->feBd(), 1.0, currentTime ); M_systemMatrix->globalAssemble(); displayer().leaderPrint ( "done\n" ); // Extra information if we want to know the exact residual if ( M_computeResidual ) { rhsIterNorm = M_rhs->norm2(); } // // STEP 3: Solving the system // displayer().leaderPrint ( "Solving the system... \n" ); SolverPolicy::solve ( M_systemMatrix, M_rhs, solution ); if ( M_computeResidual ) { vector_Type Ax ( solution->map() ); vector_Type res ( *M_rhs ); M_systemMatrix->matrixPtr()->Apply ( solution->epetraVector(), Ax.epetraVector() ); res.epetraVector().Update ( -1, Ax.epetraVector(), 1 ); Real residual; res.norm2 ( &residual ); residual /= rhsIterNorm; displayer().leaderPrint ( "Scaled residual: ", residual, "\n" ); } }
Real LinearSolver::computeResidual ( vectorPtr_Type solutionPtr ) { if ( !M_operator || !M_rhs ) { M_displayer->leaderPrint ( "SLV- WARNING: LinearSolver can not compute the residual if the operator and the RHS are not set!\n" ); return -1; } vector_Type Ax ( solutionPtr->map() ); vector_Type residual ( *M_rhs ); M_operator->Apply ( solutionPtr->epetraVector(), Ax.epetraVector() ); residual.epetraVector().Update ( 1, Ax.epetraVector(), -1 ); Real residualNorm; residual.norm2 ( &residualNorm ); return residualNorm; }
void TimeIterationPolicyNonlinear<mesh_Type, AssemblyPolicy, SolverPolicy>:: iterate ( vectorPtr_Type solution, bcContainerPtr_Type bchandler, const Real& currentTime ) { int subiter = 0; Real normRhs ( 0.0 ); Real nonLinearResidual ( 0.0 ); Real rhsIterNorm ( 0.0 ); do { // // STEP 1: Updating the system // displayer().leaderPrint ( "Updating the system... " ); *M_rhs = 0.0; M_systemMatrix.reset ( new matrix_Type ( *M_solutionMap ) ); AssemblyPolicy::assembleSystem ( M_systemMatrix, M_rhs, solution, SolverPolicy::preconditioner() ); displayer().leaderPrint ( "done\n" ); // // STEP 2: Applying the boundary conditions // displayer().leaderPrint ( "Applying BC... " ); bcManage ( *M_systemMatrix, *M_rhs, *uFESpace()->mesh(), uFESpace()->dof(), *bchandler, uFESpace()->feBd(), 1.0, currentTime ); M_systemMatrix->globalAssemble(); displayer().leaderPrint ( "done\n" ); // Norm of the rhs needed for the nonlinear convergence test if ( subiter == 0 ) { normRhs = M_rhs->norm2(); } // // STEP 3: Computing the residual // // Computing the RHS as RHS=b-Ax_k vector_Type Ax ( solution->map() ); M_systemMatrix->matrixPtr()->Apply ( solution->epetraVector(), Ax.epetraVector() ); Ax.epetraVector().Update (-1, M_rhs->epetraVector(), 1); nonLinearResidual = Ax.norm2(); displayer().leaderPrint ( "Nonlinear residual : ", nonLinearResidual, "\n" ); displayer().leaderPrint ( "Nonlinear residual (scaled) : ", nonLinearResidual / normRhs, "\n" ); if ( nonLinearResidual > M_nonLinearTolerance * normRhs ) { displayer().leaderPrint ( "---\nSubiteration [", ++subiter, "]\n" ); // Extra information if we want to know the exact residual if ( M_computeResidual ) { rhsIterNorm = M_rhs->norm2(); } // // Solving the system // displayer().leaderPrint ( "Solving the system... \n" ); *solution = 0.0; SolverPolicy::solve ( M_systemMatrix, M_rhs, solution ); // int numIter = SolverPolicy::solve( M_systemMatrix, M_rhs, solution ); // numIterSum += numIter; // if ( M_computeResidual ) { vector_Type Ax ( solution->map() ); vector_Type res ( *M_rhs ); M_systemMatrix->matrixPtr()->Apply ( solution->epetraVector(), Ax.epetraVector() ); res.epetraVector().Update ( -1, Ax.epetraVector(), 1 ); Real residual; res.norm2 ( &residual ); residual /= rhsIterNorm; displayer().leaderPrint ( "Scaled residual: ", residual, "\n" ); } } } while ( nonLinearResidual > M_nonLinearTolerance * normRhs ); displayer().leaderPrint ( "Nonlinear iterations : ", subiter, "\n" ); }
// =================================================== // Methods // =================================================== Int LinearSolver::solve ( vectorPtr_Type solutionPtr ) { // Build preconditioners if needed bool retry ( true ); if ( !isPreconditionerSet() || !M_reusePreconditioner ) { buildPreconditioner(); // There will be no retry if the preconditioner is recomputed retry = false; } else { if ( !M_silent ) { M_displayer->leaderPrint ( "SLV- Reusing precond ...\n" ); } } if ( M_rhs.get() == 0 || M_operator == 0 ) { M_displayer->leaderPrint ( "SLV- ERROR: LinearSolver failed to set up correctly!\n" ); return -1; } // Setup the Solver Operator setupSolverOperator(); // Reset status informations bool failure = false; this->resetStatus(); M_solverOperator->resetStatus(); // Solve the linear system LifeChrono chrono; chrono.start(); M_solverOperator->ApplyInverse ( M_rhs->epetraVector(), solutionPtr->epetraVector() ); M_converged = M_solverOperator->hasConverged(); M_lossOfPrecision = M_solverOperator->isLossOfAccuracyDetected(); chrono.stop(); if ( !M_silent ) { M_displayer->leaderPrintMax ( "SLV- Solution time: " , chrono.diff(), " s." ); } // Getting informations post-solve Int numIters = M_solverOperator->numIterations(); // Second run recomputing the preconditioner // This is done only if the preconditioner has not been // already recomputed and if it is a LifeV preconditioner. if ( M_converged != SolverOperator_Type::yes && retry && M_preconditioner ) { M_displayer->leaderPrint ( "SLV- Iterative solver failed, numiter = " , numIters, "\n" ); M_displayer->leaderPrint ( "SLV- retrying:\n" ); buildPreconditioner(); // Solving again, but only once (retry = false) chrono.start(); M_solverOperator->ApplyInverse ( M_rhs->epetraVector(), solutionPtr->epetraVector() ); M_converged = M_solverOperator->hasConverged(); M_lossOfPrecision = M_solverOperator->isLossOfAccuracyDetected(); chrono.stop(); if ( !M_silent ) { M_displayer->leaderPrintMax ( "SLV- Solution time: " , chrono.diff(), " s." ); } } if ( M_lossOfPrecision == SolverOperator_Type::yes ) { M_displayer->leaderPrint ( "SLV- WARNING: Loss of accuracy detected!\n" ); failure = true; } if ( M_converged == SolverOperator_Type::yes ) { if ( !M_silent ) { M_displayer->leaderPrint ( "SLV- Convergence in " , numIters, " iterations\n" ); } M_maxNumItersReached = SolverOperator_Type::no; } else { M_displayer->leaderPrint ( "SLV- WARNING: Solver failed to converged to the desired precision!\n" ); M_maxNumItersReached = SolverOperator_Type::yes; failure = true; } // If quitOnFailure is enabled and if some problems occur // the simulation is stopped if ( M_quitOnFailure && failure ) { exit ( -1 ); } // Reset the solver to free the internal pointers M_solverOperator->resetSolver(); // If the number of iterations reaches the threshold of maxIterForReuse // we reset the preconditioners to force to solver to recompute it next // time if ( numIters > M_maxItersForReuse ) { resetPreconditioner(); } return numIters; }