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

Add support for Greybox model DOF counitng in degrees_of_freedom function #1512

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
19 changes: 19 additions & 0 deletions idaes/core/util/model_diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@
deactivated_objectives_set,
variables_in_activated_constraints_set,
variables_not_in_activated_constraints_set,
number_greybox_equalities,
activated_greybox_block_set,
deactivated_greybox_block_set,
greybox_block_set,
unfixed_greybox_variables,
greybox_variables,
degrees_of_freedom,
large_residuals_set,
variables_near_bounds_set,
Expand Down Expand Up @@ -4121,4 +4127,17 @@ def _collect_model_statistics(model):
f"(Deactivated: {len(deactivated_objectives_set(model))})"
)

# Only show graybox info if they are present
if len(greybox_block_set(model)) != 0:
stats.append(
f"{TAB}Activated GreyBox model: {len(activated_greybox_block_set(model))} "
f"(Deactivated: {len(deactivated_greybox_block_set(model))})"
)
stats.append(
f"{TAB}Activated GreyBox Equalities: {number_greybox_equalities(model)}"
)
stats.append(
f"{TAB}Free Variables in GreyBox Equalities: {len(unfixed_greybox_variables(model))} (Fixed: {len(greybox_variables(model)-unfixed_greybox_variables(model))})"
)

return stats
203 changes: 201 additions & 2 deletions idaes/core/util/model_statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from pyomo.core.expr import identify_variables
from pyomo.common.collections import ComponentSet
from pyomo.common.deprecation import deprecation_warning
from pyomo.contrib.pynumero.interfaces.external_grey_box import ExternalGreyBoxBlock

import idaes.logger as idaeslog

Expand Down Expand Up @@ -115,6 +116,104 @@ def activated_blocks_set(block):
return block_set


def greybox_block_set(block):
"""
Function to return ComponentSet of all Greybox Blocks components in a
model.

Args:
block : model to be studied

Returns:
A ComponentSet including all GreyBox Block components in block
(including block itself)
"""
block_set = ComponentSet()
for grey_box in activated_block_component_generator(
block, ctype=ExternalGreyBoxBlock
):
block_set.add(grey_box)

return block_set


def activated_greybox_block_set(block):
"""
Function to return ComponentSet of activated Greybox Blocks components in a
model.

Args:
block : model to be studied

Returns:
A ComponentSet including all GreyBox Block components in block
(including block itself)
"""
block_set = ComponentSet()
for grey_box in greybox_block_set(block):
if grey_box.active:
block_set.add(grey_box)

return block_set


def deactivated_greybox_block_set(block):
"""
Function to return ComponentSet of deactivated Greybox Blocks components in a
model.

Args:
block : model to be studied

Returns:
A ComponentSet including all GreyBox Block components in block
(including block itself)
"""
return greybox_block_set(block) - activated_greybox_block_set(block)


def number_deactivated_greybox_block(block):
"""
Function to return a Number of deactivated Greybox Blocks components in a
model.

Args:
block : model to be studied

Returns:
number of deactivated greybox blocks
"""
return len(deactivated_greybox_block_set(block))


def number_greybox_blocks(block):
"""
Function to return a Number of activated Greybox Blocks components in a
model.

Args:
block : model to be studied

Returns:
number of activated greybox blocks
"""
return len(greybox_block_set(block))


def number_activated_greybox_blocks(block):
"""
Function to return a Number of activated Greybox Blocks components in a
model.

Args:
block : model to be studied

Returns:
number of activated greybox blocks
"""
return len(activated_greybox_block_set(block))


def number_activated_blocks(block):
"""
Method to return the number of activated Block components in a model.
Expand Down Expand Up @@ -377,7 +476,31 @@ def number_activated_equalities(block):
Returns:
Number of activated equality Constraint components in block
"""
return sum(1 for _ in activated_equalities_generator(block))
return sum(
1 for _ in activated_equalities_generator(block)
) + number_greybox_equalities(block)


def number_greybox_equalities(block) -> int:
"""
Function to compute total number of equality constraints for all GreyBox objects in this block.

A GreyBox model is always assumed to be 0DOFs where each output[i]==f(inputs)
where f is GreyBox model, this should be true regardless if
GreyBox model is doing internal optimization or not, as every output
is calculated through a the GreyBox internal model using provided inputs.

Args:
block : pyomo concrete model or pyomo block

Returns:
Number of equality constraints in all GreyBox objects on the provided block
"""
equalities = 0
for grey_box in activated_greybox_block_set(block):
equalities += len(grey_box.outputs)
equalities += grey_box.get_external_model().n_equality_constraints()
return equalities


def deactivated_equalities_generator(block):
Expand Down Expand Up @@ -529,7 +652,7 @@ def deactivated_inequalities_generator(block):
block : model to be studied

Returns:
A generator which returns all indeactivated equality Constraint
A generator which returns all deactivated equality Constraint
components block
"""
for c in total_inequalities_generator(block):
Expand Down Expand Up @@ -898,6 +1021,9 @@ def variables_in_activated_equalities_set(block):
for c in activated_equalities_generator(block):
for v in identify_variables(c.body):
var_set.add(v)
# include any vars in greyboxes
for v in greybox_variables(block):
var_set.add(v)
return var_set


Expand Down Expand Up @@ -1037,6 +1163,70 @@ def unfixed_variables_in_activated_equalities_set(block):
return var_set


def unfixed_greybox_variables(block):
"""
Function to return a ComponentSet of all unfixed Var in GreyBoxModels

Args:
block : model to be studied

Returns:
A ComponentSet including all unfixed Var components which appear within
activated equality Constraints in block
"""
var_set = ComponentSet()
for var in greybox_variables(block):
if not var.fixed:
var_set.add(var)
return var_set


def greybox_variables(block):
"""
Function to return a ComponentSet of all Var in GreyBoxModels

Args:
block : model to be studied

Returns:
A ComponentSet including all unfixed Var components which appear within
activated equality Constraints in block
"""
var_set = ComponentSet()
for grey_box in activated_greybox_block_set(block):
for in_var in grey_box.inputs:
var_set.add(grey_box.inputs[in_var])
for out_var in grey_box.outputs:
var_set.add(grey_box.outputs[out_var])
return var_set


def number_of_unfixed_greybox_variables(block):
"""
Function to return a number of unfixed variables in grey box
Args:
block : model to be studied

Returns:
number of unfixed greybox variables
"""

return len(unfixed_greybox_variables(block))


def number_of_greybox_variables(block):
"""
Function to return a number of variables in grey box
Args:
block : model to be studied

Returns:
number of greybox variables
"""

return len(greybox_variables(block))


def number_unfixed_variables_in_activated_equalities(block):
"""
Method to return the number of unfixed Var components which appear within
Expand Down Expand Up @@ -1574,6 +1764,15 @@ def report_statistics(block, ostream=None):
f"{number_deactivated_blocks(block)}) \n"
)
ostream.write(f"No. Expressions: " f"{number_expressions(block)} \n")
if number_activated_greybox_blocks(block) != 0:
ostream.write(
f"No. Activated GreyBox Blocks: {number_activated_greybox_blocks(block)} \n"
)
ostream.write(f"No. GreyBox Variables: {number_of_greybox_variables(block)} \n")
ostream.write(
f"No. Fixed GreyBox Variables: {number_of_greybox_variables(block)-number_of_unfixed_greybox_variables(block)} \n"
)
ostream.write(f"No. GreyBox Equalities: {number_greybox_equalities(block)} \n")
ostream.write(header + "\n")
ostream.write("\n")

Expand Down
Loading
Loading