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.
- ahuora_builder/__init__.py +0 -0
- ahuora_builder/arc_manager.py +33 -0
- ahuora_builder/build_state.py +57 -0
- ahuora_builder/custom/PIDController.py +494 -0
- ahuora_builder/custom/PySMOModel.py +178 -0
- ahuora_builder/custom/SimpleEffectivenessHX_DH.py +727 -0
- ahuora_builder/custom/__init__.py +0 -0
- ahuora_builder/custom/add_initial_dynamics.py +35 -0
- ahuora_builder/custom/custom_compressor.py +107 -0
- ahuora_builder/custom/custom_cooler.py +33 -0
- ahuora_builder/custom/custom_heat_exchanger.py +183 -0
- ahuora_builder/custom/custom_heat_exchanger_1d.py +258 -0
- ahuora_builder/custom/custom_heater.py +41 -0
- ahuora_builder/custom/custom_pressure_changer.py +34 -0
- ahuora_builder/custom/custom_pump.py +107 -0
- ahuora_builder/custom/custom_separator.py +371 -0
- ahuora_builder/custom/custom_tank.py +133 -0
- ahuora_builder/custom/custom_turbine.py +132 -0
- ahuora_builder/custom/custom_valve.py +300 -0
- ahuora_builder/custom/custom_variable.py +29 -0
- ahuora_builder/custom/direct_steam_injection.py +371 -0
- ahuora_builder/custom/energy/__init__.py +0 -0
- ahuora_builder/custom/energy/acBus.py +280 -0
- ahuora_builder/custom/energy/ac_property_package.py +279 -0
- ahuora_builder/custom/energy/battery.py +170 -0
- ahuora_builder/custom/energy/bus.py +182 -0
- ahuora_builder/custom/energy/energy_mixer.py +195 -0
- ahuora_builder/custom/energy/energy_splitter.py +228 -0
- ahuora_builder/custom/energy/grid.py +173 -0
- ahuora_builder/custom/energy/hydro.py +169 -0
- ahuora_builder/custom/energy/link.py +137 -0
- ahuora_builder/custom/energy/load.py +155 -0
- ahuora_builder/custom/energy/mainDistributionBoard.py +257 -0
- ahuora_builder/custom/energy/power_property_package.py +253 -0
- ahuora_builder/custom/energy/solar.py +176 -0
- ahuora_builder/custom/energy/storage.py +230 -0
- ahuora_builder/custom/energy/storage_wrapper +0 -0
- ahuora_builder/custom/energy/tests/__init__.py +0 -0
- ahuora_builder/custom/energy/tests/test_bus.py +44 -0
- ahuora_builder/custom/energy/tests/test_energy_mixer.py +46 -0
- ahuora_builder/custom/energy/tests/test_mdb.py +49 -0
- ahuora_builder/custom/energy/transformer.py +187 -0
- ahuora_builder/custom/energy/transformer_property_package.py +267 -0
- ahuora_builder/custom/energy/transmissionLine.py +228 -0
- ahuora_builder/custom/energy/wind.py +206 -0
- ahuora_builder/custom/hda_ideal_VLE.py +1341 -0
- ahuora_builder/custom/hda_reaction.py +182 -0
- ahuora_builder/custom/heat_exchanger_1d_wrapper.py +31 -0
- ahuora_builder/custom/integration_block.py +106 -0
- ahuora_builder/custom/inverted.py +81 -0
- ahuora_builder/custom/performance_curves.py +1 -0
- ahuora_builder/custom/reactions/__init__.py +0 -0
- ahuora_builder/custom/reactions/hda_stoich.py +10 -0
- ahuora_builder/custom/simple_separator.py +680 -0
- ahuora_builder/custom/tests/__init__.py +0 -0
- ahuora_builder/custom/tests/test_SimpleEffectivenessHX_DH.py +91 -0
- ahuora_builder/custom/tests/test_custom_tank.py +70 -0
- ahuora_builder/custom/tests/test_direct_steam_injection.py +41 -0
- ahuora_builder/custom/tests/test_simple_separator.py +46 -0
- ahuora_builder/custom/tests/test_waterpipe.py +46 -0
- ahuora_builder/custom/thermal_utility_systems/desuperheater.py +624 -0
- ahuora_builder/custom/thermal_utility_systems/header.py +889 -0
- ahuora_builder/custom/thermal_utility_systems/simple_heat_pump.py +567 -0
- ahuora_builder/custom/thermal_utility_systems/steam_header.py +353 -0
- ahuora_builder/custom/thermal_utility_systems/steam_user.py +944 -0
- ahuora_builder/custom/thermal_utility_systems/temp.py +349 -0
- ahuora_builder/custom/thermal_utility_systems/tests/test_desuperheater.py +142 -0
- ahuora_builder/custom/thermal_utility_systems/tests/test_header.py +998 -0
- ahuora_builder/custom/thermal_utility_systems/tests/test_ntu_hx.py +129 -0
- ahuora_builder/custom/thermal_utility_systems/tests/test_simple_heat_pump.py +120 -0
- ahuora_builder/custom/thermal_utility_systems/tests/test_steam_header.py +703 -0
- ahuora_builder/custom/thermal_utility_systems/tests/test_steam_user.py +277 -0
- ahuora_builder/custom/thermal_utility_systems/tests/test_waterpipe.py +36 -0
- ahuora_builder/custom/thermal_utility_systems/tests/test_willans_turbine.py +253 -0
- ahuora_builder/custom/thermal_utility_systems/willans_turbine.py +804 -0
- ahuora_builder/custom/translator.py +129 -0
- ahuora_builder/custom/updated_pressure_changer.py +1404 -0
- ahuora_builder/custom/valve_wrapper.py +38 -0
- ahuora_builder/custom/water_tank_with_units.py +456 -0
- ahuora_builder/diagnostics/__init__.py +0 -0
- ahuora_builder/diagnostics/infeasibilities.py +40 -0
- ahuora_builder/diagnostics/tests/__init__.py +0 -0
- ahuora_builder/diagnostics/tests/test_infeasibilities.py +28 -0
- ahuora_builder/flowsheet_manager.py +542 -0
- ahuora_builder/flowsheet_manager_type.py +20 -0
- ahuora_builder/generate_python_file.py +440 -0
- ahuora_builder/methods/BlockContext.py +84 -0
- ahuora_builder/methods/__init__.py +0 -0
- ahuora_builder/methods/adapter.py +355 -0
- ahuora_builder/methods/adapter_library.py +549 -0
- ahuora_builder/methods/adapter_methods.py +80 -0
- ahuora_builder/methods/expression_parsing.py +105 -0
- ahuora_builder/methods/load_unit_model.py +147 -0
- ahuora_builder/methods/slice_manipulation.py +7 -0
- ahuora_builder/methods/tests/__init__.py +0 -0
- ahuora_builder/methods/tests/test_expression_parsing.py +15 -0
- ahuora_builder/methods/units_handler.py +129 -0
- ahuora_builder/ml_wizard.py +101 -0
- ahuora_builder/port_manager.py +20 -0
- ahuora_builder/properties_manager.py +44 -0
- ahuora_builder/property_package_manager.py +78 -0
- ahuora_builder/solver.py +38 -0
- ahuora_builder/tear_manager.py +98 -0
- ahuora_builder/tests/__init__.py +0 -0
- ahuora_builder/tests/test_generate_python_file/__init__.py +0 -0
- ahuora_builder/tests/test_generate_python_file/configurations/compressor_generated.py +63 -0
- ahuora_builder/tests/test_generate_python_file/configurations/heat_exchanger_generated.py +70 -0
- ahuora_builder/tests/test_generate_python_file/configurations/pump_generated.py +84 -0
- ahuora_builder/tests/test_generate_python_file/configurations/recycle_generated.py +73 -0
- ahuora_builder/tests/test_generate_python_file/test_generate_python_file.py +108 -0
- ahuora_builder/tests/test_solver/__init__.py +0 -0
- ahuora_builder/tests/test_solver/configurations/BT_PR.json +59 -0
- ahuora_builder/tests/test_solver/configurations/BT_PR_solved.json +59 -0
- ahuora_builder/tests/test_solver/configurations/bus.json +99 -0
- ahuora_builder/tests/test_solver/configurations/bus_solved.json +50 -0
- ahuora_builder/tests/test_solver/configurations/compound_separator.json +377 -0
- ahuora_builder/tests/test_solver/configurations/compound_separator_solved.json +374 -0
- ahuora_builder/tests/test_solver/configurations/compressor.json +38 -0
- ahuora_builder/tests/test_solver/configurations/compressor_solved.json +68 -0
- ahuora_builder/tests/test_solver/configurations/constraints.json +44 -0
- ahuora_builder/tests/test_solver/configurations/constraints_solved.json +59 -0
- ahuora_builder/tests/test_solver/configurations/control.json +39 -0
- ahuora_builder/tests/test_solver/configurations/control_solved.json +68 -0
- ahuora_builder/tests/test_solver/configurations/dynamic_tank.json +733 -0
- ahuora_builder/tests/test_solver/configurations/dynamic_tank_solved.json +846 -0
- ahuora_builder/tests/test_solver/configurations/elimination.json +39 -0
- ahuora_builder/tests/test_solver/configurations/elimination_solved.json +68 -0
- ahuora_builder/tests/test_solver/configurations/expressions.json +68 -0
- ahuora_builder/tests/test_solver/configurations/expressions_solved.json +104 -0
- ahuora_builder/tests/test_solver/configurations/header.json +1192 -0
- ahuora_builder/tests/test_solver/configurations/header_solved.json +761 -0
- ahuora_builder/tests/test_solver/configurations/heat_exchanger.json +63 -0
- ahuora_builder/tests/test_solver/configurations/heat_exchanger_solved.json +104 -0
- ahuora_builder/tests/test_solver/configurations/heat_pump.json +137 -0
- ahuora_builder/tests/test_solver/configurations/heat_pump_solved.json +104 -0
- ahuora_builder/tests/test_solver/configurations/machine_learning.json +2156 -0
- ahuora_builder/tests/test_solver/configurations/machine_learning_solved.json +266 -0
- ahuora_builder/tests/test_solver/configurations/mass_flow_tear.json +77 -0
- ahuora_builder/tests/test_solver/configurations/mass_flow_tear_solved.json +68 -0
- ahuora_builder/tests/test_solver/configurations/milk_heater.json +521 -0
- ahuora_builder/tests/test_solver/configurations/milk_heater_solved.json +311 -0
- ahuora_builder/tests/test_solver/configurations/mixer.json +44 -0
- ahuora_builder/tests/test_solver/configurations/mixer_solved.json +86 -0
- ahuora_builder/tests/test_solver/configurations/optimization.json +62 -0
- ahuora_builder/tests/test_solver/configurations/optimization_solved.json +59 -0
- ahuora_builder/tests/test_solver/configurations/propane_heat_pump.json +167 -0
- ahuora_builder/tests/test_solver/configurations/propane_heat_pump_solved.json +158 -0
- ahuora_builder/tests/test_solver/configurations/propane_recycle.json +141 -0
- ahuora_builder/tests/test_solver/configurations/propane_recycle_solved.json +104 -0
- ahuora_builder/tests/test_solver/configurations/pump.json +64 -0
- ahuora_builder/tests/test_solver/configurations/pump_solved.json +59 -0
- ahuora_builder/tests/test_solver/configurations/pump_unit_conversions.json +63 -0
- ahuora_builder/tests/test_solver/configurations/recycle.json +49 -0
- ahuora_builder/tests/test_solver/configurations/recycle_solved.json +50 -0
- ahuora_builder/tests/test_solver/configurations/sb_vapor_frac.json +29 -0
- ahuora_builder/tests/test_solver/configurations/sb_vapor_frac_solved.json +29 -0
- ahuora_builder/tests/test_solver/configurations/solar.json +67 -0
- ahuora_builder/tests/test_solver/configurations/solar_solved.json +50 -0
- ahuora_builder/tests/test_solver/configurations/vapor_frac_target.json +67 -0
- ahuora_builder/tests/test_solver/configurations/vapor_frac_target_solved.json +68 -0
- ahuora_builder/tests/test_solver/test_solve_models.py +250 -0
- ahuora_builder/timing.py +65 -0
- ahuora_builder/types/__init__.py +1 -0
- ahuora_builder/unit_model_manager.py +48 -0
- ahuora_builder-0.1.0.dist-info/METADATA +14 -0
- ahuora_builder-0.1.0.dist-info/RECORD +167 -0
- 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)
|