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,277 @@
1
+ import pytest
2
+
3
+ from ahuora_builder.custom.thermal_utility_systems.steam_user import SteamUser
4
+ import pyomo.environ as pyo
5
+ from pyomo.environ import (
6
+ units as UNIT,
7
+ value,
8
+ )
9
+ from idaes.core import FlowsheetBlock
10
+ from idaes.core.util.model_statistics import degrees_of_freedom
11
+ from property_packages.build_package import build_package
12
+
13
+ @pytest.fixture
14
+ def steam_user_base_case():
15
+ def _make_case(
16
+ steam_flow,
17
+ steam_pressure,
18
+ steam_temperature,
19
+ cond_return_rate,
20
+ cond_return_temperature,
21
+ deltaT_subcool,
22
+ heat_loss,
23
+ pressure_loss,
24
+ has_desuperheating=False,
25
+ bfw_temperature=0,
26
+ deltaT_superheat=0,
27
+ ):
28
+ # This defines the base case for all tests
29
+ m = pyo.ConcreteModel()
30
+ m.fs = FlowsheetBlock(dynamic=False)
31
+ m.fs.water = build_package("helmholtz", ["water"], ["Liq", "Vap"])
32
+
33
+ # Create Steam User
34
+ m.fs.user = SteamUser(
35
+ property_package=m.fs.water,
36
+ has_desuperheating=has_desuperheating,
37
+ )
38
+ m.fs.user.inlet_steam.flow_mol.fix(
39
+ steam_flow
40
+ )
41
+ m.fs.user.inlet_steam.pressure.fix(
42
+ steam_pressure
43
+ )
44
+ m.fs.user.inlet_steam.enth_mol.fix(
45
+ m.fs.water.htpx(
46
+ T=steam_temperature,
47
+ p=m.fs.user.inlet_steam_state[0].pressure,
48
+ )
49
+ )
50
+ m.fs.user.cond_return_rate.fix(
51
+ cond_return_rate
52
+ )
53
+ m.fs.user.cond_return_temperature.fix(
54
+ cond_return_temperature
55
+ )
56
+ m.fs.user.deltaT_subcool.fix(
57
+ deltaT_subcool
58
+ )
59
+ m.fs.user.heat_loss.fix(
60
+ heat_loss
61
+ )
62
+ m.fs.user.pressure_loss.fix(
63
+ pressure_loss
64
+ )
65
+ if has_desuperheating:
66
+ m.fs.user.bfw_temperature.fix(
67
+ bfw_temperature
68
+ )
69
+ m.fs.user.deltaT_superheat.fix(
70
+ deltaT_superheat
71
+ )
72
+
73
+ dof = degrees_of_freedom(m.fs)
74
+ if not(dof == 0):
75
+ raise ValueError("DoF is not zero.")
76
+
77
+ return m
78
+ return _make_case
79
+
80
+ def assert_user_solution(
81
+ m,
82
+ steam_flow,
83
+ steam_pressure,
84
+ steam_temperature,
85
+ cond_return_rate,
86
+ cond_return_temperature,
87
+ deltaT_subcool,
88
+ heat_loss,
89
+ pressure_loss,
90
+ has_desuperheating=False,
91
+ bfw_temperature=0,
92
+ deltaT_superheat=0,
93
+ ):
94
+ eps_rel = 1e-4
95
+ eps_abs = 1e-4
96
+
97
+ # Check degrees of freedom
98
+ assert degrees_of_freedom(m.fs) == 0
99
+
100
+ # Initialize the model
101
+ m.fs.user.initialize()
102
+
103
+ # Solve the model
104
+ opt = pyo.SolverFactory("ipopt")
105
+ results = opt.solve(m, tee=False)
106
+
107
+ # Check that solve was successful
108
+ assert results.solver.termination_condition == pyo.TerminationCondition.optimal
109
+
110
+ # Verify mass balance: total inlet flow = total vapor outlet flow + liquid outlet flow
111
+ if value(steam_flow):
112
+ assert 0 == pytest.approx(value(m.fs.user.inlet_steam_state[0].flow_mol - steam_flow), rel=eps_rel, abs=eps_abs)
113
+ assert 0 == pytest.approx(value(m.fs.user.inlet_steam_state[0].pressure - steam_pressure), rel=eps_rel, abs=eps_abs)
114
+ assert 0 == pytest.approx(value(m.fs.user.inlet_steam_state[0].temperature - steam_temperature), rel=eps_rel, abs=0.1)
115
+
116
+ total_flow_in = sum([value(o[0].flow_mol) for o in m.fs.user.inlet_blocks])
117
+ total_flow_out = sum([value(o[0].flow_mol) for o in m.fs.user.outlet_blocks])
118
+ assert total_flow_in == pytest.approx(total_flow_out, rel=eps_rel, abs=eps_abs)
119
+
120
+ assert value(cond_return_rate * total_flow_in) == pytest.approx(value(m.fs.user.outlet_return.flow_mol[0]), rel=eps_rel, abs=eps_abs)
121
+ assert value(cond_return_temperature) == pytest.approx(value(m.fs.user.outlet_return_state[0].temperature), rel=eps_rel, abs=eps_abs)
122
+ assert value(deltaT_subcool) == pytest.approx(value(m.fs.user._int_outlet_sat_liq_state[0].temperature - m.fs.user._int_outlet_cond_state[0].temperature), rel=eps_rel, abs=eps_abs)
123
+
124
+ assert value(heat_loss) == pytest.approx(value(
125
+ UNIT.convert(
126
+ m.fs.user._int_mixed_inlet_state[0].flow_mol * m.fs.user._int_mixed_inlet_state[0].enth_mol - m.fs.user.heat_demand[0] - m.fs.user._int_outlet_cond_state[0].flow_mol * m.fs.user._int_outlet_cond_state[0].enth_mol,
127
+ to_units=UNIT.W
128
+ )
129
+ ), rel=eps_rel, abs=eps_abs
130
+ )
131
+ assert value(pressure_loss) == pytest.approx(value(
132
+ UNIT.convert(
133
+ m.fs.user._int_mixed_inlet_state[0].pressure - m.fs.user._int_outlet_cond_state[0].pressure,
134
+ to_units=UNIT.Pa
135
+ )
136
+ ),
137
+ rel=eps_rel, abs=eps_abs
138
+ )
139
+
140
+ if has_desuperheating:
141
+ assert value(bfw_temperature) == pytest.approx(value(m.fs.user.inlet_water_state[0].temperature), rel=eps_rel, abs=eps_abs)
142
+ assert value(deltaT_superheat) == pytest.approx(value(m.fs.user._int_mixed_inlet_state[0].temperature - m.fs.user._int_inlet_sat_vap_state[0].temperature), rel=eps_rel, abs=eps_abs)
143
+
144
+ def test_steam_user_flow_case(steam_user_base_case):
145
+ args = {
146
+ "steam_flow": 1000 * UNIT.mol / UNIT.s,
147
+ "steam_pressure": 2000 * 1000 * UNIT.Pa,
148
+ "steam_temperature": (250 + 273.15) * UNIT.K,
149
+ "cond_return_rate": 0.7,
150
+ "cond_return_temperature": (80 + 273.15) * UNIT.K,
151
+ "deltaT_subcool": 10 * UNIT.K,
152
+ "heat_loss": 1000 * UNIT.W,
153
+ "pressure_loss": 5000 * UNIT.Pa,
154
+ "has_desuperheating": False,
155
+ "bfw_temperature": (80 + 273.15) * UNIT.K,
156
+ "deltaT_superheat": 10 * UNIT.K,
157
+ }
158
+ m = steam_user_base_case(**args)
159
+ assert_user_solution(m, **args)
160
+
161
+ def test_steam_user_flow_case_with_parital_desuperheating(steam_user_base_case):
162
+ args = {
163
+ "steam_flow": 1000 * UNIT.mol / UNIT.s,
164
+ "steam_pressure": 2000 * 1000 * UNIT.Pa,
165
+ "steam_temperature": (250 + 273.15) * UNIT.K,
166
+ "cond_return_rate": 0.7,
167
+ "cond_return_temperature": (80 + 273.15) * UNIT.K,
168
+ "deltaT_subcool": 10 * UNIT.K,
169
+ "heat_loss": 1000 * UNIT.W,
170
+ "pressure_loss": 5000 * UNIT.Pa,
171
+ "has_desuperheating": True,
172
+ "bfw_temperature": (80 + 273.15) * UNIT.K,
173
+ "deltaT_superheat": 10 * UNIT.K,
174
+ }
175
+ m = steam_user_base_case(**args)
176
+ assert_user_solution(m, **args)
177
+
178
+ def test_steam_user_flow_case_with_full_desuperheating(steam_user_base_case):
179
+ args = {
180
+ "steam_flow": 1000 * UNIT.mol / UNIT.s,
181
+ "steam_pressure": 2000 * 1000 * UNIT.Pa,
182
+ "steam_temperature": (250 + 273.15) * UNIT.K,
183
+ "cond_return_rate": 0.7,
184
+ "cond_return_temperature": (80 + 273.15) * UNIT.K,
185
+ "deltaT_subcool": 10 * UNIT.K,
186
+ "heat_loss": 1000 * UNIT.W,
187
+ "pressure_loss": 5000 * UNIT.Pa,
188
+ "has_desuperheating": True,
189
+ "bfw_temperature": (80 + 273.15) * UNIT.K,
190
+ "deltaT_superheat": 0 * UNIT.K,
191
+ }
192
+ m = steam_user_base_case(**args)
193
+ assert_user_solution(m, **args)
194
+
195
+ def test_steam_user_demand_case(steam_user_base_case):
196
+ args = {
197
+ "steam_flow": 1000 * UNIT.mol / UNIT.s,
198
+ "steam_pressure": 2000 * 1000 * UNIT.Pa,
199
+ "steam_temperature": (250 + 273.15) * UNIT.K,
200
+ "cond_return_rate": 0.7,
201
+ "cond_return_temperature": (80 + 273.15) * UNIT.K,
202
+ "deltaT_subcool": 0 * UNIT.K,
203
+ "heat_loss": 0 * UNIT.W,
204
+ "pressure_loss": 0 * UNIT.Pa,
205
+ "has_desuperheating": False,
206
+ "bfw_temperature": (80 + 273.15) * UNIT.K,
207
+ "deltaT_superheat": 10 * UNIT.K,
208
+ }
209
+ m = steam_user_base_case(**args)
210
+ m.fs.user.heat_demand.fix(
211
+ 5 * 1000 * 1000 * UNIT.W
212
+ )
213
+ m.fs.user.inlet_steam.flow_mol[0].unfix()
214
+ args["steam_flow"] = False
215
+ assert_user_solution(m, **args)
216
+
217
+ def test_steam_user_demand_case_with_subcooling(steam_user_base_case):
218
+ args = {
219
+ "steam_flow": 0 * UNIT.mol / UNIT.s,
220
+ "steam_pressure": 2000 * 1000 * UNIT.Pa,
221
+ "steam_temperature": (250 + 273.15) * UNIT.K,
222
+ "cond_return_rate": 0.7,
223
+ "cond_return_temperature": (80 + 273.15) * UNIT.K,
224
+ "deltaT_subcool": 10 * UNIT.K,
225
+ "heat_loss": 0 * UNIT.W,
226
+ "pressure_loss": 0 * UNIT.Pa,
227
+ "has_desuperheating": False,
228
+ "bfw_temperature": (80 + 273.15) * UNIT.K,
229
+ "deltaT_superheat": 10 * UNIT.K,
230
+ }
231
+ m = steam_user_base_case(**args)
232
+ m.fs.user.heat_demand.fix(
233
+ 5 * 1000 * 1000 * UNIT.W
234
+ )
235
+ m.fs.user.inlet_steam.flow_mol[0].unfix()
236
+ args["steam_flow"] = False
237
+ assert_user_solution(m, **args)
238
+
239
+ def test_steam_user_demand_case_with_subcooling_and_desuperheating(steam_user_base_case):
240
+ args = {
241
+ "steam_flow": 0 * UNIT.mol / UNIT.s,
242
+ "steam_pressure": 2000 * 1000 * UNIT.Pa,
243
+ "steam_temperature": (250 + 273.15) * UNIT.K,
244
+ "cond_return_rate": 0.5,
245
+ "cond_return_temperature": (80 + 273.15) * UNIT.K,
246
+ "deltaT_subcool": 10 * UNIT.K,
247
+ "heat_loss": 1000 * UNIT.W,
248
+ "pressure_loss": 1000 * UNIT.Pa,
249
+ "has_desuperheating": True,
250
+ "bfw_temperature": (110 + 273.15) * UNIT.K,
251
+ "deltaT_superheat": 10 * UNIT.K,
252
+ }
253
+ m = steam_user_base_case(**args)
254
+ m.fs.user.heat_demand.fix(
255
+ 5 * 1000 * 1000 * UNIT.W
256
+ )
257
+ m.fs.user.inlet_steam.flow_mol[0].unfix()
258
+ args["steam_flow"] = False
259
+ assert_user_solution(m, **args)
260
+
261
+ def test_steam_user_demand_case_with_zero_flow(steam_user_base_case):
262
+ args = {
263
+ "steam_flow": 0 * UNIT.mol / UNIT.s,
264
+ "steam_pressure": 2000 * 1000 * UNIT.Pa,
265
+ "steam_temperature": (250 + 273.15) * UNIT.K,
266
+ "cond_return_rate": 0.5,
267
+ "cond_return_temperature": (80 + 273.15) * UNIT.K,
268
+ "deltaT_subcool": 0 * UNIT.K,
269
+ "heat_loss": 0 * UNIT.W,
270
+ "pressure_loss": 0 * UNIT.Pa,
271
+ "has_desuperheating": False,
272
+ "bfw_temperature": (110 + 273.15) * UNIT.K,
273
+ "deltaT_superheat": 10 * UNIT.K,
274
+ }
275
+ m = steam_user_base_case(**args)
276
+ args["steam_flow"] = False
277
+ assert_user_solution(m, **args)
@@ -0,0 +1,36 @@
1
+ import pytest
2
+
3
+ import pyomo.environ as pyo
4
+ from idaes.core import FlowsheetBlock
5
+ from idaes.core.util.model_statistics import degrees_of_freedom
6
+ from idaes.models_extra.power_generation.unit_models.waterpipe import WaterPipe
7
+ from property_packages.build_package import build_package
8
+ from idaes.core.util import DiagnosticsToolbox
9
+
10
+ def test_waterpipe():
11
+ m = pyo.ConcreteModel()
12
+ m.fs = FlowsheetBlock(dynamic=False)
13
+
14
+ m.fs.water = build_package("helmholtz", ["water"], ["Liq"])
15
+ m.fs.pipe = WaterPipe(property_package=m.fs.water)
16
+
17
+ # Fix inlet conditions
18
+ m.fs.pipe.inlet.flow_mol.fix(10)
19
+ m.fs.pipe.inlet.pressure.fix(101325)
20
+ # m.fs.pipe.inlet.temperature.fix(300)
21
+
22
+ # Fix pipe parameters
23
+ m.fs.pipe.length.fix(100) # m
24
+ m.fs.pipe.diameter.fix(0.5)
25
+ m.fs.pipe.number_of_pipes.fix(1)
26
+ m.fs.pipe.elevation_change.fix(5)
27
+ m.fs.pipe.fcorrection_dp.fix(0.7)
28
+
29
+ assert degrees_of_freedom(m.fs) == 0
30
+
31
+ m.fs.pipe.initialize()
32
+ solver = pyo.SolverFactory("ipopt")
33
+ solver.options['max_iter']= 10000
34
+ results = solver.solve(m, tee=False)
35
+
36
+ assert results.solver.termination_condition == pyo.TerminationCondition.optimal
@@ -0,0 +1,253 @@
1
+ import pytest
2
+
3
+ # Import Pyomo libraries
4
+ import pyomo.environ as pyo
5
+ from pyomo.environ import ConcreteModel, SolverFactory, SolverStatus, TerminationCondition, Block, TransformationFactory, units, Objective, value, Constraint, Var
6
+ from pyomo.network import SequentialDecomposition, Port, Arc
7
+
8
+
9
+ # Import IDAES libraries
10
+ from idaes.core import FlowsheetBlock
11
+ from idaes.core.util.model_statistics import report_statistics, degrees_of_freedom
12
+ import idaes.logger as idaeslog
13
+ from idaes.core.util.tables import _get_state_from_port
14
+
15
+ # Import required models
16
+ from idaes.models.unit_models import (
17
+ Feed,
18
+ Mixer,
19
+ Heater,
20
+ Compressor,
21
+ Product,
22
+ MomentumMixingType,
23
+ )
24
+ from idaes.models.unit_models import Separator as Splitter
25
+ from idaes.models.unit_models import Compressor, PressureChanger
26
+ from idaes.models.properties.general_helmholtz import (
27
+ HelmholtzParameterBlock,
28
+ PhaseType,
29
+ StateVars,
30
+ AmountBasis,
31
+ )
32
+ from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption, Turbine
33
+ from ahuora_builder.custom.thermal_utility_systems.willans_turbine import TurbineBase
34
+ from idaes.core.util import DiagnosticsToolbox
35
+
36
+ from pyomo.util.check_units import assert_units_consistent
37
+
38
+ @pytest.fixture
39
+ def build_model_with_inputs():
40
+ def _make_case(calculation_method):
41
+ # Define model components and blocks
42
+ m = ConcreteModel()
43
+ m.fs1 = FlowsheetBlock(dynamic=False)
44
+ m.fs1.water = HelmholtzParameterBlock(
45
+ pure_component="h2o",
46
+ phase_presentation=PhaseType.LG,
47
+ state_vars=StateVars.PH,
48
+ amount_basis=AmountBasis.MOLE,
49
+ )
50
+
51
+ m.fs1.turbine = TurbineBase(
52
+ property_package=m.fs1.water,
53
+ calculation_method=calculation_method,
54
+ )
55
+
56
+ # Inputs
57
+ n_in = 187.0 * 3.6 * 15.419020010014712 # t/h to mol/s
58
+ P_in = 41.3 # bar g
59
+ if m.fs1.turbine.config.calculation_method == "CT_willans": # CT model needs lower pressure
60
+ P_out = -0.4 # bar g
61
+ else:
62
+ P_out = 10.4 # bar g
63
+ T_in = 381 # C
64
+
65
+ m.fs1.turbine.inlet.flow_mol.fix(n_in/3.6)
66
+ m.fs1.turbine.inlet.enth_mol[0].fix(
67
+ value(
68
+ m.fs1.water.htpx(
69
+ T=(T_in+273)*units.K,
70
+ p=(P_in+1)*units.bar,
71
+ )
72
+ )
73
+ )
74
+ m.fs1.turbine.inlet.pressure[0].fix((P_in+1)*units.bar) # why the [0]
75
+ m.fs1.turbine.outlet.pressure[0].fix((P_out+1)*units.bar)
76
+
77
+ return m
78
+ return _make_case
79
+
80
+ def assert_willans_turbine_solution(m):
81
+ for i in range(10):
82
+ n_in = float(i+1) / 10 * m.fs1.turbine.willans_max_mol[0]
83
+ m.fs1.turbine.inlet.flow_mol.fix(
84
+ n_in
85
+ )
86
+ solver = SolverFactory("ipopt")
87
+ solver.options = {"tol": 1e-3, "max_iter": 5000}
88
+ assert degrees_of_freedom(m.fs1) == 0
89
+ result = solver.solve(m, tee=False)
90
+ assert result.solver.termination_condition == pyo.TerminationCondition.optimal
91
+ assert_units_consistent(m.fs1)
92
+
93
+ def test_isentropic_turbine(build_model_with_inputs):
94
+ m = build_model_with_inputs("isentropic")
95
+
96
+ m.fs1.turbine.efficiency_motor.fix(1.0)
97
+ m.fs1.turbine.efficiency_isentropic.fix(1)
98
+
99
+ solver = SolverFactory("ipopt")
100
+ solver.options = {"tol": 1e-3, "max_iter": 5000}
101
+ assert degrees_of_freedom(m.fs1) == 0
102
+ result = solver.solve(m, tee=False)
103
+
104
+ assert_units_consistent(m.fs1)
105
+
106
+ m.fs1.turbine.report()
107
+
108
+ assert result.solver.termination_condition == TerminationCondition.optimal
109
+
110
+ assert m.fs1.turbine.ratioP[0].value == pytest.approx(0.2695035460992908, rel=0.001)
111
+ assert pyo.value(m.fs1.turbine.efficiency_isentropic[0]) == pytest.approx(1, rel=0.001)
112
+ assert m.fs1.turbine.efficiency_motor[0].value == pytest.approx(1.0, rel=0.001)
113
+ assert m.fs1.turbine.work_electrical[0].value == pytest.approx(-16638744.441924531, rel=0.001)
114
+
115
+ def test_simple_willans_turbine(build_model_with_inputs):
116
+ m = build_model_with_inputs("simple_willans")
117
+
118
+ m.fs1.turbine.efficiency_motor.fix(1.0)
119
+ m.fs1.turbine.willans_slope.fix(190*18*units.J/units.mol) # Willans slope
120
+ m.fs1.turbine.willans_intercept.fix(0.1366*1000*units.W) # Willans intercept
121
+ m.fs1.turbine.willans_max_mol.fix(100*15.4*units.mol / units.s) # Willans intercept
122
+
123
+ solver = SolverFactory("ipopt")
124
+ solver.options = {"tol": 1e-3, "max_iter": 5000}
125
+ assert degrees_of_freedom(m.fs1) == 0
126
+ result = solver.solve(m, tee=False)
127
+
128
+ assert_units_consistent(m.fs1)
129
+
130
+ m.fs1.turbine.report()
131
+
132
+ assert result.solver.termination_condition == TerminationCondition.optimal
133
+
134
+ assert m.fs1.turbine.ratioP[0].value == pytest.approx(0.2695035460992908, rel=0.001)
135
+ assert pyo.value(m.fs1.turbine.efficiency_isentropic[0]) == pytest.approx(0.5926537201367845, rel=0.001)
136
+ assert m.fs1.turbine.efficiency_motor[0].value == pytest.approx(1.0, rel=0.001)
137
+ assert m.fs1.turbine.work_electrical[0].value == pytest.approx(-9861013.778938433, rel=0.001)
138
+ assert m.fs1.turbine.willans_slope[0].value == pytest.approx(3420.0, rel=0.001)
139
+ assert m.fs1.turbine.willans_intercept[0].value == pytest.approx(136.6, rel=0.001)
140
+ assert m.fs1.turbine.willans_max_mol[0].value == pytest.approx(1540.0, rel=0.001)
141
+
142
+ assert_willans_turbine_solution(m)
143
+
144
+ def test_part_load_willans_turbine(build_model_with_inputs):
145
+
146
+ m = build_model_with_inputs("part_load_willans")
147
+
148
+ m.fs1.turbine.efficiency_motor.fix(1.0)
149
+ m.fs1.turbine.willans_max_mol.fix(217.4*15.4) #
150
+ m.fs1.turbine.willans_a.fix(1.5435) # Willans slope
151
+ m.fs1.turbine.willans_b.fix(0.2*units.kW) # Willans intercept
152
+ m.fs1.turbine.willans_efficiency.fix(1 / (0.3759 + 1)) # Willans intercept
153
+
154
+ m.fs1.turbine.report()
155
+
156
+ assert_willans_turbine_solution(m)
157
+
158
+ def test_tsat_willans_turbine(build_model_with_inputs):
159
+ m = build_model_with_inputs("Tsat_willans")
160
+
161
+ m.fs1.turbine.efficiency_motor.fix(1.0)
162
+ m.fs1.turbine.willans_max_mol.fix(217.4*15.4)
163
+
164
+ solver = SolverFactory("ipopt")
165
+ solver.options = {"tol": 1e-3, "max_iter": 5000}
166
+ assert degrees_of_freedom(m.fs1) == 0
167
+ result = solver.solve(m, tee=False)
168
+
169
+ from pyomo.util.check_units import assert_units_consistent
170
+ import pytest
171
+
172
+ assert_units_consistent(m.fs1)
173
+
174
+ m.fs1.turbine.report()
175
+
176
+ assert result.solver.termination_condition == TerminationCondition.optimal
177
+
178
+ assert m.fs1.turbine.ratioP[0].value == pytest.approx(0.2695035460992908, rel=0.001)
179
+ assert pyo.value(m.fs1.turbine.efficiency_isentropic[0]) == pytest.approx(0.8000887976702635, rel=0.001)
180
+ assert m.fs1.turbine.efficiency_motor[0].value == pytest.approx(1.0, rel=0.001)
181
+ assert m.fs1.turbine.work_electrical[0].value == pytest.approx(-13312473.036723418, rel=0.001)
182
+ assert m.fs1.turbine.willans_slope[0].value == pytest.approx(5724.721486921732, rel=0.001)
183
+ assert m.fs1.turbine.willans_intercept[0].value == pytest.approx(3194420.3120209095, rel=0.001)
184
+ assert m.fs1.turbine.willans_max_mol[0].value == pytest.approx(3347.96, rel=0.001)
185
+ assert m.fs1.turbine.willans_a[0].value == pytest.approx(1.1916052938465973, rel=0.001)
186
+ assert m.fs1.turbine.willans_b[0].value == pytest.approx(287807.42187938065, rel=0.001)
187
+ assert m.fs1.turbine.willans_efficiency[0].value == pytest.approx(0.83333, rel=0.001)
188
+
189
+ assert_willans_turbine_solution(m)
190
+
191
+ def test_bpst_willians_turbine(build_model_with_inputs):
192
+ m = build_model_with_inputs("BPST_willans")
193
+
194
+ m.fs1.turbine.efficiency_motor.fix(1.0)
195
+ m.fs1.turbine.willans_max_mol.fix(217.4*15.4)
196
+
197
+ solver = SolverFactory("ipopt")
198
+ solver.options = {"tol": 1e-3, "max_iter": 5000}
199
+ assert degrees_of_freedom(m.fs1) == 0
200
+ result = solver.solve(m, tee=False)
201
+
202
+ from pyomo.util.check_units import assert_units_consistent
203
+ import pytest
204
+
205
+ assert_units_consistent(m.fs1)
206
+
207
+ m.fs1.turbine.report()
208
+
209
+ assert result.solver.termination_condition == TerminationCondition.optimal
210
+
211
+ assert m.fs1.turbine.ratioP[0].value == pytest.approx(0.2695035460992908, rel=0.001)
212
+ assert pyo.value(m.fs1.turbine.efficiency_isentropic[0]) == pytest.approx(0.7640203470049349, rel=0.001)
213
+ assert m.fs1.turbine.efficiency_motor[0].value == pytest.approx(1.0, rel=0.001)
214
+ assert m.fs1.turbine.work_electrical[0].value == pytest.approx(-12712339.29641526, rel=0.001)
215
+ assert m.fs1.turbine.willans_slope[0].value == pytest.approx(5511.348537597738, rel=0.001)
216
+ assert m.fs1.turbine.willans_intercept[0].value == pytest.approx(3179303.3709413796, rel=0.001)
217
+ assert m.fs1.turbine.willans_max_mol[0].value == pytest.approx(3347.96, rel=0.001)
218
+ assert m.fs1.turbine.willans_a[0].value == pytest.approx(1.2284271712000001, rel=0.001)
219
+ assert m.fs1.turbine.willans_b[0].value == pytest.approx(558672.9707596999, rel=0.001)
220
+ assert m.fs1.turbine.willans_efficiency[0].value == pytest.approx(0.8276966055721292, rel=0.001)
221
+
222
+ assert_willans_turbine_solution(m)
223
+
224
+ def test_ct_willians_turbine(build_model_with_inputs):
225
+ m = build_model_with_inputs("CT_willans")
226
+
227
+ m.fs1.turbine.inlet.enth_mol[0].fix(
228
+ value(
229
+ m.fs1.water.htpx(
230
+ T=(430 + 273.15) * units.K,
231
+ p=6000 * units.kPa,
232
+ )
233
+ )
234
+ )
235
+ m.fs1.turbine.inlet.flow_mol[0].fix(
236
+ 2000 * units.mol / units.s
237
+ )
238
+ m.fs1.turbine.inlet.pressure[0].fix(
239
+ 6000 * units.kPa
240
+ )
241
+ m.fs1.turbine.outlet.pressure[0].fix(
242
+ 6 * units.kPa
243
+ )
244
+
245
+ m.fs1.turbine.efficiency_motor.fix(1.0)
246
+ m.fs1.turbine.willans_max_mol.fix(2000)
247
+
248
+ solver = SolverFactory("ipopt")
249
+ solver.options = {"tol": 1e-3, "max_iter": 5000}
250
+ assert degrees_of_freedom(m.fs1) == 0
251
+ result = solver.solve(m, tee=False)
252
+
253
+ assert_units_consistent(m.fs1)