Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Flexibility Analysis #1398

Open
wants to merge 66 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
84c832f
working on a module for flexibility analysis
michaelbynum Mar 2, 2022
63d2e82
reformatting files in flexibility analysis
michaelbynum Mar 2, 2022
051db2b
flexibility: updating imports
michaelbynum Mar 2, 2022
d27ecde
flexibility analysis cleanup
michaelbynum Mar 2, 2022
73c4326
flexibility analysis cleanup
michaelbynum Mar 2, 2022
3922932
flexibility analysis cleanup
michaelbynum Mar 2, 2022
dc77dd6
flexibility analysis: working on tests
michaelbynum Mar 2, 2022
dae913f
flexibility analysis: updating imports
michaelbynum Mar 4, 2022
3ccd861
Merge branch 'main' into flex
michaelbynum Mar 9, 2022
94cee4a
flexibility analysis: minor updates
michaelbynum Mar 16, 2022
95b354f
flexibility analysis: better initialization for sampling
michaelbynum Mar 30, 2022
f8a1c03
flexibility analysis: better initialization for sampling
michaelbynum Mar 31, 2022
de53a44
flexibility analysis: better ordering of sampled points
michaelbynum Apr 1, 2022
d778ceb
flexibility analysis: cleaning up sampling code
michaelbynum Apr 7, 2022
fb236f2
flexibility analysis: adding config options for active constraint method
michaelbynum Apr 8, 2022
2312395
flexibility analysis: minor updates
michaelbynum Apr 12, 2022
d81c314
flexibility analysis: option for total violation instead of max viola…
michaelbynum Apr 19, 2022
4c63cbb
Merge branch 'main' into flex
michaelbynum Sep 2, 2023
53fc67b
update tests
michaelbynum Sep 5, 2023
5fc5458
update tests
michaelbynum Sep 15, 2023
d5bf854
update flexibility example
michaelbynum Sep 18, 2023
66b66ce
update example
michaelbynum Sep 18, 2023
4b17072
Merge branch 'main' into flex
michaelbynum Dec 20, 2023
91b8051
working on docs for flexibility analysis
michaelbynum Dec 21, 2023
5970504
flexibility analysis docs
michaelbynum Jan 9, 2024
accd15d
flexibility analysis docs
michaelbynum Jan 9, 2024
f675b34
Merge remote-tracking branch 'main_fork/main' into flex
michaelbynum Jan 19, 2024
4c5a410
working on docs
michaelbynum Jan 30, 2024
78dd253
Merge remote-tracking branch 'main_fork/main' into flex
michaelbynum Feb 2, 2024
751e788
merge main into flex
michaelbynum Apr 23, 2024
795bd3a
run black
michaelbynum Apr 23, 2024
63d1045
flexibility analysis: cleanup imports
michaelbynum Apr 23, 2024
aab76b5
flexibility analysis: cleanup imports
michaelbynum Apr 23, 2024
4e37325
flexibility analysis: cleanup imports
michaelbynum Apr 23, 2024
f8d985c
run black
michaelbynum Apr 23, 2024
7e43bbd
fix tests
michaelbynum Apr 23, 2024
1007c01
run black
michaelbynum Apr 23, 2024
e054982
fix tests
michaelbynum Apr 23, 2024
d102906
update test tags
michaelbynum Apr 23, 2024
b794932
run black
michaelbynum Apr 23, 2024
9d7f846
update flexibility analysis tests
michaelbynum Apr 24, 2024
84b6bde
flexibility tests
michaelbynum Apr 24, 2024
00effaa
add headers
michaelbynum Apr 24, 2024
8c2b8e6
update tests
michaelbynum Apr 24, 2024
4a62056
update flex tests
michaelbynum Apr 24, 2024
81a2f99
flex docs
michaelbynum Apr 24, 2024
129e455
run black
michaelbynum Apr 24, 2024
22d830b
update docs dependencies
michaelbynum Apr 24, 2024
e83afb5
update imports
michaelbynum Apr 24, 2024
c1e6f3f
update imports
michaelbynum Apr 24, 2024
955b8fd
fix pylint errors
michaelbynum Apr 24, 2024
bee33de
fix pylint errors
michaelbynum Apr 24, 2024
b451df1
fix pylint errors
michaelbynum Apr 24, 2024
23061a1
fix pylint errors
michaelbynum Apr 24, 2024
3d56508
fix pylint errors
michaelbynum Apr 24, 2024
a6aa18c
bug fix
michaelbynum Apr 24, 2024
3abd59d
debugging ci
michaelbynum Apr 24, 2024
fce9af4
debugging ci
michaelbynum Apr 24, 2024
79d4b6a
revert some changes
michaelbynum Apr 24, 2024
7f51740
speed up flexibility tests
michaelbynum Apr 24, 2024
6004260
fix tests
michaelbynum Apr 24, 2024
8cdbde9
debugging ci
michaelbynum Apr 24, 2024
4a78054
fix tests
michaelbynum Apr 24, 2024
013fa66
revert some changes
michaelbynum Apr 24, 2024
6743fb1
fix docs
michaelbynum Apr 24, 2024
7cb6ee8
more flexibility tests
michaelbynum Apr 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"sphinx.ext.autosectionlabel",
"sphinxarg.ext",
"sphinx.ext.doctest",
"enum_tools.autoenum",
"sphinx_copybutton",
]

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

Flexibility Analysis
====================

A module for performing flexibility analysis.

.. toctree::
:maxdepth: 1

overview
reference

Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@

Flexibility Analysis Overview
=============================

.. contents::
:depth: 3
:local:

Introduction
------------

The flexibility analysis module within IDAES provides a framework for
evaluating how well a given system performs with respect to a set of
uncertain parameters. Two methods are provided. The flexibility (or feasibility) test
(FT) can be used to determine if a set of performance constraints can
be satisfied for any realization of uncertain parameters. The
flexibility index (FI) can be used to quantify the size of the
uncertainty region for which the performance constraints can be
satisfied [Grossmann1987]_.

The FT is given by

.. _FT:

.. math::

\phi(\underline{\theta}, \overline{\theta}) = &\max_{\theta} \min_{z} u \\
& s.t. \\
& g_{j}(x,z,\theta) \leq u \\
& h(x,z,\theta) = 0 \\
& \underline{\theta} \leq \theta \leq \overline{\theta}

where the uncertain parameters are given by :math:`\theta`, :math:`z`
are the controls, :math:`u` is the maximum constraint violation,
:math:`g_j` are the performance constraints, and :math:`h` are the
constraints which represent physics (e.g., mass balances). Note that
the dimension of :math:`x` must match the dimension of :math:`h`. In
other words, if :math:`\theta` and :math:`z` are fixed, then :math:`h`
should completely determine :math:`x`. If
:math:`\phi(\underline{\theta}, \overline{\theta})` is less than or
equal to zero, then the FT passes indicating that, for any
:math:`\theta` between :math:`\underline{\theta}` and
:math:`\overline{\theta}`, there exists a :math:`z` such that
:math:`g_j(x, z, \theta) \leq 0` and :math:`h(x, z, \theta) = 0`. If
:math:`\phi(\underline{\theta}, \overline{\theta})` is greater than
zero, then the FT fails indicating that the performance constraints
cannot be satisfied for at least one value of :math:`\theta` between
:math:`\underline{\theta}` and :math:`\overline{\theta}`. Also note
that this formulation assumes that :math:`h(x,z,\theta) = 0` can be
satisfied for any :math:`\theta` between :math:`\underline{\theta}`
and :math:`\overline{\theta}`.

The FI is given by

.. math::

\psi(\theta^{N}, \Delta \theta) = &\max \delta \\
& s.t. \\
& \phi(\underline{\theta}, \overline{\theta}) \leq 0 \\
& \underline{\theta} = \theta^{N} - \delta \Delta \theta \\
& \overline{\theta} = \theta^{N} + \delta \Delta \theta

where :math:`\theta^{N}` is a "nominal" point. The goal of the FI is
to find the largest region around this nominal point for which the
performance constraints can be satisfied. As written, the FI searches
for the largest hyperrectangle, but other shapes (e.g., ellipses) can
be used. The hyperrectangle is all that is currently supported in the
flexibility analysis module in IDAES. Typically, :math:`\delta` is
bounded between 0 and 1.

Flexibility Test Solution Methods
---------------------------------

Vertex Enumeration
^^^^^^^^^^^^^^^^^^

Vertex enumeration solves the inner minimization problem

.. _innerProblem:

.. math::

& \min_{z} u \\
& s.t. \\
& g_{j}(x,z,\theta) \leq u \\
& h(x,z,\theta) = 0

at each vertex of the hyperrectangle :math:`[\underline{\theta}, \overline{\theta}]`. For certain problem types (e.g., linear), the solution to :ref:`FT<FT>` is guaranteed to be at one of the vertices of this hyperrectangle [Swaney1985]_. For other problem types, vertex enumeration is only a heuristic that may not find the value of :math:`\theta` that maximizes the violation of the performance constraints.

Active Constraint Method
^^^^^^^^^^^^^^^^^^^^^^^^

The active constraint method converts the bilevel problem given by :ref:`FT<FT>` to a single-level problem by formulating the KKT conditions of the :ref:`inner minimization problem<innerProblem>` and embedding them as constraints in the outer problem [Grossmann1987]_. Note that this method assumes the Haar Conditions hold and a constraint is added enforcing that the number of active inequalities (i.e., :math:`g_{j}(x,z,\theta) = u`) is equal to the number of controls plus one. If the resulting single-level problem is solved to global optimality, this method will be conservative because it will find the "worst" local minima of the inner minimization problem.

Sampling
^^^^^^^^

Sampling is similar to `Vertex Enumeration`_ except that the :ref:`inner minimization problem<innerProblem>` is solved at random samples of :math:`\theta` rather than only at the vertices of :math:`[\underline{\theta}, \overline{\theta}]`. This can be useful for nonlinear problems but still may miss the worst-case :math:`\theta`.

Decision Rules
^^^^^^^^^^^^^^

Decision rules can be used to convert the bilevel problem given by :ref:`FT<FT>` to a single-level problem by removing all degrees of freedom of the inner problem with a control policy. Suppose we have a decision rule give by :math:`z = d(\theta)`. Because the only degrees of freedom in the inner problem are :math:`z`, the :ref:`FT<FT>` may be reformulated as

.. math::

& \max_{\theta} \overline{u} \\
& s.t. \\
& g_{j}(x,z,\theta) = u_{j} \\
& h(x,z,\theta) = 0 \\
& \overline{u} = \sum u_{j} y_{j} \\
& \sum y_{j} = 1 \\
& z = d(\theta) \\
& \underline{\theta} \leq \theta \leq \overline{\theta}

Currently, the two types of decision rules supported are linear decision rules and neural network decision rules with ReLU activation functions. Because the decision rules result in suboptimal values of :math:`z`, this method is conservative.

Flexibility Index Solution Methods
----------------------------------

Bisection Method
^^^^^^^^^^^^^^^^

The bisection method simply uses bisection to find the :math:`\delta` such that :math:`\phi(\underline{\theta}, \overline{\theta}) = 0`. Bisection works because :math:`\phi(\underline{\theta}, \overline{\theta})` is monotonically increasing with :math:`\delta`. Each subproblem solves the :ref:`FT<FT>` using one of the methods described above.

Usage
-----

The flexibility analysis module within IDAES provides two primary
functions. The first is
:meth:`solve_flextest<idaes.apps.flexibility_analysis.solve_flextest>`. The
:class:`FlexTestConfig<idaes.apps.flexibility_analysis.FlexTestConfig>`
specifies how the flexibility test should be solved. The second is
:meth:`solve_flex_index<idaes.apps.flexibility_analysis.solve_flex_index>`. Examples
can be found `here
<https://github.com/michaelbynum/idaes-pse/tree/flex/idaes/apps/flexibility_analysis/examples>`_.

.. [Grossmann1987] Grossmann, Ignacio E., and
Christodoulos A. Floudas. "Active constraint
strategy for flexibility analysis in chemical
processes." Computers & Chemical Engineering 11.6
(1987): 675-693.

.. [Swaney1985] Swaney, Ross Edward, and Ignacio E. Grossmann.
"An index for operational flexibility in chemical
process design. Part I: Formulation and theory."
AIChE Journal 31.4 (1985): 621-630.
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
Flexibility Analysis Reference
==============================

Table of Contents
-----------------
Enumerations

* :py:enum:`FlexTestMethod<idaes.apps.flexibility_analysis.FlexTestMethod>`
* :py:enum:`FlexTestTermination<idaes.apps.flexibility_analysis.FlexTestTermination>`
* :py:enum:`SamplingStrategy<idaes.apps.flexibility_analysis.SamplingStrategy>`
* :py:enum:`SamplingIniStrategy<idaes.apps.flexibility_analysis.SamplingInitStrategy>`

Configuration

* :class:`FlexTestConfig<idaes.apps.flexibility_analysis.FlexTestConfig>`
* :class:`ActiveConstraintConfig<idaes.apps.flexibility_analysis.ActiveConstraintConfig>`
* :class:`SamplingConfig<idaes.apps.flexibility_analysis.SamplingConfig>`
* :class:`LinearDRConfig<idaes.apps.flexibility_analysis.LinearDRConfig>`
* :class:`ReluDRConfig<idaes.apps.flexibility_analysis.ReluDRConfig>`

Results

* :class:`FlexTestResults<idaes.apps.flexibility_analysis.FlexTestResults>`

Functions

* :meth:`solve_flextest<idaes.apps.flexibility_analysis.solve_flextest>`
* :meth:`solve_flex_index<idaes.apps.flexibility_analysis.solve_flex_index>`

Enumerations
------------

.. autoenum:: idaes.apps.flexibility_analysis.FlexTestMethod

.. autoenum:: idaes.apps.flexibility_analysis.FlexTestTermination

.. autoenum:: idaes.apps.flexibility_analysis.SamplingStrategy

.. autoenum:: idaes.apps.flexibility_analysis.SamplingInitStrategy

Configuration
-------------

.. autoclass:: idaes.apps.flexibility_analysis.FlexTestConfig

.. autoclass:: idaes.apps.flexibility_analysis.ActiveConstraintConfig

.. autoclass:: idaes.apps.flexibility_analysis.SamplingConfig

.. autoclass:: idaes.apps.flexibility_analysis.decision_rules.dr_config.DRConfig

.. autoclass:: idaes.apps.flexibility_analysis.LinearDRConfig

.. autoclass:: idaes.apps.flexibility_analysis.ReluDRConfig


Results
-------

.. autoclass:: idaes.apps.flexibility_analysis.FlexTestResults

Functions
---------

.. autofunction:: idaes.apps.flexibility_analysis.solve_flextest

.. autofunction:: idaes.apps.flexibility_analysis.solve_flex_index
1 change: 1 addition & 0 deletions docs/explanations/modeling_extensions/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ provided below.
caprese/index
uncertainty_propagation/index
diagnostics/index
flexibility_analysis/index

.. rubric:: PySMO: Python-based Surrogate Modeling Objects

Expand Down
34 changes: 34 additions & 0 deletions idaes/apps/flexibility_analysis/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#################################################################################
# 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-2023 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.
#################################################################################
"""
A module for formulating flexibility analysis problems (feasibility test and
flexibility index).
"""
from .flextest import (
solve_flextest,
SamplingStrategy,
FlexTestConfig,
FlexTestMethod,
FlexTestTermination,
FlexTestResults,
SamplingConfig,
FlexTest,
ActiveConstraintConfig,
build_active_constraint_flextest,
build_flextest_with_dr,
)
from .decision_rules.dr_enum import DecisionRuleTypes
from .decision_rules.linear_dr import LinearDRConfig
from .decision_rules.relu_dr_config import ReluDRConfig
from .flex_index import solve_flex_index
from .sampling import perform_sampling, SamplingInitStrategy
21 changes: 21 additions & 0 deletions idaes/apps/flexibility_analysis/_check_dependencies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#################################################################################
# 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-2023 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.
#################################################################################
"""
This module is only used to check dependencies for unit tests.
"""
import unittest
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seeing as this is just for testing, should it be moved into the tests folder?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great point. I'll move this.

from pyomo.common.dependencies import attempt_import

np, nump_available = attempt_import("numpy")
if not nump_available:
raise unittest.SkipTest("flexibility_analysis tests require numpy")
22 changes: 22 additions & 0 deletions idaes/apps/flexibility_analysis/_check_relu_dependencies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#################################################################################
# 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-2023 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.
#################################################################################
"""
This module is only used to check dependencies for unit tests.
"""
import unittest
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above.

from pyomo.common.dependencies import attempt_import

tensorflow, tensorflow_available = attempt_import("tensorflow")
omlt, nump_available = attempt_import("omlt")
if not tensorflow_available or not nump_available:
Comment on lines +20 to +21
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
omlt, nump_available = attempt_import("omlt")
if not tensorflow_available or not nump_available:
omlt, omlt_available = attempt_import("omlt")
if not tensorflow_available or not omlt_available:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! Thanks!

raise unittest.SkipTest("flexibility_analysis tests require tensorflow and omlt")
32 changes: 32 additions & 0 deletions idaes/apps/flexibility_analysis/check_optimal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#################################################################################
# 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-2023 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.
#################################################################################
"""
This module provides a function like Pyomo's assert_optimal_termination but that
works for both APPSI solver interfaces and non-appsi solver interfaces.
"""
import pyomo.environ as pe
from pyomo.contrib import appsi
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A minor comment (so does not need to be fixed), but this seems like it would be better located in Pyomo (probably in pyomo.contrib with the appsi code seeing as it related to that).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great point.



def assert_optimal_termination(results):
"""
Raise an exception if the termination condition was not optimal.

Parameters
----------
results: pyomo results object from calling solve()
"""
if hasattr(results, "termination_condition"):
assert results.termination_condition == appsi.base.TerminationCondition.optimal
else:
pe.assert_optimal_termination(results)
Empty file.
39 changes: 39 additions & 0 deletions idaes/apps/flexibility_analysis/decision_rules/dr_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#################################################################################
# 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-2023 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.
#################################################################################
"""
This module defines a config for specifying options related to decision rules
"""
from pyomo.common.config import ConfigDict


class DRConfig(ConfigDict):
r"""
A base class for specifying options for building
decision rules.
"""

def __init__(
self,
description=None,
doc=None,
implicit=False,
implicit_domain=None,
visibility=0,
):
super().__init__(
description=description,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the purpose of this just to change the default values for the implicit and implicit_domain arguments (whilst still leaving them as arguments)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I changed any defaults. This class is just meant to be a base class for other, related config classes. I guess it is not really necessary. I think I just created it for type hinting.

doc=doc,
implicit=implicit,
implicit_domain=implicit_domain,
visibility=visibility,
)
Loading
Loading