diff --git a/docs/src/SolverInterfaces.md b/docs/src/SolverInterfaces.md index f09f1f79..774713cf 100644 --- a/docs/src/SolverInterfaces.md +++ b/docs/src/SolverInterfaces.md @@ -5,6 +5,26 @@ CurrentModule = GridapSolvers.SolverInterfaces # GridapSolvers.SolverInterfaces -```@autodocs -Modules = [SolverInterfaces,] +## SolverTolerances + +```@docs + SolverTolerances + SolverConvergenceFlag + get_solver_tolerances + set_solver_tolerances! + finished + converged + finished_flag +``` + +## ConvergenceLogs + +```@docs + ConvergenceLog + SolverVerboseLevel + reset! + init! + update! + finalize! + print_message ``` diff --git a/src/SolverInterfaces/ConvergenceLogs.jl b/src/SolverInterfaces/ConvergenceLogs.jl index ed877fdd..b36237ed 100644 --- a/src/SolverInterfaces/ConvergenceLogs.jl +++ b/src/SolverInterfaces/ConvergenceLogs.jl @@ -1,4 +1,14 @@ +""" + @enum SolverVerboseLevel begin + SOLVER_VERBOSE_NONE = 0 + SOLVER_VERBOSE_LOW = 1 + SOLVER_VERBOSE_HIGH = 2 + end + + SolverVerboseLevel(true) = SOLVER_VERBOSE_HIGH + SolverVerboseLevel(false) = SOLVER_VERBOSE_NONE +""" @enum SolverVerboseLevel begin SOLVER_VERBOSE_NONE = 0 SOLVER_VERBOSE_LOW = 1 @@ -7,6 +17,28 @@ end SolverVerboseLevel(verbose::Bool) = (verbose ? SOLVER_VERBOSE_HIGH : SOLVER_VERBOSE_NONE) +""" + mutable struct ConvergenceLog{T} + ... + end + + ConvergenceLog( + name :: String, + tols :: SolverTolerances{T}; + verbose = SOLVER_VERBOSE_NONE, + depth = 0 + ) + + Standarized logging system for iterative linear solvers. + + # Methods: + + - [`reset!`](@ref) + - [`init!`](@ref) + - [`update!`](@ref) + - [`finalize!`](@ref) + - [`print_message`](@ref) +""" mutable struct ConvergenceLog{T<:Real} name :: String tols :: SolverTolerances{T} @@ -34,12 +66,22 @@ end @inline get_tabulation(log::ConvergenceLog) = get_tabulation(log,2) @inline get_tabulation(log::ConvergenceLog,n::Int) = repeat(' ', n + 2*log.depth) +""" + reset!(log::ConvergenceLog{T}) + + Resets the convergence log `log` to its initial state. +""" function reset!(log::ConvergenceLog{T}) where T log.num_iters = 0 fill!(log.residuals,0.0) return log end +""" + init!(log::ConvergenceLog{T},r0::T) + + Initializes the convergence log `log` with the initial residual `r0`. +""" function init!(log::ConvergenceLog{T},r0::T) where T log.num_iters = 0 log.residuals[1] = r0 @@ -57,6 +99,11 @@ function init!(log::ConvergenceLog{T},r0::T) where T return finished(log.tols,log.num_iters,r0,1.0) end +""" + update!(log::ConvergenceLog{T},r::T) + + Updates the convergence log `log` with the residual `r` at the current iteration. +""" function update!(log::ConvergenceLog{T},r::T) where T log.num_iters += 1 log.residuals[log.num_iters+1] = r @@ -69,6 +116,11 @@ function update!(log::ConvergenceLog{T},r::T) where T return finished(log.tols,log.num_iters,r,r_rel) end +""" + finalize!(log::ConvergenceLog{T},r::T) + + Finalizes the convergence log `log` with the final residual `r`. +""" function finalize!(log::ConvergenceLog{T},r::T) where T r_rel = r / log.residuals[1] flag = finished_flag(log.tols,log.num_iters,r,r_rel) @@ -83,6 +135,11 @@ function finalize!(log::ConvergenceLog{T},r::T) where T return flag end +""" + print_message(log::ConvergenceLog{T},msg::String) + + Prints the message `msg` to the output stream of the convergence log `log`. +""" function print_message(log::ConvergenceLog{T},msg::String) where T if log.verbose > SOLVER_VERBOSE_LOW println(get_tabulation(log),msg) diff --git a/src/SolverInterfaces/SolverTolerances.jl b/src/SolverInterfaces/SolverTolerances.jl index 1112b5fc..a272409c 100644 --- a/src/SolverInterfaces/SolverTolerances.jl +++ b/src/SolverInterfaces/SolverTolerances.jl @@ -1,3 +1,13 @@ +""" + @enum SolverConvergenceFlag begin + SOLVER_CONVERGED_ATOL = 0 + SOLVER_CONVERGED_RTOL = 1 + SOLVER_DIVERGED_MAXITER = 2 + SOLVER_DIVERGED_BREAKDOWN = 3 + end + + Convergence flags for iterative linear solvers. +""" @enum SolverConvergenceFlag begin SOLVER_CONVERGED_ATOL = 0 SOLVER_CONVERGED_RTOL = 1 @@ -5,6 +15,28 @@ SOLVER_DIVERGED_BREAKDOWN = 3 end +""" + mutable struct SolverTolerances{T} + ... + end + + SolverTolerances{T}( + maxiter :: Int = 1000, + atol :: T = eps(T), + rtol :: T = 1.e-5, + dtol :: T = Inf + ) + + Structure to check convergence conditions for iterative linear solvers. + + # Methods: + + - [`get_solver_tolerances`](@ref) + - [`set_solver_tolerances!`](@ref) + - [`converged`](@ref) + - [`finished`](@ref) + - [`finished_flag`](@ref) +""" mutable struct SolverTolerances{T <: Real} maxiter :: Int atol :: T @@ -16,8 +48,23 @@ function SolverTolerances{T}(;maxiter=1000, atol=eps(T), rtol=T(1.e-5), dtol=T(I return SolverTolerances{T}(maxiter, atol, rtol, dtol) end +""" + get_solver_tolerances(s::LinearSolver) + + Returns the solver tolerances of the linear solver `s`. +""" get_solver_tolerances(s::Gridap.Algebra.LinearSolver) = @abstractmethod +""" + set_solver_tolerances!(s::LinearSolver; + maxiter = 1000, + atol = eps(T), + rtol = T(1.e-5), + dtol = T(Inf) + ) + + Modifies tolerances of the linear solver `s`. +""" function set_solver_tolerances!(s::Gridap.Algebra.LinearSolver;kwargs...) set_solver_tolerances!(get_solver_tolerances(s);kwargs...) end @@ -34,7 +81,18 @@ function set_solver_tolerances!(a::SolverTolerances{T}; return a end -function finished_flag(tols::SolverTolerances,niter,e_a,e_r) +""" + finished_flag(tols::SolverTolerances,niter,e_a,e_r) :: SolverConvergenceFlag + + Computes the solver exit condition given + + - the number of iterations `niter` + - the absolute error `e_a` + - and the relative error `e_r`. + + Returns the corresponding `SolverConvergenceFlag`. +""" +function finished_flag(tols::SolverTolerances,niter,e_a,e_r) :: SolverConvergenceFlag if !finished(tols,niter,e_a,e_r) @warn "finished_flag() called with unfinished solver!" end @@ -49,11 +107,21 @@ function finished_flag(tols::SolverTolerances,niter,e_a,e_r) end end -function finished(tols::SolverTolerances,niter,e_a,e_r) +""" + finished(tols::SolverTolerances,niter,e_a,e_r) :: Bool + + Returns `true` if the solver has finished, `false` otherwise. +""" +function finished(tols::SolverTolerances,niter,e_a,e_r) :: Bool return (niter >= tols.maxiter) || converged(tols,niter,e_a,e_r) end -function converged(tols::SolverTolerances,niter,e_a,e_r) +""" + converged(tols::SolverTolerances,niter,e_a,e_r) :: Bool + + Returns `true` if the solver has converged, `false` otherwise. +""" +function converged(tols::SolverTolerances,niter,e_a,e_r) :: Bool return (e_r < tols.rtol) || (e_a < tols.atol) end