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,230 @@
|
|
|
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.exceptions import ConfigurationError
|
|
9
|
+
|
|
10
|
+
# Import IDAES cores
|
|
11
|
+
from idaes.core import (
|
|
12
|
+
declare_process_block_class,
|
|
13
|
+
UnitModelBlockData,
|
|
14
|
+
useDefault,
|
|
15
|
+
)
|
|
16
|
+
from idaes.core.util.config import is_physical_parameter_block
|
|
17
|
+
import idaes.core.util.scaling as iscale
|
|
18
|
+
import idaes.logger as idaeslog
|
|
19
|
+
from pyomo.util.check_units import assert_units_consistent
|
|
20
|
+
from pyomo.environ import value
|
|
21
|
+
|
|
22
|
+
# Set up logger
|
|
23
|
+
_log = idaeslog.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# When using this file the name "Link" is what is imported
|
|
27
|
+
@declare_process_block_class("Storage")
|
|
28
|
+
class StorageData(UnitModelBlockData):
|
|
29
|
+
"""
|
|
30
|
+
Zero order Link model
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
# CONFIG are options for the unit model, this simple model only has the mandatory config options
|
|
34
|
+
CONFIG = ConfigBlock()
|
|
35
|
+
|
|
36
|
+
CONFIG.declare(
|
|
37
|
+
"dynamic",
|
|
38
|
+
ConfigValue(
|
|
39
|
+
domain=In([False]),
|
|
40
|
+
default=False,
|
|
41
|
+
description="Dynamic model flag - must be False",
|
|
42
|
+
doc="""Indicates whether this model will be dynamic or not,
|
|
43
|
+
**default** = False. The Bus unit does not support dynamic
|
|
44
|
+
behavior, thus this must be False.""",
|
|
45
|
+
),
|
|
46
|
+
)
|
|
47
|
+
CONFIG.declare(
|
|
48
|
+
"has_holdup",
|
|
49
|
+
ConfigValue(
|
|
50
|
+
default=False,
|
|
51
|
+
domain=In([False]),
|
|
52
|
+
description="Holdup construction flag - must be False",
|
|
53
|
+
doc="""Indicates whether holdup terms should be constructed or not.
|
|
54
|
+
**default** - False. The Bus unit does not have defined volume, thus
|
|
55
|
+
this must be False.""",
|
|
56
|
+
),
|
|
57
|
+
)
|
|
58
|
+
CONFIG.declare(
|
|
59
|
+
"property_package",
|
|
60
|
+
ConfigValue(
|
|
61
|
+
default=useDefault,
|
|
62
|
+
domain=is_physical_parameter_block,
|
|
63
|
+
description="Property package to use for control volume",
|
|
64
|
+
doc="""Property parameter object used to define property calculations,
|
|
65
|
+
**default** - useDefault.
|
|
66
|
+
**Valid values:** {
|
|
67
|
+
**useDefault** - use default package from parent model or flowsheet,
|
|
68
|
+
**PhysicalParameterObject** - a PhysicalParameterBlock object.}""",
|
|
69
|
+
),
|
|
70
|
+
)
|
|
71
|
+
CONFIG.declare(
|
|
72
|
+
"property_package_args",
|
|
73
|
+
ConfigBlock(
|
|
74
|
+
implicit=True,
|
|
75
|
+
description="Arguments to use for constructing property packages",
|
|
76
|
+
doc="""A ConfigBlock with arguments to be passed to a property block(s)
|
|
77
|
+
and used when constructing these,
|
|
78
|
+
**default** - None.
|
|
79
|
+
**Valid values:** {
|
|
80
|
+
see property package for documentation.}""",
|
|
81
|
+
),
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
def build(self):
|
|
85
|
+
# build always starts by calling super().build()
|
|
86
|
+
# This triggers a lot of boilerplate in the background for you
|
|
87
|
+
super().build()
|
|
88
|
+
|
|
89
|
+
# This creates blank scaling factors, which are populated later
|
|
90
|
+
self.scaling_factor = Suffix(direction=Suffix.EXPORT)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# Add state blocks for inlet, outlet, and waste
|
|
94
|
+
# These include the state variables and any other properties on demand
|
|
95
|
+
# Add inlet block
|
|
96
|
+
tmp_dict = dict(**self.config.property_package_args)
|
|
97
|
+
tmp_dict["parameters"] = self.config.property_package
|
|
98
|
+
tmp_dict["defined_state"] = True # inlet block is an inlet
|
|
99
|
+
self.properties_in = self.config.property_package.state_block_class(
|
|
100
|
+
self.flowsheet().config.time, doc="Material properties of inlet", **tmp_dict
|
|
101
|
+
)
|
|
102
|
+
# Add outlet and waste block
|
|
103
|
+
tmp_dict["defined_state"] = True
|
|
104
|
+
self.properties_in = self.config.property_package.state_block_class(
|
|
105
|
+
self.flowsheet().config.time,
|
|
106
|
+
doc="Material properties of outlet",
|
|
107
|
+
**tmp_dict
|
|
108
|
+
)
|
|
109
|
+
tmp_dict["defined_state"] = False # outlet and waste block is not an inlet
|
|
110
|
+
self.properties_out = self.config.property_package.state_block_class(
|
|
111
|
+
self.flowsheet().config.time,
|
|
112
|
+
doc="Material properties of outlet",
|
|
113
|
+
**tmp_dict
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
# Add ports - oftentimes users interact with these rather than the state blocks
|
|
118
|
+
self.add_port(name="inlet", block=self.properties_in)
|
|
119
|
+
self.add_port(name="outlet", block=self.properties_out)
|
|
120
|
+
|
|
121
|
+
# Add variables:
|
|
122
|
+
self.charging_efficiency = Var(
|
|
123
|
+
self.flowsheet().config.time,
|
|
124
|
+
initialize=1.0,
|
|
125
|
+
doc="Charging Efficiency",
|
|
126
|
+
)
|
|
127
|
+
self.capacity = Var(self.flowsheet().config.time,
|
|
128
|
+
initialize=1.0,
|
|
129
|
+
units=pyunits.kWh,
|
|
130
|
+
doc="Capacity of the storage",
|
|
131
|
+
)
|
|
132
|
+
self.initial_SOC = Var(self.flowsheet().config.time,
|
|
133
|
+
initialize=0.4,
|
|
134
|
+
doc="Initial State of Charge",
|
|
135
|
+
)
|
|
136
|
+
self.charging_power_in = Var(self.flowsheet().config.time,
|
|
137
|
+
initialize=1.0,
|
|
138
|
+
units=pyunits.W,
|
|
139
|
+
doc="Power in",
|
|
140
|
+
)
|
|
141
|
+
self.charging_power_out = Var(self.flowsheet().config.time,
|
|
142
|
+
initialize=1.0,
|
|
143
|
+
units=pyunits.W,
|
|
144
|
+
doc="Power out",
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
@self.Expression(
|
|
148
|
+
self.flowsheet().time,
|
|
149
|
+
doc="updated state of charge",
|
|
150
|
+
)
|
|
151
|
+
def updated_SOC(b,t):
|
|
152
|
+
power_in = self.charging_power_in[t]
|
|
153
|
+
power_out = self.charging_power_out[t]
|
|
154
|
+
power_change = (power_in-power_out)/(pyunits.W *1000)
|
|
155
|
+
capacity_without_unit = self.capacity[t]/pyunits.kWh
|
|
156
|
+
if t == self.flowsheet().time.first():
|
|
157
|
+
self.updated_SOC[t] = self.initial_SOC[t] + power_change/capacity_without_unit
|
|
158
|
+
else:
|
|
159
|
+
self.updated_SOC[t] = self.updated_SOC[t-1] + power_change/capacity_without_unit
|
|
160
|
+
|
|
161
|
+
return self.updated_SOC[t]
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@self.Constraint(
|
|
166
|
+
self.flowsheet().time,
|
|
167
|
+
doc="Set output power for charging",
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
@self.Constraint(
|
|
172
|
+
self.flowsheet().time,
|
|
173
|
+
doc="Set output power for discharging",
|
|
174
|
+
)
|
|
175
|
+
def set_power_out_discharge(b,t):
|
|
176
|
+
return b.properties_out[t].power == self.charging_power_out[t]
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
@self.Constraint(
|
|
180
|
+
self.flowsheet().time,
|
|
181
|
+
doc="Set output power for charging",
|
|
182
|
+
)
|
|
183
|
+
def set_power_charge(b,t):
|
|
184
|
+
return self.charging_power_in[t] == self.properties_in[t].power
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
# Add a constraint to ensure power_change is within a range
|
|
188
|
+
@self.Constraint(
|
|
189
|
+
self.flowsheet().time,
|
|
190
|
+
doc="Ensure power_change is within a specified range",
|
|
191
|
+
)
|
|
192
|
+
def power_change_within_range(b, t):
|
|
193
|
+
power_in = self.charging_power_in[t]
|
|
194
|
+
power_out = self.charging_power_out[t]
|
|
195
|
+
power_in_out = (power_in-power_out)/(pyunits.W *1000)
|
|
196
|
+
# power_in_out = b.properties_out[t].power / (pyunits.W * 1000)
|
|
197
|
+
remaining_power = power_in_out + self.initial_SOC[t] * self.capacity[t]
|
|
198
|
+
return remaining_power <= self.capacity[t]
|
|
199
|
+
|
|
200
|
+
@self.Constraint(
|
|
201
|
+
self.flowsheet().time,
|
|
202
|
+
doc="Ensure power_change is within capacity",
|
|
203
|
+
)
|
|
204
|
+
def power_change_above_zero(b, t):
|
|
205
|
+
|
|
206
|
+
power_in = self.charging_power_in[t]
|
|
207
|
+
power_out = self.charging_power_out[t]
|
|
208
|
+
power_in_out = (power_in-power_out)/(pyunits.W *1000)
|
|
209
|
+
#power_in_out = b.properties_out[t].power / (pyunits.W * 1000)
|
|
210
|
+
remaining_power = power_in_out + self.initial_SOC[t] * self.capacity[t]
|
|
211
|
+
return remaining_power >= 0
|
|
212
|
+
|
|
213
|
+
def calculate_scaling_factors(self):
|
|
214
|
+
super().calculate_scaling_factors()
|
|
215
|
+
|
|
216
|
+
def initialize(blk, *args, **kwargs):
|
|
217
|
+
|
|
218
|
+
for i in blk.properties_in.index_set():
|
|
219
|
+
if blk.initial_SOC[i].value == 0 and abs(blk.charging_power_out[i].value)> 0 and abs(blk.charging_power_in[i].value) == 0:
|
|
220
|
+
raise ConfigurationError(
|
|
221
|
+
"Warning: There is no power to discharge in the battery."
|
|
222
|
+
)
|
|
223
|
+
if blk.charging_power_in[i].value > blk.capacity[i].value:
|
|
224
|
+
pass
|
|
225
|
+
# raise ConfigurationError(
|
|
226
|
+
# "Warning: Battery capacity is exceeded!"
|
|
227
|
+
# )
|
|
228
|
+
|
|
229
|
+
def _get_stream_table_contents(self, time_point=0):
|
|
230
|
+
pass
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
### Imports
|
|
2
|
+
from pyomo.environ import ConcreteModel, SolverFactory, SolverStatus, TerminationCondition, Block, TransformationFactory, assert_optimal_termination
|
|
3
|
+
from pyomo.network import SequentialDecomposition, Port, Arc
|
|
4
|
+
from pyomo.core.base.units_container import _PyomoUnit, units
|
|
5
|
+
from idaes.core import FlowsheetBlock
|
|
6
|
+
from idaes.core.util.model_statistics import report_statistics, degrees_of_freedom
|
|
7
|
+
from idaes.core.util.tables import _get_state_from_port
|
|
8
|
+
import idaes.logger as idaeslog
|
|
9
|
+
from property_packages.build_package import build_package
|
|
10
|
+
from idaes.models.unit_models.pressure_changer import Pump
|
|
11
|
+
from idaes.models.unit_models.heater import Heater
|
|
12
|
+
from ..power_property_package import PowerParameterBlock
|
|
13
|
+
from ..bus import Bus
|
|
14
|
+
from pyomo.environ import value
|
|
15
|
+
|
|
16
|
+
def test_bus():
|
|
17
|
+
m = ConcreteModel()
|
|
18
|
+
m.fs = FlowsheetBlock(dynamic=False)
|
|
19
|
+
m.fs.power_property_package = PowerParameterBlock()
|
|
20
|
+
|
|
21
|
+
m.fs.bus = Bus(
|
|
22
|
+
property_package=m.fs.power_property_package,
|
|
23
|
+
num_inlets=2,
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
)
|
|
27
|
+
m.fs.bus.inlet_1.power.fix(100 * units.kW)
|
|
28
|
+
m.fs.bus.inlet_2.power.fix(50 * units.kW)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
m.fs.bus.eq_power_balance.pprint()
|
|
32
|
+
|
|
33
|
+
#m.fs.bus.display()
|
|
34
|
+
|
|
35
|
+
# Check that the model is fully specified
|
|
36
|
+
assert degrees_of_freedom(m.fs.bus) == 0
|
|
37
|
+
|
|
38
|
+
# check that it solves correctly
|
|
39
|
+
|
|
40
|
+
solver = SolverFactory("ipopt")
|
|
41
|
+
solver.solve(m)
|
|
42
|
+
print(*"Post solve power:")
|
|
43
|
+
|
|
44
|
+
assert value(m.fs.bus.properties_out[0].power)- 150e3 == 0
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
### Imports
|
|
2
|
+
from pyomo.environ import ConcreteModel, SolverFactory, SolverStatus, TerminationCondition, Block, TransformationFactory, assert_optimal_termination
|
|
3
|
+
from pyomo.network import SequentialDecomposition, Port, Arc
|
|
4
|
+
from pyomo.core.base.units_container import _PyomoUnit, units
|
|
5
|
+
from idaes.core import FlowsheetBlock
|
|
6
|
+
from idaes.core.util.model_statistics import report_statistics, degrees_of_freedom
|
|
7
|
+
from idaes.core.util.tables import _get_state_from_port
|
|
8
|
+
import idaes.logger as idaeslog
|
|
9
|
+
from property_packages.build_package import build_package
|
|
10
|
+
from idaes.models.unit_models.pressure_changer import Pump
|
|
11
|
+
from idaes.models.unit_models.heater import Heater
|
|
12
|
+
from ..energy_mixer import EnergyMixer
|
|
13
|
+
from ..power_property_package import PowerParameterBlock
|
|
14
|
+
from pyomo.environ import value
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_energy_mixer():
|
|
18
|
+
m = ConcreteModel()
|
|
19
|
+
m.fs = FlowsheetBlock()
|
|
20
|
+
m.fs.power_property_package = PowerParameterBlock()
|
|
21
|
+
|
|
22
|
+
m.fs.mixer = EnergyMixer(
|
|
23
|
+
property_package=m.fs.power_property_package,
|
|
24
|
+
num_inlets=3,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
m.fs.mixer.inlet_1.power.fix(100 * units.kW)
|
|
31
|
+
m.fs.mixer.inlet_2.power.fix(1000 * units.W)
|
|
32
|
+
m.fs.mixer.inlet_3.power.fix(10 * units.kW)
|
|
33
|
+
m.fs.mixer.efficiency.fix(0.90)
|
|
34
|
+
|
|
35
|
+
# Check that the model is fully specified
|
|
36
|
+
assert degrees_of_freedom(m) == 0
|
|
37
|
+
|
|
38
|
+
# check that it solves correctly
|
|
39
|
+
|
|
40
|
+
solver = SolverFactory("ipopt")
|
|
41
|
+
solver.solve(m)
|
|
42
|
+
#assert m.fs.mixer.outlet.power[0].value == 111 * units.kW
|
|
43
|
+
assert abs(m.fs.mixer.outlet.power[0].value - 999e2) < 1e-3
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
### Imports
|
|
2
|
+
from pyomo.environ import ConcreteModel, SolverFactory, SolverStatus, TerminationCondition, Block, TransformationFactory, assert_optimal_termination
|
|
3
|
+
from pyomo.network import SequentialDecomposition, Port, Arc
|
|
4
|
+
from pyomo.core.base.units_container import _PyomoUnit, units
|
|
5
|
+
from idaes.core import FlowsheetBlock
|
|
6
|
+
from idaes.core.util.model_statistics import report_statistics, degrees_of_freedom
|
|
7
|
+
from idaes.core.util.tables import _get_state_from_port
|
|
8
|
+
import idaes.logger as idaeslog
|
|
9
|
+
from property_packages.build_package import build_package
|
|
10
|
+
from idaes.models.unit_models.pressure_changer import Pump
|
|
11
|
+
from idaes.models.unit_models.heater import Heater
|
|
12
|
+
from ..power_property_package import PowerParameterBlock
|
|
13
|
+
from ..bus import Bus
|
|
14
|
+
from ..mainDistributionBoard import MDB
|
|
15
|
+
from pyomo.environ import value
|
|
16
|
+
|
|
17
|
+
def test_mdb():
|
|
18
|
+
m = ConcreteModel()
|
|
19
|
+
m.fs = FlowsheetBlock(dynamic=False)
|
|
20
|
+
m.fs.power_property_package = PowerParameterBlock()
|
|
21
|
+
m.fs.mdb = MDB(
|
|
22
|
+
property_package=m.fs.power_property_package,
|
|
23
|
+
num_inlets=1,
|
|
24
|
+
num_outlets=3,
|
|
25
|
+
)
|
|
26
|
+
m.fs.mdb.inlet_1.power.fix(10 * units.kW)
|
|
27
|
+
m.fs.mdb.priorities[0,'outlet_1'].fix(5* units.kW)
|
|
28
|
+
m.fs.mdb.priorities[0,'outlet_2'].fix(3* units.kW)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# Check that the model is fully specified
|
|
32
|
+
assert degrees_of_freedom(m.fs.mdb) == 0
|
|
33
|
+
|
|
34
|
+
# check that it solves correctly
|
|
35
|
+
solver = SolverFactory("ipopt")
|
|
36
|
+
solver.solve(m)
|
|
37
|
+
assert abs(value(m.fs.mdb.outlet_3.power[0])) <= 2.0005e3
|
|
38
|
+
|
|
39
|
+
#Reduce input power and check that it doesn't give power to the last outlet:
|
|
40
|
+
m.fs.mdb.inlet_1.power.fix(8 * units.kW)
|
|
41
|
+
solver = SolverFactory("ipopt")
|
|
42
|
+
solver.solve(m)
|
|
43
|
+
assert abs(value(m.fs.mdb.outlet_3.power[0])) <= 0.0005
|
|
44
|
+
|
|
45
|
+
#Increase input power and check that it gives all excess power to the last outlet:
|
|
46
|
+
m.fs.mdb.inlet_1.power.fix(18 * units.kW)
|
|
47
|
+
solver = SolverFactory("ipopt")
|
|
48
|
+
solver.solve(m)
|
|
49
|
+
assert abs(value(m.fs.mdb.outlet_3.power[0])) <= 10.0005e3
|
|
@@ -0,0 +1,187 @@
|
|
|
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
|
+
|
|
9
|
+
# Import IDAES cores
|
|
10
|
+
from idaes.core import (
|
|
11
|
+
declare_process_block_class,
|
|
12
|
+
UnitModelBlockData,
|
|
13
|
+
useDefault,
|
|
14
|
+
)
|
|
15
|
+
from idaes.core.util.config import is_physical_parameter_block
|
|
16
|
+
import idaes.core.util.scaling as iscale
|
|
17
|
+
import idaes.logger as idaeslog
|
|
18
|
+
from idaes.core.util.exceptions import ConfigurationError
|
|
19
|
+
# Set up logger
|
|
20
|
+
_log = idaeslog.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# When using this file the name "Transformer" is what is imported
|
|
25
|
+
@declare_process_block_class("Transformer")
|
|
26
|
+
class TransformerData(UnitModelBlockData):
|
|
27
|
+
"""
|
|
28
|
+
Zero order Transformer model
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
# CONFIG are options for the unit model, this simple model only has the mandatory config options
|
|
32
|
+
CONFIG = ConfigBlock()
|
|
33
|
+
|
|
34
|
+
CONFIG.declare(
|
|
35
|
+
"dynamic",
|
|
36
|
+
ConfigValue(
|
|
37
|
+
domain=In([False]),
|
|
38
|
+
default=False,
|
|
39
|
+
description="Dynamic model flag - must be False",
|
|
40
|
+
doc="""Indicates whether this model will be dynamic or not,
|
|
41
|
+
**default** = False. The Bus unit does not support dynamic
|
|
42
|
+
behavior, thus this must be False.""",
|
|
43
|
+
),
|
|
44
|
+
)
|
|
45
|
+
CONFIG.declare(
|
|
46
|
+
"has_holdup",
|
|
47
|
+
ConfigValue(
|
|
48
|
+
default=False,
|
|
49
|
+
domain=In([False]),
|
|
50
|
+
description="Holdup construction flag - must be False",
|
|
51
|
+
doc="""Indicates whether holdup terms should be constructed or not.
|
|
52
|
+
**default** - False. The Transformer unit does not have defined volume, thus
|
|
53
|
+
this must be False.""",
|
|
54
|
+
),
|
|
55
|
+
)
|
|
56
|
+
CONFIG.declare(
|
|
57
|
+
"property_package",
|
|
58
|
+
ConfigValue(
|
|
59
|
+
default=useDefault,
|
|
60
|
+
domain=is_physical_parameter_block,
|
|
61
|
+
description="Property package to use for control volume",
|
|
62
|
+
doc="""Property parameter object used to define property calculations,
|
|
63
|
+
**default** - useDefault.
|
|
64
|
+
**Valid values:** {
|
|
65
|
+
**useDefault** - use default package from parent model or flowsheet,
|
|
66
|
+
**PhysicalParameterObject** - a PhysicalParameterBlock object.}""",
|
|
67
|
+
),
|
|
68
|
+
)
|
|
69
|
+
CONFIG.declare(
|
|
70
|
+
"property_package_args",
|
|
71
|
+
ConfigBlock(
|
|
72
|
+
implicit=True,
|
|
73
|
+
description="Arguments to use for constructing property packages",
|
|
74
|
+
doc="""A ConfigBlock with arguments to be passed to a property block(s)
|
|
75
|
+
and used when constructing these,
|
|
76
|
+
**default** - None.
|
|
77
|
+
**Valid values:** {
|
|
78
|
+
see property package for documentation.}""",
|
|
79
|
+
),
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
def build(self):
|
|
83
|
+
# build always starts by calling super().build()
|
|
84
|
+
# This triggers a lot of boilerplate in the background for you
|
|
85
|
+
super().build()
|
|
86
|
+
|
|
87
|
+
# This creates blank scaling factors, which are populated later
|
|
88
|
+
self.scaling_factor = Suffix(direction=Suffix.EXPORT)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
# Add state blocks for inlet, outlet, and waste
|
|
92
|
+
# These include the state variables and any other properties on demand
|
|
93
|
+
# Add inlet block
|
|
94
|
+
tmp_dict = dict(**self.config.property_package_args)
|
|
95
|
+
tmp_dict["parameters"] = self.config.property_package
|
|
96
|
+
tmp_dict["defined_state"] = True # inlet block is an inlet
|
|
97
|
+
self.properties_in = self.config.property_package.state_block_class(
|
|
98
|
+
self.flowsheet().config.time, doc="Material properties of inlet", **tmp_dict
|
|
99
|
+
)
|
|
100
|
+
# Add outlet and waste block
|
|
101
|
+
tmp_dict["defined_state"] = False # outlet and waste block is not an inlet
|
|
102
|
+
self.properties_out = self.config.property_package.state_block_class(
|
|
103
|
+
self.flowsheet().config.time,
|
|
104
|
+
doc="Material properties of outlet",
|
|
105
|
+
**tmp_dict
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# Add ports - oftentimes users interact with these rather than the state blocks
|
|
109
|
+
self.add_port(name="inlet", block=self.properties_in)
|
|
110
|
+
self.add_port(name="outlet", block=self.properties_out)
|
|
111
|
+
|
|
112
|
+
# # Add variable for turns_ratio
|
|
113
|
+
# self.turns_ratio = Var(self.flowsheet().config.time,
|
|
114
|
+
# initialize=1.0,
|
|
115
|
+
# doc="Turns Ratio of the Transformer",
|
|
116
|
+
# )
|
|
117
|
+
# # Add variable for Load Resistance
|
|
118
|
+
# self.resistance = Var(self.flowsheet().config.time,
|
|
119
|
+
# initialize=1.0,
|
|
120
|
+
# doc="Load Resistance of the Transformer",
|
|
121
|
+
# )
|
|
122
|
+
self.n_capacity = Var(
|
|
123
|
+
self.flowsheet().config.time,
|
|
124
|
+
initialize=1.0,
|
|
125
|
+
units = pyunits.W,
|
|
126
|
+
doc="N Capacity of the Transformer",
|
|
127
|
+
)
|
|
128
|
+
self.voltage = Var(self.flowsheet().config.time,
|
|
129
|
+
initialize=1.0,
|
|
130
|
+
units = pyunits.V,
|
|
131
|
+
doc="Voltage Capacity of the Transformer",
|
|
132
|
+
)
|
|
133
|
+
self.efficiency = Var(self.flowsheet().config.time,
|
|
134
|
+
initialize=1.0,
|
|
135
|
+
units = pyunits.dimensionless,
|
|
136
|
+
doc="Efficiency of the Transformer",
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# Add constraints
|
|
141
|
+
@self.Constraint(
|
|
142
|
+
self.flowsheet().time,
|
|
143
|
+
doc = "Power out",
|
|
144
|
+
)
|
|
145
|
+
def power_out(b, t):
|
|
146
|
+
return (
|
|
147
|
+
self.properties_out[t].power
|
|
148
|
+
== self.properties_in[t].power * self.efficiency[t]
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
@self.Constraint(
|
|
152
|
+
self.flowsheet().time,
|
|
153
|
+
doc = "Capacity check",
|
|
154
|
+
)
|
|
155
|
+
def capacity_check(b,t):
|
|
156
|
+
return abs(self.properties_in[t].power) <= self.n_capacity[t]
|
|
157
|
+
|
|
158
|
+
# @self.Constraint(
|
|
159
|
+
# self.flowsheet().time,
|
|
160
|
+
# doc="Voltage out",
|
|
161
|
+
# )
|
|
162
|
+
# def voltage_out(b, t):
|
|
163
|
+
# return (
|
|
164
|
+
# b.properties_in[t].voltage * self.turns_ratio[t] == self.properties_out[t].voltage
|
|
165
|
+
# )
|
|
166
|
+
# @self.Constraint(
|
|
167
|
+
# self.flowsheet().time,
|
|
168
|
+
# doc="Current out",
|
|
169
|
+
# )
|
|
170
|
+
# def current_out(b,t):
|
|
171
|
+
# return(
|
|
172
|
+
# self.properties_out[t].voltage / self.resistance[t] == self.properties_out[t].current
|
|
173
|
+
# )
|
|
174
|
+
|
|
175
|
+
def calculate_scaling_factors(self):
|
|
176
|
+
super().calculate_scaling_factors()
|
|
177
|
+
|
|
178
|
+
def initialize(blk, *args, **kwargs):
|
|
179
|
+
# Just propagate the power from inlet to outlet, good simple method of initialization
|
|
180
|
+
for i in blk.properties_in.index_set():
|
|
181
|
+
if not blk.properties_out[i].power.fixed:
|
|
182
|
+
blk.properties_out[i].power = blk.properties_in[i].power.value
|
|
183
|
+
|
|
184
|
+
if abs(blk.properties_in[i].power.value) > blk.n_capacity[i].value:
|
|
185
|
+
raise ConfigurationError(
|
|
186
|
+
"Danger: Input power exceeds transformer capacity. Please either increase capacity or lower input power."
|
|
187
|
+
)
|