Coverage for backend/idaes_service/solver/tear_manager.py: 100%

45 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2025-11-06 23:27 +0000

1from pyomo.environ import value 

2from pyomo.network import Arc 

3from idaes.core.util.tables import _get_state_from_port 

4from pyomo.core.base.expression import ScalarExpression 

5from common.models.idaes.arc_schema import TearGuessSchema 

6from .flowsheet_manager_type import FlowsheetManager 

7from common.models.idaes import PortId 

8from .methods.adapter import fix_var 

9 

10 

11class TearManager: 

12 """ 

13 Manages the tears in the flowsheet 

14 """ 

15 

16 def __init__(self, flowsheet_manager: FlowsheetManager): 

17 """ 

18 Create a new tear manager 

19 """ 

20 self._flowsheet_manager = flowsheet_manager 

21 self._tears: list[Arc] = [] 

22 

23 def load(self): 

24 """ 

25 Load all the tears (from the recycle unitops) 

26 """ 

27 schema = self._flowsheet_manager.schema 

28 

29 for arc_schema in schema.arcs: 

30 if arc_schema.tear_guess: 

31 self.add_tear(arc_schema) 

32 

33 def add_tear(self, arc_schema): 

34 """ 

35 Add a tear to the flowsheet 

36 """ 

37 portId = arc_schema.destination 

38 guess = arc_schema.tear_guess 

39 

40 port = self._flowsheet_manager.ports.get_port(portId) 

41 arc = port.arcs()[0] 

42 self._tears.append(arc) 

43 

44 """ 

45 During model loading, we add in all the constraints and fix the variables 

46 for this port. Since it is a tear, things need to be deactivated/unfixed 

47 to ensure 0 degrees of freedom 

48 

49 If the state block is defined by constraints, we need to solve it to get the 

50 correct values for the state variables. Then we deactivate the constraints 

51 since we will be fixing the state variables instead (where applicable). 

52 """ 

53 

54 # hardcoding time indexes to [0] for now 

55 time_indexes = [0] 

56 

57 # need to get the correct value for state variables before running 

58 # sequential decomposition (since all state variables are fixed 

59 # during sequential decomposition). 

60 sb = _get_state_from_port(port, time_indexes[0]) 

61 # deactivate any guesses 

62 for key, value in guess.items(): 

63 var = getattr(sb, key) 

64 if value != True: 

65 if isinstance(var,ScalarExpression): 

66 pass # we want to solve with constraints 

67 else: 

68 # this might give too few dof if we have other constraints. We need to unfix 

69 # this value 

70 var.unfix() 

71 

72 if len(list(sb.constraints.component_objects())) > 0: 

73 # state block is defined by some constraints, so we need to solve it. 

74 # initialize the state block, which should put the correct value in 

75 # the state variables 

76 sb.parent_component().initialize() 

77 # deactivate the state block constraints, since we should use the 

78 # state variables as guesses (or fix them instead) 

79 sb.constraints.deactivate() 

80 

81 blk = sb.parent_component() 

82 for key in sb.define_state_vars(): 

83 if guess.get(key, False): 

84 # deactivate the equality constraint (expanded arcs) 

85 expanded_arc = getattr( 

86 self._flowsheet_manager.model.fs, arc._name + "_expanded" 

87 ) 

88 equality_constraint = getattr(expanded_arc, key + "_equality") 

89 equality_constraint.deactivate() 

90 

91 # fix the variable 

92 for b in blk.values(): 

93 getattr(b, key).fix() 

94 

95 else: 

96 # unfix this variable 

97 for b in blk.values(): 

98 getattr(b, key).unfix()