Coverage for backend/idaes_service/solver/custom/energy/bus.py: 86%

53 statements  

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

1# Import Pyomo libraries 

2from stringprep import in_table_a1 

3from pyomo.environ import ( 

4 Var, 

5 Suffix, 

6 units as pyunits, 

7) 

8from pyomo.common.config import ConfigBlock, ConfigValue, In 

9 

10# Import IDAES cores 

11from idaes.core import ( 

12 declare_process_block_class, 

13 UnitModelBlockData, 

14 useDefault, 

15) 

16from idaes.core.util.config import is_physical_parameter_block 

17import idaes.core.util.scaling as iscale 

18import idaes.logger as idaeslog 

19 

20from idaes.core.util.tables import create_stream_table_dataframe 

21 

22from idaes.core.util.exceptions import ConfigurationError 

23 

24 

25# Set up logger 

26_log = idaeslog.getLogger(__name__) 

27 

28 

29# When using this file the name "Bus" is what is imported 

30@declare_process_block_class("Bus") 

31class BusData(UnitModelBlockData): 

32 """ 

33 Zero order bus model 

34 """ 

35 

36 # CONFIG are options for the unit model, this simple model only has the mandatory config options 

37 CONFIG = ConfigBlock() 

38 

39 CONFIG.declare( 

40 "dynamic", 

41 ConfigValue( 

42 domain=In([False]), 

43 default=False, 

44 description="Dynamic model flag - must be False", 

45 doc="""Indicates whether this model will be dynamic or not, 

46 **default** = False. The Bus unit does not support dynamic 

47 behavior, thus this must be False.""", 

48 ), 

49 ) 

50 CONFIG.declare( 

51 "has_holdup", 

52 ConfigValue( 

53 default=False, 

54 domain=In([False]), 

55 description="Holdup construction flag - must be False", 

56 doc="""Indicates whether holdup terms should be constructed or not. 

57 **default** - False. The Bus unit does not have defined volume, thus 

58 this must be False.""", 

59 ), 

60 ) 

61 CONFIG.declare( 

62 "property_package", 

63 ConfigValue( 

64 default=useDefault, 

65 domain=is_physical_parameter_block, 

66 description="Property package to use for control volume", 

67 doc="""Property parameter object used to define property calculations, 

68 **default** - useDefault. 

69 **Valid values:** { 

70 **useDefault** - use default package from parent model or flowsheet, 

71 **PhysicalParameterObject** - a PhysicalParameterBlock object.}""", 

72 ), 

73 ) 

74 CONFIG.declare( 

75 "property_package_args", 

76 ConfigBlock( 

77 implicit=True, 

78 description="Arguments to use for constructing property packages", 

79 doc="""A ConfigBlock with arguments to be passed to a property block(s) 

80 and used when constructing these, 

81 **default** - None. 

82 **Valid values:** { 

83 see property package for documentation.}""", 

84 ), 

85 ) 

86 CONFIG.declare( 

87 "num_inlets", 

88 ConfigValue( 

89 default=False, 

90 domain=int, 

91 description="Number of inlets to add", 

92 doc="""Number of inlets to add""", 

93 ), 

94 ) 

95 

96 def build(self): 

97 # build always starts by calling super().build() 

98 # This triggers a lot of boilerplate in the background for you 

99 super().build() 

100 

101 # This creates blank scaling factors, which are populated later 

102 self.scaling_factor = Suffix(direction=Suffix.EXPORT) 

103 

104 

105 # Defining parameters of state block class 

106 tmp_dict = dict(**self.config.property_package_args) 

107 tmp_dict["parameters"] = self.config.property_package 

108 tmp_dict["defined_state"] = True # inlet block is an inlet 

109 

110 # Add state blocks for inlet, outlet, and waste 

111 # These include the state variables and any other properties on demand 

112 num_inlets = self.config.num_inlets 

113 

114 self.inlet_list = [ "inlet_" + str(i+1) for i in range(num_inlets) ] 

115 

116 

117 self.inlet_blocks = [] 

118 for name in self.inlet_list: 

119 # add properties_inlet_1, properties_inlet2 etc 

120 state_block = self.config.property_package.state_block_class( 

121 self.flowsheet().config.time, doc="inlet power", **tmp_dict 

122 ) 

123 self.inlet_blocks.append(state_block) 

124 # Dynamic equivalent to self.properties_inlet_1 = stateblock 

125 setattr(self,"properties_" + name, state_block) 

126 # also add the port 

127 self.add_port(name=name,block=state_block) 

128 

129 

130 # Add outlet state block 

131 tmp_dict["defined_state"] = False # outlet and waste block is not an inlet 

132 self.properties_out = self.config.property_package.state_block_class( 

133 self.flowsheet().config.time, 

134 doc="Material properties of outlet", 

135 **tmp_dict 

136 ) 

137 

138 # Add outlet port 

139 self.add_port(name="outlet", block=self.properties_out) 

140 

141 

142 # Add constraints 

143 # Usually unit models use a control volume to do the mass, energy, and momentum 

144 # balances, however, they will be explicitly written out in this example 

145 @self.Constraint( 

146 self.flowsheet().time, 

147 doc="Power usage", 

148 ) 

149 def eq_power_balance(b, t): 

150 return ( 

151 sum( 

152 state_block[t].power for state_block in self.inlet_blocks 

153 ) 

154 == b.properties_out[t].power 

155 ) 

156 

157 

158 def calculate_scaling_factors(self): 

159 super().calculate_scaling_factors() 

160 

161 def initialize(blk, *args, **kwargs): 

162 # Just propagate the power from inlet to outlet, good simple method of initialization 

163 for t in blk.flowsheet().time: 

164 power_in = 0 

165 for state_block in blk.inlet_blocks: 

166 power_in += state_block[t].power.value 

167 if not blk.properties_out[t].power.fixed: 167 ↛ 163line 167 didn't jump to line 163 because the condition on line 167 was always true

168 blk.properties_out[t].power = power_in 

169 

170 def _get_stream_table_contents(self, time_point=0): 

171 """ 

172 Assume unit has standard configuration of 1 inlet and 1 outlet. 

173 

174 Developers should overload this as appropriate. 

175 """ 

176 

177 io_dict = {} 

178 for inlet_name in self.inlet_list: 

179 io_dict[inlet_name] = getattr(self, inlet_name) # get a reference to the port 

180 

181 io_dict["Outlet"] = self.outlet 

182 return create_stream_table_dataframe(io_dict, time_point=time_point)