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,132 @@
|
|
|
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
|
+
from idaes.models.unit_models.pressure_changer import (
|
|
21
|
+
TurbineData,
|
|
22
|
+
)
|
|
23
|
+
from idaes.core.util.exceptions import PropertyNotSupportedError, InitializationError
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# Import Python libraries
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# Import Pyomo libraries
|
|
30
|
+
from pyomo.environ import (
|
|
31
|
+
Block,
|
|
32
|
+
value,
|
|
33
|
+
Var,
|
|
34
|
+
Expression,
|
|
35
|
+
Constraint,
|
|
36
|
+
Reference,
|
|
37
|
+
check_optimal_termination,
|
|
38
|
+
Reals,
|
|
39
|
+
)
|
|
40
|
+
from pyomo.common.config import ConfigBlock, ConfigValue, In, Bool
|
|
41
|
+
from idaes.core.solvers import get_solver
|
|
42
|
+
from .thermal_utility_systems.willans_turbine import TurbineBaseData
|
|
43
|
+
from .inverted import add_inverted, initialise_inverted
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# When using this file the name "CustomCompressor" is what is imported
|
|
47
|
+
@declare_process_block_class("CustomTurbine")
|
|
48
|
+
class CustomTurbineData(TurbineBaseData):
|
|
49
|
+
"""
|
|
50
|
+
Zero order Load model
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
# CONFIG are options for the unit model, this simple model only has the mandatory config options
|
|
54
|
+
CONFIG = TurbineBaseData.CONFIG()
|
|
55
|
+
|
|
56
|
+
CONFIG.declare(
|
|
57
|
+
"power_property_package",
|
|
58
|
+
ConfigValue(
|
|
59
|
+
default=useDefault,
|
|
60
|
+
domain=is_physical_parameter_block,
|
|
61
|
+
description="Property package to use for power",
|
|
62
|
+
doc="""Power Property parameter object used to define power 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
|
+
"power_property_package_args",
|
|
71
|
+
ConfigBlock(
|
|
72
|
+
implicit=True,
|
|
73
|
+
description="Arguments to use for constructing power 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
|
+
|
|
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
|
+
# Add inlet block
|
|
98
|
+
# self.properties_in = self.config.property_package.state_block_class(
|
|
99
|
+
# self.flowsheet().config.time, doc="Material properties of inlet", **tmp_dict
|
|
100
|
+
# )
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# Add outlet and waste block
|
|
104
|
+
tmp_dict["defined_state"] = False # outlet and waste block is not an inlet
|
|
105
|
+
self.power_properties_out = self.config.power_property_package.state_block_class(
|
|
106
|
+
self.flowsheet().config.time,
|
|
107
|
+
doc="Material properties of outlet",
|
|
108
|
+
**tmp_dict
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
# Add ports - oftentimes users interact with these rather than the state blocks
|
|
112
|
+
self.add_port(name="power_outlet", block=self.power_properties_out)
|
|
113
|
+
|
|
114
|
+
# Add constraints
|
|
115
|
+
# Usually unit models use a control volume to do the mass, energy, and momentum
|
|
116
|
+
# balances, however, they will be explicitly written out in this example
|
|
117
|
+
@self.Constraint(
|
|
118
|
+
self.flowsheet().time,
|
|
119
|
+
doc="Power out",
|
|
120
|
+
)
|
|
121
|
+
def eq_power_out(b, t):
|
|
122
|
+
return (
|
|
123
|
+
self.power_properties_out[t].power == self.work_electrical[t] * -1
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
# Add inverted deltaP property
|
|
127
|
+
add_inverted(self, "deltaP")
|
|
128
|
+
|
|
129
|
+
def initialize_build(self, *args, **kwargs):
|
|
130
|
+
initialise_inverted(self, "deltaP")
|
|
131
|
+
|
|
132
|
+
super().initialize_build(*args, **kwargs)
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
#################################################################################
|
|
2
|
+
# The Institute for the Design of Advanced Energy Systems Integrated Platform
|
|
3
|
+
# Framework (IDAES IP) was produced under the DOE Institute for the
|
|
4
|
+
# Design of Advanced Energy Systems (IDAES).
|
|
5
|
+
#
|
|
6
|
+
# Copyright (c) 2018-2024 by the software owners: The Regents of the
|
|
7
|
+
# University of California, through Lawrence Berkeley National Laboratory,
|
|
8
|
+
# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon
|
|
9
|
+
# University, West Virginia University Research Corporation, et al.
|
|
10
|
+
# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md
|
|
11
|
+
# for full copyright and license information.
|
|
12
|
+
#################################################################################
|
|
13
|
+
"""
|
|
14
|
+
This provides standard valve models for adiabatic control valves. Beyond the
|
|
15
|
+
most common valve models, and adiabatic valve model can be added by supplying
|
|
16
|
+
custom callbacks for the pressure-flow relation or valve function.
|
|
17
|
+
"""
|
|
18
|
+
# Changing existing config block attributes
|
|
19
|
+
# pylint: disable=protected-access
|
|
20
|
+
|
|
21
|
+
__Author__ = "John Eslick"
|
|
22
|
+
|
|
23
|
+
from enum import Enum
|
|
24
|
+
|
|
25
|
+
import pyomo.environ as pyo
|
|
26
|
+
from pyomo.common.config import ConfigValue, In
|
|
27
|
+
|
|
28
|
+
from idaes.core import declare_process_block_class
|
|
29
|
+
from .updated_pressure_changer import (
|
|
30
|
+
ThermodynamicAssumption,
|
|
31
|
+
MaterialBalanceType,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
from .updated_pressure_changer import PressureChangerData
|
|
35
|
+
|
|
36
|
+
from idaes.core.util.exceptions import ConfigurationError
|
|
37
|
+
import idaes.logger as idaeslog
|
|
38
|
+
import idaes.core.util.scaling as iscale
|
|
39
|
+
from .inverted import add_inverted, initialise_inverted
|
|
40
|
+
|
|
41
|
+
_log = idaeslog.getLogger(__name__)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class ValveFunctionType(Enum):
|
|
45
|
+
"""
|
|
46
|
+
Enum of supported valve types.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
linear = 1
|
|
50
|
+
quick_opening = 2
|
|
51
|
+
equal_percentage = 3
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def linear_cb(valve):
|
|
55
|
+
"""
|
|
56
|
+
Linear opening valve function callback.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
@valve.Expression(valve.flowsheet().time)
|
|
60
|
+
def valve_function(b, t):
|
|
61
|
+
return b.valve_opening[t]
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def quick_cb(valve):
|
|
65
|
+
"""
|
|
66
|
+
Quick opening valve function callback.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
@valve.Expression(valve.flowsheet().time)
|
|
70
|
+
def valve_function(b, t):
|
|
71
|
+
return pyo.sqrt(b.valve_opening[t])
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def equal_percentage_cb(valve):
|
|
75
|
+
"""
|
|
76
|
+
Equal percentage valve function callback.
|
|
77
|
+
"""
|
|
78
|
+
valve.alpha = pyo.Var(initialize=100, doc="Valve function parameter")
|
|
79
|
+
valve.alpha.fix()
|
|
80
|
+
|
|
81
|
+
@valve.Expression(valve.flowsheet().time)
|
|
82
|
+
def valve_function(b, t):
|
|
83
|
+
return b.alpha ** (b.valve_opening[t] - 1)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def pressure_flow_default_callback(valve):
|
|
87
|
+
"""
|
|
88
|
+
Add the default pressure flow relation constraint. This will be used in the
|
|
89
|
+
valve model, a custom callback is provided.
|
|
90
|
+
"""
|
|
91
|
+
umeta = (
|
|
92
|
+
valve.control_volume.config.property_package.get_metadata().get_derived_units
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
valve.Cv = pyo.Var(
|
|
96
|
+
initialize=0.1,
|
|
97
|
+
doc="Valve flow coefficient",
|
|
98
|
+
units=umeta("amount") / umeta("time") / umeta("pressure") ** 0.5,
|
|
99
|
+
)
|
|
100
|
+
# valve.Cv.fix()
|
|
101
|
+
|
|
102
|
+
valve.flow_var = pyo.Reference(valve.control_volume.properties_in[:].flow_mol)
|
|
103
|
+
valve.pressure_flow_equation_scale = lambda x: x**2
|
|
104
|
+
|
|
105
|
+
@valve.Constraint(valve.flowsheet().time)
|
|
106
|
+
def pressure_flow_equation(b, t):
|
|
107
|
+
Po = b.control_volume.properties_out[t].pressure
|
|
108
|
+
Pi = b.control_volume.properties_in[t].pressure
|
|
109
|
+
F = b.control_volume.properties_in[t].flow_mol
|
|
110
|
+
Cv = b.Cv
|
|
111
|
+
fun = b.valve_function[t]
|
|
112
|
+
return F**2 == Cv**2 * (Pi - Po) * fun**2
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
@declare_process_block_class("Valve", doc="Adiabatic valves")
|
|
116
|
+
class ValveData(PressureChangerData):
|
|
117
|
+
"""
|
|
118
|
+
Basic valve model class.
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
# Same settings as the default pressure changer, but force to expander with
|
|
122
|
+
# isentropic efficiency
|
|
123
|
+
CONFIG = PressureChangerData.CONFIG()
|
|
124
|
+
CONFIG.compressor = False
|
|
125
|
+
CONFIG.get("compressor")._default = False
|
|
126
|
+
CONFIG.get("compressor")._domain = In([False])
|
|
127
|
+
CONFIG.material_balance_type = MaterialBalanceType.componentTotal
|
|
128
|
+
CONFIG.get("material_balance_type")._default = MaterialBalanceType.componentTotal
|
|
129
|
+
CONFIG.thermodynamic_assumption = ThermodynamicAssumption.adiabatic
|
|
130
|
+
CONFIG.get("thermodynamic_assumption")._default = ThermodynamicAssumption.adiabatic
|
|
131
|
+
CONFIG.get("thermodynamic_assumption")._domain = In(
|
|
132
|
+
[ThermodynamicAssumption.adiabatic]
|
|
133
|
+
)
|
|
134
|
+
CONFIG.declare(
|
|
135
|
+
"valve_function_callback",
|
|
136
|
+
ConfigValue(
|
|
137
|
+
default=ValveFunctionType.linear,
|
|
138
|
+
description="Valve function type or callback for custom",
|
|
139
|
+
doc="""This takes either an enumerated valve function type in: {
|
|
140
|
+
ValveFunctionType.linear, ValveFunctionType.quick_opening,
|
|
141
|
+
ValveFunctionType.equal_percentage, ValveFunctionType.custom} or a callback
|
|
142
|
+
function that takes a valve model object as an argument and adds a time-indexed
|
|
143
|
+
valve_function expression to it. Any additional required variables, expressions,
|
|
144
|
+
or constraints required can also be added by the callback.""",
|
|
145
|
+
),
|
|
146
|
+
)
|
|
147
|
+
CONFIG.declare(
|
|
148
|
+
"pressure_flow_callback",
|
|
149
|
+
ConfigValue(
|
|
150
|
+
default=pressure_flow_default_callback,
|
|
151
|
+
description="Callback function providing the valve_function expression",
|
|
152
|
+
doc="""This callback function takes a valve model object as an argument
|
|
153
|
+
and adds a time-indexed valve_function expression to it. Any additional required
|
|
154
|
+
variables, expressions, or constraints required can also be added by the callback.""",
|
|
155
|
+
),
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
def build(self):
|
|
159
|
+
super().build()
|
|
160
|
+
|
|
161
|
+
self.valve_opening = pyo.Var(
|
|
162
|
+
self.flowsheet().time,
|
|
163
|
+
initialize=1,
|
|
164
|
+
bounds=(0, 1),
|
|
165
|
+
doc="Fraction open for valve from 0 to 1",
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
#commented out to allow for valve opening to be set by the user
|
|
170
|
+
#self.valve_opening.fix()
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
# If the valve function callback is set to one of the known enumerated
|
|
175
|
+
# types, set the callback appropriately. If not callable and not a known
|
|
176
|
+
# type raise ConfigurationError.
|
|
177
|
+
vfcb = self.config.valve_function_callback
|
|
178
|
+
if not callable(vfcb):
|
|
179
|
+
if vfcb == ValveFunctionType.linear:
|
|
180
|
+
self.config.valve_function_callback = linear_cb
|
|
181
|
+
elif vfcb == ValveFunctionType.quick_opening:
|
|
182
|
+
self.config.valve_function_callback = quick_cb
|
|
183
|
+
elif vfcb == ValveFunctionType.equal_percentage:
|
|
184
|
+
self.config.valve_function_callback = equal_percentage_cb
|
|
185
|
+
else:
|
|
186
|
+
raise ConfigurationError("Invalid valve function callback.")
|
|
187
|
+
self.config.valve_function_callback(self)
|
|
188
|
+
self.config.pressure_flow_callback(self)
|
|
189
|
+
|
|
190
|
+
# add deltaP_inverted as a property
|
|
191
|
+
add_inverted(self,"deltaP")
|
|
192
|
+
|
|
193
|
+
def initialize_build(
|
|
194
|
+
self,
|
|
195
|
+
state_args=None,
|
|
196
|
+
outlvl=idaeslog.NOTSET,
|
|
197
|
+
solver=None,
|
|
198
|
+
optarg=None,
|
|
199
|
+
):
|
|
200
|
+
"""
|
|
201
|
+
Initialize the valve based on a deltaP guess.
|
|
202
|
+
|
|
203
|
+
Args:
|
|
204
|
+
state_args (dict): Initial state for property initialization
|
|
205
|
+
outlvl : sets output level of initialization routine
|
|
206
|
+
solver (str): Solver to use for initialization
|
|
207
|
+
optarg (dict): Solver arguments dictionary
|
|
208
|
+
"""
|
|
209
|
+
initialise_inverted(self,"deltaP")
|
|
210
|
+
|
|
211
|
+
for t in self.flowsheet().time:
|
|
212
|
+
if (
|
|
213
|
+
self.deltaP[t].fixed or self.deltaP_inverted[t].fixed
|
|
214
|
+
or self.ratioP[t].fixed
|
|
215
|
+
or self.outlet.pressure[t].fixed
|
|
216
|
+
):
|
|
217
|
+
continue
|
|
218
|
+
# Generally for the valve initialization pressure drop won't be
|
|
219
|
+
# fixed, so if there is no good guess on deltaP try to out one in
|
|
220
|
+
Pout = self.outlet.pressure[t]
|
|
221
|
+
Pin = self.inlet.pressure[t]
|
|
222
|
+
if self.deltaP[t].value is not None:
|
|
223
|
+
prdp = pyo.value((self.deltaP[t] - Pin) / Pin)
|
|
224
|
+
else:
|
|
225
|
+
prdp = -100 # crazy number to say don't use deltaP as guess
|
|
226
|
+
if pyo.value(Pout / Pin) > 1 or pyo.value(Pout / Pin) < 0.0:
|
|
227
|
+
if pyo.value(self.ratioP[t]) <= 1 and pyo.value(self.ratioP[t]) >= 0:
|
|
228
|
+
Pout.value = pyo.value(Pin * self.ratioP[t])
|
|
229
|
+
elif prdp <= 1 and prdp >= 0:
|
|
230
|
+
Pout.value = pyo.value(prdp * Pin)
|
|
231
|
+
else:
|
|
232
|
+
Pout.value = pyo.value(Pin * 0.95)
|
|
233
|
+
self.deltaP[t] = pyo.value(Pout - Pin)
|
|
234
|
+
self.ratioP[t] = pyo.value(Pout / Pin)
|
|
235
|
+
|
|
236
|
+
# one bad thing about reusing this is that the log messages aren't
|
|
237
|
+
# really compatible with being nested inside another initialization
|
|
238
|
+
super().initialize_build(
|
|
239
|
+
state_args=state_args, outlvl=outlvl, solver=solver, optarg=optarg
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
def calculate_scaling_factors(self):
|
|
243
|
+
"""
|
|
244
|
+
Calculate pressure flow constraint scaling from flow variable scale.
|
|
245
|
+
"""
|
|
246
|
+
# The value of the valve opening and the output of the valve function
|
|
247
|
+
# expression are between 0 and 1, so the only thing that needs to be
|
|
248
|
+
# scaled here is the pressure-flow constraint, which can be scaled by
|
|
249
|
+
# using the flow variable scale. The flow variable could be defined
|
|
250
|
+
# in different ways, so the flow variable is determined here from a
|
|
251
|
+
# "flow_var[t]" reference set in the pressure-flow callback. The flow
|
|
252
|
+
# term could be in various forms, so an optional
|
|
253
|
+
# "pressure_flow_equation_scale" function can be defined in the callback
|
|
254
|
+
# as well. The pressure-flow function could be flow = f(Pin, Pout), but
|
|
255
|
+
# it could also be flow**2 = f(Pin, Pout), ... The so
|
|
256
|
+
# "pressure_flow_equation_scale" provides the form of the LHS side as
|
|
257
|
+
# a function of the flow variable.
|
|
258
|
+
|
|
259
|
+
super().calculate_scaling_factors()
|
|
260
|
+
|
|
261
|
+
# Do some error trapping.
|
|
262
|
+
if not hasattr(self, "pressure_flow_equation"):
|
|
263
|
+
raise AttributeError(
|
|
264
|
+
"Pressure-flow callback must define pressure_flow_equation[t]"
|
|
265
|
+
)
|
|
266
|
+
# Check for flow term form if none assume flow = f(Pin, Pout)
|
|
267
|
+
if hasattr(self, "pressure_flow_equation_scale"):
|
|
268
|
+
ff = self.pressure_flow_equation_scale
|
|
269
|
+
else:
|
|
270
|
+
# pylint: disable-next=unnecessary-lambda-assignment
|
|
271
|
+
ff = lambda x: x
|
|
272
|
+
# if the "flow_var" is not set raise an exception
|
|
273
|
+
if not hasattr(self, "flow_var"):
|
|
274
|
+
raise AttributeError(
|
|
275
|
+
"Pressure-flow callback must define flow_var[t] reference"
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
# Calculate and set the pressure-flow relation scale.
|
|
279
|
+
if hasattr(self, "pressure_flow_equation"):
|
|
280
|
+
for t, c in self.pressure_flow_equation.items():
|
|
281
|
+
iscale.constraint_scaling_transform(
|
|
282
|
+
c,
|
|
283
|
+
ff(
|
|
284
|
+
iscale.get_scaling_factor(
|
|
285
|
+
self.flow_var[t], default=1, warning=True
|
|
286
|
+
)
|
|
287
|
+
),
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
def _get_performance_contents(self, time_point=0):
|
|
291
|
+
pc = super()._get_performance_contents(time_point=time_point)
|
|
292
|
+
|
|
293
|
+
pc["vars"]["Opening"] = self.valve_opening[time_point]
|
|
294
|
+
try:
|
|
295
|
+
pc["vars"]["Valve Coefficient"] = self.Cv
|
|
296
|
+
except AttributeError:
|
|
297
|
+
pass
|
|
298
|
+
if self.config.valve_function_callback == ValveFunctionType.equal_percentage:
|
|
299
|
+
pc["vars"]["alpha"] = self.alpha
|
|
300
|
+
return pc
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from idaes.models.control.controller import PIDControllerData, ControllerType, ControllerMVBoundType, ControllerAntiwindupType, smooth_bound, smooth_heaviside
|
|
2
|
+
from pyomo.environ import Var
|
|
3
|
+
from idaes.core import UnitModelBlockData, declare_process_block_class
|
|
4
|
+
from pyomo.common.config import ConfigValue, In, Bool
|
|
5
|
+
import pyomo.environ as pyo
|
|
6
|
+
from idaes.core.util.exceptions import ConfigurationError
|
|
7
|
+
import pyomo.dae as pyodae
|
|
8
|
+
from idaes.core.util import scaling as iscale
|
|
9
|
+
import functools
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@declare_process_block_class(
|
|
13
|
+
"CustomVariable",
|
|
14
|
+
doc="Custom variable model block. You can finally be free!",
|
|
15
|
+
)
|
|
16
|
+
class CustomVariableData(UnitModelBlockData):
|
|
17
|
+
|
|
18
|
+
CONFIG = UnitModelBlockData.CONFIG()
|
|
19
|
+
|
|
20
|
+
def build(self):
|
|
21
|
+
"""
|
|
22
|
+
Build the custom variable block
|
|
23
|
+
"""
|
|
24
|
+
super().build()
|
|
25
|
+
self.variable = Var(
|
|
26
|
+
self.flowsheet().time,
|
|
27
|
+
initialize=0.0,
|
|
28
|
+
doc="A variable you are free to do whatever you want with",
|
|
29
|
+
)
|