diff --git a/pyoptsparse/pySNOPT/pySNOPT.py b/pyoptsparse/pySNOPT/pySNOPT.py index bac40403..249f4ddd 100644 --- a/pyoptsparse/pySNOPT/pySNOPT.py +++ b/pyoptsparse/pySNOPT/pySNOPT.py @@ -15,6 +15,7 @@ from baseclasses.utils import CaseInsensitiveSet import numpy as np from numpy import ndarray +from pkg_resources import parse_version # Local modules from ..pyOpt_error import Error @@ -520,6 +521,12 @@ def __call__( sol_inform["text"] = self.informs[inform] # Create the optimization solution + if parse_version(self.version) > parse_version("7.7.0") and parse_version(self.version) < parse_version( + "7.7.7" + ): + # SNOPT obj value is buggy and returned as 0, its thus overwritten with the solution objective value + obj = np.array([obj.value * obj.scale for obj in self.optProb.objectives.values()]) + sol = self._createSolution(optTime, sol_inform, obj, xs[:nvar], multipliers=pi) restartDict = { "cw": cw, diff --git a/tests/testing_utils.py b/tests/testing_utils.py index 84fc2d37..08017b5f 100644 --- a/tests/testing_utils.py +++ b/tests/testing_utils.py @@ -118,11 +118,16 @@ def assert_solution_allclose(self, sol, tol, partial_x=False): else: # assume we have a single solution self.sol_index = 0 + # now we assert against the closest solution # objective assert_allclose(sol.fStar, self.fStar[self.sol_index], atol=tol, rtol=tol) # make sure fStar and sol.objectives values match - assert_allclose(sol.fStar, [obj.value for obj in sol.objectives.values()], rtol=1e-12) + # NOTE this is not true in general, but true for well-behaving optimizations + # which should be the case for all tests + sol_objectives = np.array([obj.value for obj in sol.objectives.values()]) + assert_allclose(sol.fStar, sol_objectives, rtol=1e-12) + # x assert_dict_allclose(sol.xStar, self.xStar[self.sol_index], atol=tol, rtol=tol, partial=partial_x) dv = sol.getDVs()