Coverage for backend/idaes_service/solver/custom/translator.py: 87%
41 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 pyomo.environ import (
3 Var,
4 Suffix,
5 units as pyunits,
6)
7from pyomo.common.config import ConfigBlock, ConfigValue, In
8from idaes.core.util.tables import create_stream_table_dataframe
9from idaes.core.util.exceptions import ConfigurationError
10from idaes.models.unit_models.translator import TranslatorData
11# Import IDAES cores
12from idaes.core import (
13 declare_process_block_class,
14 UnitModelBlockData,
15 useDefault,
16)
17from idaes.core.util.config import is_physical_parameter_block
18import idaes.core.util.scaling as iscale
19import idaes.logger as idaeslog
20from enum import Enum
22# Set up logger
23_log = idaeslog.getLogger(__name__)
25class TranslatorType(Enum):
26 """
27 Enum of supported translator types. This allows you to change what variables are translated across.
28 """
29 pressure_enthalpy = "pressure_enthalpy"
30 pressure_vapor_fraction = "pressure_vapor_fraction"
31 pressure_temperature = "pressure_temperature"
34# When using this file the name "GenericTranslator" is what is imported
35@declare_process_block_class("GenericTranslator")
36class GenericTranslatorData(TranslatorData):
37 """
38 GenericTranslator.
40 This is used to translate between two different property packages, and supports dropping compounds that are not present.
42 For example, if you have a stream of water/milk, and it's almost all water, this allows you to translate the stream to a water-only stream.
44 It works by fixing the temperature and pressure, and flow of each component in the outlet stream to be the same as the inlet stream.
46 """
47 CONFIG = TranslatorData.CONFIG()
49 CONFIG.declare(
50 "translator_type",
51 ConfigValue(
52 default=TranslatorType.pressure_enthalpy.value,
53 description="Translator type to use for translating properties",
54 doc="""
55 Depending on the property packages you are using and the phases that are present, it may make sense to use different translators.
56 This allows you to select what variables are translated across.
57 """,
58 ),
59 )
62 def build(self):
63 self.CONFIG.outlet_state_defined = False # See constraint for flow
64 #self.CONFIG.has_phase_equilibrium = True # I don't think it matters if this is set, becuase in theory the phase equilibrium should
65 # already have been calculated in the inlet stream.
66 super().build()
68 # Pressure (= inlet pressure)
69 @self.Constraint(
70 self.flowsheet().time,
71 doc="Pressure balance",
72 )
73 def eq_outlet_pressure(b, t):
74 return b.properties_in[t].pressure == b.properties_out[t].pressure
76 # Flow
77 @self.Constraint(
78 self.flowsheet().time,
79 self.config.outlet_property_package.component_list,
80 doc="Mass balance for the outlet",
81 )
82 def eq_outlet_composition(b, t, c):
83 return 0 == sum(
84 b.properties_out[t].get_material_flow_terms(p, c)
85 - b.properties_in[t].get_material_flow_terms(p, c)
86 for p in b.properties_out[t].phase_list
87 if (p, c) in b.properties_out[t].phase_component_set
88 )
90 if self.config.translator_type == TranslatorType.pressure_enthalpy.value:
91 # Enthalpy (= inlet enthalpy)
92 @self.Constraint(
93 self.flowsheet().time,
94 doc="Enthalpy balance",
95 )
96 def eq_outlet_enth_mol(b, t):
97 return (
98 b.properties_in[t].enth_mol == b.properties_out[t].enth_mol
99 )
100 elif self.config.translator_type == TranslatorType.pressure_vapor_fraction.value: 100 ↛ 105line 100 didn't jump to line 105 because the condition on line 100 was never true
101 # Vapor fraction (= inlet vapor fraction)
102 # TODO: We might be able to make this smoother, by extending the vapor fraction
103 # below 0 and above 1 to make solving more reliable. See
104 # https://github.com/waikato-ahuora-smart-energy-systems/PropertyPackages/blob/8c6ee67b9d028ba0fdd1c937d9dcda821595b7d1/property_packages/helmholtz/helmholtz_extended.py#L104
105 @self.Constraint(
106 self.flowsheet().time,
107 doc="Vapor fraction balance",
108 )
109 def eq_outlet_vapor_frac(b, t):
110 return (
111 b.properties_in[t].vapor_frac == b.properties_out[t].vapor_frac
112 )
113 elif self.config.translator_type == TranslatorType.pressure_temperature.value: 113 ↛ 124line 113 didn't jump to line 124 because the condition on line 113 was always true
114 # Temperature (= inlet temperature)
115 @self.Constraint(
116 self.flowsheet().time,
117 doc="Temperature balance",
118 )
119 def eq_outlet_temperature(b, t):
120 return (
121 b.properties_in[t].temperature == b.properties_out[t].temperature
122 )
123 else:
124 raise ConfigurationError(
125 f"Translator type {self.CONFIG.translator_type} is not supported."
126 )