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