Coverage for backend/ahuora-builder/src/ahuora_builder/methods/load_unit_model.py: 97%
56 statements
« prev ^ index » next coverage.py v7.10.7, created at 2026-05-13 02:47 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2026-05-13 02:47 +0000
1from typing import Any
2from pyomo.network import Port
3from pyomo.environ import value as pyo_value, Var
4from pyomo.core.base.constraint import ScalarConstraint
5from pyomo.core.base.units_container import units
6from idaes.core import UnitModelBlock
7from idaes.core.util.tables import _get_state_from_port
8from idaes.core.util.model_serializer import StoreSpec, from_json
9from ahuora_builder.methods.BlockContext import BlockContext
10from .adapter_library import ModelConstructor
11from .adapter_methods import parse_args_dictionary
12from ..flowsheet_manager_type import FlowsheetManager
13from ahuora_builder_types import UnitModelSchema
14from .adapter import fix_block
15from ahuora_builder.methods.adapter import get_component
17def add_unit_model_to_flowsheet(
18 unit_model_def: UnitModelSchema,
19 model_constructor: ModelConstructor,
20 flowsheet_manager: FlowsheetManager,
21) -> UnitModelBlock:
22 """
23 Add the unit model to the flowsheet.
24 Args:
25 unit_model_def: The definition of the unit model to be added to the flowsheet.
26 adapter_schema: Methods used to create the model and parse the arguments.
27 flowsheet_manager: Flowsheet manager to interact with the flowsheet.
28 """
29 # Create the model
30 kwargs : dict[str, Any] = parse_args_dictionary(unit_model_def.args,flowsheet_manager)
31 idaes_model : UnitModelBlock = model_constructor(**kwargs)
33 # Add the model to the flowsheet
34 component_name = f"{unit_model_def.name}_{unit_model_def.id}"
35 flowsheet_manager.model.fs.add_component(component_name, idaes_model)
37 # Import initial guesses
38 initial_values = unit_model_def.initial_values
40 if initial_values:
41 from_json(idaes_model, initial_values, wts=StoreSpec.value())
43 # Fix properties
44 block_context = BlockContext(flowsheet_manager.model.fs)
45 _fix_properties(idaes_model,unit_model_def, flowsheet_manager,block_context)
46 # Fix ports
47 _fix_ports(idaes_model, unit_model_def, flowsheet_manager,block_context)
48 # Apply degrees of freedom (add constraints for controlled vars)
49 block_context.apply_elimination()
51 return idaes_model
53def _fix_properties( unit_model: UnitModelBlock, unit_model_def: UnitModelSchema, flowsheet_manager : FlowsheetManager,block_context: BlockContext) -> None:
54 """
55 Fix the properties of the unit model based on the properties in the unit model definition.
56 """
57 # Loop through the properties in the unit model definition to fix the properties in the unit model
58 properties = unit_model_def.properties
59 fix_block(
60 unit_model, properties, flowsheet_manager.model.fs, block_context
61 )
64def _fix_ports(unit_model: UnitModelBlock, unit_model_def: UnitModelSchema, flowsheet_manager:FlowsheetManager,block_context: BlockContext) -> None:
65 """
66 Fix the ports of the unit model based on the ports in the unit model definition.
67 """
68 # Loop through the ports in the unit model definition to fix the ports in the unit model
69 for port_name, port_schema in unit_model_def.ports.items():
70 # Get the port from the unit model
71 port = get_component(unit_model, port_name)
72 if not isinstance(port, Port): 72 ↛ 73line 72 didn't jump to line 73 because the condition on line 72 was never true
73 raise ValueError(f"Port {port_name} not found in model")
74 # Register the port, so arcs can connect to it by id
75 flowsheet_manager.ports.register_port(port_schema.id, port)
76 # Set the port parameters
77 sb = _get_state_from_port(port, 0)
78 state_block = sb.parent_component()
80 # Prefer time-only properties_in/properties_out if available
81 # decide by port name containing "inlet"/"outlet" and "hot"/"cold"
82 pn = port_name.lower()
83 if "inlet" in pn:
84 if "hot" in pn and hasattr(unit_model, "hot_side") and hasattr(unit_model.hot_side, "properties_in"):
85 state_block = unit_model.hot_side.properties_in
86 elif "cold" in pn and hasattr(unit_model, "cold_side") and hasattr(unit_model.cold_side, "properties_in"):
87 state_block = unit_model.cold_side.properties_in
88 elif "outlet" in pn:
89 if "hot" in pn and hasattr(unit_model, "hot_side") and hasattr(unit_model.hot_side, "properties_out"):
90 state_block = unit_model.hot_side.properties_out
91 elif "cold" in pn and hasattr(unit_model, "cold_side") and hasattr(unit_model.cold_side, "properties_out"):
92 state_block = unit_model.cold_side.properties_out
94 if sb.config.defined_state:
95 """
96 ie. Inlet state.
98 The inlet state needs a separate context, because its variables
99 are all fixed during initialization, so applying elimination
100 involving variables outside the inlet state would run into
101 degrees of freedom issues.
102 """
103 inlet_ctx = BlockContext(flowsheet_manager.model.fs)
104 fix_block(
105 state_block,
106 port_schema.properties,
107 flowsheet_manager.model.fs,
108 inlet_ctx,
109 )
110 inlet_ctx.apply_elimination()
111 else:
112 # The outlet state(s) can use the unit model context.
113 fix_block(
114 state_block,
115 port_schema.properties,
116 flowsheet_manager.model.fs,
117 block_context,
118 )