From bfdfc00b97727555265de517cd06066fe0cd5d9a Mon Sep 17 00:00:00 2001 From: Eytan Adler Date: Thu, 9 May 2024 14:53:33 -0400 Subject: [PATCH 01/30] Added minimum option to KS comp and tests --- openmdao/components/ks_comp.py | 18 +++++-- openmdao/components/tests/test_ks_comp.py | 63 ++++++++++++++++++++++- 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/openmdao/components/ks_comp.py b/openmdao/components/ks_comp.py index 74ce3ecff0..9087feda5d 100644 --- a/openmdao/components/ks_comp.py +++ b/openmdao/components/ks_comp.py @@ -159,8 +159,12 @@ def initialize(self): self.options.declare('width', types=int, default=1, desc='Width of constraint vector.') self.options.declare('vec_size', types=int, default=1, desc='The number of rows to independently aggregate.') + self.options.declare('minimum', types=bool, default=False, + desc='Return the minimum instead of the maximum by multiplying both the inputs ' + 'and output by -1. It is not recommended to use both this option and the ' + 'lower_flag option (it will return the negative of the aggregated max.)') self.options.declare('lower_flag', types=bool, default=False, - desc="Set to True to reverse sign of input constraints.") + desc='Set to True to reverse sign of input constraints.') self.options.declare('rho', 50.0, desc="Constraint Aggregation Factor.") self.options.declare('upper', 0.0, desc="Upper bound for constraint, default is zero.") self.options.declare('add_constraint', types=bool, default=False, @@ -229,8 +233,15 @@ def compute(self, inputs, outputs): con_val = inputs['g'] - opt['upper'] if opt['lower_flag']: con_val = -con_val + if opt['minimum']: + con_val = -con_val + + ks_val = KSfunction.compute(con_val, opt['rho']) - outputs['KS'] = KSfunction.compute(con_val, opt['rho']) + if opt['minimum']: + ks_val = -ks_val + + outputs['KS'] = ks_val def compute_partials(self, inputs, partials): """ @@ -244,11 +255,12 @@ def compute_partials(self, inputs, partials): Sub-jac components written to partials[output_name, input_name]. """ opt = self.options - width = opt['width'] con_val = inputs['g'] - opt['upper'] if opt['lower_flag']: con_val = -con_val + if opt['minimum']: + con_val = -con_val derivs = KSfunction.derivatives(con_val, opt['rho'])[0] diff --git a/openmdao/components/tests/test_ks_comp.py b/openmdao/components/tests/test_ks_comp.py index 006dca0927..b699aae6ad 100644 --- a/openmdao/components/tests/test_ks_comp.py +++ b/openmdao/components/tests/test_ks_comp.py @@ -6,7 +6,7 @@ import openmdao.api as om from openmdao.test_suite.components.simple_comps import DoubleArrayComp from openmdao.test_suite.test_examples.beam_optimization.multipoint_beam_stress import MultipointBeamGroup -from openmdao.utils.assert_utils import assert_near_equal +from openmdao.utils.assert_utils import assert_near_equal, assert_check_partials from openmdao.utils.testing_utils import force_check_partials @@ -320,6 +320,67 @@ def test_units(self): assert_near_equal(prob.get_val('ks.KS', indices=0), np.amax(prob.get_val('x')), tolerance=1e-8) + def test_minimum(self): + + n = 10 + + model = om.Group() + + model.add_subsystem('ks', om.KSComp(width=n, minimum=True), promotes_inputs=[('g', 'x')]) + model.set_input_defaults('x', range(n)) + + prob = om.Problem(model=model) + prob.setup() + prob.run_model() + + assert_near_equal(prob.get_val('ks.KS', indices=0), np.amin(prob.get_val('x')), tolerance=1e-8) + + def test_minimum_partials(self): + + n = 10 + + model = om.Group() + + model.add_subsystem('ks', om.KSComp(width=n, minimum=True), promotes_inputs=[('g', 'x')]) + model.set_input_defaults('x', range(n)) + + prob = om.Problem(model=model) + prob.setup(force_alloc_complex=True) + prob.run_model() + + partials = force_check_partials(prob, includes=['ks'], out_stream=None, method="cs", step=1e-200) + assert_check_partials(partials) + + def test_minimum_and_lower_flag(self): + + n = 10 + + model = om.Group() + + model.add_subsystem('ks', om.KSComp(width=n, minimum=True, lower_flag=True), promotes_inputs=[('g', 'x')]) + model.set_input_defaults('x', range(n)) + + prob = om.Problem(model=model) + prob.setup() + prob.run_model() + + assert_near_equal(prob.get_val('ks.KS', indices=0), -np.amax(prob.get_val('x')), tolerance=1e-8) + + def test_minimum_and_lower_flag_partials(self): + + n = 10 + + model = om.Group() + + model.add_subsystem('ks', om.KSComp(width=n, minimum=True, lower_flag=True), promotes_inputs=[('g', 'x')]) + model.set_input_defaults('x', range(n)) + + prob = om.Problem(model=model) + prob.setup(force_alloc_complex=True) + prob.run_model() + + partials = force_check_partials(prob, includes=['ks'], out_stream=None, method="cs", step=1e-200) + assert_check_partials(partials) if __name__ == "__main__": unittest.main() From 816ab2f1dfd2613d40c60a281aaec28188af8e60 Mon Sep 17 00:00:00 2001 From: Eytan Adler Date: Thu, 9 May 2024 21:08:58 -0400 Subject: [PATCH 02/30] Fix pep8 --- openmdao/components/ks_comp.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openmdao/components/ks_comp.py b/openmdao/components/ks_comp.py index 9087feda5d..e27f3e9b2b 100644 --- a/openmdao/components/ks_comp.py +++ b/openmdao/components/ks_comp.py @@ -160,9 +160,10 @@ def initialize(self): self.options.declare('vec_size', types=int, default=1, desc='The number of rows to independently aggregate.') self.options.declare('minimum', types=bool, default=False, - desc='Return the minimum instead of the maximum by multiplying both the inputs ' - 'and output by -1. It is not recommended to use both this option and the ' - 'lower_flag option (it will return the negative of the aggregated max.)') + desc='Return the minimum instead of the maximum by multiplying both ' + 'the inputs and output by -1. It is not recommended to use both ' + 'this option and the lower_flag option (it will return the ' + 'negative of the aggregated max.)') self.options.declare('lower_flag', types=bool, default=False, desc='Set to True to reverse sign of input constraints.') self.options.declare('rho', 50.0, desc="Constraint Aggregation Factor.") From f7ca263843257d0ea58a88b0ed548c70baf32844 Mon Sep 17 00:00:00 2001 From: swryan Date: Thu, 30 May 2024 15:03:24 -0400 Subject: [PATCH 03/30] Let bandit fail test workflow; issue warning on latest workflow --- .../workflows/openmdao_latest_workflow.yml | 21 +++++++++++++++++++ .github/workflows/openmdao_test_workflow.yml | 11 ---------- openmdao/utils/code_utils.py | 2 +- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/.github/workflows/openmdao_latest_workflow.yml b/.github/workflows/openmdao_latest_workflow.yml index 99c1aaf368..bb39528e95 100644 --- a/.github/workflows/openmdao_latest_workflow.yml +++ b/.github/workflows/openmdao_latest_workflow.yml @@ -352,6 +352,27 @@ jobs: grep '^0 unique deprecation warnings' $RPT_FILE + - name: Scan for security issues + id: bandit + continue-on-error: true + run: | + python -m pip install bandit + echo "=============================================================" + echo "Run bandit scan for high/medium severity issues" + echo "=============================================================" + cd ${{ github.workspace }} + python -m bandit -c bandit.yml -ll -r openmdao + + - name: Slack security issue + if: steps.bandit.outcome == 'failure' + uses: act10ns/slack@v2.0.0 + with: + webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }} + status: 'warning' + message: + Security issue found on `${{ matrix.NAME }}` build. + ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + - name: Slack env change if: steps.env_info.outputs.errors != '' uses: act10ns/slack@v2.0.0 diff --git a/.github/workflows/openmdao_test_workflow.yml b/.github/workflows/openmdao_test_workflow.yml index 862d080c8d..715019240d 100644 --- a/.github/workflows/openmdao_test_workflow.yml +++ b/.github/workflows/openmdao_test_workflow.yml @@ -726,7 +726,6 @@ jobs: - name: Scan for security issues if: matrix.BANDIT id: bandit - continue-on-error: true run: | python -m pip install bandit echo "=============================================================" @@ -735,16 +734,6 @@ jobs: cd ${{ github.workspace }} python -m bandit -c bandit.yml -ll -r openmdao - - name: Slack security issue - if: steps.bandit.outcome == 'failure' - uses: act10ns/slack@v2.0.0 - with: - webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }} - status: ${{ steps.bandit.outcome }} - message: - Security issue found on `${{ matrix.NAME }}` build. - ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - coveralls: name: Finish coverage diff --git a/openmdao/utils/code_utils.py b/openmdao/utils/code_utils.py index 7f3e3c848c..f8cf5006dd 100644 --- a/openmdao/utils/code_utils.py +++ b/openmdao/utils/code_utils.py @@ -440,7 +440,7 @@ def __setstate__(self, state): The state of this object. """ self.__dict__.update(state) - self._func = eval(state['_func']) + self._func = eval(state['_func']) # nosec def _getsrc(self): if self._src is None: From e9c83e7ddf7f9a6ac6075827db31905956e8196f Mon Sep 17 00:00:00 2001 From: swryan Date: Fri, 31 May 2024 14:47:03 -0400 Subject: [PATCH 04/30] only run bandit on one job in latest workflow --- .github/workflows/openmdao_latest_workflow.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/openmdao_latest_workflow.yml b/.github/workflows/openmdao_latest_workflow.yml index bb39528e95..bdec9a4d55 100644 --- a/.github/workflows/openmdao_latest_workflow.yml +++ b/.github/workflows/openmdao_latest_workflow.yml @@ -56,6 +56,7 @@ jobs: PETSc: True PYOPTSPARSE: true SNOPT: true + BANDIT: true BUILD_DOCS: true # test latest versions on ubuntu @@ -353,6 +354,7 @@ jobs: grep '^0 unique deprecation warnings' $RPT_FILE - name: Scan for security issues + if: matrix.BANDIT id: bandit continue-on-error: true run: | From 93859b4d2563b7b4cd31a404f0d1e62ae5b3a69f Mon Sep 17 00:00:00 2001 From: swryan Date: Fri, 31 May 2024 15:28:04 -0400 Subject: [PATCH 05/30] newline --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 827fdf494e..8c970d15d6 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![PyPI version][10]][11] [![PyPI Monthly Downloads][12]][11] + # [OpenMDAO][0] OpenMDAO is an open-source high-performance computing platform for From 0abf45e29daaa82db42bcc25015cc9e936229cc4 Mon Sep 17 00:00:00 2001 From: swryan Date: Fri, 31 May 2024 15:44:43 -0400 Subject: [PATCH 06/30] rm perm --- .github/workflows/openmdao_update_poem.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/openmdao_update_poem.yml b/.github/workflows/openmdao_update_poem.yml index b757c19323..66a11882b5 100644 --- a/.github/workflows/openmdao_update_poem.yml +++ b/.github/workflows/openmdao_update_poem.yml @@ -8,7 +8,7 @@ on: types: [ opened, reopened, closed ] branches: [ master ] -permissions: {} +# permissions: {} jobs: From 1675e3b7aaba2dcfdc4828f263f4ff750c75d790 Mon Sep 17 00:00:00 2001 From: swryan Date: Fri, 31 May 2024 15:48:42 -0400 Subject: [PATCH 07/30] rm perm --- .github/workflows/openmdao_update_poem.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/openmdao_update_poem.yml b/.github/workflows/openmdao_update_poem.yml index b757c19323..66a11882b5 100644 --- a/.github/workflows/openmdao_update_poem.yml +++ b/.github/workflows/openmdao_update_poem.yml @@ -8,7 +8,7 @@ on: types: [ opened, reopened, closed ] branches: [ master ] -permissions: {} +# permissions: {} jobs: From 97faba719de2609ab1cb15cfee9e69da9ed42d56 Mon Sep 17 00:00:00 2001 From: swryan Date: Fri, 31 May 2024 15:56:01 -0400 Subject: [PATCH 08/30] sync --- .github/workflows/openmdao_update_poem.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/openmdao_update_poem.yml b/.github/workflows/openmdao_update_poem.yml index 66a11882b5..0d795dade4 100644 --- a/.github/workflows/openmdao_update_poem.yml +++ b/.github/workflows/openmdao_update_poem.yml @@ -5,7 +5,7 @@ name: Update Associated POEM on: pull_request: - types: [ opened, reopened, closed ] + types: [ opened, reopened, closed, synchronize ] branches: [ master ] # permissions: {} From 83bb310447148c5528c6aef23989a2d93e662d06 Mon Sep 17 00:00:00 2001 From: swryan Date: Fri, 31 May 2024 16:05:32 -0400 Subject: [PATCH 09/30] print --- .github/scripts/get_poem_id.py | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/scripts/get_poem_id.py b/.github/scripts/get_poem_id.py index 3b7899301b..f8bd863ee3 100644 --- a/.github/scripts/get_poem_id.py +++ b/.github/scripts/get_poem_id.py @@ -34,6 +34,7 @@ def get_poem_id(repository, pull_id): "issue", "view", "--json", "body", pull_id]) except subprocess.CalledProcessError as err: print(f"Unable to access pull request #{pull_id}:\nrc={err.returncode}") + print(pull_json) return ERROR pull_body = json.loads(pull_json)["body"] From 87eeb2a98e1eb6ab80752f6076a1f79f094aaea4 Mon Sep 17 00:00:00 2001 From: swryan Date: Fri, 31 May 2024 18:21:41 -0400 Subject: [PATCH 10/30] Revert "rm perm" This reverts commit 0abf45e29daaa82db42bcc25015cc9e936229cc4. --- .github/workflows/openmdao_update_poem.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/openmdao_update_poem.yml b/.github/workflows/openmdao_update_poem.yml index 66a11882b5..b757c19323 100644 --- a/.github/workflows/openmdao_update_poem.yml +++ b/.github/workflows/openmdao_update_poem.yml @@ -8,7 +8,7 @@ on: types: [ opened, reopened, closed ] branches: [ master ] -# permissions: {} +permissions: {} jobs: From 811a5ae9f24abaa82d8dffa4384d583b0bf9b75e Mon Sep 17 00:00:00 2001 From: swryan Date: Tue, 4 Jun 2024 13:37:27 -0400 Subject: [PATCH 11/30] remove unnecessary setup() from doc page --- .../adding_desvars_cons_objs/modifying_desvars_cons_obj.ipynb | 1 - 1 file changed, 1 deletion(-) diff --git a/openmdao/docs/openmdao_book/features/core_features/adding_desvars_cons_objs/modifying_desvars_cons_obj.ipynb b/openmdao/docs/openmdao_book/features/core_features/adding_desvars_cons_objs/modifying_desvars_cons_obj.ipynb index d3588501be..2b3a37f1cd 100644 --- a/openmdao/docs/openmdao_book/features/core_features/adding_desvars_cons_objs/modifying_desvars_cons_obj.ipynb +++ b/openmdao/docs/openmdao_book/features/core_features/adding_desvars_cons_objs/modifying_desvars_cons_obj.ipynb @@ -143,7 +143,6 @@ "# modify the constraint and run again\n", "\n", "model.set_constraint_options(name='con1', upper=-1.0)\n", - "prob.setup()\n", "prob.run_driver()\n", "print(f\"con1 = {prob.get_val('con1')}\")" ] From 18e9e76d0c25b7fab4a471b03bffbf14fcdb1c1a Mon Sep 17 00:00:00 2001 From: Rob Falck Date: Tue, 4 Jun 2024 14:23:45 -0400 Subject: [PATCH 12/30] release notes for 3.33.0 --- release_notes.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/release_notes.md b/release_notes.md index 948b2d6463..9279bc2d81 100644 --- a/release_notes.md +++ b/release_notes.md @@ -1,10 +1,56 @@ +*********************************** +# Release Notes for OpenMDAO 3.33.0 + +June 07, 2024 + +OpenMDAO 3.33.0 adds a new DriverResult object which is returned by the drivers. This replaces the previous "failed" flag that users often found confusing because a value of False indicated successful optimization. This object contains a `success` attribute for tracking whether the optimization was successful. + +Pyoptsparse print_results can be set to `minimal` to show only violated constraints. This requires a recent version of pyoptsparse to function, but will not cause errors in its absense. + +Users on FIPS-enabled sytems reported that OpenMDAO could not be used do to the use of `hashlib.md5` for non-security related purposes. We now pass the `usedforsecurity=False` argument that allows this behavior. + +Finally, a `list_vars` method has been added that lists all variables in component execution order, regardless of whether they are inputs or outputs. + +## New Features + +- Changed return of `prob.run_driver()` from a bool to an object containing information about the Driver execution. [#3214](https://github.com/OpenMDAO/OpenMDAO/pull/3214) +- Added ability to set pyoptsparse driver print_results to "minimal" [#3216](https://github.com/OpenMDAO/OpenMDAO/pull/3216) +- Moved get_free_port function to utils directory file [#3224](https://github.com/OpenMDAO/OpenMDAO/pull/3224) +- Added `usedforsecurity=False` flag to hashlib.md5 uses for FIPS-enabled systems. [#3237](https://github.com/OpenMDAO/OpenMDAO/pull/3237) +- Add a new `list_vars` method to list all variables by component in execution order. [#3233](https://github.com/OpenMDAO/OpenMDAO/pull/3233) + +## Bug Fixes + +- Updated `pyoptsparse_driver` to address change in `pyoptsparse v2.11.0` [#3218](https://github.com/OpenMDAO/OpenMDAO/pull/3218) +- Updating version/notes for 3.32.0 release [#3220](https://github.com/OpenMDAO/OpenMDAO/pull/3220) +- Added ability to handle reading case recorder files with class instances when the associated class cannot be imported [#3228](https://github.com/OpenMDAO/OpenMDAO/pull/3228) +- A couple of fixes for 'om total_coloring' and 'om partial_coloring' [#3234](https://github.com/OpenMDAO/OpenMDAO/pull/3234) +- Fix Cut&Paste error in docstring for `list_vars`. [#3238](https://github.com/OpenMDAO/OpenMDAO/pull/3238) +- Fix for SubmodelComp indexing bug. [#3239](https://github.com/OpenMDAO/OpenMDAO/pull/3239) +- Removed the 'distributed' option from ExecComp [#3245](https://github.com/OpenMDAO/OpenMDAO/pull/3245) +- Fix for group set_val when using set_input_defaults [#3248](https://github.com/OpenMDAO/OpenMDAO/pull/3248) +- Fixed a NumPy 2.0 compatibility issue in the test suite [#3251](https://github.com/OpenMDAO/OpenMDAO/pull/3251) +- Fixed error message when a component has an inconsistent set of variables across ranks. [#3254](https://github.com/OpenMDAO/OpenMDAO/pull/3254) +- Fix for incorrect warning about response size vs. dv size [#3255](https://github.com/OpenMDAO/OpenMDAO/pull/3255) +- Fixed a bug in Case when a VOI is not recorded [#3256](https://github.com/OpenMDAO/OpenMDAO/pull/3256) +- Fix the sparkline plots in the optimization report - height was too small [#3258](https://github.com/OpenMDAO/OpenMDAO/pull/3258) +- Added a wrapper for lambda functions to allow pickling. [#3259](https://github.com/OpenMDAO/OpenMDAO/pull/3259) + +## Miscellaneous + +- Added minimum version requirements to address vulnerable dependencies [#3227](https://github.com/OpenMDAO/OpenMDAO/pull/3227) +- Updated tests for constrained differential evolution [#3232](https://github.com/OpenMDAO/OpenMDAO/pull/3232) +- Updates for NumPy 2.0 compatibility and testing [#3241](https://github.com/OpenMDAO/OpenMDAO/pull/3241) +- Adjusted the CS step size in an approx_totals test for compatibility with SciPy 1.13 [#3257](https://github.com/OpenMDAO/OpenMDAO/pull/3257) +- Updated the test workflow to fail if a security issue is found [#3261](https://github.com/OpenMDAO/OpenMDAO/pull/3261) + + *********************************** # Release Notes for OpenMDAO 3.32.0 May 03, 2024 -OpenMDAO 3.32.0 is a regular update with a few new features and several bug fixes. We're continuing to refine our submodel implementation, and now we give the user explicit access to the subproblem so that they can interact with it -using the `Problem` API. +OpenMDAO 3.32.0 is a regular update with a few new features and several bug fixes. We're continuing to refine our submodel implementation, and now we give the user explicit access to the subproblem so that they can interact with it using the `Problem` API. POEM 093 is implemented, which allows caching of the linear solution which can improve performance in some situations. From afa7d00500330c47136955ea570d924db1556c82 Mon Sep 17 00:00:00 2001 From: Andrew Ellis Date: Wed, 5 Jun 2024 16:07:26 -0400 Subject: [PATCH 13/30] fix relevance for empty groups --- openmdao/utils/relevance.py | 6 +++++- openmdao/utils/tests/test_relevance.py | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/openmdao/utils/relevance.py b/openmdao/utils/relevance.py index 072719611c..0cc4156212 100644 --- a/openmdao/utils/relevance.py +++ b/openmdao/utils/relevance.py @@ -796,7 +796,8 @@ def is_relevant(self, name): def is_relevant_system(self, name): """ - Return True if the given named system is relevant. + Return True if the given named system is relevant. Returns False if + system has no subsystems with outputs Parameters ---------- @@ -810,6 +811,9 @@ def is_relevant_system(self, name): """ if not self._active: return True + + if name not in self._sys2idx: + return False return self._current_rel_sarray[self._sys2idx[name]] diff --git a/openmdao/utils/tests/test_relevance.py b/openmdao/utils/tests/test_relevance.py index 5cad0ffcde..9b9410e252 100644 --- a/openmdao/utils/tests/test_relevance.py +++ b/openmdao/utils/tests/test_relevance.py @@ -43,3 +43,21 @@ def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode): prob.run_model() chk = prob.check_totals(of='b', wrt='a', show_only_incorrect=True) assert_check_totals(chk) + +class TestRelevanceEmptyGroups(unittest.TestCase): + def test_emptygroup(self): + '''Tests that relevance checks do not error if empty groups are present''' + prob = om.Problem() + model = prob.model + + model.add_subsystem('empy_group', om.Group(), promotes=['*']) + grp2: om.Group = model.add_subsystem('non_empty_group', om.Group(), promotes=['*']) + grp2.add_subsystem('idv', om.IndepVarComp('x', val=1), promotes=['*']) + grp2.add_subsystem('comp', om.ExecComp('y=2*x**2'), promotes=['*']) + model.add_design_var('x') + model.add_objective('y') + + prob.driver = om.ScipyOptimizeDriver() + + prob.setup() + prob.run_driver() \ No newline at end of file From 4db3f82244b5ade0af16bebba7a0e4420790dd48 Mon Sep 17 00:00:00 2001 From: Andrew Ellis Date: Thu, 6 Jun 2024 17:42:10 -0400 Subject: [PATCH 14/30] added assert check totals --- openmdao/utils/relevance.py | 8 ++++---- openmdao/utils/tests/test_relevance.py | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/openmdao/utils/relevance.py b/openmdao/utils/relevance.py index 0cc4156212..b4bd6d6889 100644 --- a/openmdao/utils/relevance.py +++ b/openmdao/utils/relevance.py @@ -811,11 +811,11 @@ def is_relevant_system(self, name): """ if not self._active: return True - - if name not in self._sys2idx: - return False - return self._current_rel_sarray[self._sys2idx[name]] + try: + return self._current_rel_sarray[self._sys2idx[name]] + except KeyError: + return False def filter(self, systems, relevant=True): """ diff --git a/openmdao/utils/tests/test_relevance.py b/openmdao/utils/tests/test_relevance.py index 9b9410e252..78af30618b 100644 --- a/openmdao/utils/tests/test_relevance.py +++ b/openmdao/utils/tests/test_relevance.py @@ -60,4 +60,6 @@ def test_emptygroup(self): prob.driver = om.ScipyOptimizeDriver() prob.setup() - prob.run_driver() \ No newline at end of file + prob.run_driver() + + assert_check_totals(prob.check_totals(method='cs', out_stream=None)) \ No newline at end of file From 435b6df637a9319ef870165675887a1b4087d28d Mon Sep 17 00:00:00 2001 From: Andrew Ellis Date: Fri, 7 Jun 2024 08:06:24 -0400 Subject: [PATCH 15/30] fix tests --- openmdao/utils/tests/test_relevance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmdao/utils/tests/test_relevance.py b/openmdao/utils/tests/test_relevance.py index 78af30618b..af05c18f90 100644 --- a/openmdao/utils/tests/test_relevance.py +++ b/openmdao/utils/tests/test_relevance.py @@ -59,7 +59,7 @@ def test_emptygroup(self): prob.driver = om.ScipyOptimizeDriver() - prob.setup() + prob.setup(force_alloc_complex=True) prob.run_driver() assert_check_totals(prob.check_totals(method='cs', out_stream=None)) \ No newline at end of file From cbdbf61689517876fed3d3a00bb021c5f6313b0c Mon Sep 17 00:00:00 2001 From: swryan Date: Fri, 7 Jun 2024 10:10:56 -0400 Subject: [PATCH 16/30] fix docstring --- openmdao/utils/relevance.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openmdao/utils/relevance.py b/openmdao/utils/relevance.py index b4bd6d6889..7544b543f4 100644 --- a/openmdao/utils/relevance.py +++ b/openmdao/utils/relevance.py @@ -796,8 +796,9 @@ def is_relevant(self, name): def is_relevant_system(self, name): """ - Return True if the given named system is relevant. Returns False if - system has no subsystems with outputs + Return True if the given named system is relevant. + + Returns False if system has no subsystems with outputs. Parameters ---------- From f3fb0497424d01343633b0a20dced94e6771952e Mon Sep 17 00:00:00 2001 From: swryan Date: Fri, 7 Jun 2024 13:24:05 -0400 Subject: [PATCH 17/30] Update release notes for 3.33.0 --- release_notes.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/release_notes.md b/release_notes.md index 9279bc2d81..d723275eb3 100644 --- a/release_notes.md +++ b/release_notes.md @@ -7,7 +7,7 @@ OpenMDAO 3.33.0 adds a new DriverResult object which is returned by the drivers. Pyoptsparse print_results can be set to `minimal` to show only violated constraints. This requires a recent version of pyoptsparse to function, but will not cause errors in its absense. -Users on FIPS-enabled sytems reported that OpenMDAO could not be used do to the use of `hashlib.md5` for non-security related purposes. We now pass the `usedforsecurity=False` argument that allows this behavior. +Users on FIPS-enabled sytems reported that OpenMDAO could not be used due to the use of `hashlib.md5` for non-security related purposes. We now pass the `usedforsecurity=False` argument that allows this behavior. Finally, a `list_vars` method has been added that lists all variables in component execution order, regardless of whether they are inputs or outputs. @@ -16,33 +16,35 @@ Finally, a `list_vars` method has been added that lists all variables in compone - Changed return of `prob.run_driver()` from a bool to an object containing information about the Driver execution. [#3214](https://github.com/OpenMDAO/OpenMDAO/pull/3214) - Added ability to set pyoptsparse driver print_results to "minimal" [#3216](https://github.com/OpenMDAO/OpenMDAO/pull/3216) - Moved get_free_port function to utils directory file [#3224](https://github.com/OpenMDAO/OpenMDAO/pull/3224) +- Added `minimum` option to KSComp. [#3229](https://github.com/OpenMDAO/OpenMDAO/pull/3229) - Added `usedforsecurity=False` flag to hashlib.md5 uses for FIPS-enabled systems. [#3237](https://github.com/OpenMDAO/OpenMDAO/pull/3237) - Add a new `list_vars` method to list all variables by component in execution order. [#3233](https://github.com/OpenMDAO/OpenMDAO/pull/3233) ## Bug Fixes - Updated `pyoptsparse_driver` to address change in `pyoptsparse v2.11.0` [#3218](https://github.com/OpenMDAO/OpenMDAO/pull/3218) -- Updating version/notes for 3.32.0 release [#3220](https://github.com/OpenMDAO/OpenMDAO/pull/3220) - Added ability to handle reading case recorder files with class instances when the associated class cannot be imported [#3228](https://github.com/OpenMDAO/OpenMDAO/pull/3228) - A couple of fixes for 'om total_coloring' and 'om partial_coloring' [#3234](https://github.com/OpenMDAO/OpenMDAO/pull/3234) - Fix Cut&Paste error in docstring for `list_vars`. [#3238](https://github.com/OpenMDAO/OpenMDAO/pull/3238) - Fix for SubmodelComp indexing bug. [#3239](https://github.com/OpenMDAO/OpenMDAO/pull/3239) - Removed the 'distributed' option from ExecComp [#3245](https://github.com/OpenMDAO/OpenMDAO/pull/3245) - Fix for group set_val when using set_input_defaults [#3248](https://github.com/OpenMDAO/OpenMDAO/pull/3248) -- Fixed a NumPy 2.0 compatibility issue in the test suite [#3251](https://github.com/OpenMDAO/OpenMDAO/pull/3251) - Fixed error message when a component has an inconsistent set of variables across ranks. [#3254](https://github.com/OpenMDAO/OpenMDAO/pull/3254) - Fix for incorrect warning about response size vs. dv size [#3255](https://github.com/OpenMDAO/OpenMDAO/pull/3255) - Fixed a bug in Case when a VOI is not recorded [#3256](https://github.com/OpenMDAO/OpenMDAO/pull/3256) - Fix the sparkline plots in the optimization report - height was too small [#3258](https://github.com/OpenMDAO/OpenMDAO/pull/3258) - Added a wrapper for lambda functions to allow pickling. [#3259](https://github.com/OpenMDAO/OpenMDAO/pull/3259) +- Fixed relevance check for empty groups. [#3265](https://github.com/OpenMDAO/OpenMDAO/pull/3265) ## Miscellaneous - Added minimum version requirements to address vulnerable dependencies [#3227](https://github.com/OpenMDAO/OpenMDAO/pull/3227) - Updated tests for constrained differential evolution [#3232](https://github.com/OpenMDAO/OpenMDAO/pull/3232) - Updates for NumPy 2.0 compatibility and testing [#3241](https://github.com/OpenMDAO/OpenMDAO/pull/3241) +- Fixed a NumPy 2.0 compatibility issue in the test suite [#3251](https://github.com/OpenMDAO/OpenMDAO/pull/3251) - Adjusted the CS step size in an approx_totals test for compatibility with SciPy 1.13 [#3257](https://github.com/OpenMDAO/OpenMDAO/pull/3257) - Updated the test workflow to fail if a security issue is found [#3261](https://github.com/OpenMDAO/OpenMDAO/pull/3261) +- Removed unnecessary setup() from doc page [#3263](https://github.com/OpenMDAO/OpenMDAO/pull/3263) *********************************** From e10818db49310a6cbb3626b0373dfac5753cfea0 Mon Sep 17 00:00:00 2001 From: swryan Date: Fri, 7 Jun 2024 13:25:07 -0400 Subject: [PATCH 18/30] Increment version for 3.33.0 release --- .bumpversion.cfg | 2 +- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- openmdao/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index ff2a3ac3d4..c160a5c438 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 3.32.1-dev +current_version = 3.33.0 commit = False tag = False parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\-(?P[a-z]+))? diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 370c3e4863..dd5dae12fd 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -23,7 +23,7 @@ body: attributes: label: OpenMDAO Version description: What version of OpenMDAO is being used. - placeholder: "3.32.1-dev" + placeholder: "3.33.0" validations: required: true - type: textarea diff --git a/openmdao/__init__.py b/openmdao/__init__.py index 91f35f2b7d..e94274ceb8 100644 --- a/openmdao/__init__.py +++ b/openmdao/__init__.py @@ -1,3 +1,3 @@ -__version__ = '3.32.1-dev' +__version__ = '3.33.0' INF_BOUND = 1.0E30 From ce1b2abdaeab9c5162eb643091d0e0cac9fc4df4 Mon Sep 17 00:00:00 2001 From: swryan Date: Fri, 7 Jun 2024 16:33:27 -0400 Subject: [PATCH 19/30] increment version to 3.33.1-dev --- .bumpversion.cfg | 2 +- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- openmdao/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index c160a5c438..1c30d8313a 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 3.33.0 +current_version = 3.33.1-dev commit = False tag = False parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\-(?P[a-z]+))? diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index dd5dae12fd..85d3fb507e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -23,7 +23,7 @@ body: attributes: label: OpenMDAO Version description: What version of OpenMDAO is being used. - placeholder: "3.33.0" + placeholder: "3.33.1-dev" validations: required: true - type: textarea diff --git a/openmdao/__init__.py b/openmdao/__init__.py index e94274ceb8..6c93545033 100644 --- a/openmdao/__init__.py +++ b/openmdao/__init__.py @@ -1,3 +1,3 @@ -__version__ = '3.33.0' +__version__ = '3.33.1-dev' INF_BOUND = 1.0E30 From 4fa0cf5aaa3b0817df162352b165dbcabdc0f73d Mon Sep 17 00:00:00 2001 From: swryan Date: Mon, 10 Jun 2024 14:30:55 -0400 Subject: [PATCH 20/30] err --- .github/scripts/get_poem_id.py | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/scripts/get_poem_id.py b/.github/scripts/get_poem_id.py index f8bd863ee3..60c5188aba 100644 --- a/.github/scripts/get_poem_id.py +++ b/.github/scripts/get_poem_id.py @@ -64,6 +64,7 @@ def get_poem_id(repository, pull_id): "issue", "view", "--json", "body", issue_id]) except subprocess.CalledProcessError as err: print(f"Unable to access issue #{issue_id}:\nrc={err.returncode}") + print(err) return ERROR issue_body = json.loads(issue_json)["body"] From dc631c3b0430c1adae0779a853cdad586f442461 Mon Sep 17 00:00:00 2001 From: swryan Date: Mon, 10 Jun 2024 14:33:42 -0400 Subject: [PATCH 21/30] sync --- .github/workflows/openmdao_update_poem.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/openmdao_update_poem.yml b/.github/workflows/openmdao_update_poem.yml index 0d795dade4..07580bf994 100644 --- a/.github/workflows/openmdao_update_poem.yml +++ b/.github/workflows/openmdao_update_poem.yml @@ -13,7 +13,7 @@ on: jobs: check_for_poem: - if: github.event.action == 'opened' || github.event.action == 'reopened' || github.event.pull_request.merged + if: github.event.action == 'opened' || github.event.action == 'reopened' || github.event.pull_request.synchronize || github.event.pull_request.merged runs-on: ubuntu-latest From add88510ebcc3e96230cc1e349183331865634d1 Mon Sep 17 00:00:00 2001 From: swryan Date: Mon, 10 Jun 2024 14:34:59 -0400 Subject: [PATCH 22/30] sync-action --- .github/workflows/openmdao_update_poem.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/openmdao_update_poem.yml b/.github/workflows/openmdao_update_poem.yml index 07580bf994..d4a75d64ef 100644 --- a/.github/workflows/openmdao_update_poem.yml +++ b/.github/workflows/openmdao_update_poem.yml @@ -13,7 +13,7 @@ on: jobs: check_for_poem: - if: github.event.action == 'opened' || github.event.action == 'reopened' || github.event.pull_request.synchronize || github.event.pull_request.merged + if: github.event.action == 'opened' || github.event.action == 'reopened' || github.event.action == 'synchronize' || github.event.pull_request.merged runs-on: ubuntu-latest From 425d3278a1f1e4469edf1b4be4ae31782d4dcc1b Mon Sep 17 00:00:00 2001 From: swryan Date: Mon, 10 Jun 2024 14:45:06 -0400 Subject: [PATCH 23/30] stderr --- .github/scripts/get_poem_id.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/scripts/get_poem_id.py b/.github/scripts/get_poem_id.py index 60c5188aba..84b77f8e8a 100644 --- a/.github/scripts/get_poem_id.py +++ b/.github/scripts/get_poem_id.py @@ -61,10 +61,12 @@ def get_poem_id(repository, pull_id): try: issue_json = subprocess.check_output(["gh", "--repo", repository, - "issue", "view", "--json", "body", issue_id]) + "issue", "view", "--json", "body", issue_id], + stderr=subprocess.STDOUT, shell=True, + timeout=10, universal_newlines=True); except subprocess.CalledProcessError as err: print(f"Unable to access issue #{issue_id}:\nrc={err.returncode}") - print(err) + print(issue_json) return ERROR issue_body = json.loads(issue_json)["body"] From 435331ca6d3a87034c4ec0f62f08ec6f119ee3e8 Mon Sep 17 00:00:00 2001 From: swryan Date: Mon, 10 Jun 2024 14:50:11 -0400 Subject: [PATCH 24/30] pprint --- .github/scripts/get_poem_id.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/scripts/get_poem_id.py b/.github/scripts/get_poem_id.py index 84b77f8e8a..69bd274ea7 100644 --- a/.github/scripts/get_poem_id.py +++ b/.github/scripts/get_poem_id.py @@ -69,6 +69,9 @@ def get_poem_id(repository, pull_id): print(issue_json) return ERROR + from pprint import pprint + pprint(issue_json) + issue_body = json.loads(issue_json)["body"] poem_id = "" From adb22779910a318a4ccea941416107d51565a06c Mon Sep 17 00:00:00 2001 From: swryan Date: Mon, 10 Jun 2024 14:52:45 -0400 Subject: [PATCH 25/30] shell --- .github/scripts/get_poem_id.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/scripts/get_poem_id.py b/.github/scripts/get_poem_id.py index 69bd274ea7..bb8623b0ad 100644 --- a/.github/scripts/get_poem_id.py +++ b/.github/scripts/get_poem_id.py @@ -60,8 +60,7 @@ def get_poem_id(repository, pull_id): print("-------------------------------------------------------------------------------") try: - issue_json = subprocess.check_output(["gh", "--repo", repository, - "issue", "view", "--json", "body", issue_id], + issue_json = subprocess.check_output(f"gh --repo {repository} issue view --json body {issue_id}", stderr=subprocess.STDOUT, shell=True, timeout=10, universal_newlines=True); except subprocess.CalledProcessError as err: From 319a19161d9c24bdf1f2a6c0b39be5552a3bd31b Mon Sep 17 00:00:00 2001 From: swryan Date: Mon, 10 Jun 2024 14:57:18 -0400 Subject: [PATCH 26/30] repo --- .github/scripts/get_poem_id.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/scripts/get_poem_id.py b/.github/scripts/get_poem_id.py index bb8623b0ad..6b6589f520 100644 --- a/.github/scripts/get_poem_id.py +++ b/.github/scripts/get_poem_id.py @@ -30,13 +30,17 @@ def get_poem_id(repository, pull_id): print(f"Checking Pull Request #{pull_id} for associated issue...") print("-------------------------------------------------------------------------------") try: - pull_json = subprocess.check_output(["gh", "--repo", repository, - "issue", "view", "--json", "body", pull_id]) + pull_json = subprocess.check_output(f"gh --repo {repository} issue view --json body {pull_id}", + stderr=subprocess.STDOUT, shell=True, + timeout=10, universal_newlines=True); except subprocess.CalledProcessError as err: print(f"Unable to access pull request #{pull_id}:\nrc={err.returncode}") print(pull_json) return ERROR + from pprint import pprint + pprint(pull_json) + pull_body = json.loads(pull_json)["body"] issue_id = "" @@ -60,6 +64,7 @@ def get_poem_id(repository, pull_id): print("-------------------------------------------------------------------------------") try: + repository.replace('swryan', 'OpenMDAO') issue_json = subprocess.check_output(f"gh --repo {repository} issue view --json body {issue_id}", stderr=subprocess.STDOUT, shell=True, timeout=10, universal_newlines=True); From 1adf6c3620f2ee4ea635d400f9978d55fc2f365d Mon Sep 17 00:00:00 2001 From: swryan Date: Mon, 10 Jun 2024 15:06:30 -0400 Subject: [PATCH 27/30] run --- .github/scripts/get_poem_id.py | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/.github/scripts/get_poem_id.py b/.github/scripts/get_poem_id.py index 6b6589f520..46fc70b43a 100644 --- a/.github/scripts/get_poem_id.py +++ b/.github/scripts/get_poem_id.py @@ -30,18 +30,18 @@ def get_poem_id(repository, pull_id): print(f"Checking Pull Request #{pull_id} for associated issue...") print("-------------------------------------------------------------------------------") try: - pull_json = subprocess.check_output(f"gh --repo {repository} issue view --json body {pull_id}", - stderr=subprocess.STDOUT, shell=True, - timeout=10, universal_newlines=True); + p = subprocess.run(["gh", "--repo", repository, "issue", "view", "--json", "body", pull_id], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) except subprocess.CalledProcessError as err: print(f"Unable to access pull request #{pull_id}:\nrc={err.returncode}") - print(pull_json) + print(f"stdout:\n------\n{p.stdout}") + print(f"stderr:\n------\n{p.stderr}") return ERROR - from pprint import pprint - pprint(pull_json) + print(f"stdout:\n------\n{p.stdout}") + print(f"stderr:\n------\n{p.stderr}") - pull_body = json.loads(pull_json)["body"] + pull_body = json.loads(p.stdout)["body"] issue_id = "" @@ -64,19 +64,18 @@ def get_poem_id(repository, pull_id): print("-------------------------------------------------------------------------------") try: - repository.replace('swryan', 'OpenMDAO') - issue_json = subprocess.check_output(f"gh --repo {repository} issue view --json body {issue_id}", - stderr=subprocess.STDOUT, shell=True, - timeout=10, universal_newlines=True); + p = subprocess.run(["gh", "--repo", repository, "issue", "view", "--json", "body", issue_id], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) except subprocess.CalledProcessError as err: print(f"Unable to access issue #{issue_id}:\nrc={err.returncode}") - print(issue_json) + print(f"stdout:\n------\n{p.stdout}") + print(f"stderr:\n------\n{p.stderr}") return ERROR - from pprint import pprint - pprint(issue_json) + print(f"stdout:\n------\n{p.stdout}") + print(f"stderr:\n------\n{p.stderr}") - issue_body = json.loads(issue_json)["body"] + issue_body = json.loads(p.stdout)["body"] poem_id = "" From a83af3f791d7f1ce02225185aec1a03b452a57b0 Mon Sep 17 00:00:00 2001 From: swryan Date: Mon, 10 Jun 2024 15:08:04 -0400 Subject: [PATCH 28/30] repo --- .github/scripts/get_poem_id.py | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/scripts/get_poem_id.py b/.github/scripts/get_poem_id.py index 46fc70b43a..b0897c068a 100644 --- a/.github/scripts/get_poem_id.py +++ b/.github/scripts/get_poem_id.py @@ -63,6 +63,7 @@ def get_poem_id(repository, pull_id): print(f"Checking Issue #{issue_id} for associated POEM...") print("-------------------------------------------------------------------------------") + repository.replace('swryan', 'OpenMDAO') try: p = subprocess.run(["gh", "--repo", repository, "issue", "view", "--json", "body", issue_id], stdout=subprocess.PIPE, stderr=subprocess.PIPE) From 6e856ca31417f410dd75958865505ce888349373 Mon Sep 17 00:00:00 2001 From: swryan Date: Mon, 10 Jun 2024 15:09:49 -0400 Subject: [PATCH 29/30] replace --- .github/scripts/get_poem_id.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/get_poem_id.py b/.github/scripts/get_poem_id.py index b0897c068a..29741669ec 100644 --- a/.github/scripts/get_poem_id.py +++ b/.github/scripts/get_poem_id.py @@ -63,7 +63,7 @@ def get_poem_id(repository, pull_id): print(f"Checking Issue #{issue_id} for associated POEM...") print("-------------------------------------------------------------------------------") - repository.replace('swryan', 'OpenMDAO') + repository = repository.replace('swryan', 'OpenMDAO') try: p = subprocess.run(["gh", "--repo", repository, "issue", "view", "--json", "body", issue_id], stdout=subprocess.PIPE, stderr=subprocess.PIPE) From 163051e05d28209b5eefaa7ada56210aec3c245d Mon Sep 17 00:00:00 2001 From: swryan Date: Mon, 10 Jun 2024 15:14:07 -0400 Subject: [PATCH 30/30] msg --- .github/workflows/openmdao_update_poem.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/openmdao_update_poem.yml b/.github/workflows/openmdao_update_poem.yml index d4a75d64ef..854223850f 100644 --- a/.github/workflows/openmdao_update_poem.yml +++ b/.github/workflows/openmdao_update_poem.yml @@ -51,7 +51,7 @@ jobs: fi - name: Comment on PR - if: (github.event.action == 'opened' || github.event.action == 'reopened') && steps.check_for_poem.outputs.POEM_ID != '' + if: (github.event.action == 'opened' || github.event.action == 'reopened' || github.event.action == 'synchronize') && steps.check_for_poem.outputs.POEM_ID != '' env: POEM_ID: ${{ steps.check_for_poem.outputs.POEM_ID }} POEM_URL: ${{ github.server_url }}/${{ github.repository_owner }}/POEMs/blob/master/POEM_${{ steps.check_for_poem.outputs.POEM_ID }}.md