Coverage for backend/idaes_service/solver/custom/energy/transmissionLine.py: 60%

58 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 import environ 

4from pyomo.environ import ( 

5 Constraint, 

6 Set, 

7 Var, 

8 Suffix, 

9 units as pyunits, 

10 atan 

11) 

12from pyomo.environ import Reals 

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

14from pyomo.contrib.fbbt import interval 

15from idaes.core.util.model_statistics import degrees_of_freedom 

16# Import IDAES cores 

17from idaes.core import ( 

18 declare_process_block_class, 

19 UnitModelBlockData, 

20 useDefault, 

21 MaterialBalanceType, 

22 MaterialFlowBasis, 

23) 

24from idaes.core.util.config import is_physical_parameter_block 

25import idaes.core.util.scaling as iscale 

26import idaes.logger as idaeslog 

27from idaes.models.unit_models import separator 

28from idaes.core.util.tables import create_stream_table_dataframe 

29from idaes.core.util.exceptions import ConfigurationError, BurntToast, PropertyNotSupportedError 

30 

31from idaes.models.unit_models import separator 

32#Import enum 

33from enum import Enum 

34 

35# Set up logger 

36_log = idaeslog.getLogger(__name__) 

37 

38import math 

39# Enumerate options for balances 

40class SplittingType(Enum): 

41 """ 

42 Enum of supported material split types. 

43 """ 

44 

45 totalFlow = 1 

46 phaseFlow = 2 

47 componentFlow = 3 

48 phaseComponentFlow = 4 

49 

50 

51 

52# When using this file the name "transmissionLine" is what is imported 

53@declare_process_block_class("transmissionLine") 

54class transmissionLineData(UnitModelBlockData): 

55 """ 

56 Zero order transmission line model 

57 """ 

58 

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

60 CONFIG = ConfigBlock() 

61 

62 CONFIG.declare( 

63 "dynamic", 

64 ConfigValue( 

65 domain=In([False]), 

66 default=False, 

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

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

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

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

71 ), 

72 ) 

73 CONFIG.declare( 

74 "has_holdup", 

75 ConfigValue( 

76 default=False, 

77 domain=In([False]), 

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

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

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

81 this must be False.""", 

82 ), 

83 ) 

84 CONFIG.declare( 

85 "property_package", 

86 ConfigValue( 

87 default=useDefault, 

88 domain=is_physical_parameter_block, 

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

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

91 **default** - useDefault. 

92 **Valid values:** { 

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

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

95 ), 

96 ) 

97 CONFIG.declare( 

98 "property_package_args", 

99 ConfigBlock( 

100 implicit=True, 

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

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

103 and used when constructing these, 

104 **default** - None. 

105 **Valid values:** { 

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

107 ), 

108 ) 

109 CONFIG.declare( 

110 "num_inlets", 

111 ConfigValue( 

112 default=False, 

113 domain=int, 

114 description="Number of inlets to add", 

115 doc="Number of inlets to add", 

116 ), 

117 ) 

118 CONFIG.declare( 

119 "num_outlets", 

120 ConfigValue( 

121 default=False, 

122 domain=int, 

123 description="Number of outlets to add", 

124 doc="Number of outlets to add", 

125 ), 

126 ) 

127 CONFIG.declare( 

128 "material_balance_type", 

129 ConfigValue( 

130 default=MaterialBalanceType.useDefault, 

131 domain=In(MaterialBalanceType), 

132 description="Material balance construction flag", 

133 doc="""Indicates what type of mass balance should be constructed, 

134 **default** - MaterialBalanceType.useDefault. 

135 **Valid values:** { 

136 **MaterialBalanceType.useDefault - refer to property package for default 

137 balance type 

138 **MaterialBalanceType.none** - exclude material balances, 

139 **MaterialBalanceType.componentPhase** - use phase component balances, 

140 **MaterialBalanceType.componentTotal** - use total component balances, 

141 **MaterialBalanceType.elementTotal** - use total element balances, 

142 **MaterialBalanceType.total** - use total material balance.}""", 

143 ), 

144 ) 

145 

146 

147 def build(self): 

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

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

150 super().build() 

151 

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

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

154 

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

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

157 

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

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

160 # Add inlet block 

161 # tmp_dict = dict(**self.config.property_package_args) 

162 # tmp_dict["parameters"] = self.config.property_package 

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

164 # self.properties_in = self.config.property_package.state_block_class( 

165 # self.flowsheet().config.time, doc="Material properties of inlet", **tmp_dict 

166 # ) 

167 

168 # Add outlet and waste block 

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

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

171 self.flowsheet().config.time, 

172 doc="Material properties of outlet", 

173 **tmp_dict 

174 ) 

175 # Add second outlet block 

176 tmp_dict["defined_state"] = False 

177 self.properties_out2 = self.config.property_package.state_block_class( 

178 self.flowsheet().config.time, doc="Material properties of inlet", **tmp_dict 

179 ) 

180 

181 # Add ports - oftentimes users interact with these rather than the state blocks 

182 # self.add_port(name="inlet_1", block=self.properties_in) 

183 # self.add_port(name="inlet_2", block=self.properties_in2) 

184 self.add_port(name="outlet_1", block=self.properties_out) 

185 self.add_port(name="outlet_2", block=self.properties_out2) 

186 

187 self.power_transfer = Var(self.flowsheet().config.time, 

188 initialize=1.0, 

189 doc="Power transferred between busses", 

190 units = pyunits.W 

191 

192 ) 

193 

194 # Add constraints: 

195 @self.Constraint( 

196 self.flowsheet().time, 

197 doc = "Power balance" 

198 ) 

199 def eq_power_balance(b,t): 

200 return self.properties_out2[t].power == self.power_transfer[t] 

201 

202 @self.Constraint( 

203 self.flowsheet().time, 

204 doc = "Power calculation" 

205 ) 

206 def eq_power_calc(b,t): 

207 return self.properties_out[t].power == self.power_transfer[t] * -1 

208 

209 

210 

211 def calculate_scaling_factors(self): 

212 super().calculate_scaling_factors() 

213 

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

215 for i in blk.properties_out.index_set(): 

216 if not blk.properties_out[i].power.fixed: 

217 blk.properties_out[i].power = blk.power_transfer[i].value 

218 

219 

220 def _get_stream_table_contents(self, time_point=0): 

221 """ 

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

223 

224 Developers should overload this as appropriate. 

225 """ 

226 

227 

228