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,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)