Coverage for backend/ahuora-builder/src/ahuora_builder/diagnostics/infeasibilities.py: 100%
27 statements
« prev ^ index » next coverage.py v7.10.7, created at 2026-06-23 21:51 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2026-06-23 21:51 +0000
1from ..properties_manager import PropertiesManager
2from typing import Iterator, TextIO
3import sys
4import pyomo.environ as pyo
5from pyomo.core.base.constraint import ScalarConstraint
6from pyomo.contrib.incidence_analysis import IncidenceGraphInterface
7import numpy as np
8import idaes.logger as idaeslog
11_log = idaeslog.getLogger(__name__)
15def compute_infeasibilities(properties_map: PropertiesManager) -> Iterator[tuple[any,float]]:
16 """
17 Compute how far each constrained property is from its target value.
19 :param properties_map: PropertiesManager instance containing property components
20 :type properties_map: PropertiesManager
21 :return: A tuple list of property IDs and their infeasibility magnitudes
22 :rtype: list[tuple[Any, float]]
23 """
24 igraph = None
25 for id, property_component in properties_map.items():
26 if property_component.corresponding_constraint is not None:
27 # Calculate the constraint infeasibility squared error:
28 var = next(iter(property_component.corresponding_constraint))
29 if not isinstance(var, pyo.Var):
30 continue
31 if igraph is None:
32 igraph = IncidenceGraphInterface(var.model(), include_fixed=True)
33 try:
34 constraints = igraph.get_adjacent_to(var) # get all the constraints this variable is used in.
35 # Calculate the Mean Squared Error across the constraints using the slack
36 error = np.sqrt(np.mean(np.array([constraint.slack() for constraint in constraints])**2))
37 yield (id, error)
38 except Exception as e:
39 # handle properties that don't exist
40 _log.warning("Error computing infeasibility for property %s: %s", id, e)
41 continue
43def get_top_infeasibilities(properties_map: PropertiesManager, threshold: float = 1e-5) -> list[tuple[any, float]]:
44 """
45 Get the top infeasibilities above a certain threshold.
47 :param properties_map: PropertiesManager instance containing property components
48 :type properties_map: PropertiesManager
49 :param threshold: Minimum infeasibility magnitude to report
50 :type threshold: float
51 :return: A list of property IDs and their infeasibility magnitudes above the threshold
52 :rtype: list[tuple[Any, float]]
53 """
54 return [(id, infeasibility) for id, infeasibility in compute_infeasibilities(properties_map) if infeasibility > threshold]