Coverage for backend/django/idaes_factory/adapters/property_info_adapter.py: 99%

62 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2026-06-23 21:51 +0000

1from abc import ABC 

2from typing import TYPE_CHECKING 

3 

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 

10 

11if TYPE_CHECKING: 

12 from core.auxiliary.models.PropertyInfo import PropertyInfo 

13 from ..idaes_factory_context import IdaesFactoryContext 

14 

15def serialise_property_info(ctx, property_info: "PropertyInfo", 

16 is_tear: bool = False, 

17 is_indexed: bool = True) -> PropertySchema: 

18 """ 

19 A PropertyInfo object represents a single IndexedVar or ScalarVar in IDAES.  

20 This method handles unpacking the indexes and putting it in the format that 

21 idaes_service expects. see pump.json or any of the other idaes_service test files 

22 as an example of what a property looks like. 

23 """ 

24 

25 property_values = property_info.values.all() 

26 

27 has_value = False 

28 

29 if ctx.scenario != None: 

30 enable_rating = ctx.scenario.enable_rating 

31 else: 

32 enable_rating = False 

33 

34 data = [] 

35 

36 for prop in property_values: 

37 # get indexes 

38 # ie. ["0", "benzene", "Vap"] 

39 from core.auxiliary.models.PropertyValue import sort_indexes 

40 

41 unsorted_indexes = list(prop.indexedItems.all()) 

42 

43 # Get the object type and property key (e.g.: split_fraction) 

44 property_key = property_info.key 

45 schema = property_info.set.simulationObject.schema 

46 if property_key not in schema.properties: 

47 # e.g machine learning block: doesn't use the normal property schema methods. 

48 index_set_order = [] 

49 else: 

50 index_set_order : list[str] = property_info.set.simulationObject.schema.properties[property_key].indexSets 

51 

52 # Sort the indexes so that they are in the order defined in the config file 

53 # and continue serialization with the new indexes 

54 indexes = [index.key for index in sort_indexes(index_set_order, unsorted_indexes)] 

55 

56 # get value data 

57 # ie. {"id": 1, "value": 0.5, "controlled": int?, "guess": bool?, "constraint": str?} value_data = { 

58 property_value = PropertyValueSchema( 

59 id=prop.id, 

60 discrete_indexes=indexes, 

61 ) 

62 value = serialise_property_value(ctx, property_info, prop, is_indexed, is_tear=is_tear) 

63 if value is not None: 

64 has_value = True # used to determine if we should include the unit 

65 if is_tear: 

66 # only pass value for tear variables 

67 property_value.value = value 

68 if ( 

69 prop.is_control_set_point() 

70 and prop.is_externally_controlled() 

71 ): 

72 # this property is externally controlled, and will be included 

73 # on the other side of the tear. So we need to set the id to -1 

74 # to avoid clashing ids. 

75 # We need to discard this one because this side is just a guess, 

76 # while the other may be used for constraints which can be 

77 # deactivated during optimization. 

78 property_value.id = -1 

79 else: 

80 property_value.value = value 

81 if (prop.is_control_set_point()): 

82 if not enable_rating: 

83 # get the id of the thing we're manipulating 

84 property_value.controlled = prop.controlSetPoint.manipulated.id 

85 else: 

86 property_value.value = None 

87 

88 if prop.formula not in [None, ""]: 

89 property_value.constraint = convert_expression(prop.formula, ctx, prop) 

90 if (prop.is_control_manipulated() 

91 and not enable_rating): 

92 property_value.guess = True 

93 

94 # track dependencies 

95 ctx.add_property_value_dependency(prop) 

96 

97 data.append(property_value) 

98 

99 property_schema = PropertySchema(data=data) 

100 if has_value: 

101 property_schema.unit = property_info.unit 

102 

103 return property_schema 

104 

105 

106 

107class ValueAdapter(ABC): 

108 def serialise(self, ctx, model): 

109 pass 

110 

111 

112 

113 

114class SerialisePropertiesAdapter(ValueAdapter): 

115 """ 

116 This class replaced PropertyDictAdapter and PropertyKeyAdapter. 

117 """ 

118 

119 def serialise(self, ctx, model, is_tear: bool = False) -> PropertiesSchema: 

120 """ 

121 Serialise all properties in the model. 

122 """ 

123 property_set = model.properties 

124 

125 result: PropertiesSchema = {} 

126 

127 prop_key: str 

128 prop_schema: PropertyType 

129 for prop_key,prop_schema in model.schema.properties.items(): 

130 # if the propertySetGroup is not enabled, don't serialise this property 

131 if not is_group_enabled(model, ctx, prop_key): 

132 continue 

133 # if schema type is not number, skip it too 

134 if prop_schema.type != "numeric": 

135 continue 

136 # get the property from the unit model 

137 prop = get_property(property_set, prop_key) 

138 # serialise the property 

139 result[prop_key] = serialise_property_info( 

140 ctx, 

141 prop, 

142 is_tear=is_tear, # tears and streams are handled separately 

143 is_indexed=prop_schema.hasTimeIndex 

144 ) 

145 return result 

146 

147