Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add verbose option to solvers #142

Merged
merged 1 commit into from
Dec 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/ParamEstim.jl
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ end
(cf::RSSCostFunction)(params::AbstractVector) = cf(candidate(cf, params))

_solve(cf::RSSCostFunction, params::AbstractVector) = _solve(cf, cf._func(params))
_solve(::RSSCostFunction, prob::Problem) = solve(prob)
_solve(::RSSCostFunction, prob::Problem) = solve(prob, verbose = false)
_solve(::RSSCostFunction, sol::Solution) = sol

"""
Expand Down
12 changes: 8 additions & 4 deletions src/finite.jl
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ Uses backward Euler time discretization and a second-order central difference sc

# Keyword arguments
- `abstol=1e-3`: nonlinear solver tolerance.
- `verbose=true`: whether warnings are emitted if solving is unsuccessful.

---

Expand All @@ -174,13 +175,15 @@ Solve the `DirichletProblem` `prob` with a finite-difference scheme.

# Keyword arguments
- `abstol=1e-3`: nonlinear solver tolerance.
- `verbose=true`: whether warnings are emitted if solving is unsuccessful.
"""
function solve(prob::Union{
DirichletProblem{<:DiffusionEquation{1}},
FiniteProblem{<:DiffusionEquation{1}},
},
alg::FiniteDifference;
abstol = 1e-3)
abstol = 1e-3,
verbose = true)
if prob isa DirichletProblem
@argcheck iszero(prob.ob) "FiniteDifference only supports fixed boundaries"
@argcheck isnothing(alg._pre) "pre not valid for a DirichletProblem (use BoltzmannODE directly instead)"
Expand All @@ -204,7 +207,8 @@ function solve(prob::Union{
prob.i isa Number
presol = solve(DirichletProblem(prob.eq, i = prob.i, b = prob.b),
alg._pre,
abstol = abstol)
abstol = abstol,
verbose = verbose)
if presol.retcode != ReturnCode.Success
θ .= prob.i
return FiniteSolution(r,
Expand Down Expand Up @@ -348,8 +352,8 @@ function solve(prob::Union{
end
end

function solve(prob::FiniteProblem{<:DiffusionEquation{1}}; abstol = 1e-3)
solve(prob, FiniteDifference(pre = BoltzmannODE()), abstol = abstol)
function solve(prob::FiniteProblem{<:DiffusionEquation{1}}; abstol = 1e-3, verbose = true)
solve(prob, FiniteDifference(pre = BoltzmannODE()), abstol = abstol, verbose = verbose)
end

"""
Expand Down
26 changes: 17 additions & 9 deletions src/integration.jl
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,11 @@ monotonicity(odeprob::ODEProblem)::Int = sign(odeprob.u0[2])
const _ODE_ALG = RadauIIA5()
const _ODE_MAXITERS = 1000

function _init(odeprob::ODEProblem, alg::BoltzmannODE; i = nothing, abstol = 0)
function _init(odeprob::ODEProblem,
::BoltzmannODE;
i = nothing,
abstol = 0,
verbose = true)
if !isnothing(i)
direction = monotonicity(odeprob)

Expand All @@ -70,17 +74,18 @@ function _init(odeprob::ODEProblem, alg::BoltzmannODE; i = nothing, abstol = 0)
_ODE_ALG,
maxiters = _ODE_MAXITERS,
callback = past_limit,
verbose = false)
verbose = verbose)
end

return init(odeprob, _ODE_ALG, maxiters = _ODE_MAXITERS, verbose = false)
return init(odeprob, _ODE_ALG, maxiters = _ODE_MAXITERS, verbose = verbose)
end

function _init(prob::Union{CauchyProblem, SorptivityProblem},
alg::BoltzmannODE;
i = nothing,
abstol = 0)
_init(boltzmann(prob), alg, i = i, abstol = abstol)
abstol = 0,
verbose = true)
_init(boltzmann(prob), alg, i = i, abstol = abstol, verbose = verbose)
end

function _reinit!(integrator, prob::CauchyProblem)
Expand All @@ -96,15 +101,18 @@ function _reinit!(integrator, prob::SorptivityProblem)
end

"""
solve(prob::CauchyProblem[, alg::BoltzmannODE]) -> Solution
solve(prob::SorptivityProblem[, alg::BoltzmannODE]) -> Solution
solve(prob::CauchyProblem[, alg::BoltzmannODE; verbose]) -> Solution
solve(prob::SorptivityProblem[, alg::BoltzmannODE; verbose]) -> Solution

Solve the problem `prob`.

# Arguments
- `prob`: problem to solve.
- `alg=BoltzmannODE()`: algorithm to use.

# Keyword arguments
- `verbose=true`: whether warnings are emitted if solving is unsuccessful.

# References
GERLERO, G. S.; BERLI, C. L. A.; KLER, P. A. Open-source high-performance software packages for direct and inverse solving of horizontal capillary flow.
Capillarity, 2023, vol. 6, no. 2, p. 31-40.
Expand All @@ -113,8 +121,8 @@ See also: [`Solution`](@ref), [`BoltzmannODE`](@ref)
"""
function solve(prob::Union{CauchyProblem, SorptivityProblem},
alg::BoltzmannODE = BoltzmannODE();
abstol = 1e-3)
odesol = solve!(_init(prob, alg, abstol = abstol))
verbose = true)
odesol = solve!(_init(prob, alg, verbose = verbose))

@assert odesol.retcode != ReturnCode.Success

Expand Down
34 changes: 27 additions & 7 deletions src/shooting.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
function _init(prob::DirichletProblem, alg::BoltzmannODE; d_dob, abstol)
return _init(CauchyProblem(prob.eq, b = prob.b, d_dob = d_dob, ob = prob.ob),
alg,
i = prob.i, abstol = abstol)
i = prob.i, abstol = abstol, verbose = false)
end

function _shoot!(integrator, prob::DirichletProblem; d_dob, abstol)
return _shoot!(integrator,
CauchyProblem(prob.eq, b = prob.b, d_dob = d_dob, ob = prob.ob),
i = prob.i, abstol = abstol)
CauchyProblem(prob.eq, b = prob.b, d_dob = d_dob, ob = prob.ob), i = prob.i,
abstol = abstol)
end

"""
Expand All @@ -42,6 +42,7 @@
# Keyword arguments
- `abstol=1e-3`: absolute tolerance for the initial condition.
- `maxiters=100`: maximum number of iterations.
- `verbose=true`: whether warnings are emitted if solving is unsuccessful.

# References
GERLERO, G. S.; BERLI, C. L. A.; KLER, P. A. Open-source high-performance software packages for direct and inverse solving of horizontal capillary flow.
Expand All @@ -51,7 +52,8 @@
"""
function solve(prob::DirichletProblem, alg::BoltzmannODE = BoltzmannODE();
abstol = 1e-3,
maxiters = 100)
maxiters = 100,
verbose = true)
@argcheck abstol ≥ zero(abstol)
@argcheck maxiters ≥ 0

Expand All @@ -71,6 +73,9 @@
@assert integrator.sol.retcode != ReturnCode.Success
retcode = integrator.sol.retcode == ReturnCode.Terminated ? ReturnCode.Success :
integrator.sol.retcode
if verbose && !SciMLBase.successful_retcode(integrator.sol)
@warn "Problem has a trivial solution but failed to obtain it"

Check warning on line 77 in src/shooting.jl

View check run for this annotation

Codecov / codecov/patch

src/shooting.jl#L77

Added line #L77 was not covered by tests
end
return Solution(integrator.sol, prob, alg, _retcode = retcode, _niter = 0)
end

Expand All @@ -90,6 +95,9 @@
end
end

if verbose
@warn "Maximum number of iterations reached without convergence"
end
return Solution(integrator.sol,
prob,
alg,
Expand All @@ -103,7 +111,8 @@
return _init(SorptivityProblem(prob.eq, b = b, S = 2prob.Qb / prob._αh / ob, ob = ob),
alg,
i = prob.i,
abstol = abstol)
abstol = abstol,
verbose = false)
end

function _shoot!(integrator, prob::FlowrateProblem; b, abstol)
Expand All @@ -126,6 +135,7 @@
# Keyword arguments
- `abstol=1e-3`: absolute tolerance for the initial condition.
- `maxiters=100`: maximum number of iterations.
- `verbose=true`: whether warnings are emitted if solving is unsuccessful.

# References
GERLERO, G. S.; BERLI, C. L. A.; KLER, P. A. Open-source high-performance software packages for direct and inverse solving of horizontal capillary flow.
Expand All @@ -135,7 +145,8 @@
"""
function solve(prob::FlowrateProblem; alg::BoltzmannODE = BoltzmannODE(),
abstol = 1e-3,
maxiters = 100)
maxiters = 100,
verbose = true)
@argcheck abstol ≥ zero(abstol)
@argcheck maxiters ≥ 0

Expand All @@ -153,10 +164,16 @@
if monotonicity(prob) == 0
integrator, resid = _shoot!(integrator, prob, b = prob.i, abstol = abstol)
@assert iszero(resid)
@assert integrator.sol.retcode != ReturnCode.Success
retcode = integrator.sol.retcode == ReturnCode.Terminated ? ReturnCode.Success :
integrator.sol.retcode
if verbose && !SciMLBase.successful_retcode(integrator.sol)
@warn "Problem has a trivial solution but failed to obtain it"

Check warning on line 171 in src/shooting.jl

View check run for this annotation

Codecov / codecov/patch

src/shooting.jl#L171

Added line #L171 was not covered by tests
end
return Solution(integrator.sol,
prob,
alg,
_retcode = ReturnCode.Success,
_retcode = retcode,
_niter = 0)
end

Expand All @@ -174,6 +191,9 @@
end
end

if verbose
@warn "Maximum number of iterations reached without convergence"

Check warning on line 195 in src/shooting.jl

View check run for this annotation

Codecov / codecov/patch

src/shooting.jl#L194-L195

Added lines #L194 - L195 were not covered by tests
end
return Solution(integrator.sol,
prob,
alg,
Expand Down
13 changes: 2 additions & 11 deletions test/test_dirichlet.jl
Original file line number Diff line number Diff line change
Expand Up @@ -121,17 +121,8 @@

@testset "unsolved" begin
prob = DirichletProblem(identity, i = 0, b = 1)
θ = solve(prob, maxiters = 0)
θ = @test_logs (:warn, "Maximum number of iterations reached without convergence") solve(prob,
maxiters = 0)
@test θ.retcode == ReturnCode.MaxIters
end

@testset "unsolvable" begin
prob = DirichletProblem(identity, i = -1e-3, b = 1)
θ = solve(prob)
@test_broken θ.retcode == ReturnCode.Unstable

prob = DirichletProblem(identity, i = 0, b = -1)
θ = solve(prob)
@test_broken θ.retcode == ReturnCode.Unstable
end
end
Loading