@@ -28,13 +28,29 @@ class AlgebraicSolver(pybamm.BaseSolver):
28
28
Any options to pass to the rootfinder. Vary depending on which method is chosen.
29
29
Please consult `SciPy documentation
30
30
<https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.show_options.html>`_
31
- for details.
31
+ for details. Addititional options to pass to the solver, by default:
32
+
33
+ .. code-block:: python
34
+
35
+ extra_options = {
36
+ # Tolerance for termination by the change of the independent variables.
37
+ "xtol": 1e-12,
38
+ # Tolerance for termination by the norm of the gradient.
39
+ "gtol": 1e-12,
40
+ }
32
41
"""
33
42
34
43
def __init__ (self , method = "lm" , tol = 1e-6 , extra_options = None ):
35
44
super ().__init__ (method = method )
36
45
self .tol = tol
37
- self .extra_options = extra_options or {}
46
+
47
+ default_extra_options = {
48
+ "xtol" : 1e-12 ,
49
+ "gtol" : 1e-12 ,
50
+ }
51
+ extra_options = extra_options or {}
52
+ self .extra_options = default_extra_options | extra_options
53
+
38
54
self .name = f"Algebraic solver ({ method } )"
39
55
self ._algebraic_solver = True
40
56
pybamm .citations .register ("Virtanen2020" )
@@ -158,6 +174,7 @@ def jac_fn(y_alg, jac=jac):
158
174
** self .extra_options ,
159
175
)
160
176
integration_time += timer .time ()
177
+ success |= sol .success
161
178
# Methods which use minimize are specified as either "minimize",
162
179
# which uses the default method, or with "minimize__methodname"
163
180
elif self .method .startswith ("minimize" ):
@@ -183,17 +200,31 @@ def jac_norm(y, jac_fn=jac_fn):
183
200
bounds = [
184
201
(lb , ub ) for lb , ub in zip (model .bounds [0 ], model .bounds [1 ])
185
202
]
186
- extra_options ["bounds" ] = bounds
203
+ else :
204
+ bounds = None
205
+
206
+ hess = extra_options .get ("hess" , None )
207
+ hessp = extra_options .get ("hessp" , None )
208
+ constraints = extra_options .get ("constraints" , ())
209
+ callback = extra_options .get ("callback" , None )
210
+
187
211
timer .reset ()
188
212
sol = optimize .minimize (
189
213
root_norm ,
190
214
y0_alg ,
191
215
method = method ,
192
216
tol = self .tol ,
193
217
jac = jac_norm ,
194
- ** extra_options ,
218
+ bounds = bounds ,
219
+ hess = hess ,
220
+ hessp = hessp ,
221
+ constraints = constraints ,
222
+ callback = callback ,
223
+ options = extra_options ,
195
224
)
196
225
integration_time += timer .time ()
226
+ # The solution.success flag is unreliable, so we ignore
227
+ # it and use the norm of the residual instead
197
228
else :
198
229
timer .reset ()
199
230
sol = optimize .root (
@@ -205,25 +236,21 @@ def jac_norm(y, jac_fn=jac_fn):
205
236
options = self .extra_options ,
206
237
)
207
238
integration_time += timer .time ()
239
+ # The solution.success flag is unreliable, so we ignore
240
+ # it and use the norm of the residual instead
208
241
209
- if sol .success and np .all (abs (sol .fun ) < self .tol ):
210
- # update initial guess for the next iteration
211
- y0_alg = sol .x
212
- # update solution array
242
+ y0_alg = sol .x
243
+ success |= np .all (abs (sol .fun ) < self .tol )
244
+ if success :
213
245
y_alg [:, idx ] = y0_alg
214
- success = True
215
- elif not sol .success :
246
+ break
247
+
248
+ if itr > maxiter :
216
249
raise pybamm .SolverError (
217
- f"Could not find acceptable solution: { sol .message } "
250
+ "Could not find acceptable solution: solver terminated "
251
+ "unsuccessfully and maximum solution error "
252
+ f"({ np .max (abs (sol .fun ))} ) above tolerance ({ self .tol } )"
218
253
)
219
- else :
220
- y0_alg = sol .x
221
- if itr > maxiter :
222
- raise pybamm .SolverError (
223
- "Could not find acceptable solution: solver terminated "
224
- "successfully, but maximum solution error "
225
- f"({ np .max (abs (sol .fun ))} ) above tolerance ({ self .tol } )"
226
- )
227
254
itr += 1
228
255
229
256
# Concatenate differential part
0 commit comments