Coverage for backend/idaes_service/solver/custom/energy/acBus.py: 34%
91 statements
« prev ^ index » next coverage.py v7.10.7, created at 2025-11-06 23:27 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2025-11-06 23:27 +0000
1# Import Pyomo libraries
2from stringprep import in_table_a1
3from pyomo.environ import (
4 Constraint,
5 Set,
6 Var,
7 Suffix,
8 units as pyunits,
9)
10from pyomo.environ import Reals
11from pyomo.common.config import ConfigBlock, ConfigValue, In
12from idaes.core.util.model_statistics import degrees_of_freedom
13# Import IDAES cores
14from idaes.core import (
15 declare_process_block_class,
16 UnitModelBlockData,
17 useDefault,
18 MaterialBalanceType,
19 MaterialFlowBasis,
20)
21from idaes.core.util.config import is_physical_parameter_block
22import idaes.core.util.scaling as iscale
23import idaes.logger as idaeslog
24from idaes.models.unit_models import separator
25from idaes.core.util.tables import create_stream_table_dataframe
26from idaes.core.util.exceptions import ConfigurationError, BurntToast, PropertyNotSupportedError
28from idaes.models.unit_models import separator
29#Import enum
30from enum import Enum
32# Set up logger
33_log = idaeslog.getLogger(__name__)
35# Enumerate options for balances
36class SplittingType(Enum):
37 """
38 Enum of supported material split types.
39 """
41 totalFlow = 1
42 phaseFlow = 2
43 componentFlow = 3
44 phaseComponentFlow = 4
48# When using this file the name "acBus" is what is imported
49@declare_process_block_class("acBus")
50class acBusData(UnitModelBlockData):
51 """
52 Zero order acbus model
53 """
55 # CONFIG are options for the unit model, this simple model only has the mandatory config options
56 CONFIG = ConfigBlock()
58 CONFIG.declare(
59 "dynamic",
60 ConfigValue(
61 domain=In([False]),
62 default=False,
63 description="Dynamic model flag - must be False",
64 doc="""Indicates whether this model will be dynamic or not,
65 **default** = False. The Bus unit does not support dynamic
66 behavior, thus this must be False.""",
67 ),
68 )
69 CONFIG.declare(
70 "has_holdup",
71 ConfigValue(
72 default=False,
73 domain=In([False]),
74 description="Holdup construction flag - must be False",
75 doc="""Indicates whether holdup terms should be constructed or not.
76 **default** - False. The Bus unit does not have defined volume, thus
77 this must be False.""",
78 ),
79 )
80 CONFIG.declare(
81 "property_package",
82 ConfigValue(
83 default=useDefault,
84 domain=is_physical_parameter_block,
85 description="Property package to use for control volume",
86 doc="""Property parameter object used to define property calculations,
87 **default** - useDefault.
88 **Valid values:** {
89 **useDefault** - use default package from parent model or flowsheet,
90 **PhysicalParameterObject** - a PhysicalParameterBlock object.}""",
91 ),
92 )
93 CONFIG.declare(
94 "property_package_args",
95 ConfigBlock(
96 implicit=True,
97 description="Arguments to use for constructing property packages",
98 doc="""A ConfigBlock with arguments to be passed to a property block(s)
99 and used when constructing these,
100 **default** - None.
101 **Valid values:** {
102 see property package for documentation.}""",
103 ),
104 )
105 CONFIG.declare(
106 "num_inlets",
107 ConfigValue(
108 default=False,
109 domain=int,
110 description="Number of inlets to add",
111 doc="Number of inlets to add",
112 ),
113 )
114 CONFIG.declare(
115 "num_outlets",
116 ConfigValue(
117 default=False,
118 domain=int,
119 description="Number of outlets to add",
120 doc="Number of outlets to add",
121 ),
122 )
123 CONFIG.declare(
124 "material_balance_type",
125 ConfigValue(
126 default=MaterialBalanceType.useDefault,
127 domain=In(MaterialBalanceType),
128 description="Material balance construction flag",
129 doc="""Indicates what type of mass balance should be constructed,
130 **default** - MaterialBalanceType.useDefault.
131 **Valid values:** {
132 **MaterialBalanceType.useDefault - refer to property package for default
133 balance type
134 **MaterialBalanceType.none** - exclude material balances,
135 **MaterialBalanceType.componentPhase** - use phase component balances,
136 **MaterialBalanceType.componentTotal** - use total component balances,
137 **MaterialBalanceType.elementTotal** - use total element balances,
138 **MaterialBalanceType.total** - use total material balance.}""",
139 ),
140 )
143 def build(self):
144 # build always starts by calling super().build()
145 # This triggers a lot of boilerplate in the background for you
146 super().build()
148 # This creates blank scaling factors, which are populated later
149 self.scaling_factor = Suffix(direction=Suffix.EXPORT)
152 # Defining parameters of state block class
153 tmp_dict = dict(**self.config.property_package_args)
154 tmp_dict["parameters"] = self.config.property_package
155 tmp_dict["defined_state"] = True # inlet block is an inlet
157 # Add state blocks for inlet, outlet, and waste
158 # These include the state variables and any other properties on demand
159 num_inlets = self.config.num_inlets
160 self.inlet_list = [ "inlet_" + str(i+1) for i in range(num_inlets) ]
161 self.inlet_set = Set(initialize=self.inlet_list)
162 self.inlet_blocks = []
164 for name in self.inlet_list:
165 # add properties_inlet_1, properties_inlet2 etc
166 state_block = self.config.property_package.state_block_class(
167 self.flowsheet().config.time, doc="inlet power", **tmp_dict
168 )
169 self.inlet_blocks.append(state_block)
170 # Dynamic equivalent to self.properties_inlet_1 = stateblock
171 setattr(self,"properties_" + name, state_block)
172 # also add the port
173 self.add_port(name=name,block=state_block)
176 # Add outlet state blocks
178 num_outlets = self.config.num_outlets
179 self.outlet_list = [ "outlet_" + str(i+1) for i in range(num_outlets) ]
180 self.outlet_set = Set(initialize=self.outlet_list)
181 self.outlet_blocks = []
183 for name in self.outlet_list:
184 tmp_dict["defined_state"] = False
185 state_block = self.config.property_package.state_block_class(
186 self.flowsheet().config.time, doc="outlet power", **tmp_dict
187 )
188 self.outlet_blocks.append(state_block)
189 setattr(self,"properties_" + name, state_block)
190 self.add_port(name=name,block=state_block)
192 # Add variable for power splitting
193 self.split_fraction = Var(
194 self.flowsheet().time,
195 self.outlet_set,
196 initialize=1.0,
197 #units = pyunits.dimensionless,
198 doc="How the power is split between outlets",
199 )
201 #Obtain the power components from the inlets
202 @self.Expression(
203 self.flowsheet().time,
204 )
205 def total_active_power(b,t):
206 return sum(state_block[t].active_power for state_block in self.inlet_blocks)
208 @self.Expression(
209 self.flowsheet().time,
210 )
211 def total_reactive_power(b,t):
212 return sum(state_block[t].reactive_power for state_block in self.inlet_blocks)
214 @self.Expression(
215 self.flowsheet().time,
216 )
217 def total_voltage(b,t):
218 return sum(state_block[t].voltage for state_block in self.inlet_blocks)
220 #Add constraints
222 @self.Constraint(
223 self.flowsheet().time,
224 self.outlet_list,
225 doc="active power split",
226 )
227 def eq_active_power(b,t,o):
228 outlet_block = getattr(self,"properties_" + o)
229 return outlet_block[t].active_power == (
230 self.total_active_power[t] * b.split_fraction[t,o])
232 @self.Constraint(
233 self.flowsheet().time,
234 self.outlet_list,
235 doc="reactive power split",
236 )
237 def eq_reactive_power(b,t,o):
238 outlet_block = getattr(self,"properties_" + o)
239 return outlet_block[t].reactive_power == (
240 self.total_reactive_power[t] * b.split_fraction[t,o])
242 @self.Constraint(
243 self.flowsheet().time,
244 self.outlet_list,
245 doc="voltage split",
246 )
247 def eq_voltage(b,t,o):
248 outlet_block = getattr(self,"properties_" + o)
249 return outlet_block[t].voltage == (
250 self.total_voltage[t] * b.split_fraction[t,o])
253 @self.Constraint(
254 self.flowsheet().time,
255 doc="Split fraction sum to 1",
256 )
257 def eq_split_fraction_sum(b, t):
258 return sum(b.split_fraction[t, o] for o in self.outlet_list) == 1.0
261 def calculate_scaling_factors(self):
262 super().calculate_scaling_factors()
264 def initialize(blk, *args, **kwargs):
266 pass
269 def _get_stream_table_contents(self, time_point=0):
271 io_dict = {}
272 for inlet_name in self.inlet_list:
273 io_dict[inlet_name] = getattr(self, inlet_name) # get a reference to the port
275 out_dict = {}
276 for outlet_name in self.outlet_list:
277 out_dict[outlet_name] = getattr(self, outlet_name) # get a reference to the port