From af144420591be492db62b04fba0313ff28ffe14a Mon Sep 17 00:00:00 2001 From: Dan Gunter Date: Fri, 15 May 2026 07:21:04 -0700 Subject: [PATCH 1/4] fixed headers --- addheader.yml | 10 ++++++++++ file_header.txt | 14 ++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 addheader.yml create mode 100644 file_header.txt diff --git a/addheader.yml b/addheader.yml new file mode 100644 index 0000000..c6444fe --- /dev/null +++ b/addheader.yml @@ -0,0 +1,10 @@ +# Usage: +# addheader -c addheader.yml +--- +root: src +text: file_header.txt +patterns: + - "*.py" +verbose: 1 +sep-len: 80 +... diff --git a/file_header.txt b/file_header.txt new file mode 100644 index 0000000..e2ed372 --- /dev/null +++ b/file_header.txt @@ -0,0 +1,14 @@ +Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 + +“Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +copyrighted by the software owners: The Regents of the University of California, through Lawrence +Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +Virginia University Research Corporation. + +NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +publicly and display publicly, and to permit other to do so. From 84d20a777fd54f44fc077f975db7caf45b11a248 Mon Sep 17 00:00:00 2001 From: Dan Gunter Date: Fri, 15 May 2026 07:41:52 -0700 Subject: [PATCH 2/4] added fileheader & refactored --- docs/api.ipynb | 2 +- src/idaes_fi/__init__.py | 17 + src/idaes_fi/compute_diagnostics.py | 27 +- src/idaes_fi/gitutil.py | 23 +- src/idaes_fi/scripts/copy_template.py | 17 + src/idaes_fi/structfs/__init__.py | 23 +- src/idaes_fi/structfs/action_base.py | 23 +- src/idaes_fi/structfs/common.py | 23 +- src/idaes_fi/structfs/fsrunner.py | 25 +- src/idaes_fi/structfs/logutil.py | 23 +- src/idaes_fi/structfs/reportdb.py | 23 +- src/idaes_fi/structfs/runner.py | 23 +- src/idaes_fi/structfs/runner_actions.py | 864 ------------------ src/idaes_fi/structfs/simple_wrap.py | 25 +- src/idaes_fi/structfs/tests/demo_flowsheet.py | 23 +- .../structfs/tests/demo_flowsheet_fi_main.py | 17 + .../tests/demo_flowsheet_structured.py | 17 + .../tests/demo_flowsheet_structured_multi.py | 17 + .../structfs/tests/flash_flowsheet.py | 23 +- src/idaes_fi/structfs/tests/flash_main.py | 17 + src/idaes_fi/structfs/tests/hda_flowsheet.py | 27 +- src/idaes_fi/structfs/tests/hda_ideal_VLE.py | 27 +- src/idaes_fi/structfs/tests/hda_reaction.py | 23 +- .../structfs/tests/model_from_template.py | 17 + src/idaes_fi/structfs/tests/test_common.py | 23 +- .../structfs/tests/test_demo_flowsheet.py | 17 + src/idaes_fi/structfs/tests/test_fsrunner.py | 23 +- src/idaes_fi/structfs/tests/test_logutil.py | 23 +- src/idaes_fi/structfs/tests/test_runner.py | 24 +- .../structfs/tests/test_runner_actions.py | 25 +- .../structfs/tests/test_simple_wrap.py | 23 +- src/idaes_fi/structfs/tests/test_structfs.py | 25 +- src/idaes_fi/tests/test_import.py | 17 + 33 files changed, 472 insertions(+), 1074 deletions(-) delete mode 100644 src/idaes_fi/structfs/runner_actions.py diff --git a/docs/api.ipynb b/docs/api.ipynb index a88b43d..002beb7 100644 --- a/docs/api.ipynb +++ b/docs/api.ipynb @@ -605,7 +605,7 @@ "source": [ "\n", "See the pre-defined actions in the\n", - "{py:mod}`runner_actions `\n", + "{py:mod}`actions `\n", "module, and their usage in the {py:class}`FlowsheetRunner ` \n", "class, for more examples." ] diff --git a/src/idaes_fi/__init__.py b/src/idaes_fi/__init__.py index 58cbec5..7959dcf 100644 --- a/src/idaes_fi/__init__.py +++ b/src/idaes_fi/__init__.py @@ -1,3 +1,20 @@ +################################################################################# +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. +# +################################################################################# """Top-level package for idaes-fi.""" __all__ = ["__version__"] diff --git a/src/idaes_fi/compute_diagnostics.py b/src/idaes_fi/compute_diagnostics.py index 378eb44..2304510 100644 --- a/src/idaes_fi/compute_diagnostics.py +++ b/src/idaes_fi/compute_diagnostics.py @@ -1,15 +1,20 @@ # -*- coding: utf-8 -*- ################################################################################# -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. # -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. ################################################################################# """ Compute diagnostics values and return as Pydantic data models. @@ -352,7 +357,7 @@ def all_as_obj(self) -> dict[str, BaseModel]: """Same as `all_as_dict` except each top-level value is an object instead of a dict. Note that the keys returned here should match the attributes - of `idaes_fi.structfs.runner_actions.Diagnostics.Report`. + of `idaes_fi.structfs.actions.Diagnostics.Report`. Returns: dict: Diagnostics data with string keys and Pydantic model object values @@ -545,7 +550,7 @@ def _set_variables( if un_func is None: u = str(v.get_units()) # replace 'None' with an empty string - # -- to match `runner_actions.ModelVariables` + # -- to match `actions.ModelVariables` if u == "None": u = "" else: diff --git a/src/idaes_fi/gitutil.py b/src/idaes_fi/gitutil.py index 6eab253..2519889 100644 --- a/src/idaes_fi/gitutil.py +++ b/src/idaes_fi/gitutil.py @@ -1,14 +1,19 @@ ################################################################################# -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. # -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. ################################################################################# """ Git utility code diff --git a/src/idaes_fi/scripts/copy_template.py b/src/idaes_fi/scripts/copy_template.py index 73f1fa0..25edc14 100644 --- a/src/idaes_fi/scripts/copy_template.py +++ b/src/idaes_fi/scripts/copy_template.py @@ -1,4 +1,21 @@ #!/usr/bin/env python3 +################################################################################# +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. +# +################################################################################# """ Instantiate model from template """ diff --git a/src/idaes_fi/structfs/__init__.py b/src/idaes_fi/structfs/__init__.py index de7a495..369670e 100644 --- a/src/idaes_fi/structfs/__init__.py +++ b/src/idaes_fi/structfs/__init__.py @@ -1,14 +1,19 @@ ################################################################################# -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. # -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. ################################################################################# import logging diff --git a/src/idaes_fi/structfs/action_base.py b/src/idaes_fi/structfs/action_base.py index 87875cc..a7be9ae 100644 --- a/src/idaes_fi/structfs/action_base.py +++ b/src/idaes_fi/structfs/action_base.py @@ -1,14 +1,19 @@ ################################################################################# -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. # -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. ################################################################################# """ Base class for runner actions. diff --git a/src/idaes_fi/structfs/common.py b/src/idaes_fi/structfs/common.py index 5c0f463..33abf77 100644 --- a/src/idaes_fi/structfs/common.py +++ b/src/idaes_fi/structfs/common.py @@ -1,14 +1,19 @@ ################################################################################# -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. # -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. ################################################################################# """ Common constants and functions diff --git a/src/idaes_fi/structfs/fsrunner.py b/src/idaes_fi/structfs/fsrunner.py index 7b0a71c..43f21d2 100644 --- a/src/idaes_fi/structfs/fsrunner.py +++ b/src/idaes_fi/structfs/fsrunner.py @@ -1,14 +1,19 @@ ################################################################################# -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. # -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. ################################################################################# """ Specialize the generic `Runner` class to running a flowsheet, @@ -316,7 +321,7 @@ def __init__(self, solve_steps: list[str] = None, **kwargs): **kwargs: Additional keyword arguments passed to `BaseFlowsheetRunner`. """ - from .runner_actions import ( # pylint: disable=C0415 + from .actions import ( # pylint: disable=C0415 Timer, CaptureSolverOutput, GetSolverResults, diff --git a/src/idaes_fi/structfs/logutil.py b/src/idaes_fi/structfs/logutil.py index ec0e333..127d58e 100644 --- a/src/idaes_fi/structfs/logutil.py +++ b/src/idaes_fi/structfs/logutil.py @@ -1,14 +1,19 @@ ################################################################################# -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. # -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. ################################################################################# """ Utility functions for logging diff --git a/src/idaes_fi/structfs/reportdb.py b/src/idaes_fi/structfs/reportdb.py index c62e95b..ee206fb 100644 --- a/src/idaes_fi/structfs/reportdb.py +++ b/src/idaes_fi/structfs/reportdb.py @@ -1,14 +1,19 @@ ################################################################################# -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. # -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. ################################################################################# """ Simple database to contain reports for any number of flowsheets. diff --git a/src/idaes_fi/structfs/runner.py b/src/idaes_fi/structfs/runner.py index e807a06..c081b09 100644 --- a/src/idaes_fi/structfs/runner.py +++ b/src/idaes_fi/structfs/runner.py @@ -1,14 +1,19 @@ ################################################################################# -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. # -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. ################################################################################# """ Run functions in a module in a defined, named, sequence. diff --git a/src/idaes_fi/structfs/runner_actions.py b/src/idaes_fi/structfs/runner_actions.py deleted file mode 100644 index 61cd0d3..0000000 --- a/src/idaes_fi/structfs/runner_actions.py +++ /dev/null @@ -1,864 +0,0 @@ -################################################################################# -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). -# -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. -################################################################################# -""" -## Runner actions - -This module defines a set of 'actions' that can be automatically -executed before, during, and after a run of a flowsheet that is -wrapped with the `Runner` decorators. - -The Action subclasses in this module return Pydantic models -that can be formatted as JSON. By convention, the model is -defined in a nested class called `Report`. -""" - -# stdlib -from collections.abc import Callable -from datetime import datetime -from io import StringIO -import logging -import re -import sys -import time -from typing import Union, Optional - -# third-party -from pyomo.network import Arc -from pyomo.network.port import ScalarPort, Port -from pyomo.core.base.var import IndexedVar -from pyomo.core.base.param import IndexedParam -from pyomo.opt.results.container import ScalarData -import pyomo.environ as pyo -from pydantic import BaseModel, Field - -try: - from idaes_connectivity.base import Connectivity, Mermaid -except ImportError: - Connectivity = None - -# package -from idaes.core.util.model_statistics import degrees_of_freedom -from idaes.core.util.tables import create_stream_table_ui -from idaes.core.base.unit_model import ProcessBlockData -from ..compute_diagnostics import ( - DiagnosticsData, - StructuralIssuesData, - NumericalIssuesData, - ComponentList, - DiagnosticsError, -) -from .action_base import Action -from .fsrunner import BaseFlowsheetRunner - - -class Timer(Action): - """Simple step/run timer action.""" - - class Report(BaseModel): - """Report returned by report() method.""" - - # {"step_name": , ..} for each step - timings: dict[str, float] = Field(default={}) - run_time: float = -1.0 - - def __init__(self, runner, **kwargs): - """Constructor. - - Args: - runner: Associated Runner object - kwargs: Additional optional arguments for Action constructor - - Attributes: - step_times: Dict with key step name and value a list of - timings for that step - run_times: List of timings for a run (sequence of steps) - """ - super().__init__(runner, **kwargs) - self._step_order = runner.list_steps() - # initialize all step times to -1 - self.step_times: dict[str, float] = {step: -1 for step in self._step_order} - self.run_time: float = -1 - # initialize internal variables - self._run_begin, self._step_begin = None, {} - - def before_step(self, step_name): - """Record the start time for a step. - - Args: - step_name: Name of the step about to run. - """ - self._step_begin[step_name] = time.time() - - def after_step(self, step_name): - """Record the elapsed time for a completed step. - - Args: - step_name: Name of the step that just finished. - """ - t1 = time.time() - t0 = self._step_begin.get(step_name, None) - if t0 is None: - self.log.warning(f"Timer: step '{step_name}' end without begin") - else: - self._cur_step_times[step_name] = t1 - t0 - self._step_begin[step_name] = None - - def before_run(self): - """Initialize timer state before a run starts.""" - self._run_begin = time.time() - self._cur_step_times = {} - self._step_begin = {} - - def after_run(self): - """Finalize run timing data after a run completes.""" - t1 = time.time() - - # set run time - if self._run_begin is None: - self.log.warning("Timer: run end without begin") - self.run_time = -1 - else: - self.run_time = t1 - self._run_begin - self._run_begin = None - - # set all step times - self.step_times = { - step: self._cur_step_times.get(step, -1) for step in self._step_order - } - - def report(self) -> Report: - """Report the timings. - - Returns: - The report object - """ - rpt = self.Report(timings=self.step_times, run_time=self.run_time) - return rpt - - -# Hold degrees of freedom for one BaseFlowsheetRunner 'step' -# {key=component: value=dof} -UnitDofType = dict[str, int] - - -class UnitDofChecker(Action): - """Check degrees of freedom on unit models. - - After a (caller-named) step or steps, check the degrees - of freedom on each unit model by the method of - fixing the inlet, applying the `degrees_of_freedom()` function, - and unfixing the inlet again. The calculated values are - saved and passed to an optional caller-provided function. - - At the end of a run, the degrees of freedom for the entire - model are checked, saved, and passed to an optional function. - """ - - class Report(BaseModel): - """Report on degrees of freedom in a model.""" - - steps: dict[str, UnitDofType] = Field( - default={}, - description="Degrees of freedom for each named step", - examples=[{"build": 2, "set_operating_conditions": 1, "solve": 1}], - ) - model: int = Field( - default=0, description="Degrees of freedom for the entire model" - ) - - def __init__( - self, - runner: BaseFlowsheetRunner, - flowsheet: str, - steps: Union[str, list[str]], - step_func: Optional[Callable[[str, UnitDofType], None]] = None, - run_func: Optional[Callable[[dict[str, UnitDofType], int], None]] = None, - **kwargs, - ): - """Constructor. - - Args: - runner: Associated Runner object (provided by `add_action`) - flowsheet: Variable name for flowsheet, e.g. "fs" - steps: Step or steps at which to run the checking action - step_func: Function to call with calculated DoF values for one step. - Takes name of step and dictionary with per-unit degrees of freedom - (see `UnitDofType` alias). - run_func: Function to call with calculated DoF values for each step, as well - as overall model DoF. - kwargs: Additional optional arguments for Action constructor - - Raises: - ValueError: if `steps` list is empty, or no callback functions provided - """ - super().__init__(runner, **kwargs) - if hasattr(steps, "lower"): # string-like - self._steps = {steps} - else: # assume it is list-like - if len(steps) == 0: - raise ValueError("At least one step name must be provided") - self._steps = set(steps) - self._steps_dof: dict[str, UnitDofType] = {} - self._model_dof = 0 - self._step_func, self._run_func = step_func, run_func - self._fs = flowsheet - - def after_step(self, step_name: str): - """Compute unit and model degrees of freedom after a step. - - Args: - step_name: Name of the step that just completed. - """ - step_name = self._runner.normalize_name(step_name) - if step_name not in self._steps: - self.log.debug(f"Do not check DoF for step: {step_name}") - return - - try: - fs = self._get_flowsheet() - except AttributeError: - self.log.error( - f"Could not access flowsheet: attribute '{self._fs}' not found." - ) - return - - model_dof = degrees_of_freedom(self._get_flowsheet()) - units_dof = {self._fs: model_dof} - for unit in fs.component_objects(descend_into=True): - if self._is_unit_model(unit): - units_dof[unit.name] = self._get_dof(unit) - self._steps_dof[step_name] = units_dof # save - if self._step_func: - self._step_func(step_name, units_dof) - - def after_run(self): - """Actions performed after a run.""" - fs = self._get_flowsheet() - model_dof = degrees_of_freedom(fs) - self._model_dof = model_dof - if self._run_func: - self._run_func(self._steps_dof, model_dof) - - def _get_flowsheet(self): - m = self._runner.model - if self._fs: - return getattr(m, self._fs) - return m - - @staticmethod - def _is_unit_model(block): - return isinstance(block, ProcessBlockData) - - def get_dof(self) -> dict[str, UnitDofType]: - """Get degrees of freedom - - Returns: - dict[str, UnitDofType]: Mapping of step name to per-unit DoF when - the step completed. - """ - return self._steps_dof.copy() - - def get_dof_model(self) -> int: - """Get degrees of freedom for the model. - - Returns: - int: Last calculated DoF for the model. - """ - return self._model_dof - - def steps(self, only_with_data: bool = False) -> list[str]: - """Get list of steps for which unit degrees of freedom are calculated. - - Args: - only_with_data: If True, do not return steps with no data - - Returns: - list of step names - """ - if only_with_data: - return [s for s in self._steps if s in self._steps_dof] - return list(self._steps) - - def report(self) -> Report: - """Machine-readable report of degrees of freedom. - - Returns: - Report object - """ - return self.Report(steps=self.get_dof(), model=self.get_dof_model()) - - @staticmethod - def _get_dof(block, fix_inlets: bool = True): - if fix_inlets: - inlets = [ - c - for c in block.component_objects(descend_into=False) - if isinstance(c, ScalarPort) - and (c.name.endswith("inlet") or c.name.endswith("recycle")) - ] - free_me = [] - for inlet in inlets: - if not inlet.is_fixed(): - inlet.fix() - free_me.append(inlet) - - dof = degrees_of_freedom(block) - - if fix_inlets: - for inlet in free_me: - inlet.free() - - return dof - - -class SolverActionBase(Action): - """Base class for actions to get solver state, output, etc.""" - - #: By default, consider any step with 'solve' in its name to - #: be a solver step. This can be overridden by setting :attr:`solve_steps` - #: to some other list of step names. - DEFAULT_SOLVE_STEPS = [s for s in BaseFlowsheetRunner.STEPS if "solve" in s] - - def __init__(self, runner: BaseFlowsheetRunner, **kwargs): - """Initialize solver output capture state. - - Args: - runner: Runner that owns this action. - **kwargs: Additional keyword arguments passed to `Action`. - """ - super().__init__(runner, **kwargs) - self._solve_steps = self.DEFAULT_SOLVE_STEPS - - @property - def solve_steps(self) -> list[str]: - """Get list of solve steps""" - return self._solve_steps.copy() - - @solve_steps.setter - def solve_steps(self, value: list[str]): - """Set new list of solve steps""" - self._solve_steps = value - - def is_solve_step(self, name: str) -> bool: - """Whether step `name` is the solve step. - - Args: - name: step name - - Returns: - True if it is the solve step, otherwise False - """ - return name in self._solve_steps - - -class CaptureSolverOutput(SolverActionBase): - """Capture the solver output.""" - - class Report(BaseModel): - """Report object for captured solver output action""" - - #: String of output keyed by step - output: dict[str, str] = {} - - def __init__(self, runner, **kwargs): - """Constructor - - Args: - runner: BaseFlowsheetRunner object - kwargs: Arguments passed through to superclass - """ - super().__init__(runner, **kwargs) - self._logs = {} - self._solver_out = None - self._save_stdout = None - - def before_step(self, step_name: str): - """Action performed before the step.""" - if self.is_solve_step(step_name): - self._solver_out = StringIO() - self._save_stdout, sys.stdout = sys.stdout, self._solver_out - - def after_step(self, step_name: str): - """Action performed after the step.""" - if self._solver_out is not None: - self._logs[step_name] = self._solver_out.getvalue() - self._solver_out = None - sys.stdout = self._save_stdout - - def step_failed(self, step_name: str, err: Exception): - if self._save_stdout: - sys.stdout = self._save_stdout - self._solver_out.flush() - # print stored stdout for debugging help - print(self._solver_out.getvalue()) - - def report(self) -> Report: - """Machine-readable report with solver output. - - Returns: - CaptureSolverOutput.Report - """ - return self.Report(output=self._logs) - - -class SolverResult(BaseModel): - """One solver result in `GetSolverResults.Report.result`""" - - problem: dict[str, int | float | str] = {} - solver: dict[str, int | float | str] = {} - values: dict[str, int | float | str | dict] = {} - - -class GetSolverResults(SolverActionBase): - """Retrieve and structure the results from the solver.""" - - class Report(BaseModel): - """Report object for action""" - - #: Result from Pyomo solver Result object - #: Since multiple results may be returned, - #: this is a list. - results: list[SolverResult] = [] - - def __init__(self, runner: BaseFlowsheetRunner, **kwargs): - """Constructor. - - Args: - runner: Runner that owns this action. - **kwargs: Additional keyword arguments passed to `Action`. - """ - super().__init__(runner, **kwargs) - self._results = [] - - def after_step(self, step_name: str): - """Action performed after the step.""" - if self.is_solve_step(step_name): - self._extract_results() - - @staticmethod - def _sval(v): - # convert to a numeric or string value - if isinstance(v, datetime): - return v.timestamp() - elif isinstance(v, float) or isinstance(v, int): - return v - return str(v) - - def _extract_results(self): - r = self._runner.results - - if r is None: - self._results = [] - return - - # extract Pyomo dict of lists into a list of SolverResult objs - # eg {"Solver": [{...}, ], "Problem": [{...},]} -> - # [SolverResult, SolverResult] - # Add ScalarData items (single values) to every object - result_list, scalars = [], {} - for k, v in r.items(): - - # Special processing for single-values - if isinstance(v, ScalarData): - vv = v.get_value() - if isinstance(vv, dict): - scalar_value = {} - for k2, v2 in vv.items(): - scalar_value[k2] = self._sval(v2) - else: - scalar_value = self._sval(vv) - scalars[k] = scalar_value - continue # done - - n = len(v) - # make sure result list has space - while n > len(result_list): - result_list.append(SolverResult()) - # choose which part of result this is - if k in ("Solver", "Problem"): - sr_attr = k.lower() - else: - self.log.info(f"Ignoring unknown key in solver results: {k}") - continue - # extract Pyomo list for a given attr into SolverResult - for i in range(n): - v_dict = {} - # convert values in dict to int, str, float, or None - for v_k, v_v in v[i].items(): - if hasattr(v_v, "get_value"): - v_v = v_v.get_value() - if isinstance(v_v, int) or isinstance(v_v, float): - v_dict[v_k] = v_v - else: - s = str(v_v) - if s == "": - pass # who cares? skip it - else: - v_dict[v_k] = s - # set the corresponding i-th result attribute - setattr(result_list[i], sr_attr, v_dict) - - # Add collected scalar values to every result in list - for r in result_list: - for k, v in scalars.items(): - r.values[k] = v - - self._results = result_list - - def report(self) -> Report: - """Report solver result. - - Returns: - GetSolverResult.Report - """ - return self.Report(results=self._results) - - -class ModelVariables(Action): - """Extract and format model variables.""" - - VAR_TYPE, PARAM_TYPE = "V", "P" - - class Report(BaseModel): - """Report for ModelVariables.""" - - #: Tree of variables - variables: dict = Field(default={}) - port_aliases: dict = Field(default={}) - - def __init__(self, runner, **kwargs): - """Initialize model variable extraction state. - - Args: - runner: Flowsheet runner that owns this action. - **kwargs: Additional keyword arguments passed to `Action`. - """ - assert isinstance(runner, BaseFlowsheetRunner) # makes no sense otherwise - super().__init__(runner, **kwargs) - self._vars = {} - self._port_vars = {} - self._ports = {} - - def after_run(self): - """Actions performed after the run.""" - self._saved_paths = {} # fast lookup used in _add_block() - self.log = logging.getLogger(self.log.name) - self._extract_vars(self._runner.model) - - def _extract_vars(self, m): - var_tree = {} - port_aliases = {} - for c in m.component_objects(): - # get component type - if self._is_var(c): - subtype = self.VAR_TYPE - elif self._is_param(c): - subtype = self.PARAM_TYPE - else: - # find and extract aliases to vars on assoc. ports - if hasattr(c, "component_data_objects"): - for port_data in c.component_data_objects(Port, descend_into=False): - comp_name = port_data.name # proper name of port's component - for port_name, port_var in port_data.vars.items(): - if isinstance(port_var, pyo.Var): # only variables - port_aliases[f"{comp_name}.{port_name}"] = port_var.name - continue # do nothing else - # start new block - b = [subtype] - # add its variables - items = [] - indexed = False - # add each value from an indexed var/param, - # this also works ok for non-indexed ones - for index in c: - v = c[index] - indexed = index is not None - v_value = self._safe_scalar_value(v) - if subtype == self.VAR_TYPE: - # index, value, fixed, stale, lower bound, upper bound, domain - item = ( - index, - v_value, - v.fixed, - v.stale, - v.lb, - v.ub, - str(v.domain), - ) - else: - # index, value - item = (index, v_value) - items.append(item) - b.append(indexed) - b.append(items) - # add block to tree - self._add_block(var_tree, c.name, b) - - self._vars = var_tree - self._ports = port_aliases - - @staticmethod - def _safe_scalar_value(v): - """Get value, allowing for uninitialized values. - An uninitialized value will return None. - """ - if isinstance(v, float) or isinstance(v, int): - return v - if not v.is_fixed() and v.stale: - # avoids logged errors from uninitialized vars - return None - try: - return pyo.value(v) - except ValueError: - return None - - def _get_values(self, c, subtype) -> tuple[list, bool]: - """Add each value from an indexed var/param, - This also works ok for non-indexed ones. - - Returns: - (list of items, indexed flag) - """ - items = [] - indexed = False - for index in c: - v = c[index] - indexed = index is not None - if subtype == self.VAR_TYPE: - # index, value, units, is-fixed, is-stale, lower-bound, upper-bound, domain - item = ( - index, - pyo.value(v), - self._unitstr(c), - v.fixed, - v.stale, - v.lb, - v.ub, - str(v.domain), - ) - else: - # index, value, units, domain - item = (index, pyo.value(v), self._unitstr(c)) - items.append(item) - return items, indexed - - @staticmethod - def _unitstr(c): - # Convert Pyomo units obj to string - s = str(c.get_units()) - # Replace 'None' with an empty string - return "" if s == "None" else s - - @staticmethod - def _is_var(c): - return c.is_variable_type() or isinstance(c, IndexedVar) - - @staticmethod - def _is_param(c): - return c.is_parameter_type() or isinstance(c, IndexedParam) - - @staticmethod - def _add_block(tree: dict, name: str, block): - # get parts of the name - # - mostly logic to handle 'foo.bar[0.0].baz' crap - p = name.split(".") - parts, i, n = [], 0, len(p) - while i < n: - cur = p[i] - # since split('.') creates ('foo[0.', '0]') from 'foo[0.0]', - # we need to rejoin them - if i < n - 1 and re.match(r".*\[\d+$", cur): - next_ = p[i + 1] - parts.append(cur + "." + next_) - i += 2 - else: - parts.append(cur) - i += 1 - # insert in tree by walking down each - # key in 'parts', adding empty dicts - # as we go - t, prev = tree, None - for p in parts: - prev = t - if p not in t: - t[p] = {} - t = t[p] - # add the block in the final dict - prev[p] = block - - def report(self) -> Report: - """Report containing model variable values.""" - return self.Report(variables=self._vars, port_aliases=self._ports) - - -class MermaidDiagram(Action): - """Action to generate a Mermaid diagram after the run.""" - - class Report(BaseModel): - """Report containing a Mermaid diagram.""" - - diagram: list[str] #: each item is one line - - def __init__(self, runner, **kwargs): - """Initialize Mermaid diagram generation settings. - - Args: - runner: Runner that owns this action. - **kwargs: Additional keyword arguments passed to `Action`. - """ - super().__init__(runner, **kwargs) - self._images = False # TODO: make this configurable - self._model_root_split = [] - self.diagram = None - - def show_unit_images(self, value: bool): - """Whether Mermaid displays images for units. - - Args: - value: If true, display images. Otherwise, don't. - """ - self._images = bool(value) - - def set_model_root(self, path: str): - """Set path to root of model to display (default is model itself). - - Args: - path: Dotted path like "fs" or "fs.component" - """ - self._model_root_split = path.split(".") - - def after_run(self): - """Build Mermaid diagram after the run.""" - if Connectivity is None: - self.diagram = None - else: - root = self._runner.model - for p in self._model_root_split: - root = getattr(root, p) - conn = Connectivity(input_model=root) - self.diagram = Mermaid(conn, component_images=self._images) - - def report(self) -> Report | dict: - """Report containing the Mermaid diagram. - - Returns: - Report object if idaes_connectivity is active, otherwise - an empty dictionary - """ - if self.diagram is None: - return {} - mermaid_lines = self.diagram.write(None).split("\n") - return self.Report(diagram=mermaid_lines) - - -class StreamTable(Action): - """Action to generate a stream table from the current model.""" - - class Report(BaseModel): - """Stream table, where each row is a variable and each column is a stream.""" - - index: list[str] # name of each row, i.e. the stream name - units: list[str] # units for each row - columns: list[str] # column header: , , ... - #: rows, where each value is a tuple of the value and fixed/free/parameter/expression - data: list[list[tuple[float, str]]] - - def __init__(self, runner, **kwargs): - assert isinstance(runner, BaseFlowsheetRunner) # makes no sense otherwise - super().__init__(runner, **kwargs) - self._stream_table = {} - - def after_run(self): - """Build stream table after the run.""" - # get streams - streams = {} - for component in self._runner.model.component_objects(Arc, descend_into=True): - streams[component.getname()] = component - - # create stream table using existing utility function - df = create_stream_table_ui(streams) - dd = df.to_dict(orient="split") - - # move units column to its own list - dd["columns"] = dd["columns"][1:] # delete first column of header - dd["units"] = [str(r[0]) for r in dd["data"]] # copy Units obj, convert to str - dd["data"] = [r[1:] for r in dd["data"]] # delete 1st column of data - - self._stream_table = dd - - def report(self) -> Report: - if self._stream_table: - report = self.Report(**self._stream_table) - else: - report = self.Report(index=[], units=[], columns=[], data=[]) - return report - - -class Diagnostics(SolverActionBase): - """Action to get model diagnostics.""" - - class Report(BaseModel): - """Report containing model diagnostics. - - These attributes should match keys of dict returned by the method - `idaes_fi.compute_diagnostics.DiagnosticsData.all_as_obj()`. - """ - - #: This is False if there was no model to diagnose - valid: bool = False - #: If valid is True, all these should have values, - #: otherwise they will all be None/null - variables: ComponentList | None = None - constraints: ComponentList | None = None - structural_issues: StructuralIssuesData | None = None - numerical_issues: NumericalIssuesData | None = None - - def __init__(self, runner, **kwargs): - super().__init__(runner, **kwargs) - self._had_solve = False - self.diagnostics = {} - - def after_step(self, name): - if self.is_solve_step(name): - self._had_solve = True - - def after_run(self): - """Get model diagnostics after the run.""" - m = self._runner.model - if m is not None: - try: - dd = DiagnosticsData(model=m) - if self._had_solve: - # get everything if a solve - self.diagnostics = dd.all_as_obj() - else: - # TODO: get structural issues? - self.diagnostics = {} - except DiagnosticsError as err: - self.log.error(f"Diagnostics will be empty due to error: {err}") - self.diagnostics = {} - except TypeError as err: - self.log.warning(f"Diagnostics error due to model object type: {err}") - self.diagnostics = {} - - def report(self) -> Report: - """Report containing model diagnostics information. - - Returns: - Report object - """ - report = self.Report() - for key, val in self.diagnostics.items(): - setattr(report, key, val) - report.valid = bool(self.diagnostics) - return report diff --git a/src/idaes_fi/structfs/simple_wrap.py b/src/idaes_fi/structfs/simple_wrap.py index 9965391..79dded6 100644 --- a/src/idaes_fi/structfs/simple_wrap.py +++ b/src/idaes_fi/structfs/simple_wrap.py @@ -1,14 +1,19 @@ ################################################################################# -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. # -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. ################################################################################# """ Simple wrapper @@ -35,7 +40,7 @@ class SimpleFlowsheetRunner(BaseFlowsheetRunner): def __init__(self, *args, **kwargs): """Constructor.""" - from .runner_actions import ( # pylint: disable=C0415 + from .actions import ( # pylint: disable=C0415 Timer, UnitDofChecker, CaptureSolverOutput, diff --git a/src/idaes_fi/structfs/tests/demo_flowsheet.py b/src/idaes_fi/structfs/tests/demo_flowsheet.py index ac13fa0..9f1ce1f 100644 --- a/src/idaes_fi/structfs/tests/demo_flowsheet.py +++ b/src/idaes_fi/structfs/tests/demo_flowsheet.py @@ -1,14 +1,19 @@ ################################################################################# -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. # -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. ################################################################################# """ Demonstration flowsheet for testing purposes. diff --git a/src/idaes_fi/structfs/tests/demo_flowsheet_fi_main.py b/src/idaes_fi/structfs/tests/demo_flowsheet_fi_main.py index 93b8644..f9cdd64 100644 --- a/src/idaes_fi/structfs/tests/demo_flowsheet_fi_main.py +++ b/src/idaes_fi/structfs/tests/demo_flowsheet_fi_main.py @@ -1,3 +1,20 @@ +################################################################################# +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. +# +################################################################################# """ Import functions from demo flowsheet, call them in a main() function decorated with @fi_main diff --git a/src/idaes_fi/structfs/tests/demo_flowsheet_structured.py b/src/idaes_fi/structfs/tests/demo_flowsheet_structured.py index 9f4f742..14f9567 100644 --- a/src/idaes_fi/structfs/tests/demo_flowsheet_structured.py +++ b/src/idaes_fi/structfs/tests/demo_flowsheet_structured.py @@ -1,3 +1,20 @@ +################################################################################# +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. +# +################################################################################# """ Import functions from demo flowsheet and wrap them with the FlowsheetRunner """ diff --git a/src/idaes_fi/structfs/tests/demo_flowsheet_structured_multi.py b/src/idaes_fi/structfs/tests/demo_flowsheet_structured_multi.py index 9a5cd59..1303555 100644 --- a/src/idaes_fi/structfs/tests/demo_flowsheet_structured_multi.py +++ b/src/idaes_fi/structfs/tests/demo_flowsheet_structured_multi.py @@ -1,3 +1,20 @@ +################################################################################# +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. +# +################################################################################# """ Import functions from demo flowsheet and wrap them with the FlowsheetRunner """ diff --git a/src/idaes_fi/structfs/tests/flash_flowsheet.py b/src/idaes_fi/structfs/tests/flash_flowsheet.py index 7479ebe..eae70c7 100644 --- a/src/idaes_fi/structfs/tests/flash_flowsheet.py +++ b/src/idaes_fi/structfs/tests/flash_flowsheet.py @@ -1,14 +1,19 @@ ################################################################################# -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. # -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. ################################################################################# """ Simple Flash flowsheet for use in testing. diff --git a/src/idaes_fi/structfs/tests/flash_main.py b/src/idaes_fi/structfs/tests/flash_main.py index 81b650e..35b2a69 100644 --- a/src/idaes_fi/structfs/tests/flash_main.py +++ b/src/idaes_fi/structfs/tests/flash_main.py @@ -1,3 +1,20 @@ +################################################################################# +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. +# +################################################################################# from pyomo.environ import ConcreteModel, SolverFactory from idaes.core import FlowsheetBlock diff --git a/src/idaes_fi/structfs/tests/hda_flowsheet.py b/src/idaes_fi/structfs/tests/hda_flowsheet.py index b2165c9..34a195d 100644 --- a/src/idaes_fi/structfs/tests/hda_flowsheet.py +++ b/src/idaes_fi/structfs/tests/hda_flowsheet.py @@ -1,15 +1,20 @@ -############################################################################### -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). +################################################################################# +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 # -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. -############################################################################### +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. +# +################################################################################# # diff --git a/src/idaes_fi/structfs/tests/hda_ideal_VLE.py b/src/idaes_fi/structfs/tests/hda_ideal_VLE.py index a44363d..7c14c05 100644 --- a/src/idaes_fi/structfs/tests/hda_ideal_VLE.py +++ b/src/idaes_fi/structfs/tests/hda_ideal_VLE.py @@ -1,15 +1,20 @@ -############################################################################## -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). +################################################################################# +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 # -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. -############################################################################## +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. +# +################################################################################# """ Example ideal parameter block for the VLE calculations for a Benzene-Toluene-o-Xylene system. diff --git a/src/idaes_fi/structfs/tests/hda_reaction.py b/src/idaes_fi/structfs/tests/hda_reaction.py index b0d2332..0f9409f 100644 --- a/src/idaes_fi/structfs/tests/hda_reaction.py +++ b/src/idaes_fi/structfs/tests/hda_reaction.py @@ -1,14 +1,19 @@ ################################################################################# -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. # -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. ################################################################################# """ Property package for the hydrodealkylation of toluene to form benzene diff --git a/src/idaes_fi/structfs/tests/model_from_template.py b/src/idaes_fi/structfs/tests/model_from_template.py index cc43631..b468ac7 100644 --- a/src/idaes_fi/structfs/tests/model_from_template.py +++ b/src/idaes_fi/structfs/tests/model_from_template.py @@ -1,3 +1,20 @@ +################################################################################# +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. +# +################################################################################# """ Template for creating a new IDAES/PrOMMiS/WaterTAP flowsheet. """ diff --git a/src/idaes_fi/structfs/tests/test_common.py b/src/idaes_fi/structfs/tests/test_common.py index 2e56f32..80a3f20 100644 --- a/src/idaes_fi/structfs/tests/test_common.py +++ b/src/idaes_fi/structfs/tests/test_common.py @@ -1,14 +1,19 @@ ################################################################################# -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. # -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. ################################################################################# diff --git a/src/idaes_fi/structfs/tests/test_demo_flowsheet.py b/src/idaes_fi/structfs/tests/test_demo_flowsheet.py index 2b8f676..fb10642 100644 --- a/src/idaes_fi/structfs/tests/test_demo_flowsheet.py +++ b/src/idaes_fi/structfs/tests/test_demo_flowsheet.py @@ -1,3 +1,20 @@ +################################################################################# +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. +# +################################################################################# """ Tests that utilize the demo_flowsheet_structured.py module in this directory. diff --git a/src/idaes_fi/structfs/tests/test_fsrunner.py b/src/idaes_fi/structfs/tests/test_fsrunner.py index 0272470..2883f5a 100644 --- a/src/idaes_fi/structfs/tests/test_fsrunner.py +++ b/src/idaes_fi/structfs/tests/test_fsrunner.py @@ -1,14 +1,19 @@ ################################################################################# -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. # -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. ################################################################################# from pathlib import Path from types import SimpleNamespace diff --git a/src/idaes_fi/structfs/tests/test_logutil.py b/src/idaes_fi/structfs/tests/test_logutil.py index 1734484..090fde0 100644 --- a/src/idaes_fi/structfs/tests/test_logutil.py +++ b/src/idaes_fi/structfs/tests/test_logutil.py @@ -1,14 +1,19 @@ ################################################################################# -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. # -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. ################################################################################# """ Tests for logutil module diff --git a/src/idaes_fi/structfs/tests/test_runner.py b/src/idaes_fi/structfs/tests/test_runner.py index 090f988..f697682 100644 --- a/src/idaes_fi/structfs/tests/test_runner.py +++ b/src/idaes_fi/structfs/tests/test_runner.py @@ -1,19 +1,23 @@ ################################################################################# -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. # -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. ################################################################################# import pytest from pydantic import BaseModel from ..runner import Runner, Action -from .. import runner_actions ## -- setup -- diff --git a/src/idaes_fi/structfs/tests/test_runner_actions.py b/src/idaes_fi/structfs/tests/test_runner_actions.py index 4f678f5..6b1ef9f 100644 --- a/src/idaes_fi/structfs/tests/test_runner_actions.py +++ b/src/idaes_fi/structfs/tests/test_runner_actions.py @@ -1,14 +1,19 @@ ################################################################################# -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. # -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. ################################################################################# # stdlib @@ -21,7 +26,7 @@ from .. import runner from . import flash_flowsheet, hda_flowsheet -from ..runner_actions import ( +from ..actions import ( MermaidDiagram, Timer, UnitDofChecker, diff --git a/src/idaes_fi/structfs/tests/test_simple_wrap.py b/src/idaes_fi/structfs/tests/test_simple_wrap.py index 2858915..a5d6610 100644 --- a/src/idaes_fi/structfs/tests/test_simple_wrap.py +++ b/src/idaes_fi/structfs/tests/test_simple_wrap.py @@ -1,14 +1,19 @@ ################################################################################# -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. # -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. ################################################################################# """ Tests for simplified wrapper API. diff --git a/src/idaes_fi/structfs/tests/test_structfs.py b/src/idaes_fi/structfs/tests/test_structfs.py index 821950d..3986b76 100644 --- a/src/idaes_fi/structfs/tests/test_structfs.py +++ b/src/idaes_fi/structfs/tests/test_structfs.py @@ -1,14 +1,19 @@ -################################################################################ -# The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the -# Design of Advanced Energy Systems (IDAES). +################################################################################# +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. # -# Copyright (c) 2018-2026 by the software owners: The Regents of the -# University of California, through Lawrence Berkeley National Laboratory, -# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon -# University, West Virginia University Research Corporation, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md -# for full copyright and license information. ################################################################################# """ Tests for structfs __init__.py diff --git a/src/idaes_fi/tests/test_import.py b/src/idaes_fi/tests/test_import.py index ad78c7e..3c0f8e2 100644 --- a/src/idaes_fi/tests/test_import.py +++ b/src/idaes_fi/tests/test_import.py @@ -1,3 +1,20 @@ +################################################################################# +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. +# +################################################################################# from idaes_fi import __version__ from idaes_fi import compute_diagnostics From 4341503926d01d52438bd1f891bc1e0803432123 Mon Sep 17 00:00:00 2001 From: Dan Gunter Date: Fri, 15 May 2026 07:45:08 -0700 Subject: [PATCH 3/4] added actions dir --- src/idaes_fi/structfs/actions/__init__.py | 62 ++++ .../structfs/actions/mermaid_diagram.py | 87 +++++ .../structfs/actions/model_variables.py | 207 ++++++++++++ src/idaes_fi/structfs/actions/solver.py | 298 ++++++++++++++++++ src/idaes_fi/structfs/actions/stream_table.py | 68 ++++ src/idaes_fi/structfs/actions/timer.py | 109 +++++++ .../structfs/actions/unit_dof_checker.py | 203 ++++++++++++ 7 files changed, 1034 insertions(+) create mode 100644 src/idaes_fi/structfs/actions/__init__.py create mode 100644 src/idaes_fi/structfs/actions/mermaid_diagram.py create mode 100644 src/idaes_fi/structfs/actions/model_variables.py create mode 100644 src/idaes_fi/structfs/actions/solver.py create mode 100644 src/idaes_fi/structfs/actions/stream_table.py create mode 100644 src/idaes_fi/structfs/actions/timer.py create mode 100644 src/idaes_fi/structfs/actions/unit_dof_checker.py diff --git a/src/idaes_fi/structfs/actions/__init__.py b/src/idaes_fi/structfs/actions/__init__.py new file mode 100644 index 0000000..8794f51 --- /dev/null +++ b/src/idaes_fi/structfs/actions/__init__.py @@ -0,0 +1,62 @@ +################################################################################# +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# “Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)” was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability (“PrOMMiS”) initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. +# +################################################################################# + +"""Runner action implementations.""" + +from importlib import import_module + +__all__ = [ + "CaptureSolverOutput", + "Diagnostics", + "GetSolverResults", + "MermaidDiagram", + "ModelVariables", + "SolverActionBase", + "SolverResult", + "StreamTable", + "Timer", + "UnitDofChecker", + "UnitDofType", +] + +_EXPORT_MODULES = { + "CaptureSolverOutput": "solver", + "Diagnostics": "solver", + "GetSolverResults": "solver", + "MermaidDiagram": "mermaid_diagram", + "ModelVariables": "model_variables", + "SolverActionBase": "solver", + "SolverResult": "solver", + "StreamTable": "stream_table", + "Timer": "timer", + "UnitDofChecker": "unit_dof_checker", + "UnitDofType": "unit_dof_checker", +} + + +# Lazy-load allows you to not install dependencies +# for actions that you never import and use +def __getattr__(name): + try: + module_name = _EXPORT_MODULES[name] + except KeyError as err: + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") from err + module = import_module(f".{module_name}", __name__) + value = getattr(module, name) + globals()[name] = value + return value diff --git a/src/idaes_fi/structfs/actions/mermaid_diagram.py b/src/idaes_fi/structfs/actions/mermaid_diagram.py new file mode 100644 index 0000000..6663149 --- /dev/null +++ b/src/idaes_fi/structfs/actions/mermaid_diagram.py @@ -0,0 +1,87 @@ +################################################################################# +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# "Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)" was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability ("PrOMMiS") initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. +# +################################################################################# +"""Mermaid diagram action.""" + +from pydantic import BaseModel + +from ..action_base import Action + +try: + from idaes_connectivity.base import Connectivity, Mermaid +except ImportError: + Connectivity = None + + +class MermaidDiagram(Action): + """Action to generate a Mermaid diagram after the run.""" + + class Report(BaseModel): + """Report containing a Mermaid diagram.""" + + diagram: list[str] #: each item is one line + + def __init__(self, runner, **kwargs): + """Initialize Mermaid diagram generation settings. + + Args: + runner: Runner that owns this action. + **kwargs: Additional keyword arguments passed to `Action`. + """ + super().__init__(runner, **kwargs) + self._images = False # TODO: make this configurable + self._model_root_split = [] + self.diagram = None + + def show_unit_images(self, value: bool): + """Whether Mermaid displays images for units. + + Args: + value: If true, display images. Otherwise, don't. + """ + self._images = bool(value) + + def set_model_root(self, path: str): + """Set path to root of model to display (default is model itself). + + Args: + path: Dotted path like "fs" or "fs.component" + """ + self._model_root_split = path.split(".") + + def after_run(self): + """Build Mermaid diagram after the run.""" + if Connectivity is None: + self.diagram = None + else: + root = self._runner.model + for p in self._model_root_split: + root = getattr(root, p) + conn = Connectivity(input_model=root) + self.diagram = Mermaid(conn, component_images=self._images) + + def report(self) -> Report | dict: + """Report containing the Mermaid diagram. + + Returns: + Report object if idaes_connectivity is active, otherwise + an empty dictionary + """ + if self.diagram is None: + return {} + mermaid_lines = self.diagram.write(None).split("\n") + return self.Report(diagram=mermaid_lines) diff --git a/src/idaes_fi/structfs/actions/model_variables.py b/src/idaes_fi/structfs/actions/model_variables.py new file mode 100644 index 0000000..0548beb --- /dev/null +++ b/src/idaes_fi/structfs/actions/model_variables.py @@ -0,0 +1,207 @@ +################################################################################# +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# "Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)" was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability ("PrOMMiS") initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. +# +################################################################################# +"""Model variable extraction action.""" + +import logging +import re + +import pyomo.environ as pyo +from pydantic import BaseModel, Field +from pyomo.core.base.param import IndexedParam +from pyomo.core.base.var import IndexedVar +from pyomo.network.port import Port + +from ..action_base import Action +from ..fsrunner import BaseFlowsheetRunner + + +class ModelVariables(Action): + """Extract and format model variables.""" + + VAR_TYPE, PARAM_TYPE = "V", "P" + + class Report(BaseModel): + """Report for ModelVariables.""" + + #: Tree of variables + variables: dict = Field(default={}) + port_aliases: dict = Field(default={}) + + def __init__(self, runner, **kwargs): + """Initialize model variable extraction state. + + Args: + runner: Flowsheet runner that owns this action. + **kwargs: Additional keyword arguments passed to `Action`. + """ + assert isinstance(runner, BaseFlowsheetRunner) # makes no sense otherwise + super().__init__(runner, **kwargs) + self._vars = {} + self._port_vars = {} + self._ports = {} + + def after_run(self): + """Actions performed after the run.""" + self._saved_paths = {} # fast lookup used in _add_block() + self.log = logging.getLogger(self.log.name) + self._extract_vars(self._runner.model) + + def _extract_vars(self, m): + var_tree = {} + port_aliases = {} + for c in m.component_objects(): + # get component type + if self._is_var(c): + subtype = self.VAR_TYPE + elif self._is_param(c): + subtype = self.PARAM_TYPE + else: + # find and extract aliases to vars on assoc. ports + if hasattr(c, "component_data_objects"): + for port_data in c.component_data_objects(Port, descend_into=False): + comp_name = port_data.name # proper name of port's component + for port_name, port_var in port_data.vars.items(): + if isinstance(port_var, pyo.Var): # only variables + port_aliases[f"{comp_name}.{port_name}"] = port_var.name + continue # do nothing else + # start new block + b = [subtype] + # add its variables + items = [] + indexed = False + # add each value from an indexed var/param, + # this also works ok for non-indexed ones + for index in c: + v = c[index] + indexed = index is not None + v_value = self._safe_scalar_value(v) + if subtype == self.VAR_TYPE: + # index, value, fixed, stale, lower bound, upper bound, domain + item = ( + index, + v_value, + v.fixed, + v.stale, + v.lb, + v.ub, + str(v.domain), + ) + else: + # index, value + item = (index, v_value) + items.append(item) + b.append(indexed) + b.append(items) + # add block to tree + self._add_block(var_tree, c.name, b) + + self._vars = var_tree + self._ports = port_aliases + + @staticmethod + def _safe_scalar_value(v): + """Get value, allowing for uninitialized values. + An uninitialized value will return None. + """ + if isinstance(v, float) or isinstance(v, int): + return v + if not v.is_fixed() and v.stale: + # avoids logged errors from uninitialized vars + return None + try: + return pyo.value(v) + except ValueError: + return None + + def _get_values(self, c, subtype) -> tuple[list, bool]: + """Add each value from an indexed var/param, + This also works ok for non-indexed ones. + + Returns: + (list of items, indexed flag) + """ + items = [] + indexed = False + for index in c: + v = c[index] + indexed = index is not None + if subtype == self.VAR_TYPE: + # index, value, units, is-fixed, is-stale, lower-bound, upper-bound, domain + item = ( + index, + pyo.value(v), + self._unitstr(c), + v.fixed, + v.stale, + v.lb, + v.ub, + str(v.domain), + ) + else: + # index, value, units, domain + item = (index, pyo.value(v), self._unitstr(c)) + items.append(item) + return items, indexed + + @staticmethod + def _unitstr(c): + # Convert Pyomo units obj to string + s = str(c.get_units()) + # Replace 'None' with an empty string + return "" if s == "None" else s + + @staticmethod + def _is_var(c): + return c.is_variable_type() or isinstance(c, IndexedVar) + + @staticmethod + def _is_param(c): + return c.is_parameter_type() or isinstance(c, IndexedParam) + + @staticmethod + def _add_block(tree: dict, name: str, block): + # get parts of the name + # - mostly logic to handle 'foo.bar[0.0].baz' crap + p = name.split(".") + parts, i, n = [], 0, len(p) + while i < n: + cur = p[i] + # since split('.') creates ('foo[0.', '0]') from 'foo[0.0]', + # we need to rejoin them + if i < n - 1 and re.match(r".*\[\d+$", cur): + next_ = p[i + 1] + parts.append(cur + "." + next_) + i += 2 + else: + parts.append(cur) + i += 1 + # insert in tree by walking down each + # key in 'parts', adding empty dicts + # as we go + t, prev = tree, None + for p in parts: + prev = t + if p not in t: + t[p] = {} + t = t[p] + # add the block in the final dict + prev[p] = block + + def report(self) -> Report: + """Report containing model variable values.""" + return self.Report(variables=self._vars, port_aliases=self._ports) diff --git a/src/idaes_fi/structfs/actions/solver.py b/src/idaes_fi/structfs/actions/solver.py new file mode 100644 index 0000000..af648ce --- /dev/null +++ b/src/idaes_fi/structfs/actions/solver.py @@ -0,0 +1,298 @@ +################################################################################# +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# "Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)" was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability ("PrOMMiS") initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. +# +################################################################################# +"""Solver-related runner actions.""" + +from datetime import datetime +from io import StringIO +import sys + +from pydantic import BaseModel +from pyomo.opt.results.container import ScalarData + +from ...compute_diagnostics import ( + ComponentList, + DiagnosticsData, + DiagnosticsError, + NumericalIssuesData, + StructuralIssuesData, +) +from ..action_base import Action +from ..fsrunner import BaseFlowsheetRunner + + +class SolverActionBase(Action): + """Base class for actions to get solver state, output, etc.""" + + #: By default, consider any step with 'solve' in its name to + #: be a solver step. This can be overridden by setting :attr:`solve_steps` + #: to some other list of step names. + DEFAULT_SOLVE_STEPS = [s for s in BaseFlowsheetRunner.STEPS if "solve" in s] + + def __init__(self, runner: BaseFlowsheetRunner, **kwargs): + """Initialize solver output capture state. + + Args: + runner: Runner that owns this action. + **kwargs: Additional keyword arguments passed to `Action`. + """ + super().__init__(runner, **kwargs) + self._solve_steps = self.DEFAULT_SOLVE_STEPS + + @property + def solve_steps(self) -> list[str]: + """Get list of solve steps""" + return self._solve_steps.copy() + + @solve_steps.setter + def solve_steps(self, value: list[str]): + """Set new list of solve steps""" + self._solve_steps = value + + def is_solve_step(self, name: str) -> bool: + """Whether step `name` is the solve step. + + Args: + name: step name + + Returns: + True if it is the solve step, otherwise False + """ + return name in self._solve_steps + + +class CaptureSolverOutput(SolverActionBase): + """Capture the solver output.""" + + class Report(BaseModel): + """Report object for captured solver output action""" + + #: String of output keyed by step + output: dict[str, str] = {} + + def __init__(self, runner, **kwargs): + """Constructor + + Args: + runner: BaseFlowsheetRunner object + kwargs: Arguments passed through to superclass + """ + super().__init__(runner, **kwargs) + self._logs = {} + self._solver_out = None + self._save_stdout = None + + def before_step(self, step_name: str): + """Action performed before the step.""" + if self.is_solve_step(step_name): + self._solver_out = StringIO() + self._save_stdout, sys.stdout = sys.stdout, self._solver_out + + def after_step(self, step_name: str): + """Action performed after the step.""" + if self._solver_out is not None: + self._logs[step_name] = self._solver_out.getvalue() + self._solver_out = None + sys.stdout = self._save_stdout + + def step_failed(self, step_name: str, err: Exception): + if self._save_stdout: + sys.stdout = self._save_stdout + self._solver_out.flush() + # print stored stdout for debugging help + print(self._solver_out.getvalue()) + + def report(self) -> Report: + """Machine-readable report with solver output. + + Returns: + CaptureSolverOutput.Report + """ + return self.Report(output=self._logs) + + +class SolverResult(BaseModel): + """One solver result in `GetSolverResults.Report.result`""" + + problem: dict[str, int | float | str] = {} + solver: dict[str, int | float | str] = {} + values: dict[str, int | float | str | dict] = {} + + +class GetSolverResults(SolverActionBase): + """Retrieve and structure the results from the solver.""" + + class Report(BaseModel): + """Report object for action""" + + #: Result from Pyomo solver Result object + #: Since multiple results may be returned, + #: this is a list. + results: list[SolverResult] = [] + + def __init__(self, runner: BaseFlowsheetRunner, **kwargs): + """Constructor. + + Args: + runner: Runner that owns this action. + **kwargs: Additional keyword arguments passed to `Action`. + """ + super().__init__(runner, **kwargs) + self._results = [] + + def after_step(self, step_name: str): + """Action performed after the step.""" + if self.is_solve_step(step_name): + self._extract_results() + + @staticmethod + def _sval(v): + # convert to a numeric or string value + if isinstance(v, datetime): + return v.timestamp() + elif isinstance(v, float) or isinstance(v, int): + return v + return str(v) + + def _extract_results(self): + r = self._runner.results + + if r is None: + self._results = [] + return + + # extract Pyomo dict of lists into a list of SolverResult objs + # eg {"Solver": [{...}, ], "Problem": [{...},]} -> + # [SolverResult, SolverResult] + # Add ScalarData items (single values) to every object + result_list, scalars = [], {} + for k, v in r.items(): + + # Special processing for single-values + if isinstance(v, ScalarData): + vv = v.get_value() + if isinstance(vv, dict): + scalar_value = {} + for k2, v2 in vv.items(): + scalar_value[k2] = self._sval(v2) + else: + scalar_value = self._sval(vv) + scalars[k] = scalar_value + continue # done + + n = len(v) + # make sure result list has space + while n > len(result_list): + result_list.append(SolverResult()) + # choose which part of result this is + if k in ("Solver", "Problem"): + sr_attr = k.lower() + else: + self.log.info(f"Ignoring unknown key in solver results: {k}") + continue + # extract Pyomo list for a given attr into SolverResult + for i in range(n): + v_dict = {} + # convert values in dict to int, str, float, or None + for v_k, v_v in v[i].items(): + if hasattr(v_v, "get_value"): + v_v = v_v.get_value() + if isinstance(v_v, int) or isinstance(v_v, float): + v_dict[v_k] = v_v + else: + s = str(v_v) + if s == "": + pass # who cares? skip it + else: + v_dict[v_k] = s + # set the corresponding i-th result attribute + setattr(result_list[i], sr_attr, v_dict) + + # Add collected scalar values to every result in list + for r in result_list: + for k, v in scalars.items(): + r.values[k] = v + + self._results = result_list + + def report(self) -> Report: + """Report solver result. + + Returns: + GetSolverResult.Report + """ + return self.Report(results=self._results) + + +class Diagnostics(SolverActionBase): + """Action to get model diagnostics.""" + + class Report(BaseModel): + """Report containing model diagnostics. + + These attributes should match keys of dict returned by the method + `idaes_fi.compute_diagnostics.DiagnosticsData.all_as_obj()`. + """ + + #: This is False if there was no model to diagnose + valid: bool = False + #: If valid is True, all these should have values, + #: otherwise they will all be None/null + variables: ComponentList | None = None + constraints: ComponentList | None = None + structural_issues: StructuralIssuesData | None = None + numerical_issues: NumericalIssuesData | None = None + + def __init__(self, runner, **kwargs): + super().__init__(runner, **kwargs) + self._had_solve = False + self.diagnostics = {} + + def after_step(self, name): + if self.is_solve_step(name): + self._had_solve = True + + def after_run(self): + """Get model diagnostics after the run.""" + m = self._runner.model + if m is not None: + try: + dd = DiagnosticsData(model=m) + if self._had_solve: + # get everything if a solve + self.diagnostics = dd.all_as_obj() + else: + # TODO: get structural issues? + self.diagnostics = {} + except DiagnosticsError as err: + self.log.error(f"Diagnostics will be empty due to error: {err}") + self.diagnostics = {} + except TypeError as err: + self.log.warning(f"Diagnostics error due to model object type: {err}") + self.diagnostics = {} + + def report(self) -> Report: + """Report containing model diagnostics information. + + Returns: + Report object + """ + report = self.Report() + for key, val in self.diagnostics.items(): + setattr(report, key, val) + report.valid = bool(self.diagnostics) + return report diff --git a/src/idaes_fi/structfs/actions/stream_table.py b/src/idaes_fi/structfs/actions/stream_table.py new file mode 100644 index 0000000..fbf9be5 --- /dev/null +++ b/src/idaes_fi/structfs/actions/stream_table.py @@ -0,0 +1,68 @@ +################################################################################# +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# "Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)" was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability ("PrOMMiS") initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. +# +################################################################################# +"""Stream table action.""" + +from idaes.core.util.tables import create_stream_table_ui +from pydantic import BaseModel +from pyomo.network import Arc + +from ..action_base import Action +from ..fsrunner import BaseFlowsheetRunner + + +class StreamTable(Action): + """Action to generate a stream table from the current model.""" + + class Report(BaseModel): + """Stream table, where each row is a variable and each column is a stream.""" + + index: list[str] # name of each row, i.e. the stream name + units: list[str] # units for each row + columns: list[str] # column header: , , ... + #: rows, where each value is a tuple of the value and fixed/free/parameter/expression + data: list[list[tuple[float, str]]] + + def __init__(self, runner, **kwargs): + assert isinstance(runner, BaseFlowsheetRunner) # makes no sense otherwise + super().__init__(runner, **kwargs) + self._stream_table = {} + + def after_run(self): + """Build stream table after the run.""" + # get streams + streams = {} + for component in self._runner.model.component_objects(Arc, descend_into=True): + streams[component.getname()] = component + + # create stream table using existing utility function + df = create_stream_table_ui(streams) + dd = df.to_dict(orient="split") + + # move units column to its own list + dd["columns"] = dd["columns"][1:] # delete first column of header + dd["units"] = [str(r[0]) for r in dd["data"]] # copy Units obj, convert to str + dd["data"] = [r[1:] for r in dd["data"]] # delete 1st column of data + + self._stream_table = dd + + def report(self) -> Report: + if self._stream_table: + report = self.Report(**self._stream_table) + else: + report = self.Report(index=[], units=[], columns=[], data=[]) + return report diff --git a/src/idaes_fi/structfs/actions/timer.py b/src/idaes_fi/structfs/actions/timer.py new file mode 100644 index 0000000..1bc80ee --- /dev/null +++ b/src/idaes_fi/structfs/actions/timer.py @@ -0,0 +1,109 @@ +################################################################################# +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# "Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)" was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability ("PrOMMiS") initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. +# +################################################################################# +"""Timing action for flowsheet runner steps.""" + +import time + +from pydantic import BaseModel, Field + +from ..action_base import Action + + +class Timer(Action): + """Simple step/run timer action.""" + + class Report(BaseModel): + """Report returned by report() method.""" + + # {"step_name": , ..} for each step + timings: dict[str, float] = Field(default={}) + run_time: float = -1.0 + + def __init__(self, runner, **kwargs): + """Constructor. + + Args: + runner: Associated Runner object + kwargs: Additional optional arguments for Action constructor + + Attributes: + step_times: Dict with key step name and value a list of + timings for that step + run_times: List of timings for a run (sequence of steps) + """ + super().__init__(runner, **kwargs) + self._step_order = runner.list_steps() + # initialize all step times to -1 + self.step_times: dict[str, float] = {step: -1 for step in self._step_order} + self.run_time: float = -1 + # initialize internal variables + self._run_begin, self._step_begin = None, {} + + def before_step(self, step_name): + """Record the start time for a step. + + Args: + step_name: Name of the step about to run. + """ + self._step_begin[step_name] = time.time() + + def after_step(self, step_name): + """Record the elapsed time for a completed step. + + Args: + step_name: Name of the step that just finished. + """ + t1 = time.time() + t0 = self._step_begin.get(step_name, None) + if t0 is None: + self.log.warning(f"Timer: step '{step_name}' end without begin") + else: + self._cur_step_times[step_name] = t1 - t0 + self._step_begin[step_name] = None + + def before_run(self): + """Initialize timer state before a run starts.""" + self._run_begin = time.time() + self._cur_step_times = {} + self._step_begin = {} + + def after_run(self): + """Finalize run timing data after a run completes.""" + t1 = time.time() + + # set run time + if self._run_begin is None: + self.log.warning("Timer: run end without begin") + self.run_time = -1 + else: + self.run_time = t1 - self._run_begin + self._run_begin = None + + # set all step times + self.step_times = { + step: self._cur_step_times.get(step, -1) for step in self._step_order + } + + def report(self) -> Report: + """Report the timings. + + Returns: + The report object + """ + rpt = self.Report(timings=self.step_times, run_time=self.run_time) + return rpt diff --git a/src/idaes_fi/structfs/actions/unit_dof_checker.py b/src/idaes_fi/structfs/actions/unit_dof_checker.py new file mode 100644 index 0000000..4f71330 --- /dev/null +++ b/src/idaes_fi/structfs/actions/unit_dof_checker.py @@ -0,0 +1,203 @@ +################################################################################# +# Process Optimization and Modeling for Minerals Sustainability (PrOMMiS) Copyright (c) 2023-2026 +# +# "Process Optimization and Modeling for Minerals Sustainability (PrOMMiS)" was produced under the DOE +# Process Optimization and Modeling for Minerals Sustainability ("PrOMMiS") initiative, and is +# copyrighted by the software owners: The Regents of the University of California, through Lawrence +# Berkeley National Laboratory, National Technology & Engineering Solutions of Sandia, LLC through +# Sandia National Laboratories, Carnegie Mellon University, University of Notre Dame, and West +# Virginia University Research Corporation. +# +# NOTICE. This Software was developed under funding from the U.S. Department of Energy and the +# U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted +# for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license +# in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform +# publicly and display publicly, and to permit other to do so. +# +################################################################################# +"""Degrees-of-freedom checking action.""" + +from collections.abc import Callable +from typing import Optional, Union + +from idaes.core.base.unit_model import ProcessBlockData +from idaes.core.util.model_statistics import degrees_of_freedom +from pydantic import BaseModel, Field +from pyomo.network.port import ScalarPort + +from ..action_base import Action +from ..fsrunner import BaseFlowsheetRunner + +# Hold degrees of freedom for one BaseFlowsheetRunner 'step' +# {key=component: value=dof} +UnitDofType = dict[str, int] + + +class UnitDofChecker(Action): + """Check degrees of freedom on unit models. + + After a (caller-named) step or steps, check the degrees + of freedom on each unit model by the method of + fixing the inlet, applying the `degrees_of_freedom()` function, + and unfixing the inlet again. The calculated values are + saved and passed to an optional caller-provided function. + + At the end of a run, the degrees of freedom for the entire + model are checked, saved, and passed to an optional function. + """ + + class Report(BaseModel): + """Report on degrees of freedom in a model.""" + + steps: dict[str, UnitDofType] = Field( + default={}, + description="Degrees of freedom for each named step", + examples=[{"build": 2, "set_operating_conditions": 1, "solve": 1}], + ) + model: int = Field( + default=0, description="Degrees of freedom for the entire model" + ) + + def __init__( + self, + runner: BaseFlowsheetRunner, + flowsheet: str, + steps: Union[str, list[str]], + step_func: Optional[Callable[[str, UnitDofType], None]] = None, + run_func: Optional[Callable[[dict[str, UnitDofType], int], None]] = None, + **kwargs, + ): + """Constructor. + + Args: + runner: Associated Runner object (provided by `add_action`) + flowsheet: Variable name for flowsheet, e.g. "fs" + steps: Step or steps at which to run the checking action + step_func: Function to call with calculated DoF values for one step. + Takes name of step and dictionary with per-unit degrees of freedom + (see `UnitDofType` alias). + run_func: Function to call with calculated DoF values for each step, as well + as overall model DoF. + kwargs: Additional optional arguments for Action constructor + + Raises: + ValueError: if `steps` list is empty, or no callback functions provided + """ + super().__init__(runner, **kwargs) + if hasattr(steps, "lower"): # string-like + self._steps = {steps} + else: # assume it is list-like + if len(steps) == 0: + raise ValueError("At least one step name must be provided") + self._steps = set(steps) + self._steps_dof: dict[str, UnitDofType] = {} + self._model_dof = 0 + self._step_func, self._run_func = step_func, run_func + self._fs = flowsheet + + def after_step(self, step_name: str): + """Compute unit and model degrees of freedom after a step. + + Args: + step_name: Name of the step that just completed. + """ + step_name = self._runner.normalize_name(step_name) + if step_name not in self._steps: + self.log.debug(f"Do not check DoF for step: {step_name}") + return + + try: + fs = self._get_flowsheet() + except AttributeError: + self.log.error( + f"Could not access flowsheet: attribute '{self._fs}' not found." + ) + return + + model_dof = degrees_of_freedom(self._get_flowsheet()) + units_dof = {self._fs: model_dof} + for unit in fs.component_objects(descend_into=True): + if self._is_unit_model(unit): + units_dof[unit.name] = self._get_dof(unit) + self._steps_dof[step_name] = units_dof # save + if self._step_func: + self._step_func(step_name, units_dof) + + def after_run(self): + """Actions performed after a run.""" + fs = self._get_flowsheet() + model_dof = degrees_of_freedom(fs) + self._model_dof = model_dof + if self._run_func: + self._run_func(self._steps_dof, model_dof) + + def _get_flowsheet(self): + m = self._runner.model + if self._fs: + return getattr(m, self._fs) + return m + + @staticmethod + def _is_unit_model(block): + return isinstance(block, ProcessBlockData) + + def get_dof(self) -> dict[str, UnitDofType]: + """Get degrees of freedom + + Returns: + dict[str, UnitDofType]: Mapping of step name to per-unit DoF when + the step completed. + """ + return self._steps_dof.copy() + + def get_dof_model(self) -> int: + """Get degrees of freedom for the model. + + Returns: + int: Last calculated DoF for the model. + """ + return self._model_dof + + def steps(self, only_with_data: bool = False) -> list[str]: + """Get list of steps for which unit degrees of freedom are calculated. + + Args: + only_with_data: If True, do not return steps with no data + + Returns: + list of step names + """ + if only_with_data: + return [s for s in self._steps if s in self._steps_dof] + return list(self._steps) + + def report(self) -> Report: + """Machine-readable report of degrees of freedom. + + Returns: + Report object + """ + return self.Report(steps=self.get_dof(), model=self.get_dof_model()) + + @staticmethod + def _get_dof(block, fix_inlets: bool = True): + if fix_inlets: + inlets = [ + c + for c in block.component_objects(descend_into=False) + if isinstance(c, ScalarPort) + and (c.name.endswith("inlet") or c.name.endswith("recycle")) + ] + free_me = [] + for inlet in inlets: + if not inlet.is_fixed(): + inlet.fix() + free_me.append(inlet) + + dof = degrees_of_freedom(block) + + if fix_inlets: + for inlet in free_me: + inlet.free() + + return dof From fa46e63f5c7517df1653589e9ba760741d6c3873 Mon Sep 17 00:00:00 2001 From: Dan Gunter Date: Fri, 15 May 2026 07:56:51 -0700 Subject: [PATCH 4/4] python 3.14 added --- .github/workflows/pytest.yml | 2 +- pyproject.toml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 854c220..9c465a3 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -32,7 +32,7 @@ jobs: needs: code-formatting strategy: matrix: - python-version: ["3.11", "3.12", "3.13"] + python-version: ["3.11", "3.12", "3.13", "3.14"] steps: - name: Set up Conda environment diff --git a/pyproject.toml b/pyproject.toml index 1cfbcc5..d4426ca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,23 +5,23 @@ build-backend = "setuptools.build_meta" [project] name = "idaes-fi" version = "0.1.0" -description = "Library modules and API for the IDAES Flowsheet Inspector user interface." +description = "Library modules and API for the Flowsheet Inspector user interface." readme = "README.md" requires-python = ">=3.10" license = { file = "LICENSE.md" } authors = [ { name = "PrOMMiS contributors" }, ] -keywords = ["idaes", "flowsheet", "process-modeling"] +keywords = ["idaes", "prommis", "flowsheet", "process-modeling"] classifiers = [ "Development Status :: 2 - Pre-Alpha", "Intended Audience :: Science/Research", "License :: OSI Approved :: BSD License", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", ] dependencies = [