ahuora-builder 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. ahuora_builder/__init__.py +0 -0
  2. ahuora_builder/arc_manager.py +33 -0
  3. ahuora_builder/build_state.py +57 -0
  4. ahuora_builder/custom/PIDController.py +494 -0
  5. ahuora_builder/custom/PySMOModel.py +178 -0
  6. ahuora_builder/custom/SimpleEffectivenessHX_DH.py +727 -0
  7. ahuora_builder/custom/__init__.py +0 -0
  8. ahuora_builder/custom/add_initial_dynamics.py +35 -0
  9. ahuora_builder/custom/custom_compressor.py +107 -0
  10. ahuora_builder/custom/custom_cooler.py +33 -0
  11. ahuora_builder/custom/custom_heat_exchanger.py +183 -0
  12. ahuora_builder/custom/custom_heat_exchanger_1d.py +258 -0
  13. ahuora_builder/custom/custom_heater.py +41 -0
  14. ahuora_builder/custom/custom_pressure_changer.py +34 -0
  15. ahuora_builder/custom/custom_pump.py +107 -0
  16. ahuora_builder/custom/custom_separator.py +371 -0
  17. ahuora_builder/custom/custom_tank.py +133 -0
  18. ahuora_builder/custom/custom_turbine.py +132 -0
  19. ahuora_builder/custom/custom_valve.py +300 -0
  20. ahuora_builder/custom/custom_variable.py +29 -0
  21. ahuora_builder/custom/direct_steam_injection.py +371 -0
  22. ahuora_builder/custom/energy/__init__.py +0 -0
  23. ahuora_builder/custom/energy/acBus.py +280 -0
  24. ahuora_builder/custom/energy/ac_property_package.py +279 -0
  25. ahuora_builder/custom/energy/battery.py +170 -0
  26. ahuora_builder/custom/energy/bus.py +182 -0
  27. ahuora_builder/custom/energy/energy_mixer.py +195 -0
  28. ahuora_builder/custom/energy/energy_splitter.py +228 -0
  29. ahuora_builder/custom/energy/grid.py +173 -0
  30. ahuora_builder/custom/energy/hydro.py +169 -0
  31. ahuora_builder/custom/energy/link.py +137 -0
  32. ahuora_builder/custom/energy/load.py +155 -0
  33. ahuora_builder/custom/energy/mainDistributionBoard.py +257 -0
  34. ahuora_builder/custom/energy/power_property_package.py +253 -0
  35. ahuora_builder/custom/energy/solar.py +176 -0
  36. ahuora_builder/custom/energy/storage.py +230 -0
  37. ahuora_builder/custom/energy/storage_wrapper +0 -0
  38. ahuora_builder/custom/energy/tests/__init__.py +0 -0
  39. ahuora_builder/custom/energy/tests/test_bus.py +44 -0
  40. ahuora_builder/custom/energy/tests/test_energy_mixer.py +46 -0
  41. ahuora_builder/custom/energy/tests/test_mdb.py +49 -0
  42. ahuora_builder/custom/energy/transformer.py +187 -0
  43. ahuora_builder/custom/energy/transformer_property_package.py +267 -0
  44. ahuora_builder/custom/energy/transmissionLine.py +228 -0
  45. ahuora_builder/custom/energy/wind.py +206 -0
  46. ahuora_builder/custom/hda_ideal_VLE.py +1341 -0
  47. ahuora_builder/custom/hda_reaction.py +182 -0
  48. ahuora_builder/custom/heat_exchanger_1d_wrapper.py +31 -0
  49. ahuora_builder/custom/integration_block.py +106 -0
  50. ahuora_builder/custom/inverted.py +81 -0
  51. ahuora_builder/custom/performance_curves.py +1 -0
  52. ahuora_builder/custom/reactions/__init__.py +0 -0
  53. ahuora_builder/custom/reactions/hda_stoich.py +10 -0
  54. ahuora_builder/custom/simple_separator.py +680 -0
  55. ahuora_builder/custom/tests/__init__.py +0 -0
  56. ahuora_builder/custom/tests/test_SimpleEffectivenessHX_DH.py +91 -0
  57. ahuora_builder/custom/tests/test_custom_tank.py +70 -0
  58. ahuora_builder/custom/tests/test_direct_steam_injection.py +41 -0
  59. ahuora_builder/custom/tests/test_simple_separator.py +46 -0
  60. ahuora_builder/custom/tests/test_waterpipe.py +46 -0
  61. ahuora_builder/custom/thermal_utility_systems/desuperheater.py +624 -0
  62. ahuora_builder/custom/thermal_utility_systems/header.py +889 -0
  63. ahuora_builder/custom/thermal_utility_systems/simple_heat_pump.py +567 -0
  64. ahuora_builder/custom/thermal_utility_systems/steam_header.py +353 -0
  65. ahuora_builder/custom/thermal_utility_systems/steam_user.py +944 -0
  66. ahuora_builder/custom/thermal_utility_systems/temp.py +349 -0
  67. ahuora_builder/custom/thermal_utility_systems/tests/test_desuperheater.py +142 -0
  68. ahuora_builder/custom/thermal_utility_systems/tests/test_header.py +998 -0
  69. ahuora_builder/custom/thermal_utility_systems/tests/test_ntu_hx.py +129 -0
  70. ahuora_builder/custom/thermal_utility_systems/tests/test_simple_heat_pump.py +120 -0
  71. ahuora_builder/custom/thermal_utility_systems/tests/test_steam_header.py +703 -0
  72. ahuora_builder/custom/thermal_utility_systems/tests/test_steam_user.py +277 -0
  73. ahuora_builder/custom/thermal_utility_systems/tests/test_waterpipe.py +36 -0
  74. ahuora_builder/custom/thermal_utility_systems/tests/test_willans_turbine.py +253 -0
  75. ahuora_builder/custom/thermal_utility_systems/willans_turbine.py +804 -0
  76. ahuora_builder/custom/translator.py +129 -0
  77. ahuora_builder/custom/updated_pressure_changer.py +1404 -0
  78. ahuora_builder/custom/valve_wrapper.py +38 -0
  79. ahuora_builder/custom/water_tank_with_units.py +456 -0
  80. ahuora_builder/diagnostics/__init__.py +0 -0
  81. ahuora_builder/diagnostics/infeasibilities.py +40 -0
  82. ahuora_builder/diagnostics/tests/__init__.py +0 -0
  83. ahuora_builder/diagnostics/tests/test_infeasibilities.py +28 -0
  84. ahuora_builder/flowsheet_manager.py +542 -0
  85. ahuora_builder/flowsheet_manager_type.py +20 -0
  86. ahuora_builder/generate_python_file.py +440 -0
  87. ahuora_builder/methods/BlockContext.py +84 -0
  88. ahuora_builder/methods/__init__.py +0 -0
  89. ahuora_builder/methods/adapter.py +355 -0
  90. ahuora_builder/methods/adapter_library.py +549 -0
  91. ahuora_builder/methods/adapter_methods.py +80 -0
  92. ahuora_builder/methods/expression_parsing.py +105 -0
  93. ahuora_builder/methods/load_unit_model.py +147 -0
  94. ahuora_builder/methods/slice_manipulation.py +7 -0
  95. ahuora_builder/methods/tests/__init__.py +0 -0
  96. ahuora_builder/methods/tests/test_expression_parsing.py +15 -0
  97. ahuora_builder/methods/units_handler.py +129 -0
  98. ahuora_builder/ml_wizard.py +101 -0
  99. ahuora_builder/port_manager.py +20 -0
  100. ahuora_builder/properties_manager.py +44 -0
  101. ahuora_builder/property_package_manager.py +78 -0
  102. ahuora_builder/solver.py +38 -0
  103. ahuora_builder/tear_manager.py +98 -0
  104. ahuora_builder/tests/__init__.py +0 -0
  105. ahuora_builder/tests/test_generate_python_file/__init__.py +0 -0
  106. ahuora_builder/tests/test_generate_python_file/configurations/compressor_generated.py +63 -0
  107. ahuora_builder/tests/test_generate_python_file/configurations/heat_exchanger_generated.py +70 -0
  108. ahuora_builder/tests/test_generate_python_file/configurations/pump_generated.py +84 -0
  109. ahuora_builder/tests/test_generate_python_file/configurations/recycle_generated.py +73 -0
  110. ahuora_builder/tests/test_generate_python_file/test_generate_python_file.py +108 -0
  111. ahuora_builder/tests/test_solver/__init__.py +0 -0
  112. ahuora_builder/tests/test_solver/configurations/BT_PR.json +59 -0
  113. ahuora_builder/tests/test_solver/configurations/BT_PR_solved.json +59 -0
  114. ahuora_builder/tests/test_solver/configurations/bus.json +99 -0
  115. ahuora_builder/tests/test_solver/configurations/bus_solved.json +50 -0
  116. ahuora_builder/tests/test_solver/configurations/compound_separator.json +377 -0
  117. ahuora_builder/tests/test_solver/configurations/compound_separator_solved.json +374 -0
  118. ahuora_builder/tests/test_solver/configurations/compressor.json +38 -0
  119. ahuora_builder/tests/test_solver/configurations/compressor_solved.json +68 -0
  120. ahuora_builder/tests/test_solver/configurations/constraints.json +44 -0
  121. ahuora_builder/tests/test_solver/configurations/constraints_solved.json +59 -0
  122. ahuora_builder/tests/test_solver/configurations/control.json +39 -0
  123. ahuora_builder/tests/test_solver/configurations/control_solved.json +68 -0
  124. ahuora_builder/tests/test_solver/configurations/dynamic_tank.json +733 -0
  125. ahuora_builder/tests/test_solver/configurations/dynamic_tank_solved.json +846 -0
  126. ahuora_builder/tests/test_solver/configurations/elimination.json +39 -0
  127. ahuora_builder/tests/test_solver/configurations/elimination_solved.json +68 -0
  128. ahuora_builder/tests/test_solver/configurations/expressions.json +68 -0
  129. ahuora_builder/tests/test_solver/configurations/expressions_solved.json +104 -0
  130. ahuora_builder/tests/test_solver/configurations/header.json +1192 -0
  131. ahuora_builder/tests/test_solver/configurations/header_solved.json +761 -0
  132. ahuora_builder/tests/test_solver/configurations/heat_exchanger.json +63 -0
  133. ahuora_builder/tests/test_solver/configurations/heat_exchanger_solved.json +104 -0
  134. ahuora_builder/tests/test_solver/configurations/heat_pump.json +137 -0
  135. ahuora_builder/tests/test_solver/configurations/heat_pump_solved.json +104 -0
  136. ahuora_builder/tests/test_solver/configurations/machine_learning.json +2156 -0
  137. ahuora_builder/tests/test_solver/configurations/machine_learning_solved.json +266 -0
  138. ahuora_builder/tests/test_solver/configurations/mass_flow_tear.json +77 -0
  139. ahuora_builder/tests/test_solver/configurations/mass_flow_tear_solved.json +68 -0
  140. ahuora_builder/tests/test_solver/configurations/milk_heater.json +521 -0
  141. ahuora_builder/tests/test_solver/configurations/milk_heater_solved.json +311 -0
  142. ahuora_builder/tests/test_solver/configurations/mixer.json +44 -0
  143. ahuora_builder/tests/test_solver/configurations/mixer_solved.json +86 -0
  144. ahuora_builder/tests/test_solver/configurations/optimization.json +62 -0
  145. ahuora_builder/tests/test_solver/configurations/optimization_solved.json +59 -0
  146. ahuora_builder/tests/test_solver/configurations/propane_heat_pump.json +167 -0
  147. ahuora_builder/tests/test_solver/configurations/propane_heat_pump_solved.json +158 -0
  148. ahuora_builder/tests/test_solver/configurations/propane_recycle.json +141 -0
  149. ahuora_builder/tests/test_solver/configurations/propane_recycle_solved.json +104 -0
  150. ahuora_builder/tests/test_solver/configurations/pump.json +64 -0
  151. ahuora_builder/tests/test_solver/configurations/pump_solved.json +59 -0
  152. ahuora_builder/tests/test_solver/configurations/pump_unit_conversions.json +63 -0
  153. ahuora_builder/tests/test_solver/configurations/recycle.json +49 -0
  154. ahuora_builder/tests/test_solver/configurations/recycle_solved.json +50 -0
  155. ahuora_builder/tests/test_solver/configurations/sb_vapor_frac.json +29 -0
  156. ahuora_builder/tests/test_solver/configurations/sb_vapor_frac_solved.json +29 -0
  157. ahuora_builder/tests/test_solver/configurations/solar.json +67 -0
  158. ahuora_builder/tests/test_solver/configurations/solar_solved.json +50 -0
  159. ahuora_builder/tests/test_solver/configurations/vapor_frac_target.json +67 -0
  160. ahuora_builder/tests/test_solver/configurations/vapor_frac_target_solved.json +68 -0
  161. ahuora_builder/tests/test_solver/test_solve_models.py +250 -0
  162. ahuora_builder/timing.py +65 -0
  163. ahuora_builder/types/__init__.py +1 -0
  164. ahuora_builder/unit_model_manager.py +48 -0
  165. ahuora_builder-0.1.0.dist-info/METADATA +14 -0
  166. ahuora_builder-0.1.0.dist-info/RECORD +167 -0
  167. ahuora_builder-0.1.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,371 @@
1
+ # Import Pyomo libraries
2
+ from pyomo.environ import (
3
+ Var,
4
+ Suffix,
5
+ units as pyunits,
6
+ )
7
+ from pyomo.common.config import ConfigBlock, ConfigValue, In
8
+ from idaes.core.util.tables import create_stream_table_dataframe
9
+ from idaes.core.util.exceptions import ConfigurationError
10
+
11
+ # Import IDAES cores
12
+ from idaes.core import (
13
+ declare_process_block_class,
14
+ UnitModelBlockData,
15
+ useDefault,
16
+ )
17
+ from idaes.core.util.config import is_physical_parameter_block
18
+ import idaes.core.util.scaling as iscale
19
+ import idaes.logger as idaeslog
20
+
21
+ # Set up logger
22
+ _log = idaeslog.getLogger(__name__)
23
+
24
+
25
+ # When using this file the name "Load" is what is imported
26
+ @declare_process_block_class("Dsi")
27
+ class dsiData(UnitModelBlockData):
28
+ """
29
+ Direct Steam Injection Unit Model
30
+
31
+ This unit model is used to represent a direct steam injection
32
+ process. There are no degrees of freedom, but the steam is mixed with the inlet fluid to heat it up.
33
+ It is assumed that the pressure of the fluid doesn't change, i.e the steam loses its pressure.
34
+ However, the enthalpy of the steam remains the same.
35
+ This allows to use two different property packages for the steam and for the inlet fluid, however,
36
+ it only works if the reference enthalpy of the steam and the inlet fluid are the same.
37
+
38
+ It's basically a combination of a mixer and a translator.
39
+ """
40
+
41
+ # CONFIG are options for the unit model
42
+ CONFIG = ConfigBlock()
43
+
44
+ CONFIG.declare(
45
+ "dynamic",
46
+ ConfigValue(
47
+ domain=In([False]),
48
+ default=False,
49
+ description="Dynamic model flag - must be False",
50
+ doc="""Indicates whether this model will be dynamic or not,
51
+ **default** = False. The Bus unit does not support dynamic
52
+ behavior, thus this must be False.""",
53
+ ),
54
+ )
55
+ CONFIG.declare(
56
+ "has_holdup",
57
+ ConfigValue(
58
+ default=False,
59
+ domain=In([False]),
60
+ description="Holdup construction flag - must be False",
61
+ doc="""Indicates whether holdup terms should be constructed or not.
62
+ **default** - False. The Bus unit does not have defined volume, thus
63
+ this must be False.""",
64
+ ),
65
+ )
66
+ CONFIG.declare(
67
+ "property_package",
68
+ ConfigValue(
69
+ default=useDefault,
70
+ domain=is_physical_parameter_block,
71
+ description="Property package to use for control volume",
72
+ doc="""Property parameter object used to define property calculations,
73
+ **default** - useDefault.
74
+ **Valid values:** {
75
+ **useDefault** - use default package from parent model or flowsheet,
76
+ **PhysicalParameterObject** - a PhysicalParameterBlock object.}""",
77
+ ),
78
+ )
79
+ CONFIG.declare(
80
+ "property_package_args",
81
+ ConfigBlock(
82
+ implicit=True,
83
+ description="Arguments to use for constructing property packages",
84
+ doc="""A ConfigBlock with arguments to be passed to a property block(s)
85
+ and used when constructing these,
86
+ **default** - None.
87
+ **Valid values:** {
88
+ see property package for documentation.}""",
89
+ ),
90
+ )
91
+ CONFIG.declare(
92
+ "steam_property_package",
93
+ ConfigValue(
94
+ default=useDefault,
95
+ domain=is_physical_parameter_block,
96
+ description="Property package to use for control volume",
97
+ doc="""Property parameter object used to define property calculations,
98
+ **default** - useDefault.
99
+ **Valid values:** {
100
+ **useDefault** - use default package from parent model or flowsheet,
101
+ **PhysicalParameterObject** - a PhysicalParameterBlock object.}""",
102
+ ),
103
+ )
104
+ CONFIG.declare(
105
+ "steam_property_package_args",
106
+ ConfigBlock(
107
+ implicit=True,
108
+ description="Arguments to use for constructing property packages",
109
+ doc="""A ConfigBlock with arguments to be passed to a property block(s)
110
+ and used when constructing these,
111
+ **default** - None.
112
+ **Valid values:** {
113
+ see property package for documentation.}""",
114
+ ),
115
+ )
116
+
117
+ def build(self):
118
+ # build always starts by calling super().build()
119
+ # This triggers a lot of boilerplate in the background for you
120
+ super().build()
121
+
122
+ # This creates blank scaling factors, which are populated later
123
+ self.scaling_factor = Suffix(direction=Suffix.EXPORT)
124
+
125
+ # Add state blocks for inlet, outlet, and waste
126
+ # These include the state variables and any other properties on demand
127
+ # Add inlet block
128
+ tmp_dict = dict(**self.config.property_package_args)
129
+ tmp_dict["parameters"] = self.config.property_package
130
+ tmp_dict["defined_state"] = True # inlet block is an inlet
131
+ self.properties_milk_in = self.config.property_package.state_block_class(
132
+ self.flowsheet().config.time, doc="Material properties of inlet", **tmp_dict
133
+ )
134
+
135
+ # We need to calculate the enthalpy of the composition, before adding additional enthalpy from the temperature difference.
136
+ # so we'll add another state block to do that.
137
+ tmp_dict["defined_state"] = False
138
+ tmp_dict["has_phase_equilibrium"] = False
139
+ self.properties_mixed_unheated = self.config.property_package.state_block_class(
140
+ self.flowsheet().config.time,
141
+ doc="Material properties of mixture, before accounting for temperature difference",
142
+ **tmp_dict,
143
+ )
144
+
145
+ # Add outlet block
146
+ tmp_dict["defined_state"] = False
147
+ tmp_dict["has_phase_equilibrium"] = False
148
+ self.properties_out = self.config.property_package.state_block_class(
149
+ self.flowsheet().config.time,
150
+ doc="Material properties of outlet",
151
+ **tmp_dict,
152
+ )
153
+
154
+ # Add steam inlet block
155
+ steam_dict = dict(**self.config.steam_property_package_args)
156
+ steam_dict["parameters"] = self.config.steam_property_package
157
+ steam_dict["defined_state"] = True
158
+ tmp_dict["has_phase_equilibrium"] = True
159
+
160
+ self.properties_steam_in = self.config.steam_property_package.state_block_class(
161
+ self.flowsheet().config.time,
162
+ doc="Material properties of steam inlet",
163
+ **steam_dict,
164
+ )
165
+
166
+ # To calculate the amount of enthalpy to add to the inlet fluid, we need to know the difference in enthalpy between steam at that T and P
167
+ # and steam at its inlet conditions. Note this is assuming that effects of composition (the steam will no longer be pure water) are negligible.
168
+ # Note that this state block is just for calcuating, and not an actual inlet or outlet.
169
+
170
+ steam_dict["defined_state"] = False # This doesn't affect pure components.
171
+ steam_dict["has_phase_equilibrium"] = True
172
+ self.properties_steam_cooled = (
173
+ self.config.steam_property_package.state_block_class(
174
+ self.flowsheet().config.time,
175
+ doc="Material properties of cooled steam",
176
+ **steam_dict,
177
+ )
178
+ )
179
+
180
+ # Add ports
181
+ self.add_port(name="outlet", block=self.properties_out)
182
+ self.add_port(name="inlet", block=self.properties_milk_in, doc="Inlet port")
183
+ self.add_port(
184
+ name="steam_inlet", block=self.properties_steam_in, doc="Steam inlet port"
185
+ )
186
+
187
+ # CONDITIONS
188
+
189
+ # STEAM INTERMEDIATE BLOCK
190
+
191
+ # Temperature (= other inlet temperature)
192
+ @self.Constraint(
193
+ self.flowsheet().time,
194
+ doc="Set the temperature of the cooled steam to be the same as the inlet fluid",
195
+ )
196
+ def eq_steam_cooled_temperature(b, t):
197
+ return (
198
+ b.properties_steam_cooled[t].temperature
199
+ == b.properties_milk_in[t].temperature
200
+ )
201
+
202
+ # Pressure (= other inlet pressure)
203
+ @self.Constraint(
204
+ self.flowsheet().time,
205
+ doc="Set the pressure of the cooled steam to be the same as the inlet fluid",
206
+ )
207
+ def eq_steam_cooled_pressure(b, t):
208
+ return (
209
+ b.properties_steam_cooled[t].pressure
210
+ == b.properties_milk_in[t].pressure
211
+ )
212
+
213
+ # Flow = steam_flow
214
+ @self.Constraint(
215
+ self.flowsheet().time,
216
+ self.config.steam_property_package.component_list,
217
+ doc="Set the composition of the cooled steam to be the same as the steam inlet",
218
+ )
219
+ def eq_steam_cooled_composition(b, t, c):
220
+ return 0 == sum(
221
+ b.properties_steam_cooled[t].get_material_flow_terms(p, c)
222
+ - b.properties_steam_in[t].get_material_flow_terms(p, c)
223
+ for p in b.properties_steam_in[t].phase_list
224
+ )
225
+
226
+ # CALCULATE ENTHALPY DIFFERENCE
227
+ @self.Expression(
228
+ self.flowsheet().time,
229
+ )
230
+ def steam_delta_h(b, t):
231
+ """
232
+ Calculate the difference in enthalpy between the steam inlet and the cooled steam.
233
+ This is used to calculate the amount of enthalpy to add to the inlet fluid.
234
+ """
235
+ return (
236
+ b.properties_steam_in[t].enth_mol
237
+ - b.properties_steam_cooled[t].enth_mol
238
+ ) * b.properties_steam_in[t].flow_mol
239
+
240
+ # MIXING (without changing temperature)
241
+
242
+ # Pressure (= inlet pressure)
243
+ @self.Constraint(
244
+ self.flowsheet().time,
245
+ doc="Equivalent pressure balance",
246
+ )
247
+ def eq_mixed_pressure(b, t):
248
+ return (
249
+ b.properties_mixed_unheated[t].pressure
250
+ == b.properties_milk_in[t].pressure
251
+ )
252
+
253
+ # Temperature (= inlet temperature)
254
+ @self.Constraint(
255
+ self.flowsheet().time,
256
+ doc="Equivalent temperature balance",
257
+ )
258
+ def eq_mixed_temperature(b, t):
259
+ return (
260
+ b.properties_mixed_unheated[t].temperature
261
+ == b.properties_milk_in[t].temperature
262
+ )
263
+
264
+ # Flow = inlet flow + steam flow
265
+ @self.Constraint(
266
+ self.flowsheet().time,
267
+ self.config.property_package.component_list,
268
+ doc="Mass balance",
269
+ )
270
+ def eq_mixed_composition(b, t, c):
271
+ return 0 == sum(
272
+ b.properties_milk_in[t].get_material_flow_terms(p, c)
273
+ + (
274
+ b.properties_steam_in[t].get_material_flow_terms(p, c)
275
+ if c
276
+ in b.properties_steam_in[
277
+ t
278
+ ].component_list # handle the case where a component isn't in the steam inlet (e.g no milk in helmholtz)
279
+ else 0
280
+ )
281
+ - b.properties_mixed_unheated[t].get_material_flow_terms(p, c)
282
+ for p in b.properties_milk_in[t].phase_list
283
+ if (p, c) in b.properties_milk_in[t].phase_component_set
284
+ ) # handle the case where a component is not in that phase (e.g no milk vapor)
285
+
286
+ # OUTLET BLOCK
287
+
288
+ # Pressure (= inlet pressure)
289
+ @self.Constraint(
290
+ self.flowsheet().time,
291
+ doc="Pressure balance",
292
+ )
293
+ def eq_outlet_pressure(b, t):
294
+ return b.properties_out[t].pressure == b.properties_milk_in[t].pressure
295
+
296
+ # Enthalpy (= mixed enthalpy + delta steam enthalpy)
297
+ @self.Constraint(
298
+ self.flowsheet().time,
299
+ doc="Energy balance",
300
+ )
301
+ def eq_outlet_combined_enthalpy(b, t):
302
+ return b.properties_out[t].enth_mol == b.properties_mixed_unheated[
303
+ t
304
+ ].enth_mol + (b.steam_delta_h[t] / b.properties_mixed_unheated[t].flow_mol)
305
+
306
+ # Flow = mixed flow
307
+
308
+ @self.Constraint(
309
+ self.flowsheet().time,
310
+ self.config.property_package.component_list,
311
+ doc="Mass balance for the outlet",
312
+ )
313
+ def eq_outlet_composition(b, t, c):
314
+ return 0 == sum(
315
+ b.properties_out[t].get_material_flow_terms(p, c)
316
+ - b.properties_mixed_unheated[t].get_material_flow_terms(p, c)
317
+ for p in b.properties_out[t].phase_list
318
+ if (p, c) in b.properties_out[t].phase_component_set
319
+ ) # handle the case where a component is not in that phase (e.g no milk vapor)
320
+
321
+
322
+
323
+ def calculate_scaling_factors(self):
324
+ super().calculate_scaling_factors()
325
+
326
+ def initialize(blk, *args, **kwargs):
327
+ blk.properties_milk_in.initialize()
328
+ blk.properties_steam_in.initialize()
329
+
330
+ for t in blk.flowsheet().time:
331
+ # copy temperature and pressure from properties_milk_in to properties_steam_cooled
332
+ # blk.properties_steam_cooled[t].temperature.set_value(
333
+ # blk.properties_milk_in[t].temperature.value
334
+ # )
335
+ blk.properties_steam_cooled[t].pressure.set_value(
336
+ blk.properties_milk_in[t].pressure.value
337
+ )
338
+ # Copy composition from properties_steam_in to properties_steam_cooled
339
+ blk.properties_steam_cooled[t].flow_mol.set_value(
340
+ blk.properties_steam_in[t].flow_mol.value
341
+ )
342
+ # If it's steam, there's only one component, so we prolly don't need to worry about composition.
343
+ # But may want TODO this for other cases.
344
+
345
+ blk.properties_steam_cooled.initialize()
346
+ blk.properties_mixed_unheated.initialize()
347
+
348
+ blk.properties_out.initialize()
349
+ pass
350
+
351
+ def _get_stream_table_contents(self, time_point=0):
352
+ """
353
+ Assume unit has standard configuration of 1 inlet and 1 outlet.
354
+
355
+ Developers should overload this as appropriate.
356
+ """
357
+ try:
358
+ return create_stream_table_dataframe(
359
+ {
360
+ "outlet": self.outlet,
361
+ "inlet": self.inlet,
362
+ "steam_inlet": self.steam_inlet,
363
+ },
364
+ time_point=time_point,
365
+ )
366
+ except AttributeError:
367
+ raise ConfigurationError(
368
+ f"Unit model {self.name} does not have the standard Port "
369
+ f"names (inlet and outlet). Please contact the unit model "
370
+ f"developer to develop a unit specific stream table."
371
+ )
File without changes
@@ -0,0 +1,280 @@
1
+ # Import Pyomo libraries
2
+ from stringprep import in_table_a1
3
+ from pyomo.environ import (
4
+ Constraint,
5
+ Set,
6
+ Var,
7
+ Suffix,
8
+ units as pyunits,
9
+ )
10
+ from pyomo.environ import Reals
11
+ from pyomo.common.config import ConfigBlock, ConfigValue, In
12
+ from idaes.core.util.model_statistics import degrees_of_freedom
13
+ # Import IDAES cores
14
+ from idaes.core import (
15
+ declare_process_block_class,
16
+ UnitModelBlockData,
17
+ useDefault,
18
+ MaterialBalanceType,
19
+ MaterialFlowBasis,
20
+ )
21
+ from idaes.core.util.config import is_physical_parameter_block
22
+ import idaes.core.util.scaling as iscale
23
+ import idaes.logger as idaeslog
24
+ from idaes.models.unit_models import separator
25
+ from idaes.core.util.tables import create_stream_table_dataframe
26
+ from idaes.core.util.exceptions import ConfigurationError, BurntToast, PropertyNotSupportedError
27
+
28
+ from idaes.models.unit_models import separator
29
+ #Import enum
30
+ from enum import Enum
31
+
32
+ # Set up logger
33
+ _log = idaeslog.getLogger(__name__)
34
+
35
+ # Enumerate options for balances
36
+ class SplittingType(Enum):
37
+ """
38
+ Enum of supported material split types.
39
+ """
40
+
41
+ totalFlow = 1
42
+ phaseFlow = 2
43
+ componentFlow = 3
44
+ phaseComponentFlow = 4
45
+
46
+
47
+
48
+ # When using this file the name "acBus" is what is imported
49
+ @declare_process_block_class("acBus")
50
+ class acBusData(UnitModelBlockData):
51
+ """
52
+ Zero order acbus model
53
+ """
54
+
55
+ # CONFIG are options for the unit model, this simple model only has the mandatory config options
56
+ CONFIG = ConfigBlock()
57
+
58
+ CONFIG.declare(
59
+ "dynamic",
60
+ ConfigValue(
61
+ domain=In([False]),
62
+ default=False,
63
+ description="Dynamic model flag - must be False",
64
+ doc="""Indicates whether this model will be dynamic or not,
65
+ **default** = False. The Bus unit does not support dynamic
66
+ behavior, thus this must be False.""",
67
+ ),
68
+ )
69
+ CONFIG.declare(
70
+ "has_holdup",
71
+ ConfigValue(
72
+ default=False,
73
+ domain=In([False]),
74
+ description="Holdup construction flag - must be False",
75
+ doc="""Indicates whether holdup terms should be constructed or not.
76
+ **default** - False. The Bus unit does not have defined volume, thus
77
+ this must be False.""",
78
+ ),
79
+ )
80
+ CONFIG.declare(
81
+ "property_package",
82
+ ConfigValue(
83
+ default=useDefault,
84
+ domain=is_physical_parameter_block,
85
+ description="Property package to use for control volume",
86
+ doc="""Property parameter object used to define property calculations,
87
+ **default** - useDefault.
88
+ **Valid values:** {
89
+ **useDefault** - use default package from parent model or flowsheet,
90
+ **PhysicalParameterObject** - a PhysicalParameterBlock object.}""",
91
+ ),
92
+ )
93
+ CONFIG.declare(
94
+ "property_package_args",
95
+ ConfigBlock(
96
+ implicit=True,
97
+ description="Arguments to use for constructing property packages",
98
+ doc="""A ConfigBlock with arguments to be passed to a property block(s)
99
+ and used when constructing these,
100
+ **default** - None.
101
+ **Valid values:** {
102
+ see property package for documentation.}""",
103
+ ),
104
+ )
105
+ CONFIG.declare(
106
+ "num_inlets",
107
+ ConfigValue(
108
+ default=False,
109
+ domain=int,
110
+ description="Number of inlets to add",
111
+ doc="Number of inlets to add",
112
+ ),
113
+ )
114
+ CONFIG.declare(
115
+ "num_outlets",
116
+ ConfigValue(
117
+ default=False,
118
+ domain=int,
119
+ description="Number of outlets to add",
120
+ doc="Number of outlets to add",
121
+ ),
122
+ )
123
+ CONFIG.declare(
124
+ "material_balance_type",
125
+ ConfigValue(
126
+ default=MaterialBalanceType.useDefault,
127
+ domain=In(MaterialBalanceType),
128
+ description="Material balance construction flag",
129
+ doc="""Indicates what type of mass balance should be constructed,
130
+ **default** - MaterialBalanceType.useDefault.
131
+ **Valid values:** {
132
+ **MaterialBalanceType.useDefault - refer to property package for default
133
+ balance type
134
+ **MaterialBalanceType.none** - exclude material balances,
135
+ **MaterialBalanceType.componentPhase** - use phase component balances,
136
+ **MaterialBalanceType.componentTotal** - use total component balances,
137
+ **MaterialBalanceType.elementTotal** - use total element balances,
138
+ **MaterialBalanceType.total** - use total material balance.}""",
139
+ ),
140
+ )
141
+
142
+
143
+ def build(self):
144
+ # build always starts by calling super().build()
145
+ # This triggers a lot of boilerplate in the background for you
146
+ super().build()
147
+
148
+ # This creates blank scaling factors, which are populated later
149
+ self.scaling_factor = Suffix(direction=Suffix.EXPORT)
150
+
151
+
152
+ # Defining parameters of state block class
153
+ tmp_dict = dict(**self.config.property_package_args)
154
+ tmp_dict["parameters"] = self.config.property_package
155
+ tmp_dict["defined_state"] = True # inlet block is an inlet
156
+
157
+ # Add state blocks for inlet, outlet, and waste
158
+ # These include the state variables and any other properties on demand
159
+ num_inlets = self.config.num_inlets
160
+ self.inlet_list = [ "inlet_" + str(i+1) for i in range(num_inlets) ]
161
+ self.inlet_set = Set(initialize=self.inlet_list)
162
+ self.inlet_blocks = []
163
+
164
+ for name in self.inlet_list:
165
+ # add properties_inlet_1, properties_inlet2 etc
166
+ state_block = self.config.property_package.state_block_class(
167
+ self.flowsheet().config.time, doc="inlet power", **tmp_dict
168
+ )
169
+ self.inlet_blocks.append(state_block)
170
+ # Dynamic equivalent to self.properties_inlet_1 = stateblock
171
+ setattr(self,"properties_" + name, state_block)
172
+ # also add the port
173
+ self.add_port(name=name,block=state_block)
174
+
175
+
176
+ # Add outlet state blocks
177
+
178
+ num_outlets = self.config.num_outlets
179
+ self.outlet_list = [ "outlet_" + str(i+1) for i in range(num_outlets) ]
180
+ self.outlet_set = Set(initialize=self.outlet_list)
181
+ self.outlet_blocks = []
182
+
183
+ for name in self.outlet_list:
184
+ tmp_dict["defined_state"] = False
185
+ state_block = self.config.property_package.state_block_class(
186
+ self.flowsheet().config.time, doc="outlet power", **tmp_dict
187
+ )
188
+ self.outlet_blocks.append(state_block)
189
+ setattr(self,"properties_" + name, state_block)
190
+ self.add_port(name=name,block=state_block)
191
+
192
+ # Add variable for power splitting
193
+ self.split_fraction = Var(
194
+ self.flowsheet().time,
195
+ self.outlet_set,
196
+ initialize=1.0,
197
+ #units = pyunits.dimensionless,
198
+ doc="How the power is split between outlets",
199
+ )
200
+
201
+ #Obtain the power components from the inlets
202
+ @self.Expression(
203
+ self.flowsheet().time,
204
+ )
205
+ def total_active_power(b,t):
206
+ return sum(state_block[t].active_power for state_block in self.inlet_blocks)
207
+
208
+ @self.Expression(
209
+ self.flowsheet().time,
210
+ )
211
+ def total_reactive_power(b,t):
212
+ return sum(state_block[t].reactive_power for state_block in self.inlet_blocks)
213
+
214
+ @self.Expression(
215
+ self.flowsheet().time,
216
+ )
217
+ def total_voltage(b,t):
218
+ return sum(state_block[t].voltage for state_block in self.inlet_blocks)
219
+
220
+ #Add constraints
221
+
222
+ @self.Constraint(
223
+ self.flowsheet().time,
224
+ self.outlet_list,
225
+ doc="active power split",
226
+ )
227
+ def eq_active_power(b,t,o):
228
+ outlet_block = getattr(self,"properties_" + o)
229
+ return outlet_block[t].active_power == (
230
+ self.total_active_power[t] * b.split_fraction[t,o])
231
+
232
+ @self.Constraint(
233
+ self.flowsheet().time,
234
+ self.outlet_list,
235
+ doc="reactive power split",
236
+ )
237
+ def eq_reactive_power(b,t,o):
238
+ outlet_block = getattr(self,"properties_" + o)
239
+ return outlet_block[t].reactive_power == (
240
+ self.total_reactive_power[t] * b.split_fraction[t,o])
241
+
242
+ @self.Constraint(
243
+ self.flowsheet().time,
244
+ self.outlet_list,
245
+ doc="voltage split",
246
+ )
247
+ def eq_voltage(b,t,o):
248
+ outlet_block = getattr(self,"properties_" + o)
249
+ return outlet_block[t].voltage == (
250
+ self.total_voltage[t] * b.split_fraction[t,o])
251
+
252
+
253
+ @self.Constraint(
254
+ self.flowsheet().time,
255
+ doc="Split fraction sum to 1",
256
+ )
257
+ def eq_split_fraction_sum(b, t):
258
+ return sum(b.split_fraction[t, o] for o in self.outlet_list) == 1.0
259
+
260
+
261
+ def calculate_scaling_factors(self):
262
+ super().calculate_scaling_factors()
263
+
264
+ def initialize(blk, *args, **kwargs):
265
+
266
+ pass
267
+
268
+
269
+ def _get_stream_table_contents(self, time_point=0):
270
+
271
+ io_dict = {}
272
+ for inlet_name in self.inlet_list:
273
+ io_dict[inlet_name] = getattr(self, inlet_name) # get a reference to the port
274
+
275
+ out_dict = {}
276
+ for outlet_name in self.outlet_list:
277
+ out_dict[outlet_name] = getattr(self, outlet_name) # get a reference to the port
278
+
279
+
280
+