1
+ """
2
+ GeneralKlement(; max_resets = 5, linsolve = nothing,
3
+ linesearch = LineSearch(), precs = DEFAULT_PRECS)
4
+
5
+ An implementation of `Klement` with line search, preconditioning and customizable linear
6
+ solves.
7
+
8
+ ## Keyword Arguments
9
+
10
+ - `max_resets`: the maximum number of resets to perform. Defaults to `5`.
11
+ - `linsolve`: the [LinearSolve.jl](https://github.com/SciML/LinearSolve.jl) used for the
12
+ linear solves within the Newton method. Defaults to `nothing`, which means it uses the
13
+ LinearSolve.jl default algorithm choice. For more information on available algorithm
14
+ choices, see the [LinearSolve.jl documentation](https://docs.sciml.ai/LinearSolve/stable/).
15
+ - `precs`: the choice of preconditioners for the linear solver. Defaults to using no
16
+ preconditioners. For more information on specifying preconditioners for LinearSolve
17
+ algorithms, consult the
18
+ [LinearSolve.jl documentation](https://docs.sciml.ai/LinearSolve/stable/).
19
+ - `linesearch`: the line search algorithm to use. Defaults to [`LineSearch()`](@ref),
20
+ which means that no line search is performed. Algorithms from `LineSearches.jl` can be
21
+ used here directly, and they will be converted to the correct `LineSearch`.
22
+ """
1
23
@concrete struct GeneralKlement <: AbstractNewtonAlgorithm{false, Nothing}
2
24
max_resets:: Int
3
25
linsolve
4
26
precs
5
27
linesearch
6
- singular_tolerance
7
28
end
8
29
9
30
function GeneralKlement (; max_resets:: Int = 5 , linsolve = nothing ,
10
- linesearch = LineSearch (), precs = DEFAULT_PRECS, singular_tolerance = nothing )
31
+ linesearch = LineSearch (), precs = DEFAULT_PRECS)
11
32
linesearch = linesearch isa LineSearch ? linesearch : LineSearch (; method = linesearch)
12
- return GeneralKlement (max_resets, linsolve, precs, linesearch, singular_tolerance )
33
+ return GeneralKlement (max_resets, linsolve, precs, linesearch)
13
34
end
14
35
15
36
@concrete mutable struct GeneralKlementCache{iip} <: AbstractNonlinearSolveCache{iip}
27
48
Jᵀ²du
28
49
Jdu
29
50
resets
30
- singular_tolerance
31
51
force_stop
32
52
maxiters:: Int
33
53
internalnorm
@@ -51,20 +71,20 @@ function SciMLBase.__init(prob::NonlinearProblem{uType, iip}, alg::GeneralKlemen
51
71
if u isa Number
52
72
linsolve = nothing
53
73
else
74
+ # For General Julia Arrays default to LU Factorization
75
+ linsolve_alg = alg. linsolve === nothing && u isa Array ? LUFactorization () :
76
+ nothing
54
77
weight = similar (u)
55
78
recursivefill! (weight, true )
56
79
Pl, Pr = wrapprecs (alg. precs (J, nothing , u, p, nothing , nothing , nothing , nothing ,
57
80
nothing )... , weight)
58
81
linprob = LinearProblem (J, _vec (fu); u0 = _vec (fu))
59
- linsolve = init (linprob, alg . linsolve ; alias_A = true , alias_b = true , Pl, Pr,
82
+ linsolve = init (linprob, linsolve_alg ; alias_A = true , alias_b = true , Pl, Pr,
60
83
linsolve_kwargs... )
61
84
end
62
85
63
- singular_tolerance = alg. singular_tolerance === nothing ? inv (sqrt (eps (eltype (u)))) :
64
- eltype (u)(alg. singular_tolerance)
65
-
66
86
return GeneralKlementCache {iip} (f, alg, u, fu, zero (fu), _mutable_zero (u), p, linsolve,
67
- J, zero (J), zero (J), zero (fu), zero (fu), 0 , singular_tolerance , false ,
87
+ J, zero (J), zero (J), _vec ( zero (fu)), _vec ( zero (fu)) , 0 , false ,
68
88
maxiters, internalnorm, ReturnCode. Default, abstol, prob, NLStats (1 , 0 , 0 , 0 , 0 ),
69
89
init_linesearch_cache (alg. linesearch, f, u, p, fu, Val (iip)))
70
90
end
@@ -73,21 +93,23 @@ function perform_step!(cache::GeneralKlementCache{true})
73
93
@unpack u, fu, f, p, alg, J, linsolve, du = cache
74
94
T = eltype (J)
75
95
76
- # FIXME : How can we do this faster?
77
- if cond (J) > cache. singular_tolerance
96
+ singular, fact_done = _try_factorize_and_check_singular! (linsolve, J)
97
+
98
+ if singular
78
99
if cache. resets == alg. max_resets
79
100
cache. force_stop = true
80
101
cache. retcode = ReturnCode. Unstable
81
102
return nothing
82
103
end
104
+ fact_done = false
83
105
fill! (J, zero (T))
84
106
J[diagind (J)] .= T (1 )
85
107
cache. resets += 1
86
108
end
87
109
88
110
# u = u - J \ fu
89
- linres = dolinsolve (alg. precs, linsolve; A = J, b = - _vec (fu), linu = _vec (du ),
90
- p, reltol = cache. abstol)
111
+ linres = dolinsolve (alg. precs, linsolve; A = ifelse (fact_done, nothing , J ),
112
+ b = - _vec (fu), linu = _vec (du), p, reltol = cache. abstol)
91
113
cache. linsolve = linres. cache
92
114
93
115
# Line Search
@@ -108,7 +130,8 @@ function perform_step!(cache::GeneralKlementCache{true})
108
130
mul! (cache. Jᵀ²du, cache. J_cache, cache. Jdu)
109
131
mul! (cache. Jdu, J, _vec (du))
110
132
cache. fu .= cache. fu2 .- cache. fu
111
- cache. fu .= (cache. fu .- _restructure (cache. fu, cache. Jdu)) ./ max .(cache. Jᵀ²du, eps (T))
133
+ cache. fu .= _restructure (cache. fu,
134
+ (_vec (cache. fu) .- cache. Jdu) ./ max .(cache. Jᵀ²du, eps (T)))
112
135
mul! (cache. J_cache, _vec (cache. fu), _vec (du)' )
113
136
cache. J_cache .*= J
114
137
mul! (cache. J_cache2, cache. J_cache, J)
@@ -123,23 +146,25 @@ function perform_step!(cache::GeneralKlementCache{false})
123
146
@unpack fu, f, p, alg, J, linsolve = cache
124
147
T = eltype (J)
125
148
126
- # FIXME : How can we do this faster?
127
- if cond (J) > cache. singular_tolerance
149
+ singular, fact_done = _try_factorize_and_check_singular! (linsolve, J)
150
+
151
+ if singular
128
152
if cache. resets == alg. max_resets
129
153
cache. force_stop = true
130
154
cache. retcode = ReturnCode. Unstable
131
155
return nothing
132
156
end
133
- cache. J = __init_identity_jacobian (u, fu)
157
+ fact_done = false
158
+ cache. J = __init_identity_jacobian (cache. u, fu)
134
159
cache. resets += 1
135
160
end
136
161
137
162
# u = u - J \ fu
138
163
if linsolve === nothing
139
164
cache. du = - fu / cache. J
140
165
else
141
- linres = dolinsolve (alg. precs, linsolve; A = J, b = - _vec (fu ),
142
- linu = _vec (cache. du), p, reltol = cache. abstol)
166
+ linres = dolinsolve (alg. precs, linsolve; A = ifelse (fact_done, nothing , J ),
167
+ b = - _vec (fu), linu = _vec (cache. du), p, reltol = cache. abstol)
143
168
cache. linsolve = linres. cache
144
169
end
145
170
@@ -161,7 +186,8 @@ function perform_step!(cache::GeneralKlementCache{false})
161
186
cache. Jᵀ²du = cache. J_cache * cache. Jdu
162
187
cache. Jdu = J * _vec (cache. du)
163
188
cache. fu = cache. fu2 .- cache. fu
164
- cache. fu = (cache. fu .- _restructure (cache. fu, cache. Jdu)) ./ max .(cache. Jᵀ²du, eps (T))
189
+ cache. fu = _restructure (cache. fu,
190
+ (_vec (cache. fu) .- cache. Jdu) ./ max .(cache. Jᵀ²du, eps (T)))
165
191
cache. J_cache = ((_vec (cache. fu) * _vec (cache. du)' ) .* J) * J
166
192
cache. J = J .+ cache. J_cache
167
193
0 commit comments