Skip to content

Commit ae6e024

Browse files
committed
Added error messages for fitting failure
1 parent 4eb4d55 commit ae6e024

File tree

2 files changed

+63
-7
lines changed

2 files changed

+63
-7
lines changed

burnman/optimize/nonlinear_fitting.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -339,13 +339,29 @@ def _update_beta(lmbda):
339339
return (current_params - new_params) / mod_params
340340

341341
for n_it in range(max_lm_iterations):
342-
# update the parameters with a LM iteration
343-
f_delta_beta = _update_beta(lm_damping)
344-
max_f = np.max(np.abs(f_delta_beta))
345-
if verbose:
346-
print(f"Iteration {n_it}: max param change = {max_f:.2e}")
347-
if max_f < param_tolerance:
348-
break
342+
try:
343+
# update the parameters with a LM iteration
344+
f_delta_beta = _update_beta(lm_damping)
345+
max_f = np.max(np.abs(f_delta_beta))
346+
347+
if np.isnan(max_f):
348+
raise ValueError(
349+
"The Levenberg-Marquardt update for "
350+
f"Iteration {n_it} was non-numerical."
351+
)
352+
353+
if verbose:
354+
print(f"Iteration {n_it}: max param change = {max_f:.2e}")
355+
if max_f < param_tolerance:
356+
break
357+
except Exception:
358+
raise Exception(
359+
f"During non-linear fitting, Iteration {n_it} produced an "
360+
"exception. This is probably due to numerical failure of "
361+
"the input model. "
362+
"Consider imposing bounds on fitting or priors on your "
363+
"parameter values to prevent this behaviour."
364+
)
349365

350366
J = model.jacobian
351367
r = model.weighted_residuals

tests/test_fitting.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,46 @@ def test_fit_bounded_PVT_data(self):
214214
self.assertEqual(len(s[1]), 3)
215215
self.assertEqual(len(s[2]), 3)
216216

217+
def test_PTV_data_eos_numerical_failure(self):
218+
fo = burnman.minerals.HP_2011_ds62.fo()
219+
220+
pressures = np.linspace(1.0e9, 2.0e9, 8)
221+
temperatures = np.ones_like(pressures) * fo.params["T_0"]
222+
223+
fo.set_state(1.0e9, fo.params["T_0"])
224+
V0 = fo.V
225+
fo.set_state(2.0e9, fo.params["T_0"])
226+
V1 = fo.V
227+
volumes = V0 + (V1 - V0) * (pressures - 1.0e9) / 1.0e9
228+
PTV = np.array([pressures, temperatures, volumes]).T
229+
params = ["V_0", "K_0", "Kprime_0"]
230+
231+
try:
232+
_ = burnman.eos_fitting.fit_PTV_data(fo, params, PTV, verbose=False)
233+
self.assertTrue(False)
234+
except Exception:
235+
self.assertTrue(True)
236+
237+
def test_PTV_data_eos_exception(self):
238+
fo = burnman.minerals.SLB_2011.forsterite()
239+
240+
pressures = np.linspace(1.0e9, 100.0e9, 8)
241+
temperatures = np.ones_like(pressures) * fo.params["T_0"]
242+
243+
fo.set_state(1.0e9, fo.params["T_0"])
244+
V0 = fo.V
245+
fo.set_state(2.0e9, fo.params["T_0"])
246+
V1 = fo.V
247+
volumes = V0 + (V1 - V0) * (pressures - 1.0e9) / 1.0e9
248+
PTV = np.array([pressures, temperatures, volumes]).T
249+
params = ["V_0", "K_0", "Kprime_0"]
250+
251+
try:
252+
_ = burnman.eos_fitting.fit_PTV_data(fo, params, PTV, verbose=False)
253+
self.assertTrue(False)
254+
except Exception:
255+
self.assertTrue(True)
256+
217257
def test_bounded_solution_fitting(self):
218258
solution = burnman.minerals.SLB_2011.mg_fe_olivine()
219259
solution.set_state(1.0e5, 300.0)

0 commit comments

Comments
 (0)