diff --git a/.github/workflows/release_wheel_creation.yml b/.github/workflows/release_wheel_creation.yml index 2637a315878..419921c795d 100644 --- a/.github/workflows/release_wheel_creation.yml +++ b/.github/workflows/release_wheel_creation.yml @@ -27,7 +27,7 @@ jobs: strategy: fail-fast: true matrix: - os: [ubuntu-22.04, windows-latest, macos-latest] + os: [ubuntu-latest, windows-latest, macos-latest] arch: [all] wheel-version: ['cp39*', 'cp310*', 'cp311*', 'cp312*', 'cp313*'] @@ -91,7 +91,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-22.04] + os: [ubuntu-latest] arch: [all] wheel-version: ['cp39*', 'cp310*', 'cp311*', 'cp312*', 'cp313*'] diff --git a/.github/workflows/test_branches.yml b/.github/workflows/test_branches.yml index 3315c5250df..653ef6eba54 100644 --- a/.github/workflows/test_branches.yml +++ b/.github/workflows/test_branches.yml @@ -234,7 +234,7 @@ jobs: # have support for OSX. - name: Set up UI testing infrastructure if: ${{ matrix.TARGET != 'osx' }} - uses: pyvista/setup-headless-display-action@v2 + uses: pyvista/setup-headless-display-action@v3 with: qt: true pyvista: false @@ -428,6 +428,9 @@ jobs: mkdir -p "$DOWNLOAD_DIR" echo "TPL_DIR=$TPL_DIR" >> $GITHUB_ENV echo "DOWNLOAD_DIR=$DOWNLOAD_DIR" >> $GITHUB_ENV + # Create a new PYOMO_PATH variable so we can ensure that we are actually + # getting the right PATH at the end + echo "PYOMO_PATH=$PATH" >> $GITHUB_ENV - name: Install Ipopt if: ${{ ! matrix.slim }} @@ -435,6 +438,8 @@ jobs: IPOPT_DIR=$TPL_DIR/ipopt echo "$IPOPT_DIR" >> $GITHUB_PATH echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$IPOPT_DIR" >> $GITHUB_ENV + NEW_PYOMO_PATH="$IPOPT_DIR:$PYOMO_PATH" + echo "PYOMO_PATH=$NEW_PYOMO_PATH" >> $GITHUB_ENV mkdir -p $IPOPT_DIR IPOPT_TAR=${DOWNLOAD_DIR}/ipopt.tar.gz if test ! -e $IPOPT_TAR; then @@ -511,7 +516,9 @@ jobs: - name: Install GAMS Python bindings if: ${{ ! matrix.slim }} run: | - GAMS_DIR="${env:TPL_DIR}/gams" + GAMS_DIR="$TPL_DIR/gams" + NEW_PYOMO_PATH="$GAMS_DIR:$PYOMO_PATH" + echo "PYOMO_PATH=$NEW_PYOMO_PATH" >> $GITHUB_ENV py_ver=$($PYTHON_EXE -c 'import sys;v="_%s%s" % sys.version_info[:2] \ ;print(v if v != "_27" else "")') if test -e $GAMS_DIR/apifiles/Python/api$py_ver; then @@ -528,6 +535,17 @@ jobs: $BARON_DIR = "${env:TPL_DIR}/baron" echo "$BARON_DIR" | ` Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + $CURRENT_PYOMO_PATH="${env:PYOMO_PATH}" + # Prepend BARON_DIR with appropriate path separator + if ( "${{matrix.TARGET}}" -eq "win" ) { + $PATH_SEPARATOR = ";" + } else { + $PATH_SEPARATOR = ":" + } + $NEW_PYOMO_PATH = "$BARON_DIR$PATH_SEPARATOR$CURRENT_PYOMO_PATH" + echo "New PYOMO_PATH: $NEW_PYOMO_PATH" + echo "PYOMO_PATH=$NEW_PYOMO_PATH" | ` + Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append $URL = "https://minlp-downloads.nyc3.cdn.digitaloceanspaces.com/xecs/baron/current/" if ( "${{matrix.TARGET}}" -eq "win" ) { $INSTALLER = "${env:DOWNLOAD_DIR}/baron_install.exe" @@ -562,6 +580,8 @@ jobs: run: | GJH_DIR="$TPL_DIR/gjh" echo "${GJH_DIR}" >> $GITHUB_PATH + NEW_PYOMO_PATH="$GJH_DIR:$PYOMO_PATH" + echo "PYOMO_PATH=$NEW_PYOMO_PATH" >> $GITHUB_ENV INSTALL_DIR="${DOWNLOAD_DIR}/gjh" if test ! -e "$INSTALL_DIR/bin"; then mkdir -p "$INSTALL_DIR" @@ -637,6 +657,11 @@ jobs: - name: Report pyomo plugin information run: | + # MRM / Jan 9, 2025: We update the PATH manually to make sure we + # capture all of our changes. This is necessary because of an + # issue with how the PATH rearranges on Windows. + # Issue: https://github.com/actions/runner-images/issues/11328 + export PATH=$PYOMO_PATH echo "$PATH" pyomo help --solvers || exit 1 pyomo help --transformations || exit 1 @@ -645,6 +670,7 @@ jobs: - name: Run Pyomo tests if: matrix.mpi == 0 run: | + export PATH=$PYOMO_PATH $PYTHON_EXE -m pytest -v \ -W ignore::Warning ${{matrix.category}} \ pyomo `pwd`/pyomo-model-libraries \ diff --git a/.github/workflows/test_pr_and_main.yml b/.github/workflows/test_pr_and_main.yml index 98ec7fd933b..2506573db4d 100644 --- a/.github/workflows/test_pr_and_main.yml +++ b/.github/workflows/test_pr_and_main.yml @@ -152,7 +152,7 @@ jobs: PACKAGES: pyutilib - os: ubuntu-latest - python: pypy-3.9 + python: 'pypy-3.10' skip_doctest: 1 TARGET: linux PYENV: pip @@ -266,7 +266,7 @@ jobs: # have support for OSX. - name: Set up UI testing infrastructure if: ${{ matrix.TARGET != 'osx' }} - uses: pyvista/setup-headless-display-action@v2 + uses: pyvista/setup-headless-display-action@v3 with: qt: true pyvista: false @@ -460,6 +460,9 @@ jobs: mkdir -p "$DOWNLOAD_DIR" echo "TPL_DIR=$TPL_DIR" >> $GITHUB_ENV echo "DOWNLOAD_DIR=$DOWNLOAD_DIR" >> $GITHUB_ENV + # Create a new PYOMO_PATH variable so we can ensure that we are actually + # getting the right PATH at the end + echo "PYOMO_PATH=$PATH" >> $GITHUB_ENV - name: Install Ipopt if: ${{ ! matrix.slim }} @@ -467,6 +470,8 @@ jobs: IPOPT_DIR=$TPL_DIR/ipopt echo "$IPOPT_DIR" >> $GITHUB_PATH echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$IPOPT_DIR" >> $GITHUB_ENV + NEW_PYOMO_PATH="$IPOPT_DIR:$PYOMO_PATH" + echo "PYOMO_PATH=$NEW_PYOMO_PATH" >> $GITHUB_ENV mkdir -p $IPOPT_DIR IPOPT_TAR=${DOWNLOAD_DIR}/ipopt.tar.gz if test ! -e $IPOPT_TAR; then @@ -543,7 +548,9 @@ jobs: - name: Install GAMS Python bindings if: ${{ ! matrix.slim }} run: | - GAMS_DIR="${env:TPL_DIR}/gams" + GAMS_DIR="$TPL_DIR/gams" + NEW_PYOMO_PATH="$GAMS_DIR:$PYOMO_PATH" + echo "PYOMO_PATH=$NEW_PYOMO_PATH" >> $GITHUB_ENV py_ver=$($PYTHON_EXE -c 'import sys;v="_%s%s" % sys.version_info[:2] \ ;print(v if v != "_27" else "")') if test -e $GAMS_DIR/apifiles/Python/api$py_ver; then @@ -560,6 +567,17 @@ jobs: $BARON_DIR = "${env:TPL_DIR}/baron" echo "$BARON_DIR" | ` Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + $CURRENT_PYOMO_PATH="${env:PYOMO_PATH}" + # Prepend BARON_DIR with appropriate path separator + if ( "${{matrix.TARGET}}" -eq "win" ) { + $PATH_SEPARATOR = ";" + } else { + $PATH_SEPARATOR = ":" + } + $NEW_PYOMO_PATH = "$BARON_DIR$PATH_SEPARATOR$CURRENT_PYOMO_PATH" + echo "New PYOMO_PATH: $NEW_PYOMO_PATH" + echo "PYOMO_PATH=$NEW_PYOMO_PATH" | ` + Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append $URL = "https://minlp-downloads.nyc3.cdn.digitaloceanspaces.com/xecs/baron/current/" if ( "${{matrix.TARGET}}" -eq "win" ) { $INSTALLER = "${env:DOWNLOAD_DIR}/baron_install.exe" @@ -594,6 +612,8 @@ jobs: run: | GJH_DIR="$TPL_DIR/gjh" echo "${GJH_DIR}" >> $GITHUB_PATH + NEW_PYOMO_PATH="$GJH_DIR:$PYOMO_PATH" + echo "PYOMO_PATH=$NEW_PYOMO_PATH" >> $GITHUB_ENV INSTALL_DIR="${DOWNLOAD_DIR}/gjh" if test ! -e "$INSTALL_DIR/bin"; then mkdir -p "$INSTALL_DIR" @@ -670,6 +690,11 @@ jobs: - name: Report pyomo plugin information run: | + # MRM / Jan 9, 2025: We update the PATH manually to make sure we + # capture all of our changes. This is necessary because of an + # issue with how the PATH rearranges on Windows. + # Issue: https://github.com/actions/runner-images/issues/11328 + export PATH=$PYOMO_PATH echo "$PATH" pyomo help --solvers || exit 1 pyomo help --transformations || exit 1 @@ -678,6 +703,7 @@ jobs: - name: Run Pyomo tests if: matrix.mpi == 0 run: | + export PATH=$PYOMO_PATH $PYTHON_EXE -m pytest -v \ -W ignore::Warning ${{matrix.category}} \ pyomo `pwd`/pyomo-model-libraries \ diff --git a/README.md b/README.md index 1cb773788f2..45ccce5b769 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Pyomo is available under the BSD License - see the Pyomo is currently tested with the following Python implementations: * CPython: 3.9, 3.10, 3.11, 3.12, 3.13 -* PyPy: 3.9 +* PyPy: 3.10 _Testing and support policy_: diff --git a/doc/OnlineDocs/explanation/analysis/doe/doe.rst b/doc/OnlineDocs/explanation/analysis/doe/doe.rst index f80878b67eb..05d9d867e2b 100644 --- a/doc/OnlineDocs/explanation/analysis/doe/doe.rst +++ b/doc/OnlineDocs/explanation/analysis/doe/doe.rst @@ -3,7 +3,7 @@ Pyomo.DoE **Pyomo.DoE** (Pyomo Design of Experiments) is a Python library for model-based design of experiments using science-based models. -Pyomo.DoE was developed by **Jialu Wang** and **Alexander W. Dowling** at the University of Notre Dame as part of the `Carbon Capture Simulation for Industry Impact (CCSI2) `_. +Pyomo.DoE was developed by **Jialu Wang** and **Alexander W. Dowling** at the University of Notre Dame as part of the `Carbon Capture Simulation for Industry Impact (CCSI2) `_. project, funded through the U.S. Department Of Energy Office of Fossil Energy. If you use Pyomo.DoE, please cite: diff --git a/doc/OnlineDocs/explanation/analysis/sensitivity_toolbox.rst b/doc/OnlineDocs/explanation/analysis/sensitivity_toolbox.rst index 17c0e765541..6d3bbea426a 100644 --- a/doc/OnlineDocs/explanation/analysis/sensitivity_toolbox.rst +++ b/doc/OnlineDocs/explanation/analysis/sensitivity_toolbox.rst @@ -67,6 +67,18 @@ And finally we call sIPOPT or k_aug: >>> m_sipopt = sensitivity_calculation('sipopt', m, [m.eta1, m.eta2], [m.perturbed_eta1, m.perturbed_eta2], tee=False) >>> m_kaug_dsdp = sensitivity_calculation('k_aug', m, [m.eta1, m.eta2], [m.perturbed_eta1, m.perturbed_eta2], tee=False) +.. testcode:: python + :skipif: not sipopt_available or not k_aug_available or not dot_sens_available + :hide: + + # The x3 result can come back -0.000 depending on the platform or + # solver version; map it so that tests don't fail. + for _m in (m, m_sipopt, m_kaug_dsdp): + if f'{_m.x3():.3f}' == '-0.000': + _m.x3 = 0. + if f'{m_sipopt.sens_sol_state_1[m_sipopt.x3]:.3f}' == '-0.000': + m_sipopt.sens_sol_state_1[m_sipopt.x3] = 0. + The first argument specifies the method, either 'sipopt' or 'k_aug'. The second argument is the Pyomo model. The third argument is a list of the original parameters. The fourth argument is a list of the perturbed parameters. It's important that these two lists are the same length and in the same order. First, we can inspect the initial point: @@ -138,7 +150,7 @@ Note that k_aug does not save the solution with the original parameter values. F x2 = 0.667 >>> print("x3 = %0.3f" % x3) - x3 = -0.000 + x3 = 0.000 # *k_aug* # New parameter values: @@ -162,7 +174,7 @@ Note that k_aug does not save the solution with the original parameter values. F x2 = 0.667 >>> print("x3 = %0.3f" % x3) - x3 = -0.000 + x3 = 0.000 Installing sIPOPT and k_aug diff --git a/pyomo/common/config.py b/pyomo/common/config.py index b6ff0ebfee3..ddeac28e521 100644 --- a/pyomo/common/config.py +++ b/pyomo/common/config.py @@ -1840,7 +1840,11 @@ def __call__( assert default is NOTSET else: fields += ('domain',) - kwds['default'] = self.value() if default is NOTSET else default + if default is NOTSET: + default = self.value() + if default is NOTSET: + default = None + kwds['default'] = default assert implicit is NOTSET assert implicit_domain is NOTSET for field in fields: diff --git a/pyomo/contrib/doe/doe.py b/pyomo/contrib/doe/doe.py index 5f3151961fb..3a616b714b8 100644 --- a/pyomo/contrib/doe/doe.py +++ b/pyomo/contrib/doe/doe.py @@ -1458,7 +1458,7 @@ def compute_FIM_full_factorial( } ) - succeses = 0 + successes = 0 failures = 0 total_points = np.prod( np.array([len(v) for k, v in design_ranges_enum.items()]) @@ -1477,14 +1477,14 @@ def compute_FIM_full_factorial( # Compute FIM with given options try: - curr_point = succeses + failures + 1 + curr_point = successes + failures + 1 # Logging information for each run self.logger.info("This is run %s out of %s.", curr_point, total_points) # Attempt the FIM computation self.compute_FIM(model=model, method=method) - succeses += 1 + successes += 1 # iteration time iter_t = iter_timer.toc(msg=None) diff --git a/pyomo/contrib/pynumero/algorithms/solvers/tests/test_cyipopt_solver.py b/pyomo/contrib/pynumero/algorithms/solvers/tests/test_cyipopt_solver.py index 8a35449d94d..9578be510a7 100644 --- a/pyomo/contrib/pynumero/algorithms/solvers/tests/test_cyipopt_solver.py +++ b/pyomo/contrib/pynumero/algorithms/solvers/tests/test_cyipopt_solver.py @@ -11,7 +11,7 @@ import pyomo.common.unittest as unittest import pyomo.environ as pyo -import os +from pyomo.common.tempfiles import TempfileManager from pyomo.contrib.pynumero.dependencies import ( numpy as np, @@ -219,24 +219,25 @@ def test_model1_with_scaling(self): m.scaling_factor[m.d] = 3.0 # scale the inequality constraint m.scaling_factor[m.x[1]] = 4.0 # scale one of the x variables - cynlp = CyIpoptNLP(PyomoNLP(m)) - options = { - 'nlp_scaling_method': 'user-scaling', - 'output_file': '_cyipopt-scaling.log', - 'file_print_level': 10, - 'max_iter': 0, - } - solver = CyIpoptSolver(cynlp, options=options) - x, info = solver.solve() - - with open('_cyipopt-scaling.log', 'r') as fd: - solver_trace = fd.read() - cynlp.close() - os.remove('_cyipopt-scaling.log') - - # check for the following strings in the log and then delete the log + with TempfileManager.new_context() as temp: + cynlp = CyIpoptNLP(PyomoNLP(m)) + logfile = temp.create_tempfile('_cyipopt-scaling.log') + options = { + 'nlp_scaling_method': 'user-scaling', + 'output_file': logfile, + 'file_print_level': 10, + 'max_iter': 0, + } + solver = CyIpoptSolver(cynlp, options=options) + x, info = solver.solve() + cynlp.close() + + with open(logfile, 'r') as fd: + solver_trace = fd.read() + + # check for the following strings in the log self.assertIn('nlp_scaling_method = user-scaling', solver_trace) - self.assertIn('output_file = _cyipopt-scaling.log', solver_trace) + self.assertIn(f"output_file = {logfile}", solver_trace) self.assertIn('objective scaling factor = 1e-06', solver_trace) self.assertIn('x scaling provided', solver_trace) self.assertIn('c scaling provided', solver_trace) diff --git a/pyomo/contrib/pynumero/algorithms/solvers/tests/test_pyomo_ext_cyipopt.py b/pyomo/contrib/pynumero/algorithms/solvers/tests/test_pyomo_ext_cyipopt.py index 0036a6b3623..5cb0fef91ba 100644 --- a/pyomo/contrib/pynumero/algorithms/solvers/tests/test_pyomo_ext_cyipopt.py +++ b/pyomo/contrib/pynumero/algorithms/solvers/tests/test_pyomo_ext_cyipopt.py @@ -9,9 +9,9 @@ # This software is distributed under the 3-clause BSD License. # ___________________________________________________________________________ -import os import pyomo.common.unittest as unittest import pyomo.environ as pyo +from pyomo.common.tempfiles import TempfileManager from pyomo.contrib.pynumero.dependencies import ( numpy as np, @@ -157,33 +157,33 @@ def test_pyomo_external_model_scaling(self): m.scaling_factor[m.F_con] = 8.0 # scale the pyomo constraint m.scaling_factor[m.Pin_con] = 9.0 # scale the pyomo constraint - cyipopt_problem = PyomoExternalCyIpoptProblem( - pyomo_model=m, - ex_input_output_model=PressureDropModel(), - inputs=[m.Pin, m.c1, m.c2, m.F], - outputs=[m.P1, m.P2], - outputs_eqn_scaling=[10.0, 11.0], - nl_file_options={'file_determinism': 2}, - ) - - # solve the problem - options = { - 'hessian_approximation': 'limited-memory', - 'nlp_scaling_method': 'user-scaling', - 'output_file': '_cyipopt-pyomo-ext-scaling.log', - 'file_print_level': 10, - 'max_iter': 0, - } - solver = CyIpoptSolver(cyipopt_problem, options=options) - x, info = solver.solve(tee=False) - - with open('_cyipopt-pyomo-ext-scaling.log', 'r') as fd: - solver_trace = fd.read() - cyipopt_problem.close() - os.remove('_cyipopt-pyomo-ext-scaling.log') + with TempfileManager.new_context() as temp: + cyipopt_problem = PyomoExternalCyIpoptProblem( + pyomo_model=m, + ex_input_output_model=PressureDropModel(), + inputs=[m.Pin, m.c1, m.c2, m.F], + outputs=[m.P1, m.P2], + outputs_eqn_scaling=[10.0, 11.0], + nl_file_options={'file_determinism': 2}, + ) + logfile = temp.create_tempfile('_cyipopt-pyomo-ext-scaling.log') + # solve the problem + options = { + 'hessian_approximation': 'limited-memory', + 'nlp_scaling_method': 'user-scaling', + 'output_file': logfile, + 'file_print_level': 10, + 'max_iter': 0, + } + solver = CyIpoptSolver(cyipopt_problem, options=options) + x, info = solver.solve(tee=False) + cyipopt_problem.close() + + with open(logfile, 'r') as fd: + solver_trace = fd.read() self.assertIn('nlp_scaling_method = user-scaling', solver_trace) - self.assertIn('output_file = _cyipopt-pyomo-ext-scaling.log', solver_trace) + self.assertIn(f"output_file = {logfile}", solver_trace) self.assertIn('objective scaling factor = 0.1', solver_trace) self.assertIn('x scaling provided', solver_trace) self.assertIn('c scaling provided', solver_trace) @@ -232,35 +232,33 @@ def test_pyomo_external_model_ndarray_scaling(self): m.scaling_factor[m.Pin_con] = 9.0 # scale the pyomo constraint # test that this all works with ndarray input as well - cyipopt_problem = PyomoExternalCyIpoptProblem( - pyomo_model=m, - ex_input_output_model=PressureDropModel(), - inputs=[m.Pin, m.c1, m.c2, m.F], - outputs=[m.P1, m.P2], - outputs_eqn_scaling=np.asarray([10.0, 11.0], dtype=np.float64), - nl_file_options={'file_determinism': 2}, - ) - - # solve the problem - options = { - 'hessian_approximation': 'limited-memory', - 'nlp_scaling_method': 'user-scaling', - 'output_file': '_cyipopt-pyomo-ext-scaling-ndarray.log', - 'file_print_level': 10, - 'max_iter': 0, - } - solver = CyIpoptSolver(cyipopt_problem, options=options) - x, info = solver.solve(tee=False) - - with open('_cyipopt-pyomo-ext-scaling-ndarray.log', 'r') as fd: - solver_trace = fd.read() - cyipopt_problem.close() - os.remove('_cyipopt-pyomo-ext-scaling-ndarray.log') + with TempfileManager.new_context() as temp: + cyipopt_problem = PyomoExternalCyIpoptProblem( + pyomo_model=m, + ex_input_output_model=PressureDropModel(), + inputs=[m.Pin, m.c1, m.c2, m.F], + outputs=[m.P1, m.P2], + outputs_eqn_scaling=np.asarray([10.0, 11.0], dtype=np.float64), + nl_file_options={'file_determinism': 2}, + ) + logfile = temp.create_tempfile('_cyipopt-pyomo-ext-scaling-ndarray.log') + # solve the problem + options = { + 'hessian_approximation': 'limited-memory', + 'nlp_scaling_method': 'user-scaling', + 'output_file': logfile, + 'file_print_level': 10, + 'max_iter': 0, + } + solver = CyIpoptSolver(cyipopt_problem, options=options) + x, info = solver.solve(tee=False) + cyipopt_problem.close() + + with open(logfile, 'r') as fd: + solver_trace = fd.read() self.assertIn('nlp_scaling_method = user-scaling', solver_trace) - self.assertIn( - 'output_file = _cyipopt-pyomo-ext-scaling-ndarray.log', solver_trace - ) + self.assertIn(f'output_file = {logfile}', solver_trace) self.assertIn('objective scaling factor = 0.1', solver_trace) self.assertIn('x scaling provided', solver_trace) self.assertIn('c scaling provided', solver_trace) diff --git a/pyomo/contrib/pynumero/examples/tests/test_cyipopt_examples.py b/pyomo/contrib/pynumero/examples/tests/test_cyipopt_examples.py index 2df43c1e797..f735e98b026 100644 --- a/pyomo/contrib/pynumero/examples/tests/test_cyipopt_examples.py +++ b/pyomo/contrib/pynumero/examples/tests/test_cyipopt_examples.py @@ -10,14 +10,16 @@ # ___________________________________________________________________________ import os.path +from io import StringIO +import logging + from pyomo.common.fileutils import this_file_dir, import_file +from pyomo.common.tempfiles import TempfileManager import pyomo.common.unittest as unittest import pyomo.environ as pyo from pyomo.common.dependencies import attempt_import from pyomo.common.log import LoggingIntercept from pyomo.opt import TerminationCondition -from io import StringIO -import logging from pyomo.contrib.pynumero.dependencies import ( numpy as np, @@ -87,30 +89,34 @@ def test_external_grey_box_react_example_maximize_cb_outputs_scaling(self): 'maximize_cb_ratio_residuals.py', ) ) - aoptions = { - 'nlp_scaling_method': 'user-scaling', - 'output_file': '_cyipopt-external-greybox-react-scaling.log', - 'file_print_level': 10, - } - m = ex.maximize_cb_ratio_residuals_with_output_scaling( - additional_options=aoptions - ) - self.assertAlmostEqual(pyo.value(m.reactor.inputs['sv']), 1.26541996, places=3) - self.assertAlmostEqual( - pyo.value(m.reactor.inputs['cb']), 1071.7410089, places=2 - ) - self.assertAlmostEqual( - pyo.value(m.reactor.outputs['cb_ratio']), 0.15190409266, places=3 - ) - with open('_cyipopt-external-greybox-react-scaling.log', 'r') as fd: - solver_trace = fd.read() - os.remove('_cyipopt-external-greybox-react-scaling.log') + with TempfileManager.new_context() as temp: + logfile = temp.create_tempfile( + '_cyipopt-external-greybox-react-scaling.log' + ) + aoptions = { + 'nlp_scaling_method': 'user-scaling', + 'output_file': logfile, + 'file_print_level': 10, + } + m = ex.maximize_cb_ratio_residuals_with_output_scaling( + additional_options=aoptions + ) + self.assertAlmostEqual( + pyo.value(m.reactor.inputs['sv']), 1.26541996, places=3 + ) + self.assertAlmostEqual( + pyo.value(m.reactor.inputs['cb']), 1071.7410089, places=2 + ) + self.assertAlmostEqual( + pyo.value(m.reactor.outputs['cb_ratio']), 0.15190409266, places=3 + ) + + with open(logfile, 'r') as fd: + solver_trace = fd.read() self.assertIn('nlp_scaling_method = user-scaling', solver_trace) - self.assertIn( - 'output_file = _cyipopt-external-greybox-react-scaling.log', solver_trace - ) + self.assertIn(f'output_file = {logfile}', solver_trace) self.assertIn('objective scaling factor = 1', solver_trace) self.assertIn('x scaling provided', solver_trace) self.assertIn('c scaling provided', solver_trace) diff --git a/pyomo/contrib/pynumero/interfaces/tests/test_external_grey_box_model.py b/pyomo/contrib/pynumero/interfaces/tests/test_external_grey_box_model.py index 0fc342c4e40..1ea17b5e223 100644 --- a/pyomo/contrib/pynumero/interfaces/tests/test_external_grey_box_model.py +++ b/pyomo/contrib/pynumero/interfaces/tests/test_external_grey_box_model.py @@ -9,9 +9,9 @@ # This software is distributed under the 3-clause BSD License. # ___________________________________________________________________________ -import os import pyomo.common.unittest as unittest import pyomo.environ as pyo +from pyomo.common.tempfiles import TempfileManager from pyomo.contrib.pynumero.dependencies import ( numpy as np, @@ -31,8 +31,11 @@ from pyomo.contrib.pynumero.algorithms.solvers.cyipopt_solver import cyipopt_available -from ..external_grey_box import ExternalGreyBoxModel, ExternalGreyBoxBlock -from ..pyomo_nlp import PyomoGreyBoxNLP +from pyomo.contrib.pynumero.interfaces.external_grey_box import ( + ExternalGreyBoxModel, + ExternalGreyBoxBlock, +) +from pyomo.contrib.pynumero.interfaces.pyomo_nlp import PyomoGreyBoxNLP from pyomo.contrib.pynumero.interfaces.tests.compare_utils import ( check_vectors_specific_order, check_sparse_matrix_specific_order, @@ -2074,24 +2077,23 @@ def test_external_greybox_solve_scaling(self): m.scaling_factor[m.mu] = 1.9 m.scaling_factor[m.pincon] = 2.2 - solver = pyo.SolverFactory('cyipopt') - solver.config.options = { - 'hessian_approximation': 'limited-memory', - 'nlp_scaling_method': 'user-scaling', - 'output_file': '_cyipopt-external-greybox-scaling.log', - 'file_print_level': 10, - 'max_iter': 0, - } - status = solver.solve(m, tee=False) - - with open('_cyipopt-external-greybox-scaling.log', 'r') as fd: - solver_trace = fd.read() - os.remove('_cyipopt-external-greybox-scaling.log') + with TempfileManager.new_context() as temp: + logfile = temp.create_tempfile('_cyipopt-external-greybox-scaling.log') + solver = pyo.SolverFactory('cyipopt') + solver.config.options = { + 'hessian_approximation': 'limited-memory', + 'nlp_scaling_method': 'user-scaling', + 'output_file': logfile, + 'file_print_level': 10, + 'max_iter': 0, + } + status = solver.solve(m, tee=False) + + with open(logfile, 'r') as fd: + solver_trace = fd.read() self.assertIn('nlp_scaling_method = user-scaling', solver_trace) - self.assertIn( - 'output_file = _cyipopt-external-greybox-scaling.log', solver_trace - ) + self.assertIn(f'output_file = {logfile}', solver_trace) self.assertIn('objective scaling factor = 0.1', solver_trace) self.assertIn('x scaling provided', solver_trace) self.assertIn('c scaling provided', solver_trace) @@ -2149,4 +2151,4 @@ def test_external_greybox_solve_scaling(self): if __name__ == '__main__': - TestPyomoGreyBoxNLP().test_external_greybox_solve(self) + TestPyomoGreyBoxNLP().test_external_greybox_solve() diff --git a/pyomo/contrib/pynumero/interfaces/tests/test_pyomo_grey_box_nlp.py b/pyomo/contrib/pynumero/interfaces/tests/test_pyomo_grey_box_nlp.py index ecadf40e5cf..053c9aba4ea 100644 --- a/pyomo/contrib/pynumero/interfaces/tests/test_pyomo_grey_box_nlp.py +++ b/pyomo/contrib/pynumero/interfaces/tests/test_pyomo_grey_box_nlp.py @@ -9,9 +9,9 @@ # This software is distributed under the 3-clause BSD License. # ___________________________________________________________________________ -import os import pyomo.common.unittest as unittest import pyomo.environ as pyo +from pyomo.common.tempfiles import TempfileManager from pyomo.contrib.pynumero.dependencies import ( numpy as np, @@ -2495,24 +2495,23 @@ def test_external_greybox_solve_scaling(self): m.scaling_factor[m.mu] = 1.9 m.scaling_factor[m.pincon] = 2.2 - solver = pyo.SolverFactory('cyipopt') - solver.config.options = { - 'hessian_approximation': 'limited-memory', - 'nlp_scaling_method': 'user-scaling', - 'output_file': '_cyipopt-external-greybox-scaling.log', - 'file_print_level': 10, - 'max_iter': 0, - } - status = solver.solve(m, tee=False) - - with open('_cyipopt-external-greybox-scaling.log', 'r') as fd: - solver_trace = fd.read() - os.remove('_cyipopt-external-greybox-scaling.log') + with TempfileManager.new_context() as temp: + logfile = temp.create_tempfile('_cyipopt-external-greybox-scaling.log') + solver = pyo.SolverFactory('cyipopt') + solver.config.options = { + 'hessian_approximation': 'limited-memory', + 'nlp_scaling_method': 'user-scaling', + 'output_file': logfile, + 'file_print_level': 10, + 'max_iter': 0, + } + status = solver.solve(m, tee=False) + + with open(logfile, 'r') as fd: + solver_trace = fd.read() self.assertIn('nlp_scaling_method = user-scaling', solver_trace) - self.assertIn( - 'output_file = _cyipopt-external-greybox-scaling.log', solver_trace - ) + self.assertIn(f'output_file = {logfile}', solver_trace) self.assertIn('objective scaling factor = 0.1', solver_trace) self.assertIn('x scaling provided', solver_trace) self.assertIn('c scaling provided', solver_trace) diff --git a/pyomo/contrib/simplification/build.py b/pyomo/contrib/simplification/build.py index b4bec63088a..d7fac9522dc 100644 --- a/pyomo/contrib/simplification/build.py +++ b/pyomo/contrib/simplification/build.py @@ -63,7 +63,7 @@ def build_ginac_library(parallel=None, argv=None, env=None): assert subprocess.run(make_cmd, cwd=cln_dir, env=env).returncode == 0 assert subprocess.run(install_cmd, cwd=cln_dir, env=env).returncode == 0 - url = 'https://www.ginac.de/ginac-1.8.7.tar.bz2' + url = 'https://www.ginac.de/ginac-1.8.8.tar.bz2' ginac_dir = os.path.join(tmpdir, 'ginac') downloader.set_destination_filename(ginac_dir) logger.info( diff --git a/pyomo/core/base/indexed_component.py b/pyomo/core/base/indexed_component.py index ee1fe1e0037..4fcbd30d1ff 100644 --- a/pyomo/core/base/indexed_component.py +++ b/pyomo/core/base/indexed_component.py @@ -344,7 +344,7 @@ def _create_objects_for_deepcopy(self, memo, component_list): # For indexed components, we will pre-emptively clone all # component data objects as well (as those are the objects # that will be referenced by things like expressions). It - # is important to only clone "normal" ComponentData obects: + # is important to only clone "normal" ComponentData objects: # so we will want to skip this for all scalar components # (where the _data points back to self) and references # (where the data may be stored outside this block tree and diff --git a/pyomo/core/expr/taylor_series.py b/pyomo/core/expr/taylor_series.py index 2658dd36ff5..7dc24f3ccf4 100644 --- a/pyomo/core/expr/taylor_series.py +++ b/pyomo/core/expr/taylor_series.py @@ -43,7 +43,7 @@ def taylor_series_expansion( The method for differentiation. order: The order of the taylor series expansion If order is not 1, then symbolic differentiation must - be used (differentiation.Modes.reverse_sybolic or + be used (differentiation.Modes.reverse_symbolic or differentiation.Modes.sympy). Returns diff --git a/pyomo/solvers/plugins/solvers/cplex_direct.py b/pyomo/solvers/plugins/solvers/cplex_direct.py index 93d8015514e..b758453df7d 100644 --- a/pyomo/solvers/plugins/solvers/cplex_direct.py +++ b/pyomo/solvers/plugins/solvers/cplex_direct.py @@ -846,7 +846,9 @@ def _postsolve(self): if extract_slacks: linear_slacks = self._solver_model.solution.get_linear_slacks() - qudratic_slacks = self._solver_model.solution.get_quadratic_slacks() + quadratic_slacks = ( + self._solver_model.solution.get_quadratic_slacks() + ) for i, con_name in enumerate( self._solver_model.linear_constraints.get_names() ): @@ -869,7 +871,7 @@ def _postsolve(self): for i, con_name in enumerate( self._solver_model.quadratic_constraints.get_names() ): - soln_constraints[con_name]["Slack"] = qudratic_slacks[i] + soln_constraints[con_name]["Slack"] = quadratic_slacks[i] elif self._load_solutions: if cpxprob.solution.get_solution_type() > 0: self.load_vars()