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.
Files changed (167) hide show
  1. ahuora_builder/__init__.py +0 -0
  2. ahuora_builder/arc_manager.py +33 -0
  3. ahuora_builder/build_state.py +57 -0
  4. ahuora_builder/custom/PIDController.py +494 -0
  5. ahuora_builder/custom/PySMOModel.py +178 -0
  6. ahuora_builder/custom/SimpleEffectivenessHX_DH.py +727 -0
  7. ahuora_builder/custom/__init__.py +0 -0
  8. ahuora_builder/custom/add_initial_dynamics.py +35 -0
  9. ahuora_builder/custom/custom_compressor.py +107 -0
  10. ahuora_builder/custom/custom_cooler.py +33 -0
  11. ahuora_builder/custom/custom_heat_exchanger.py +183 -0
  12. ahuora_builder/custom/custom_heat_exchanger_1d.py +258 -0
  13. ahuora_builder/custom/custom_heater.py +41 -0
  14. ahuora_builder/custom/custom_pressure_changer.py +34 -0
  15. ahuora_builder/custom/custom_pump.py +107 -0
  16. ahuora_builder/custom/custom_separator.py +371 -0
  17. ahuora_builder/custom/custom_tank.py +133 -0
  18. ahuora_builder/custom/custom_turbine.py +132 -0
  19. ahuora_builder/custom/custom_valve.py +300 -0
  20. ahuora_builder/custom/custom_variable.py +29 -0
  21. ahuora_builder/custom/direct_steam_injection.py +371 -0
  22. ahuora_builder/custom/energy/__init__.py +0 -0
  23. ahuora_builder/custom/energy/acBus.py +280 -0
  24. ahuora_builder/custom/energy/ac_property_package.py +279 -0
  25. ahuora_builder/custom/energy/battery.py +170 -0
  26. ahuora_builder/custom/energy/bus.py +182 -0
  27. ahuora_builder/custom/energy/energy_mixer.py +195 -0
  28. ahuora_builder/custom/energy/energy_splitter.py +228 -0
  29. ahuora_builder/custom/energy/grid.py +173 -0
  30. ahuora_builder/custom/energy/hydro.py +169 -0
  31. ahuora_builder/custom/energy/link.py +137 -0
  32. ahuora_builder/custom/energy/load.py +155 -0
  33. ahuora_builder/custom/energy/mainDistributionBoard.py +257 -0
  34. ahuora_builder/custom/energy/power_property_package.py +253 -0
  35. ahuora_builder/custom/energy/solar.py +176 -0
  36. ahuora_builder/custom/energy/storage.py +230 -0
  37. ahuora_builder/custom/energy/storage_wrapper +0 -0
  38. ahuora_builder/custom/energy/tests/__init__.py +0 -0
  39. ahuora_builder/custom/energy/tests/test_bus.py +44 -0
  40. ahuora_builder/custom/energy/tests/test_energy_mixer.py +46 -0
  41. ahuora_builder/custom/energy/tests/test_mdb.py +49 -0
  42. ahuora_builder/custom/energy/transformer.py +187 -0
  43. ahuora_builder/custom/energy/transformer_property_package.py +267 -0
  44. ahuora_builder/custom/energy/transmissionLine.py +228 -0
  45. ahuora_builder/custom/energy/wind.py +206 -0
  46. ahuora_builder/custom/hda_ideal_VLE.py +1341 -0
  47. ahuora_builder/custom/hda_reaction.py +182 -0
  48. ahuora_builder/custom/heat_exchanger_1d_wrapper.py +31 -0
  49. ahuora_builder/custom/integration_block.py +106 -0
  50. ahuora_builder/custom/inverted.py +81 -0
  51. ahuora_builder/custom/performance_curves.py +1 -0
  52. ahuora_builder/custom/reactions/__init__.py +0 -0
  53. ahuora_builder/custom/reactions/hda_stoich.py +10 -0
  54. ahuora_builder/custom/simple_separator.py +680 -0
  55. ahuora_builder/custom/tests/__init__.py +0 -0
  56. ahuora_builder/custom/tests/test_SimpleEffectivenessHX_DH.py +91 -0
  57. ahuora_builder/custom/tests/test_custom_tank.py +70 -0
  58. ahuora_builder/custom/tests/test_direct_steam_injection.py +41 -0
  59. ahuora_builder/custom/tests/test_simple_separator.py +46 -0
  60. ahuora_builder/custom/tests/test_waterpipe.py +46 -0
  61. ahuora_builder/custom/thermal_utility_systems/desuperheater.py +624 -0
  62. ahuora_builder/custom/thermal_utility_systems/header.py +889 -0
  63. ahuora_builder/custom/thermal_utility_systems/simple_heat_pump.py +567 -0
  64. ahuora_builder/custom/thermal_utility_systems/steam_header.py +353 -0
  65. ahuora_builder/custom/thermal_utility_systems/steam_user.py +944 -0
  66. ahuora_builder/custom/thermal_utility_systems/temp.py +349 -0
  67. ahuora_builder/custom/thermal_utility_systems/tests/test_desuperheater.py +142 -0
  68. ahuora_builder/custom/thermal_utility_systems/tests/test_header.py +998 -0
  69. ahuora_builder/custom/thermal_utility_systems/tests/test_ntu_hx.py +129 -0
  70. ahuora_builder/custom/thermal_utility_systems/tests/test_simple_heat_pump.py +120 -0
  71. ahuora_builder/custom/thermal_utility_systems/tests/test_steam_header.py +703 -0
  72. ahuora_builder/custom/thermal_utility_systems/tests/test_steam_user.py +277 -0
  73. ahuora_builder/custom/thermal_utility_systems/tests/test_waterpipe.py +36 -0
  74. ahuora_builder/custom/thermal_utility_systems/tests/test_willans_turbine.py +253 -0
  75. ahuora_builder/custom/thermal_utility_systems/willans_turbine.py +804 -0
  76. ahuora_builder/custom/translator.py +129 -0
  77. ahuora_builder/custom/updated_pressure_changer.py +1404 -0
  78. ahuora_builder/custom/valve_wrapper.py +38 -0
  79. ahuora_builder/custom/water_tank_with_units.py +456 -0
  80. ahuora_builder/diagnostics/__init__.py +0 -0
  81. ahuora_builder/diagnostics/infeasibilities.py +40 -0
  82. ahuora_builder/diagnostics/tests/__init__.py +0 -0
  83. ahuora_builder/diagnostics/tests/test_infeasibilities.py +28 -0
  84. ahuora_builder/flowsheet_manager.py +542 -0
  85. ahuora_builder/flowsheet_manager_type.py +20 -0
  86. ahuora_builder/generate_python_file.py +440 -0
  87. ahuora_builder/methods/BlockContext.py +84 -0
  88. ahuora_builder/methods/__init__.py +0 -0
  89. ahuora_builder/methods/adapter.py +355 -0
  90. ahuora_builder/methods/adapter_library.py +549 -0
  91. ahuora_builder/methods/adapter_methods.py +80 -0
  92. ahuora_builder/methods/expression_parsing.py +105 -0
  93. ahuora_builder/methods/load_unit_model.py +147 -0
  94. ahuora_builder/methods/slice_manipulation.py +7 -0
  95. ahuora_builder/methods/tests/__init__.py +0 -0
  96. ahuora_builder/methods/tests/test_expression_parsing.py +15 -0
  97. ahuora_builder/methods/units_handler.py +129 -0
  98. ahuora_builder/ml_wizard.py +101 -0
  99. ahuora_builder/port_manager.py +20 -0
  100. ahuora_builder/properties_manager.py +44 -0
  101. ahuora_builder/property_package_manager.py +78 -0
  102. ahuora_builder/solver.py +38 -0
  103. ahuora_builder/tear_manager.py +98 -0
  104. ahuora_builder/tests/__init__.py +0 -0
  105. ahuora_builder/tests/test_generate_python_file/__init__.py +0 -0
  106. ahuora_builder/tests/test_generate_python_file/configurations/compressor_generated.py +63 -0
  107. ahuora_builder/tests/test_generate_python_file/configurations/heat_exchanger_generated.py +70 -0
  108. ahuora_builder/tests/test_generate_python_file/configurations/pump_generated.py +84 -0
  109. ahuora_builder/tests/test_generate_python_file/configurations/recycle_generated.py +73 -0
  110. ahuora_builder/tests/test_generate_python_file/test_generate_python_file.py +108 -0
  111. ahuora_builder/tests/test_solver/__init__.py +0 -0
  112. ahuora_builder/tests/test_solver/configurations/BT_PR.json +59 -0
  113. ahuora_builder/tests/test_solver/configurations/BT_PR_solved.json +59 -0
  114. ahuora_builder/tests/test_solver/configurations/bus.json +99 -0
  115. ahuora_builder/tests/test_solver/configurations/bus_solved.json +50 -0
  116. ahuora_builder/tests/test_solver/configurations/compound_separator.json +377 -0
  117. ahuora_builder/tests/test_solver/configurations/compound_separator_solved.json +374 -0
  118. ahuora_builder/tests/test_solver/configurations/compressor.json +38 -0
  119. ahuora_builder/tests/test_solver/configurations/compressor_solved.json +68 -0
  120. ahuora_builder/tests/test_solver/configurations/constraints.json +44 -0
  121. ahuora_builder/tests/test_solver/configurations/constraints_solved.json +59 -0
  122. ahuora_builder/tests/test_solver/configurations/control.json +39 -0
  123. ahuora_builder/tests/test_solver/configurations/control_solved.json +68 -0
  124. ahuora_builder/tests/test_solver/configurations/dynamic_tank.json +733 -0
  125. ahuora_builder/tests/test_solver/configurations/dynamic_tank_solved.json +846 -0
  126. ahuora_builder/tests/test_solver/configurations/elimination.json +39 -0
  127. ahuora_builder/tests/test_solver/configurations/elimination_solved.json +68 -0
  128. ahuora_builder/tests/test_solver/configurations/expressions.json +68 -0
  129. ahuora_builder/tests/test_solver/configurations/expressions_solved.json +104 -0
  130. ahuora_builder/tests/test_solver/configurations/header.json +1192 -0
  131. ahuora_builder/tests/test_solver/configurations/header_solved.json +761 -0
  132. ahuora_builder/tests/test_solver/configurations/heat_exchanger.json +63 -0
  133. ahuora_builder/tests/test_solver/configurations/heat_exchanger_solved.json +104 -0
  134. ahuora_builder/tests/test_solver/configurations/heat_pump.json +137 -0
  135. ahuora_builder/tests/test_solver/configurations/heat_pump_solved.json +104 -0
  136. ahuora_builder/tests/test_solver/configurations/machine_learning.json +2156 -0
  137. ahuora_builder/tests/test_solver/configurations/machine_learning_solved.json +266 -0
  138. ahuora_builder/tests/test_solver/configurations/mass_flow_tear.json +77 -0
  139. ahuora_builder/tests/test_solver/configurations/mass_flow_tear_solved.json +68 -0
  140. ahuora_builder/tests/test_solver/configurations/milk_heater.json +521 -0
  141. ahuora_builder/tests/test_solver/configurations/milk_heater_solved.json +311 -0
  142. ahuora_builder/tests/test_solver/configurations/mixer.json +44 -0
  143. ahuora_builder/tests/test_solver/configurations/mixer_solved.json +86 -0
  144. ahuora_builder/tests/test_solver/configurations/optimization.json +62 -0
  145. ahuora_builder/tests/test_solver/configurations/optimization_solved.json +59 -0
  146. ahuora_builder/tests/test_solver/configurations/propane_heat_pump.json +167 -0
  147. ahuora_builder/tests/test_solver/configurations/propane_heat_pump_solved.json +158 -0
  148. ahuora_builder/tests/test_solver/configurations/propane_recycle.json +141 -0
  149. ahuora_builder/tests/test_solver/configurations/propane_recycle_solved.json +104 -0
  150. ahuora_builder/tests/test_solver/configurations/pump.json +64 -0
  151. ahuora_builder/tests/test_solver/configurations/pump_solved.json +59 -0
  152. ahuora_builder/tests/test_solver/configurations/pump_unit_conversions.json +63 -0
  153. ahuora_builder/tests/test_solver/configurations/recycle.json +49 -0
  154. ahuora_builder/tests/test_solver/configurations/recycle_solved.json +50 -0
  155. ahuora_builder/tests/test_solver/configurations/sb_vapor_frac.json +29 -0
  156. ahuora_builder/tests/test_solver/configurations/sb_vapor_frac_solved.json +29 -0
  157. ahuora_builder/tests/test_solver/configurations/solar.json +67 -0
  158. ahuora_builder/tests/test_solver/configurations/solar_solved.json +50 -0
  159. ahuora_builder/tests/test_solver/configurations/vapor_frac_target.json +67 -0
  160. ahuora_builder/tests/test_solver/configurations/vapor_frac_target_solved.json +68 -0
  161. ahuora_builder/tests/test_solver/test_solve_models.py +250 -0
  162. ahuora_builder/timing.py +65 -0
  163. ahuora_builder/types/__init__.py +1 -0
  164. ahuora_builder/unit_model_manager.py +48 -0
  165. ahuora_builder-0.1.0.dist-info/METADATA +14 -0
  166. ahuora_builder-0.1.0.dist-info/RECORD +167 -0
  167. 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
+ )