Coverage for backend/django/idaes_factory/adapters/property_info_adapter.py: 99%
67 statements
« prev ^ index » next coverage.py v7.10.7, created at 2026-07-22 05:22 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2026-07-22 05:22 +0000
1from abc import ABC
2from typing import TYPE_CHECKING
4from ahuora_builder_types import PropertySchema, PropertiesSchema, PropertyValueSchema
5from common.config_types import *
6from ..queryset_lookup import get_property
7from .convert_expression import convert_expression
8from .property_value_adapter import serialise_property_value
9from .serialisation_rules import is_group_enabled
11if TYPE_CHECKING:
12 from core.auxiliary.models.PropertyInfo import PropertyInfo
13 from ..idaes_factory_context import IdaesFactoryContext
15def serialise_property_info(ctx, property_info: "PropertyInfo",
16 is_tear: bool = False,
17 is_indexed: bool = True,
18 force_enabled: bool = False) -> PropertySchema:
19 """
20 A PropertyInfo object represents a single IndexedVar or ScalarVar in IDAES.
21 This method handles unpacking the indexes and putting it in the format that
22 idaes_service expects. see pump.json or any of the other idaes_service test files
23 as an example of what a property looks like.
24 """
26 property_values = property_info.values.all()
28 has_value = False
30 if ctx.scenario != None:
31 enable_rating = ctx.scenario.enable_rating
32 else:
33 enable_rating = False
35 data = []
37 for prop in property_values:
38 # get indexes
39 # ie. ["0", "benzene", "Vap"]
40 from core.auxiliary.models.PropertyValue import sort_indexes
42 unsorted_indexes = list(prop.indexedItems.all())
44 # Get the object type and property key (e.g.: split_fraction)
45 property_key = property_info.key
46 schema = property_info.set.simulationObject.schema
47 if property_key not in schema.properties:
48 # e.g machine learning block: doesn't use the normal property schema methods.
49 index_set_order = []
50 else:
51 property_schema = schema.properties[property_key]
52 index_set_order : list[str] = property_schema.indexSets
53 group = property_schema.propertySetGroup
54 is_state_var = property_info.key in schema.propertySetGroups[group].stateVars
55 if force_enabled and not is_state_var:
56 # if the property is not a state variable, we don't want to force it to be enabled
57 force_enabled = False
59 # Sort the indexes so that they are in the order defined in the config file
60 # and continue serialization with the new indexes
61 indexes = [index.key for index in sort_indexes(index_set_order, unsorted_indexes)]
63 # get value data
64 # ie. {"id": 1, "value": 0.5, "controlled": int?, "guess": bool?, "constraint": str?} value_data = {
65 property_value = PropertyValueSchema(
66 id=prop.id,
67 discrete_indexes=indexes,
68 )
69 value = serialise_property_value(
70 ctx,
71 property_info,
72 prop,
73 is_indexed,
74 is_tear=is_tear,
75 force_enabled=force_enabled,
76 )
77 if value is not None:
78 has_value = True # used to determine if we should include the unit
79 if is_tear:
80 # only pass value for tear variables
81 property_value.value = value
82 if (
83 prop.is_control_set_point()
84 and prop.is_externally_controlled()
85 ):
86 # this property is externally controlled, and will be included
87 # on the other side of the tear. So we need to set the id to -1
88 # to avoid clashing ids.
89 # We need to discard this one because this side is just a guess,
90 # while the other may be used for constraints which can be
91 # deactivated during optimization.
92 property_value.id = -1
93 else:
94 property_value.value = value
95 if (prop.is_control_set_point()):
96 if not enable_rating:
97 # get the id of the thing we're manipulating
98 property_value.controlled = prop.controlSetPoint.manipulated.id
99 else:
100 property_value.value = None
102 if prop.formula not in [None, ""]:
103 property_value.constraint = convert_expression(prop.formula, ctx, prop)
104 if (prop.is_control_manipulated()
105 and not enable_rating):
106 property_value.guess = True
108 # track dependencies
109 ctx.add_property_value_dependency(prop)
111 data.append(property_value)
113 property_schema = PropertySchema(data=data)
114 if has_value:
115 property_schema.unit = property_info.unit
117 return property_schema
121class ValueAdapter(ABC):
122 def serialise(self, ctx, model):
123 pass
128class SerialisePropertiesAdapter(ValueAdapter):
129 """
130 This class replaced PropertyDictAdapter and PropertyKeyAdapter.
131 """
133 def serialise(
134 self,
135 ctx,
136 model,
137 is_tear: bool = False,
138 force_enabled: bool = False,
139 ) -> PropertiesSchema:
140 """
141 Serialise all properties in the model.
142 """
143 property_set = model.properties
145 result: PropertiesSchema = {}
147 prop_key: str
148 prop_schema: PropertyType
149 for prop_key,prop_schema in model.schema.properties.items():
150 # if the propertySetGroup is not enabled, don't serialise this property
151 if not is_group_enabled(model, ctx, prop_key):
152 continue
153 # if schema type is not number, skip it too
154 if prop_schema.type != "numeric":
155 continue
156 # get the property from the unit model
157 prop = get_property(property_set, prop_key)
158 # serialise the property
159 result[prop_key] = serialise_property_info(
160 ctx,
161 prop,
162 is_tear=is_tear, # tears and streams are handled separately
163 is_indexed=prop_schema.hasTimeIndex,
164 force_enabled=force_enabled,
165 )
166 return result