Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Omnibus testing / platform portability fixes #3335

Merged
merged 27 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
55e0224
Add FreeBSD to the set o known OSes
jsiirola Jun 20, 2024
615c646
Fix typo in test (exercised by unknown playform)
jsiirola Jun 20, 2024
e2941a4
Add `has_linear_solver()` to the IPOPT solver interfaces
jsiirola Jun 20, 2024
f6fbfd4
Fix log message string formatting
jsiirola Jun 20, 2024
800fe28
DoE: only specify linear solver if it is available.
jsiirola Jun 20, 2024
308d2a9
ensure testing global sets are unregistered
jsiirola Jun 20, 2024
3f84340
Fix state bleedover between tests
jsiirola Jun 20, 2024
c61d2d2
Guard tests that require k_aug
jsiirola Jun 20, 2024
2455454
Update test guards to correctly skip when pynumero_ASL missing
jsiirola Jun 21, 2024
f4aeeed
Relax baseline comparisons
jsiirola Jun 21, 2024
a1a75b8
Update compare_baseline to use both ABS an REL tolerance
jsiirola Jun 21, 2024
94af65b
Merge branch 'main' into freebsd-fixes
jsiirola Aug 6, 2024
73ca0fc
Guard additional tests for pynumero availability
jsiirola Aug 6, 2024
31cb420
Remove tests of k_aug functionality that is no longer supported
jsiirola Aug 6, 2024
3ba93e5
Fix GJH version() to return the expected tuple
jsiirola Aug 6, 2024
d1c7952
Update "pyomo help -s"
jsiirola Aug 6, 2024
8a4dcf1
Guard against platforms missing lsb_release
jsiirola Aug 6, 2024
0a87a53
Add missing import
jsiirola Aug 6, 2024
353fb6c
NFC: apply black
jsiirola Aug 6, 2024
9c744c7
Merge branch 'main' into freebsd-fixes
jsiirola Aug 6, 2024
7ae66e3
fix UnknownSolver logic, missing import
jsiirola Aug 6, 2024
0f79ae0
Updating baseline due to new ipopt has_linear_solver method
jsiirola Aug 7, 2024
2629cfd
Additional test guard for ipopt availability
jsiirola Aug 7, 2024
a4946df
Update pyomo/contrib/doe/tests/test_fim_doe.py
mrmundt Aug 8, 2024
0855619
Add testing of ipopt.has_linear_solver()
jsiirola Aug 9, 2024
cbd702d
Add active_writer_version, test writer activation functions
jsiirola Aug 9, 2024
658dab3
NFC: fix typo
jsiirola Aug 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion pyomo/common/fileutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,10 +286,17 @@ def find_dir(
)


_exeExt = {'linux': None, 'windows': '.exe', 'cygwin': '.exe', 'darwin': None}
_exeExt = {
'linux': None,
'freebsd': None,
'windows': '.exe',
'cygwin': '.exe',
'darwin': None,
}

_libExt = {
'linux': ('.so', '.so.*'),
'freebsd': ('.so', '.so.*'),
'windows': ('.dll', '.pyd'),
'cygwin': ('.dll', '.so', '.so.*'),
'darwin': ('.dylib', '.so', '.so.*'),
Expand Down
7 changes: 4 additions & 3 deletions pyomo/common/tests/test_download.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import pyomo.common.envvar as envvar

from pyomo.common import DeveloperError
from pyomo.common.fileutils import this_file
from pyomo.common.fileutils import this_file, Executable
from pyomo.common.download import FileDownloader, distro_available
from pyomo.common.log import LoggingIntercept
from pyomo.common.tee import capture_output
Expand Down Expand Up @@ -173,7 +173,8 @@ def test_get_os_version(self):
self.assertTrue(v.replace('.', '').startswith(dist_ver))

if (
subprocess.run(
Executable('lsb_release').available()
and subprocess.run(
['lsb_release'],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
Expand Down Expand Up @@ -206,7 +207,7 @@ def test_get_os_version(self):
self.assertEqual(_os, 'win')
self.assertEqual(_norm, _os + ''.join(_ver.split('.')[:2]))
else:
self.assertEqual(ans, '')
self.assertEqual(_os, '')

self.assertEqual((_os, _ver), FileDownloader._os_version)
# Exercise the fetch from CACHE
Expand Down
2 changes: 1 addition & 1 deletion pyomo/common/unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,7 @@ def filter_file_contents(self, lines, abstol=None):

return filtered

def compare_baseline(self, test_output, baseline, abstol=1e-6, reltol=None):
def compare_baseline(self, test_output, baseline, abstol=1e-6, reltol=1e-8):
# Filter files independently and then compare filtered contents
out_filtered = self.filter_file_contents(
test_output.strip().split('\n'), abstol
Expand Down
21 changes: 21 additions & 0 deletions pyomo/contrib/appsi/solvers/ipopt.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,3 +567,24 @@
return ComponentMap((k, v) for k, v in self._reduced_costs.items())
else:
return ComponentMap((v, self._reduced_costs[v]) for v in vars_to_load)

def has_linear_solver(self, linear_solver):
import pyomo.core as AML
from pyomo.common.tee import capture_output

m = AML.ConcreteModel()
m.x = AML.Var()
m.o = AML.Objective(expr=(m.x - 2) ** 2)
with capture_output() as OUT:
solver = self.__class__()
solver.config.stream_solver = True
solver.config.load_solution = False
solver.ipopt_options['linear_solver'] = linear_solver
try:
solver.solve(m)
except FileNotFoundError:

Check warning on line 585 in pyomo/contrib/appsi/solvers/ipopt.py

View check run for this annotation

Codecov / codecov/patch

pyomo/contrib/appsi/solvers/ipopt.py#L585

Added line #L585 was not covered by tests
# The APPSI interface always tries to open the SOL file,
# and will generate a FileNotFoundError if ipopt didn't
# generate one
return False

Check warning on line 589 in pyomo/contrib/appsi/solvers/ipopt.py

View check run for this annotation

Codecov / codecov/patch

pyomo/contrib/appsi/solvers/ipopt.py#L589

Added line #L589 was not covered by tests
return 'running with linear solver' in OUT.getvalue()
42 changes: 42 additions & 0 deletions pyomo/contrib/appsi/tests/test_ipopt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of Sandia, LLC
# Under the terms of Contract DE-NA0003525 with National Technology and
# Engineering Solutions of Sandia, LLC, the U.S. Government retains certain
# rights in this software.
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________

from pyomo.common import unittest
from pyomo.contrib.appsi.solvers import ipopt


ipopt_available = ipopt.Ipopt().available()


@unittest.skipIf(not ipopt_available, "The 'ipopt' command is not available")
class TestIpoptInterface(unittest.TestCase):
def test_has_linear_solver(self):
opt = ipopt.Ipopt()
self.assertTrue(
any(
map(
opt.has_linear_solver,
[
'mumps',
'ma27',
'ma57',
'ma77',
'ma86',
'ma97',
'pardiso',
'pardisomkl',
'spral',
'wsmp',
],
)
)
)
self.assertFalse(opt.has_linear_solver('bogus_linear_solver'))
9 changes: 6 additions & 3 deletions pyomo/contrib/doe/doe.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
A Python ``function`` that returns a Concrete Pyomo model, similar to the interface for ``parmest``
solver:
A ``solver`` object that User specified, default=None.
If not specified, default solver is IPOPT MA57.
If not specified, default solver is IPOPT (with MA57, if available).
prior_FIM:
A 2D numpy array containing Fisher information matrix (FIM) for prior experiments.
The default None means there is no prior information.
Expand Down Expand Up @@ -995,7 +995,7 @@
)
count += 1
failed_count += 1
self.logger.warning("failed count:", failed_count)
self.logger.warning("failed count: %s", failed_count)

Check warning on line 998 in pyomo/contrib/doe/doe.py

View check run for this annotation

Codecov / codecov/patch

pyomo/contrib/doe/doe.py#L998

Added line #L998 was not covered by tests
result_combine[tuple(design_set_iter)] = None

# For user's access
Expand Down Expand Up @@ -1387,7 +1387,10 @@
def _get_default_ipopt_solver(self):
"""Default solver"""
solver = SolverFactory("ipopt")
solver.options["linear_solver"] = "ma57"
for linear_solver in ('ma57', 'ma27', 'ma97'):
if solver.has_linear_solver(linear_solver):
solver.options["linear_solver"] = linear_solver
break
solver.options["halt_on_ampl_error"] = "yes"
solver.options["max_iter"] = 3000
return solver
Expand Down
2 changes: 2 additions & 0 deletions pyomo/contrib/doe/tests/test_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
from pyomo.opt import SolverFactory

ipopt_available = SolverFactory("ipopt").available()
k_aug_available = SolverFactory("k_aug").available(exception_flag=False)


class TestReactorExamples(unittest.TestCase):
Expand All @@ -57,6 +58,7 @@ def test_reactor_optimize_doe(self):

reactor_optimize_doe.main()

@unittest.skipIf(not k_aug_available, "The 'k_aug' command is not available")
@unittest.skipIf(not ipopt_available, "The 'ipopt' command is not available")
@unittest.skipIf(not pandas_available, "pandas is not available")
@unittest.skipIf(not numpy_available, "Numpy is not available")
Expand Down
4 changes: 4 additions & 0 deletions pyomo/contrib/doe/tests/test_fim_doe.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@
VariablesWithIndices,
)
from pyomo.contrib.doe.examples.reactor_kinetics import create_model, disc_for_measure
from pyomo.environ import SolverFactory

ipopt_available = SolverFactory("ipopt").available()


class TestMeasurementError(unittest.TestCase):
Expand Down Expand Up @@ -196,6 +199,7 @@ def test(self):


@unittest.skipIf(not numpy_available, "Numpy is not available")
@unittest.skipIf(not ipopt_available, "ipopt is not available")
class TestPriorFIMError(unittest.TestCase):
def test(self):
# Control time set [h]
Expand Down
2 changes: 2 additions & 0 deletions pyomo/contrib/doe/tests/test_reactor_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from pyomo.opt import SolverFactory

ipopt_available = SolverFactory("ipopt").available()
k_aug_available = SolverFactory("k_aug").available(exception_flag=False)


class Test_Reaction_Kinetics_Example(unittest.TestCase):
Expand Down Expand Up @@ -133,6 +134,7 @@ def test_kinetics_example_sequential_finite_then_optimize(self):
# self.assertAlmostEqual(value(optimize_result.model.T[0.5]), 300, places=2)
self.assertAlmostEqual(np.log10(optimize_result.trace), 3.340, places=2)

@unittest.skipIf(not k_aug_available, "The 'k_aug' solver is not available")
@unittest.skipIf(not ipopt_available, "The 'ipopt' solver is not available")
@unittest.skipIf(not numpy_available, "Numpy is not available")
@unittest.skipIf(not pandas_available, "Pandas is not available")
Expand Down
12 changes: 8 additions & 4 deletions pyomo/contrib/parmest/tests/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
import pyomo.common.unittest as unittest
import pyomo.contrib.parmest.parmest as parmest
from pyomo.contrib.parmest.graphics import matplotlib_available, seaborn_available
from pyomo.contrib.pynumero.asl import AmplInterface
from pyomo.opt import SolverFactory

ipopt_available = SolverFactory("ipopt").available()
pynumero_ASL_available = AmplInterface.available()


@unittest.skipIf(
Expand Down Expand Up @@ -43,6 +45,7 @@ def test_model_with_constraint(self):

rooney_biegler_with_constraint.main()

@unittest.skipUnless(pynumero_ASL_available, "test requires libpynumero_ASL")
@unittest.skipUnless(seaborn_available, "test requires seaborn")
def test_parameter_estimation_example(self):
from pyomo.contrib.parmest.examples.rooney_biegler import (
Expand All @@ -66,11 +69,11 @@ def test_likelihood_ratio_example(self):
likelihood_ratio_example.main()


@unittest.skipIf(
not parmest.parmest_available,
"Cannot test parmest: required dependencies are missing",
@unittest.skipUnless(pynumero_ASL_available, "test requires libpynumero_ASL")
@unittest.skipUnless(ipopt_available, "The 'ipopt' solver is not available")
@unittest.skipUnless(
parmest.parmest_available, "Cannot test parmest: required dependencies are missing"
)
@unittest.skipIf(not ipopt_available, "The 'ipopt' solver is not available")
class TestReactionKineticsExamples(unittest.TestCase):
@classmethod
def setUpClass(self):
Expand Down Expand Up @@ -140,6 +143,7 @@ def test_model(self):

reactor_design.main()

@unittest.skipUnless(pynumero_ASL_available, "test requires libpynumero_ASL")
def test_parameter_estimation_example(self):
from pyomo.contrib.parmest.examples.reactor_design import (
parameter_estimation_example,
Expand Down
Loading
Loading