Coverage for backend/idaes_service/solver/methods/BlockContext.py: 100%

35 statements  

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

1from idaes_service.solver.methods.adapter import add_corresponding_constraint, fix_var,fix_slice, load_initial_guess 

2 

3 

4from idaes.core import FlowsheetBlock 

5from pyomo.core.base.constraint import Constraint 

6from pyomo.environ import Block, Component, Reference 

7from common.models.idaes.id_types import PropertyValueId 

8from pyomo.core.base.indexed_component_slice import ( 

9 IndexedComponent_slice, 

10 _IndexedComponent_slice_iter, 

11) 

12from pyomo.core.base.indexed_component import UnindexedComponent_set, IndexedComponent 

13 

14 

15class BlockContext: 

16 """ 

17 Where possible, we want to fix variables at the block level (ie. unit model, state block) 

18 rather than at the flowsheet level. This is because it is easier to solve a smaller model 

19 during initialization, rather than dumping complexity on the solver when solving the entire 

20 flowsheet. 

21 

22 Each controlling variable in the model is accompanied by a guess variable. Normally, the 

23 guess variable is fixed during initialization, and unfixed after, while the controlling 

24 variable (set point) is a constraint at the flowsheet level. However, if both the guess and 

25 controlling variable are on the same block, we can avoid this and fix the controlling variable 

26 directly at the block level. 

27 

28 This class provides a context to store controlling variables and guess variables while fixing 

29 within a block. We can then apply a simple heuristic to eliminate as many pairs of guess and 

30 controlling variables as possible. 

31 """ 

32 

33 def __init__(self, flowsheet: FlowsheetBlock): 

34 """ 

35 - blk: Pyomo block the Var is on (can add constraints to this block) 

36 - var: Pyomo Var to fix/constrain 

37 - value: value to fix/constrain the Var to 

38 - id: id of the property, to store the created Constraint in the properties map 

39 """ 

40 # property id: ( var_reference, values) 

41 self._guess_vars: dict[PropertyValueId, tuple[ IndexedComponent | IndexedComponent_slice, list[float]]] = {} 

42 # property id: ( var_reference, values, guess_id) 

43 self._controlled_vars: dict[PropertyValueId, tuple[IndexedComponent | IndexedComponent_slice, list[float], PropertyValueId]] = {} 

44 self._flowsheet = flowsheet 

45 

46 def add_guess_var(self, var_references : IndexedComponent | IndexedComponent_slice, values : list[float], propertyvalue_id : PropertyValueId): 

47 self._guess_vars[propertyvalue_id] = ( var_references, values) 

48 

49 def add_controlled_var(self, var_references: IndexedComponent | IndexedComponent_slice, values: list[float], propertyvalue_id: PropertyValueId, guess_propertyvalue_id: PropertyValueId): 

50 self._controlled_vars[propertyvalue_id] = (var_references, values, guess_propertyvalue_id) 

51 

52 def apply_elimination(self): 

53 """ 

54 Try to eliminate as many guess vars/flowsheet-level constraints as possible. 

55 Fix the remaining guess vars or add the remaining controlled vars as constraints. 

56 """ 

57 # TODO: Update apply_elimination with the lists of values now. 

58 fs = self._flowsheet 

59 for id, (var_refs, values, guess_id) in self._controlled_vars.items(): 

60 # see if we can eliminate this controlled var 

61 if guess_id in self._guess_vars: 

62 # fix the controlled var 

63 c = fix_slice(var_refs, values) 

64 add_corresponding_constraint(fs, c, id) 

65 # load the initial guess for the guess var 

66 var_refs, values = self._guess_vars[guess_id] 

67 load_initial_guess(var_refs, values) 

68 # eliminate the guess var 

69 del self._guess_vars[guess_id] 

70 else: 

71 # add the control as a flowsheet-level constraint 

72 # As the values are flattended into a list, we also need to flatten the index set into a list. 

73 var_refs_list = list(var_refs.values()) # returns a list of VarData or ExpressionData objects 

74 def constraint_rule(blk,idx): 

75 return var_refs_list[idx] == values[idx] 

76 c = Constraint(range(len(var_refs_list)), rule=constraint_rule) 

77 name = f"control_constraint_{id}" # Maybe we could use the var name or something here? but it's a bit harder with indexed constraints. 

78 self._flowsheet.add_component(name, c) 

79 add_corresponding_constraint(fs, c, id) 

80 

81 # fix the remaining guess vars 

82 for id, (var_refs, values) in self._guess_vars.items(): 

83 c = fix_slice(var_refs, values) 

84 self._flowsheet.guess_vars.append(c)