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,279 @@
|
|
|
1
|
+
# Import Pyomo tools
|
|
2
|
+
from pyomo.environ import (
|
|
3
|
+
Constraint,
|
|
4
|
+
Var,
|
|
5
|
+
Param,
|
|
6
|
+
Expression,
|
|
7
|
+
Reals,
|
|
8
|
+
NonNegativeReals,
|
|
9
|
+
Suffix,
|
|
10
|
+
)
|
|
11
|
+
from pyomo.environ import units as pyunits
|
|
12
|
+
from pyomo.common.config import ConfigBlock, ConfigValue, Bool
|
|
13
|
+
|
|
14
|
+
# Import IDAES cores
|
|
15
|
+
from idaes.core import (
|
|
16
|
+
declare_process_block_class,
|
|
17
|
+
MaterialFlowBasis,
|
|
18
|
+
PhysicalParameterBlock,
|
|
19
|
+
StateBlockData,
|
|
20
|
+
StateBlock,
|
|
21
|
+
MaterialBalanceType,
|
|
22
|
+
EnergyBalanceType,
|
|
23
|
+
)
|
|
24
|
+
from idaes.core.base.components import Component
|
|
25
|
+
from idaes.core.base.phases import LiquidPhase
|
|
26
|
+
from idaes.core.util.initialization import (
|
|
27
|
+
fix_state_vars,
|
|
28
|
+
revert_state_vars,
|
|
29
|
+
solve_indexed_blocks,
|
|
30
|
+
)
|
|
31
|
+
from idaes.core.base.process_base import ProcessBlockData
|
|
32
|
+
from idaes.core.base import property_meta
|
|
33
|
+
from idaes.core.util.model_statistics import (
|
|
34
|
+
degrees_of_freedom,
|
|
35
|
+
number_unfixed_variables,
|
|
36
|
+
)
|
|
37
|
+
from idaes.core.util.exceptions import PropertyPackageError
|
|
38
|
+
import idaes.core.util.scaling as iscale
|
|
39
|
+
import idaes.logger as idaeslog
|
|
40
|
+
from idaes.core.solvers import get_solver
|
|
41
|
+
|
|
42
|
+
# Set up logger
|
|
43
|
+
_log = idaeslog.getLogger(__name__)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# STEP 2
|
|
47
|
+
|
|
48
|
+
# When using this file the name "acParameterBlock" is what is imported
|
|
49
|
+
@declare_process_block_class("acParameterBlock")
|
|
50
|
+
class acParameterData(PhysicalParameterBlock):
|
|
51
|
+
CONFIG = ProcessBlockData.CONFIG()
|
|
52
|
+
CONFIG.declare(
|
|
53
|
+
"default_arguments",
|
|
54
|
+
ConfigBlock(
|
|
55
|
+
implicit=True, description="Default arguments to use with Property Package"
|
|
56
|
+
),
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
def build(self):
|
|
60
|
+
"""
|
|
61
|
+
Callable method for Block construction.
|
|
62
|
+
"""
|
|
63
|
+
super(acParameterData, self).build()
|
|
64
|
+
|
|
65
|
+
self._state_block_class = acStateBlock
|
|
66
|
+
|
|
67
|
+
# Variables
|
|
68
|
+
self.active_power = Var(initialize=0, domain=Reals, units=pyunits.W)
|
|
69
|
+
self.reactive_power = Var(initialize=0, domain=Reals, units=pyunits.W)
|
|
70
|
+
self.voltage = Var(initialize=0, domain=Reals, units=pyunits.V)
|
|
71
|
+
|
|
72
|
+
# Default scaling values should be provided so that our tools can ensure the model is well-scaled
|
|
73
|
+
# Generally scaling factors should be such that if it is multiplied by the variable it will range between 0.01 and 100
|
|
74
|
+
self.set_default_scaling("active_power", 1e-3)
|
|
75
|
+
self.set_default_scaling("reactive_power", 1e-3)
|
|
76
|
+
self.set_default_scaling("voltage", 1e-3)
|
|
77
|
+
|
|
78
|
+
@classmethod
|
|
79
|
+
def define_metadata(cls, obj):
|
|
80
|
+
# see https://github.com/watertap-org/watertap/blob/main/tutorials/creating_a_simple_property_model.ipynb
|
|
81
|
+
obj.add_properties(
|
|
82
|
+
{
|
|
83
|
+
"active_power": {"method": None},
|
|
84
|
+
"reactive_power": {"method": None},
|
|
85
|
+
"voltage": {"method": None},
|
|
86
|
+
}
|
|
87
|
+
)
|
|
88
|
+
obj.add_default_units(
|
|
89
|
+
{
|
|
90
|
+
"time": pyunits.s,
|
|
91
|
+
"length": pyunits.m,
|
|
92
|
+
"mass": pyunits.kg,
|
|
93
|
+
}
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
def build_state_block(self, *args, **kwargs):
|
|
97
|
+
"""
|
|
98
|
+
Methods to construct a StateBlock associated with this
|
|
99
|
+
PhysicalParameterBlock. This will automatically set the parameters
|
|
100
|
+
construction argument for the StateBlock.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
StateBlock
|
|
104
|
+
|
|
105
|
+
"""
|
|
106
|
+
# default = kwargs.pop("default", {})
|
|
107
|
+
initialize = kwargs.pop("initialize", {})
|
|
108
|
+
|
|
109
|
+
if initialize == {}:
|
|
110
|
+
kwargs["parameters"] = self
|
|
111
|
+
else:
|
|
112
|
+
for i in initialize.keys():
|
|
113
|
+
initialize[i]["parameters"] = self
|
|
114
|
+
|
|
115
|
+
return self.state_block_class( # pylint: disable=not-callable
|
|
116
|
+
*args, **kwargs, initialize=initialize
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
@property
|
|
120
|
+
def state_block_class(self):
|
|
121
|
+
if self._state_block_class is not None:
|
|
122
|
+
return self._state_block_class
|
|
123
|
+
else:
|
|
124
|
+
raise AttributeError(
|
|
125
|
+
"{} has not assigned a StateBlock class to be associated "
|
|
126
|
+
"with this property package. Please contact the developer of "
|
|
127
|
+
"the property package.".format(self.name)
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
# STEP 3: State Block
|
|
131
|
+
class _acStateBlock(StateBlock):
|
|
132
|
+
def initialize(
|
|
133
|
+
self,
|
|
134
|
+
state_args=None,
|
|
135
|
+
state_vars_fixed=False,
|
|
136
|
+
hold_state=False,
|
|
137
|
+
outlvl=idaeslog.NOTSET,
|
|
138
|
+
solver=None,
|
|
139
|
+
optarg=None,
|
|
140
|
+
):
|
|
141
|
+
"""
|
|
142
|
+
Initialization routine for property package.
|
|
143
|
+
Keyword Arguments:
|
|
144
|
+
state_args : Dictionary with initial guesses for the state vars
|
|
145
|
+
chosen. Note that if this method is triggered
|
|
146
|
+
through the control volume, and if initial guesses
|
|
147
|
+
were not provided at the unit model level, the
|
|
148
|
+
control volume passes the inlet values as initial
|
|
149
|
+
guess.The keys for the state_args dictionary are:
|
|
150
|
+
|
|
151
|
+
flow_mass_phase_comp : value at which to initialize
|
|
152
|
+
phase component flows
|
|
153
|
+
pressure : value at which to initialize pressure
|
|
154
|
+
temperature : value at which to initialize temperature
|
|
155
|
+
|
|
156
|
+
state_vars_fixed: Flag to denote if state vars have already been
|
|
157
|
+
fixed.
|
|
158
|
+
- True - states have already been fixed by the
|
|
159
|
+
control volume 1D. Control volume 0D
|
|
160
|
+
does not fix the state vars, so will
|
|
161
|
+
be False if this state block is used
|
|
162
|
+
with 0D blocks.
|
|
163
|
+
- False - states have not been fixed. The state
|
|
164
|
+
block will deal with fixing/unfixing.
|
|
165
|
+
hold_state : flag indicating whether the initialization routine
|
|
166
|
+
should unfix any state variables fixed during
|
|
167
|
+
initialization (default=False).
|
|
168
|
+
- True - states variables are not unfixed, and
|
|
169
|
+
a dict of returned containing flags for
|
|
170
|
+
which states were fixed during
|
|
171
|
+
initialization.
|
|
172
|
+
- False - state variables are unfixed after
|
|
173
|
+
initialization by calling the
|
|
174
|
+
release_state method
|
|
175
|
+
outlvl : sets output level of initialization routine (default=idaeslog.NOTSET)
|
|
176
|
+
solver : Solver object to use during initialization if None is provided
|
|
177
|
+
it will use the default solver for IDAES (default = None)
|
|
178
|
+
optarg : solver options dictionary object (default=None)
|
|
179
|
+
Returns:
|
|
180
|
+
If hold_states is True, returns a dict containing flags for
|
|
181
|
+
which states were fixed during initialization.
|
|
182
|
+
"""
|
|
183
|
+
|
|
184
|
+
# Fix state variables
|
|
185
|
+
flags = fix_state_vars(self, state_args)
|
|
186
|
+
# Check that dof = 0 when state variables are fixed
|
|
187
|
+
for k in self.keys():
|
|
188
|
+
dof = degrees_of_freedom(self[k])
|
|
189
|
+
if dof != 0:
|
|
190
|
+
raise PropertyPackageError(
|
|
191
|
+
"\nWhile initializing {sb_name}, the degrees of freedom "
|
|
192
|
+
"are {dof}, when zero is required. \nInitialization assumes "
|
|
193
|
+
"that the state variables should be fixed and that no other "
|
|
194
|
+
"variables are fixed. \nIf other properties have a "
|
|
195
|
+
"predetermined value, use the calculate_state method "
|
|
196
|
+
"before using initialize to determine the values for "
|
|
197
|
+
"the state variables and avoid fixing the property variables."
|
|
198
|
+
"".format(sb_name=self.name, dof=dof)
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
# If input block, return flags, else release state
|
|
202
|
+
if state_vars_fixed is False:
|
|
203
|
+
if hold_state is True:
|
|
204
|
+
return flags
|
|
205
|
+
else:
|
|
206
|
+
self.release_state(flags)
|
|
207
|
+
|
|
208
|
+
def release_state(self, flags, outlvl=idaeslog.NOTSET):
|
|
209
|
+
"""
|
|
210
|
+
Method to release state variables fixed during initialisation.
|
|
211
|
+
|
|
212
|
+
Keyword Arguments:
|
|
213
|
+
flags : dict containing information of which state variables
|
|
214
|
+
were fixed during initialization, and should now be
|
|
215
|
+
unfixed. This dict is returned by initialize if
|
|
216
|
+
hold_state=True.
|
|
217
|
+
outlvl : sets output level of of logging
|
|
218
|
+
"""
|
|
219
|
+
if flags is None:
|
|
220
|
+
return
|
|
221
|
+
# Unfix state variables
|
|
222
|
+
for attr in flags:
|
|
223
|
+
if flags[attr] is True:
|
|
224
|
+
getattr(self, attr).unfix()
|
|
225
|
+
return
|
|
226
|
+
|
|
227
|
+
# STEP 4:
|
|
228
|
+
@declare_process_block_class("acStateBlock", block_class=_acStateBlock)
|
|
229
|
+
class acStateBlockData(StateBlockData):
|
|
230
|
+
def build(self):
|
|
231
|
+
"""Callable method for Block construction."""
|
|
232
|
+
super(acStateBlockData, self).build()
|
|
233
|
+
|
|
234
|
+
self.scaling_factor = Suffix(direction=Suffix.EXPORT)
|
|
235
|
+
|
|
236
|
+
self.active_power = Var(
|
|
237
|
+
initialize=0,
|
|
238
|
+
domain=Reals,
|
|
239
|
+
units=pyunits.W,
|
|
240
|
+
doc="active power flow",
|
|
241
|
+
)
|
|
242
|
+
self.reactive_power = Var(
|
|
243
|
+
initialize=0,
|
|
244
|
+
domain=Reals,
|
|
245
|
+
units=pyunits.W,
|
|
246
|
+
doc="reactive power flow",
|
|
247
|
+
)
|
|
248
|
+
self.voltage = Var(
|
|
249
|
+
initialize=0,
|
|
250
|
+
domain=Reals,
|
|
251
|
+
units=pyunits.V,
|
|
252
|
+
doc="voltage",
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
# -----------------------------------------------------------------------------
|
|
256
|
+
|
|
257
|
+
def define_state_vars(self):
|
|
258
|
+
"""Define state vars."""
|
|
259
|
+
return {
|
|
260
|
+
"active_power": self.active_power,
|
|
261
|
+
"reactive_power" : self.reactive_power,
|
|
262
|
+
"voltage": self.voltage
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
# -----------------------------------------------------------------------------
|
|
267
|
+
# Scaling methods
|
|
268
|
+
def calculate_scaling_factors(self):
|
|
269
|
+
super().calculate_scaling_factors()
|
|
270
|
+
# This doesn't do anything, but it's a good example of how to get and set scaling factors in relation to each other.
|
|
271
|
+
sfa = iscale.get_scaling_factor(self.active_power)
|
|
272
|
+
iscale.set_scaling_factor(self.active_power, sfa)
|
|
273
|
+
sfr = iscale.get_scaling_factor(self.reactive_power)
|
|
274
|
+
iscale.set_scaling_factor(self.reactive_power, sfr)
|
|
275
|
+
sfv = iscale.get_scaling_factor(self.active_power)
|
|
276
|
+
iscale.set_scaling_factor(self.voltage, sfv)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
|
|
@@ -0,0 +1,170 @@
|
|
|
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
|
+
|
|
19
|
+
from idaes.core.util.tables import create_stream_table_dataframe
|
|
20
|
+
|
|
21
|
+
from idaes.core.util.exceptions import ConfigurationError
|
|
22
|
+
|
|
23
|
+
# Set up logger
|
|
24
|
+
_log = idaeslog.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# When using this file the name "Solar" is what is imported
|
|
28
|
+
@declare_process_block_class("Solar")
|
|
29
|
+
class SolarData(UnitModelBlockData):
|
|
30
|
+
"""
|
|
31
|
+
Zero order Link model
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
# CONFIG are options for the unit model, this simple model only has the mandatory config options
|
|
35
|
+
CONFIG = ConfigBlock()
|
|
36
|
+
|
|
37
|
+
CONFIG.declare(
|
|
38
|
+
"dynamic",
|
|
39
|
+
ConfigValue(
|
|
40
|
+
domain=In([False]),
|
|
41
|
+
default=False,
|
|
42
|
+
description="Dynamic model flag - must be False",
|
|
43
|
+
doc="""Indicates whether this model will be dynamic or not,
|
|
44
|
+
**default** = False. The Bus unit does not support dynamic
|
|
45
|
+
behavior, thus this must be False.""",
|
|
46
|
+
),
|
|
47
|
+
)
|
|
48
|
+
CONFIG.declare(
|
|
49
|
+
"has_holdup",
|
|
50
|
+
ConfigValue(
|
|
51
|
+
default=False,
|
|
52
|
+
domain=In([False]),
|
|
53
|
+
description="Holdup construction flag - must be False",
|
|
54
|
+
doc="""Indicates whether holdup terms should be constructed or not.
|
|
55
|
+
**default** - False. The Bus unit does not have defined volume, thus
|
|
56
|
+
this must be False.""",
|
|
57
|
+
),
|
|
58
|
+
)
|
|
59
|
+
CONFIG.declare(
|
|
60
|
+
"property_package",
|
|
61
|
+
ConfigValue(
|
|
62
|
+
default=useDefault,
|
|
63
|
+
domain=is_physical_parameter_block,
|
|
64
|
+
description="Property package to use for control volume",
|
|
65
|
+
doc="""Property parameter object used to define property calculations,
|
|
66
|
+
**default** - useDefault.
|
|
67
|
+
**Valid values:** {
|
|
68
|
+
**useDefault** - use default package from parent model or flowsheet,
|
|
69
|
+
**PhysicalParameterObject** - a PhysicalParameterBlock object.}""",
|
|
70
|
+
),
|
|
71
|
+
)
|
|
72
|
+
CONFIG.declare(
|
|
73
|
+
"property_package_args",
|
|
74
|
+
ConfigBlock(
|
|
75
|
+
implicit=True,
|
|
76
|
+
description="Arguments to use for constructing property packages",
|
|
77
|
+
doc="""A ConfigBlock with arguments to be passed to a property block(s)
|
|
78
|
+
and used when constructing these,
|
|
79
|
+
**default** - None.
|
|
80
|
+
**Valid values:** {
|
|
81
|
+
see property package for documentation.}""",
|
|
82
|
+
),
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
def build(self):
|
|
86
|
+
# build always starts by calling super().build()
|
|
87
|
+
# This triggers a lot of boilerplate in the background for you
|
|
88
|
+
super().build()
|
|
89
|
+
|
|
90
|
+
# This creates blank scaling factors, which are populated later
|
|
91
|
+
self.scaling_factor = Suffix(direction=Suffix.EXPORT)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# Add state blocks for inlet, outlet, and waste
|
|
95
|
+
# These include the state variables and any other properties on demand
|
|
96
|
+
# Add inlet block
|
|
97
|
+
tmp_dict = dict(**self.config.property_package_args)
|
|
98
|
+
tmp_dict["parameters"] = self.config.property_package
|
|
99
|
+
#tmp_dict["defined_state"] = True # inlet block is an inlet
|
|
100
|
+
|
|
101
|
+
# Add outlet
|
|
102
|
+
tmp_dict["defined_state"] = False # outlet is not an inlet
|
|
103
|
+
self.properties_out = self.config.property_package.state_block_class(
|
|
104
|
+
self.flowsheet().config.time,
|
|
105
|
+
doc="Material properties of outlet",
|
|
106
|
+
**tmp_dict
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# Add ports - oftentimes users interact with these rather than the state blocks
|
|
110
|
+
|
|
111
|
+
self.add_port(name="outlet", block=self.properties_out)
|
|
112
|
+
|
|
113
|
+
# Add variable for efficiency
|
|
114
|
+
self.efficiency = Var(
|
|
115
|
+
initialize=1.0,
|
|
116
|
+
doc="Efficiency of the panel",
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# Add variable for solar irradiation
|
|
120
|
+
self.irradiation = Var(self.flowsheet().config.time,
|
|
121
|
+
initialize=1.0, units = pyunits.W/pyunits.m**2,
|
|
122
|
+
doc="Amount of sunlight hitting the panel",
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
# Add variable for area
|
|
126
|
+
self.area = Var(
|
|
127
|
+
initialize=1.0, units = pyunits.m**2,
|
|
128
|
+
doc="Size of the panel",
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Add variable for no. of solar panels
|
|
132
|
+
self.panel_count = Var(
|
|
133
|
+
initialize=1.0,
|
|
134
|
+
doc="Number of solar panels",
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
# Add constraints
|
|
138
|
+
@self.Constraint(
|
|
139
|
+
self.flowsheet().time,
|
|
140
|
+
doc="Power usage",
|
|
141
|
+
)
|
|
142
|
+
def eq_power_balance(b, t):
|
|
143
|
+
return (
|
|
144
|
+
self.irradiation[t] * self.efficiency * self.area * self.panel_count == b.properties_out[t].power
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def calculate_scaling_factors(self):
|
|
149
|
+
super().calculate_scaling_factors()
|
|
150
|
+
|
|
151
|
+
def initialize(blk, *args, **kwargs):
|
|
152
|
+
# Just propagate the power from inlet to outlet, good simple method of initialization
|
|
153
|
+
pass
|
|
154
|
+
|
|
155
|
+
def _get_stream_table_contents(self, time_point=0):
|
|
156
|
+
"""
|
|
157
|
+
Assume unit has standard configuration of 1 inlet and 1 outlet.
|
|
158
|
+
|
|
159
|
+
Developers should overload this as appropriate.
|
|
160
|
+
"""
|
|
161
|
+
try:
|
|
162
|
+
return create_stream_table_dataframe(
|
|
163
|
+
{"Outlet": self.outlet}, time_point=time_point
|
|
164
|
+
)
|
|
165
|
+
except AttributeError:
|
|
166
|
+
raise ConfigurationError(
|
|
167
|
+
f"Unit model {self.name} does not have the standard Port "
|
|
168
|
+
f"names (inlet and outlet). Please contact the unit model "
|
|
169
|
+
f"developer to develop a unit specific stream table."
|
|
170
|
+
)
|
|
@@ -0,0 +1,182 @@
|
|
|
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
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# Set up logger
|
|
26
|
+
_log = idaeslog.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# When using this file the name "Bus" is what is imported
|
|
30
|
+
@declare_process_block_class("Bus")
|
|
31
|
+
class BusData(UnitModelBlockData):
|
|
32
|
+
"""
|
|
33
|
+
Zero order bus 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
|
+
|
|
96
|
+
def build(self):
|
|
97
|
+
# build always starts by calling super().build()
|
|
98
|
+
# This triggers a lot of boilerplate in the background for you
|
|
99
|
+
super().build()
|
|
100
|
+
|
|
101
|
+
# This creates blank scaling factors, which are populated later
|
|
102
|
+
self.scaling_factor = Suffix(direction=Suffix.EXPORT)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
# Defining parameters of state block class
|
|
106
|
+
tmp_dict = dict(**self.config.property_package_args)
|
|
107
|
+
tmp_dict["parameters"] = self.config.property_package
|
|
108
|
+
tmp_dict["defined_state"] = True # inlet block is an inlet
|
|
109
|
+
|
|
110
|
+
# Add state blocks for inlet, outlet, and waste
|
|
111
|
+
# These include the state variables and any other properties on demand
|
|
112
|
+
num_inlets = self.config.num_inlets
|
|
113
|
+
|
|
114
|
+
self.inlet_list = [ "inlet_" + str(i+1) for i in range(num_inlets) ]
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
self.inlet_blocks = []
|
|
118
|
+
for name in self.inlet_list:
|
|
119
|
+
# add properties_inlet_1, properties_inlet2 etc
|
|
120
|
+
state_block = self.config.property_package.state_block_class(
|
|
121
|
+
self.flowsheet().config.time, doc="inlet power", **tmp_dict
|
|
122
|
+
)
|
|
123
|
+
self.inlet_blocks.append(state_block)
|
|
124
|
+
# Dynamic equivalent to self.properties_inlet_1 = stateblock
|
|
125
|
+
setattr(self,"properties_" + name, state_block)
|
|
126
|
+
# also add the port
|
|
127
|
+
self.add_port(name=name,block=state_block)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
# Add outlet state block
|
|
131
|
+
tmp_dict["defined_state"] = False # outlet and waste block is not an inlet
|
|
132
|
+
self.properties_out = self.config.property_package.state_block_class(
|
|
133
|
+
self.flowsheet().config.time,
|
|
134
|
+
doc="Material properties of outlet",
|
|
135
|
+
**tmp_dict
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
# Add outlet port
|
|
139
|
+
self.add_port(name="outlet", block=self.properties_out)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
# Add constraints
|
|
143
|
+
# Usually unit models use a control volume to do the mass, energy, and momentum
|
|
144
|
+
# balances, however, they will be explicitly written out in this example
|
|
145
|
+
@self.Constraint(
|
|
146
|
+
self.flowsheet().time,
|
|
147
|
+
doc="Power usage",
|
|
148
|
+
)
|
|
149
|
+
def eq_power_balance(b, t):
|
|
150
|
+
return (
|
|
151
|
+
sum(
|
|
152
|
+
state_block[t].power for state_block in self.inlet_blocks
|
|
153
|
+
)
|
|
154
|
+
== b.properties_out[t].power
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def calculate_scaling_factors(self):
|
|
159
|
+
super().calculate_scaling_factors()
|
|
160
|
+
|
|
161
|
+
def initialize(blk, *args, **kwargs):
|
|
162
|
+
# Just propagate the power from inlet to outlet, good simple method of initialization
|
|
163
|
+
for t in blk.flowsheet().time:
|
|
164
|
+
power_in = 0
|
|
165
|
+
for state_block in blk.inlet_blocks:
|
|
166
|
+
power_in += state_block[t].power.value
|
|
167
|
+
if not blk.properties_out[t].power.fixed:
|
|
168
|
+
blk.properties_out[t].power = power_in
|
|
169
|
+
|
|
170
|
+
def _get_stream_table_contents(self, time_point=0):
|
|
171
|
+
"""
|
|
172
|
+
Assume unit has standard configuration of 1 inlet and 1 outlet.
|
|
173
|
+
|
|
174
|
+
Developers should overload this as appropriate.
|
|
175
|
+
"""
|
|
176
|
+
|
|
177
|
+
io_dict = {}
|
|
178
|
+
for inlet_name in self.inlet_list:
|
|
179
|
+
io_dict[inlet_name] = getattr(self, inlet_name) # get a reference to the port
|
|
180
|
+
|
|
181
|
+
io_dict["Outlet"] = self.outlet
|
|
182
|
+
return create_stream_table_dataframe(io_dict, time_point=time_point)
|