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,195 @@
|
|
|
1
|
+
# Import Pyomo libraries
|
|
2
|
+
from stringprep import in_table_a1
|
|
3
|
+
from pyomo.environ import (
|
|
4
|
+
Var,
|
|
5
|
+
Suffix,
|
|
6
|
+
units as pyunits,
|
|
7
|
+
)
|
|
8
|
+
from pyomo.common.config import ConfigBlock, ConfigValue, In
|
|
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
|
+
|
|
20
|
+
from idaes.core.util.tables import create_stream_table_dataframe
|
|
21
|
+
|
|
22
|
+
from idaes.core.util.exceptions import ConfigurationError, BurntToast
|
|
23
|
+
|
|
24
|
+
# Set up logger
|
|
25
|
+
_log = idaeslog.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# When using this file the name "EnergyMixer" is what is imported
|
|
29
|
+
@declare_process_block_class("EnergyMixer")
|
|
30
|
+
class EnergyMixerData(UnitModelBlockData):
|
|
31
|
+
"""
|
|
32
|
+
Zero order energy_mixer model
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
# CONFIG are options for the unit model, this simple model only has the mandatory config options
|
|
36
|
+
CONFIG = ConfigBlock()
|
|
37
|
+
|
|
38
|
+
CONFIG.declare(
|
|
39
|
+
"dynamic",
|
|
40
|
+
ConfigValue(
|
|
41
|
+
domain=In([False]),
|
|
42
|
+
default=False,
|
|
43
|
+
description="Dynamic model flag - must be False",
|
|
44
|
+
doc="""Indicates whether this model will be dynamic or not,
|
|
45
|
+
**default** = False. The Bus unit does not support dynamic
|
|
46
|
+
behavior, thus this must be False.""",
|
|
47
|
+
),
|
|
48
|
+
)
|
|
49
|
+
CONFIG.declare(
|
|
50
|
+
"has_holdup",
|
|
51
|
+
ConfigValue(
|
|
52
|
+
default=False,
|
|
53
|
+
domain=In([False]),
|
|
54
|
+
description="Holdup construction flag - must be False",
|
|
55
|
+
doc="""Indicates whether holdup terms should be constructed or not.
|
|
56
|
+
**default** - False. The Bus unit does not have defined volume, thus
|
|
57
|
+
this must be False.""",
|
|
58
|
+
),
|
|
59
|
+
)
|
|
60
|
+
CONFIG.declare(
|
|
61
|
+
"property_package",
|
|
62
|
+
ConfigValue(
|
|
63
|
+
default=useDefault,
|
|
64
|
+
domain=is_physical_parameter_block,
|
|
65
|
+
description="Property package to use for control volume",
|
|
66
|
+
doc="""Property parameter object used to define property calculations,
|
|
67
|
+
**default** - useDefault.
|
|
68
|
+
**Valid values:** {
|
|
69
|
+
**useDefault** - use default package from parent model or flowsheet,
|
|
70
|
+
**PhysicalParameterObject** - a PhysicalParameterBlock object.}""",
|
|
71
|
+
),
|
|
72
|
+
)
|
|
73
|
+
CONFIG.declare(
|
|
74
|
+
"property_package_args",
|
|
75
|
+
ConfigBlock(
|
|
76
|
+
implicit=True,
|
|
77
|
+
description="Arguments to use for constructing property packages",
|
|
78
|
+
doc="""A ConfigBlock with arguments to be passed to a property block(s)
|
|
79
|
+
and used when constructing these,
|
|
80
|
+
**default** - None.
|
|
81
|
+
**Valid values:** {
|
|
82
|
+
see property package for documentation.}""",
|
|
83
|
+
),
|
|
84
|
+
)
|
|
85
|
+
CONFIG.declare(
|
|
86
|
+
"num_inlets",
|
|
87
|
+
ConfigValue(
|
|
88
|
+
default=False,
|
|
89
|
+
domain=int,
|
|
90
|
+
description="Number of inlets to add",
|
|
91
|
+
doc="""Number of inlets to add""",
|
|
92
|
+
),
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
def build(self):
|
|
96
|
+
# build always starts by calling super().build()
|
|
97
|
+
# This triggers a lot of boilerplate in the background for you
|
|
98
|
+
super().build()
|
|
99
|
+
|
|
100
|
+
# This creates blank scaling factors, which are populated later
|
|
101
|
+
self.scaling_factor = Suffix(direction=Suffix.EXPORT)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
# Defining parameters of state block class
|
|
105
|
+
tmp_dict = dict(**self.config.property_package_args)
|
|
106
|
+
tmp_dict["parameters"] = self.config.property_package
|
|
107
|
+
tmp_dict["defined_state"] = True # inlet block is an inlet
|
|
108
|
+
|
|
109
|
+
# Add state blocks for inlet, outlet, and waste
|
|
110
|
+
# These include the state variables and any other properties on demand
|
|
111
|
+
num_inlets = self.config.num_inlets
|
|
112
|
+
|
|
113
|
+
self.inlet_list = [ "inlet_" + str(i+1) for i in range(num_inlets) ]
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
self.inlet_blocks = []
|
|
117
|
+
for name in self.inlet_list:
|
|
118
|
+
# add properties_inlet_1, properties_inlet2 etc
|
|
119
|
+
state_block = self.config.property_package.state_block_class(
|
|
120
|
+
self.flowsheet().config.time, doc="inlet power", **tmp_dict
|
|
121
|
+
)
|
|
122
|
+
self.inlet_blocks.append(state_block)
|
|
123
|
+
# Dynamic equivalent to self.properties_inlet_1 = stateblock
|
|
124
|
+
setattr(self,"properties_" + name, state_block)
|
|
125
|
+
# also add the port
|
|
126
|
+
self.add_port(name=name,block=state_block)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# Add outlet state block
|
|
130
|
+
tmp_dict["defined_state"] = False # outlet and waste block is not an inlet
|
|
131
|
+
self.properties_out = self.config.property_package.state_block_class(
|
|
132
|
+
self.flowsheet().config.time,
|
|
133
|
+
doc="Material properties of outlet",
|
|
134
|
+
**tmp_dict
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
# Add outlet port
|
|
138
|
+
self.add_port(name="outlet", block=self.properties_out)
|
|
139
|
+
|
|
140
|
+
#Add variables for capacity and efficiency:
|
|
141
|
+
self.efficiency = Var(self.flowsheet().config.time,
|
|
142
|
+
initialize=1.0,
|
|
143
|
+
doc="Efficiency of the link",
|
|
144
|
+
)
|
|
145
|
+
self.capacity = Var(
|
|
146
|
+
initialize=1.0,
|
|
147
|
+
units = pyunits.W,
|
|
148
|
+
doc="Capacity of the link",
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
# Add constraints
|
|
153
|
+
# Usually unit models use a control volume to do the mass, energy, and momentum
|
|
154
|
+
# balances, however, they will be explicitly written out in this example
|
|
155
|
+
|
|
156
|
+
@self.Constraint(
|
|
157
|
+
self.flowsheet().time,
|
|
158
|
+
doc="Power usage",
|
|
159
|
+
)
|
|
160
|
+
def eq_power_balance(b, t):
|
|
161
|
+
return (
|
|
162
|
+
sum(
|
|
163
|
+
state_block[t].power for state_block in self.inlet_blocks
|
|
164
|
+
) * self.efficiency[t]
|
|
165
|
+
== b.properties_out[t].power
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
def calculate_scaling_factors(self):
|
|
169
|
+
super().calculate_scaling_factors()
|
|
170
|
+
|
|
171
|
+
def initialize(blk, *args, **kwargs):
|
|
172
|
+
# Just propagate the power from inlet to outlet, good simple method of initialization
|
|
173
|
+
for t in blk.flowsheet().time:
|
|
174
|
+
power_in = 0
|
|
175
|
+
for state_block in blk.inlet_blocks:
|
|
176
|
+
power_in += state_block[t].power.value
|
|
177
|
+
if not blk.properties_out[t].power.fixed:
|
|
178
|
+
blk.properties_out[t].power = power_in
|
|
179
|
+
if(power_in > blk.capacity.value):
|
|
180
|
+
raise BurntToast(
|
|
181
|
+
"Danger: Input power exceeds energy mixer capacity. Please either increase capacity or lower input power.".format(blk.name)
|
|
182
|
+
)
|
|
183
|
+
def _get_stream_table_contents(self, time_point=0):
|
|
184
|
+
"""
|
|
185
|
+
Assume unit has standard configuration of 1 inlet and 1 outlet.
|
|
186
|
+
|
|
187
|
+
Developers should overload this as appropriate.
|
|
188
|
+
"""
|
|
189
|
+
|
|
190
|
+
io_dict = {}
|
|
191
|
+
for inlet_name in self.inlet_list:
|
|
192
|
+
io_dict[inlet_name] = getattr(self, inlet_name) # get a reference to the port
|
|
193
|
+
|
|
194
|
+
io_dict["Outlet"] = self.outlet
|
|
195
|
+
return create_stream_table_dataframe(io_dict, time_point=time_point)
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# Import Pyomo libraries
|
|
2
|
+
from stringprep import in_table_a1
|
|
3
|
+
from pyomo.environ import (
|
|
4
|
+
Var,
|
|
5
|
+
Suffix,
|
|
6
|
+
units as pyunits,
|
|
7
|
+
Set,
|
|
8
|
+
)
|
|
9
|
+
from pyomo.common.config import ConfigBlock, ConfigValue, In
|
|
10
|
+
|
|
11
|
+
# Import IDAES cores
|
|
12
|
+
from idaes.core import (
|
|
13
|
+
declare_process_block_class,
|
|
14
|
+
UnitModelBlockData,
|
|
15
|
+
useDefault,
|
|
16
|
+
)
|
|
17
|
+
from idaes.core.util.config import is_physical_parameter_block
|
|
18
|
+
import idaes.core.util.scaling as iscale
|
|
19
|
+
import idaes.logger as idaeslog
|
|
20
|
+
|
|
21
|
+
from idaes.core.util.tables import create_stream_table_dataframe
|
|
22
|
+
|
|
23
|
+
from idaes.core.util.exceptions import ConfigurationError
|
|
24
|
+
|
|
25
|
+
# Set up logger
|
|
26
|
+
_log = idaeslog.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# When using this file the name "EnergyMixer" is what is imported
|
|
30
|
+
@declare_process_block_class("EnergySplitter")
|
|
31
|
+
class EnergySplitterData(UnitModelBlockData):
|
|
32
|
+
"""
|
|
33
|
+
Zero order energy splitter model
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
# CONFIG are options for the unit model, this simple model only has the mandatory config options
|
|
37
|
+
CONFIG = ConfigBlock()
|
|
38
|
+
|
|
39
|
+
CONFIG.declare(
|
|
40
|
+
"dynamic",
|
|
41
|
+
ConfigValue(
|
|
42
|
+
domain=In([False]),
|
|
43
|
+
default=False,
|
|
44
|
+
description="Dynamic model flag - must be False",
|
|
45
|
+
doc="""Indicates whether this model will be dynamic or not,
|
|
46
|
+
**default** = False. The Bus unit does not support dynamic
|
|
47
|
+
behavior, thus this must be False.""",
|
|
48
|
+
),
|
|
49
|
+
)
|
|
50
|
+
CONFIG.declare(
|
|
51
|
+
"has_holdup",
|
|
52
|
+
ConfigValue(
|
|
53
|
+
default=False,
|
|
54
|
+
domain=In([False]),
|
|
55
|
+
description="Holdup construction flag - must be False",
|
|
56
|
+
doc="""Indicates whether holdup terms should be constructed or not.
|
|
57
|
+
**default** - False. The Bus unit does not have defined volume, thus
|
|
58
|
+
this must be False.""",
|
|
59
|
+
),
|
|
60
|
+
)
|
|
61
|
+
CONFIG.declare(
|
|
62
|
+
"property_package",
|
|
63
|
+
ConfigValue(
|
|
64
|
+
default=useDefault,
|
|
65
|
+
domain=is_physical_parameter_block,
|
|
66
|
+
description="Property package to use for control volume",
|
|
67
|
+
doc="""Property parameter object used to define property calculations,
|
|
68
|
+
**default** - useDefault.
|
|
69
|
+
**Valid values:** {
|
|
70
|
+
**useDefault** - use default package from parent model or flowsheet,
|
|
71
|
+
**PhysicalParameterObject** - a PhysicalParameterBlock object.}""",
|
|
72
|
+
),
|
|
73
|
+
)
|
|
74
|
+
CONFIG.declare(
|
|
75
|
+
"property_package_args",
|
|
76
|
+
ConfigBlock(
|
|
77
|
+
implicit=True,
|
|
78
|
+
description="Arguments to use for constructing property packages",
|
|
79
|
+
doc="""A ConfigBlock with arguments to be passed to a property block(s)
|
|
80
|
+
and used when constructing these,
|
|
81
|
+
**default** - None.
|
|
82
|
+
**Valid values:** {
|
|
83
|
+
see property package for documentation.}""",
|
|
84
|
+
),
|
|
85
|
+
)
|
|
86
|
+
CONFIG.declare(
|
|
87
|
+
"num_inlets",
|
|
88
|
+
ConfigValue(
|
|
89
|
+
default=False,
|
|
90
|
+
domain=int,
|
|
91
|
+
description="Number of inlets to add",
|
|
92
|
+
doc="""Number of inlets to add""",
|
|
93
|
+
),
|
|
94
|
+
)
|
|
95
|
+
CONFIG.declare(
|
|
96
|
+
"num_outlets",
|
|
97
|
+
ConfigValue(
|
|
98
|
+
default=False,
|
|
99
|
+
domain=int,
|
|
100
|
+
description="Number of outlets to add",
|
|
101
|
+
doc="""Number of outlets to add""",
|
|
102
|
+
),
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
def build(self):
|
|
106
|
+
# build always starts by calling super().build()
|
|
107
|
+
# This triggers a lot of boilerplate in the background for you
|
|
108
|
+
super().build()
|
|
109
|
+
|
|
110
|
+
# This creates blank scaling factors, which are populated later
|
|
111
|
+
self.scaling_factor = Suffix(direction=Suffix.EXPORT)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# Defining parameters of state block class
|
|
115
|
+
tmp_dict = dict(**self.config.property_package_args)
|
|
116
|
+
tmp_dict["parameters"] = self.config.property_package
|
|
117
|
+
tmp_dict["defined_state"] = True # inlet block is an inlet
|
|
118
|
+
|
|
119
|
+
# Add state blocks for inlet, outlet, and waste
|
|
120
|
+
# These include the state variables and any other properties on demand
|
|
121
|
+
num_inlets = self.config.num_inlets
|
|
122
|
+
|
|
123
|
+
self.inlet_list = [ "inlet_" + str(i+1) for i in range(num_inlets) ]
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
self.inlet_blocks = []
|
|
127
|
+
for name in self.inlet_list:
|
|
128
|
+
# add properties_inlet_1, properties_inlet2 etc
|
|
129
|
+
state_block = self.config.property_package.state_block_class(
|
|
130
|
+
self.flowsheet().config.time, doc="inlet power", **tmp_dict
|
|
131
|
+
)
|
|
132
|
+
self.inlet_blocks.append(state_block)
|
|
133
|
+
# Dynamic equivalent to self.properties_inlet_1 = stateblock
|
|
134
|
+
setattr(self,"properties_" + name, state_block)
|
|
135
|
+
# also add the port
|
|
136
|
+
self.add_port(name=name,block=state_block)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
num_outlets = self.config.num_outlets
|
|
140
|
+
self.outlet_list = [ "outlet_" + str(i+1) for i in range(num_outlets) ]
|
|
141
|
+
self.outlet_set = Set(initialize=self.outlet_list)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
self.outlet_blocks = []
|
|
145
|
+
for name in self.outlet_list:
|
|
146
|
+
# add properties_inlet_1, properties_inlet2 etc
|
|
147
|
+
state_block = self.config.property_package.state_block_class(
|
|
148
|
+
self.flowsheet().config.time, doc="inlet power", **tmp_dict
|
|
149
|
+
)
|
|
150
|
+
self.outlet_blocks.append(state_block)
|
|
151
|
+
# Dynamic equivalent to self.properties_inlet_1 = stateblock
|
|
152
|
+
setattr(self,"properties_" + name, state_block)
|
|
153
|
+
# also add the port
|
|
154
|
+
self.add_port(name=name,block=state_block)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
#Add variable for capacity:
|
|
158
|
+
self.capacity = Var(
|
|
159
|
+
self.flowsheet().config.time,
|
|
160
|
+
initialize=1.0,
|
|
161
|
+
units = pyunits.W,
|
|
162
|
+
doc="Capacity of the link",
|
|
163
|
+
)
|
|
164
|
+
# Add variable for power splitting
|
|
165
|
+
self.split_fraction = Var(
|
|
166
|
+
self.flowsheet().time,
|
|
167
|
+
self.outlet_set,
|
|
168
|
+
initialize=1.0,
|
|
169
|
+
#units = pyunits.dimensionless,
|
|
170
|
+
doc="How the power is split between outlets",
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
@self.Expression(
|
|
175
|
+
self.flowsheet().time,
|
|
176
|
+
)
|
|
177
|
+
def total_power(b, t):
|
|
178
|
+
return (
|
|
179
|
+
sum(
|
|
180
|
+
state_block[t].power for state_block in self.inlet_blocks
|
|
181
|
+
)
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
# Add constraints
|
|
185
|
+
@self.Constraint(
|
|
186
|
+
self.flowsheet().time,
|
|
187
|
+
self.outlet_list,
|
|
188
|
+
doc="power split",
|
|
189
|
+
)
|
|
190
|
+
def eq_power(b,t,o):
|
|
191
|
+
outlet_block = getattr(self,"properties_" + o)
|
|
192
|
+
return outlet_block[t].power == (
|
|
193
|
+
self.total_power[t] * b.split_fraction[t,o])
|
|
194
|
+
|
|
195
|
+
@self.Constraint(
|
|
196
|
+
self.flowsheet().time,
|
|
197
|
+
doc="Split fraction sum to 1",
|
|
198
|
+
)
|
|
199
|
+
def eq_split_fraction_sum(b, t):
|
|
200
|
+
return sum(b.split_fraction[t, o] for o in self.outlet_list) == 1.0
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def calculate_scaling_factors(self):
|
|
204
|
+
super().calculate_scaling_factors()
|
|
205
|
+
|
|
206
|
+
def initialize(blk, *args, **kwargs):
|
|
207
|
+
# Just propagate the power from inlet to outlet, good simple method of initialization
|
|
208
|
+
for t in blk.flowsheet().time:
|
|
209
|
+
for state_block in blk.inlet_blocks:
|
|
210
|
+
if(state_block[t].power.value > blk.capacity[t].value):
|
|
211
|
+
raise ConfigurationError(
|
|
212
|
+
"Danger: Input power exceeds splitter capacity. Please either increase capacity or lower input power."
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
def _get_stream_table_contents(self, time_point=0):
|
|
216
|
+
"""
|
|
217
|
+
Assume unit has standard configuration of 1 inlet and 1 outlet.
|
|
218
|
+
|
|
219
|
+
Developers should overload this as appropriate.
|
|
220
|
+
"""
|
|
221
|
+
|
|
222
|
+
io_dict = {}
|
|
223
|
+
for inlet_name in self.inlet_list:
|
|
224
|
+
io_dict[inlet_name] = getattr(self, inlet_name) # get a reference to the port
|
|
225
|
+
|
|
226
|
+
io_dict = {}
|
|
227
|
+
for outlet_name in self.outlet_list:
|
|
228
|
+
io_dict[outlet_name] = getattr(self, outlet_name)
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# Import Pyomo libraries
|
|
2
|
+
from pyomo.environ import (
|
|
3
|
+
Var,
|
|
4
|
+
Suffix,
|
|
5
|
+
units as pyunits,
|
|
6
|
+
)
|
|
7
|
+
from pyomo.common.config import ConfigBlock, ConfigValue, In
|
|
8
|
+
from idaes.core.util.tables import create_stream_table_dataframe
|
|
9
|
+
from idaes.core.util.exceptions import ConfigurationError
|
|
10
|
+
# 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
|
+
|
|
20
|
+
# Set up logger
|
|
21
|
+
_log = idaeslog.getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# When using this file the name "Grid" is what is imported
|
|
25
|
+
@declare_process_block_class("Grid")
|
|
26
|
+
class gridData(UnitModelBlockData):
|
|
27
|
+
"""
|
|
28
|
+
Zero order Grid 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 Bus 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
|
+
|
|
111
|
+
# Add variables
|
|
112
|
+
self.n_capacity = Var(self.flowsheet().config.time,
|
|
113
|
+
initialize=1.0,
|
|
114
|
+
doc="N Capacity",
|
|
115
|
+
units = pyunits.W
|
|
116
|
+
)
|
|
117
|
+
self.n_minus_one = Var(self.flowsheet().config.time,
|
|
118
|
+
initialize=1.0,
|
|
119
|
+
doc="N-1 Capacity",
|
|
120
|
+
units = pyunits.W
|
|
121
|
+
)
|
|
122
|
+
self.import_export = Var(self.flowsheet().config.time,
|
|
123
|
+
initialize=1.0,
|
|
124
|
+
doc="Power being import or exported from grid",
|
|
125
|
+
units = pyunits.W
|
|
126
|
+
)
|
|
127
|
+
# Add constraints
|
|
128
|
+
# Usually unit models use a control volume to do the mass, energy, and momentum
|
|
129
|
+
# balances, however, they will be explicitly written out in this example
|
|
130
|
+
@self.Constraint(
|
|
131
|
+
self.flowsheet().time,
|
|
132
|
+
doc="Power usage",
|
|
133
|
+
)
|
|
134
|
+
def eq_power_in_balance(b, t):
|
|
135
|
+
return (
|
|
136
|
+
self.import_export[t] == b.properties_in[t].power
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
# @self.Constraint(
|
|
140
|
+
# self.flowsheet().time,
|
|
141
|
+
# doc="capacity_check",
|
|
142
|
+
# )
|
|
143
|
+
# def eq_capacity_check(b,t):
|
|
144
|
+
# return(
|
|
145
|
+
# abs(self.properties_in[t].power) <= self.n_capacity[t]
|
|
146
|
+
# )
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def calculate_scaling_factors(self):
|
|
150
|
+
super().calculate_scaling_factors()
|
|
151
|
+
|
|
152
|
+
def initialize(blk, *args, **kwargs):
|
|
153
|
+
# Just propagate the power from inlet to outlet, good simple method of initialization
|
|
154
|
+
for i in blk.properties_in.index_set():
|
|
155
|
+
if not blk.properties_out[i].power.fixed:
|
|
156
|
+
blk.properties_out[i].power = blk.properties_in[i].power.value
|
|
157
|
+
|
|
158
|
+
def _get_stream_table_contents(self, time_point=0):
|
|
159
|
+
"""
|
|
160
|
+
Assume unit has standard configuration of 1 inlet and 1 outlet.
|
|
161
|
+
|
|
162
|
+
Developers should overload this as appropriate.
|
|
163
|
+
"""
|
|
164
|
+
try:
|
|
165
|
+
return create_stream_table_dataframe(
|
|
166
|
+
{"inlet": self.inlet}, time_point=time_point
|
|
167
|
+
)
|
|
168
|
+
except AttributeError:
|
|
169
|
+
raise ConfigurationError(
|
|
170
|
+
f"Unit model {self.name} does not have the standard Port "
|
|
171
|
+
f"names (inlet and outlet). Please contact the unit model "
|
|
172
|
+
f"developer to develop a unit specific stream table."
|
|
173
|
+
)
|