Skip to content

Commit

Permalink
reuse option in Newton Raphson method
Browse files Browse the repository at this point in the history
  • Loading branch information
frankschae committed Sep 13, 2023
1 parent f1703e6 commit 4dcc2f6
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 12 deletions.
37 changes: 26 additions & 11 deletions src/raphson.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
```julia
NewtonRaphson(; chunk_size = Val{0}(), autodiff = Val{true}(),
standardtag = Val{true}(), concrete_jac = nothing,
diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS)
diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS, reuse = true)
```
An advanced NewtonRaphson implementation with support for efficient handling of sparse
Expand Down Expand Up @@ -42,7 +42,9 @@ for large-scale and numerically-difficult nonlinear systems.
preconditioners. For more information on specifying preconditioners for LinearSolve
algorithms, consult the
[LinearSolve.jl documentation](https://docs.sciml.ai/LinearSolve/stable/).
- `reuse`: Determines if the Jacobian is reused between (quasi-)Newton steps. Defaults to
`true`. If `true` we check convergence, and automatically take a new Jacobian if
convergence slows or starts to diverge. If `false`, the Jacobian is updated in each step.
!!! note
Currently, the linear solver and chunk size choice only applies to in-place defined
Expand All @@ -52,15 +54,16 @@ struct NewtonRaphson{CS, AD, FDT, L, P, ST, CJ} <:
AbstractNewtonAlgorithm{CS, AD, FDT, ST, CJ}
linsolve::L
precs::P
reuse::Bool
end

function NewtonRaphson(; chunk_size = Val{0}(), autodiff = Val{true}(),
standardtag = Val{true}(), concrete_jac = nothing,
diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS)
diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS, reuse = true)
NewtonRaphson{_unwrap_val(chunk_size), _unwrap_val(autodiff), diff_type,
typeof(linsolve), typeof(precs), _unwrap_val(standardtag),
_unwrap_val(concrete_jac)}(linsolve,
precs)
precs, reuse)
end

mutable struct NewtonRaphsonCache{iip, fType, algType, uType, duType, resType, pType,
Expand Down Expand Up @@ -105,7 +108,7 @@ mutable struct NewtonRaphsonCache{iip, fType, algType, uType, duType, resType, p
end

function jacobian_caches(alg::NewtonRaphson, f, u, p, ::Val{false})
JacobianWrapper(f, p), nothing, nothing, nothing, nothing
JacobianWrapper(f, p), nothing, ArrayInterface.undefmatrix(u), nothing, nothing
end

function SciMLBase.__init(prob::NonlinearProblem{uType, iip}, alg::NewtonRaphson,
Expand All @@ -129,7 +132,6 @@ function SciMLBase.__init(prob::NonlinearProblem{uType, iip}, alg::NewtonRaphson
fu = f(u, p)
end
uf, linsolve, J, du1, jac_config = jacobian_caches(alg, f, u, p, Val(iip))

return NewtonRaphsonCache{iip}(f, alg, u, fu, p, uf, linsolve, J, du1, jac_config,
false, maxiters, internalnorm,
ReturnCode.Default, abstol, prob, NLStats(1, 0, 0, 0, 0))
Expand All @@ -138,7 +140,13 @@ end
function perform_step!(cache::NewtonRaphsonCache{true})
@unpack u, fu, f, p, alg = cache
@unpack J, linsolve, du1 = cache
jacobian!(J, cache)
@unpack reuse = alg

if !reuse || cache.stats.njacs == 0
jacobian!(J, cache)
cache.stats.njacs += 1
@info cache.stats.njacs J
end

# u = u - J \ fu
linres = dolinsolve(alg.precs, linsolve, A = J, b = _vec(fu), linu = _vec(du1),
Expand All @@ -151,22 +159,29 @@ function perform_step!(cache::NewtonRaphsonCache{true})
cache.force_stop = true
end
cache.stats.nf += 1
cache.stats.njacs += 1
cache.stats.nsolve += 1
cache.stats.nfactors += 1
return nothing
end

function perform_step!(cache::NewtonRaphsonCache{false})
@unpack u, fu, f, p = cache
J = jacobian(cache, f)
@unpack u, fu, f, p, alg = cache
@unpack J = cache
@unpack reuse = alg
@show cache.internalnorm(cache.fu)
if !reuse || cache.stats.njacs == 0
J = jacobian(cache, f)
cache.J = J
cache.stats.njacs += 1
@info cache.stats.njacs J
end

cache.u = u - J \ fu
cache.fu = f(cache.u, p)
if iszero(cache.fu) || cache.internalnorm(cache.fu) < cache.abstol
cache.force_stop = true
end
cache.stats.nf += 1
cache.stats.njacs += 1
cache.stats.nsolve += 1
cache.stats.nfactors += 1
return nothing
Expand Down
2 changes: 1 addition & 1 deletion test/basictests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ u0 = [1.0, 1.0]

precs = [
NonlinearSolve.DEFAULT_PRECS,
(args...) -> (Diagonal(rand!(similar(u0))), nothing)
(args...) -> (Diagonal(rand!(similar(u0))), nothing),
]

for prec in precs, linsolve in (nothing, KrylovJL_GMRES())
Expand Down

0 comments on commit 4dcc2f6

Please sign in to comment.