Coverage for backend/django/core/auxiliary/serializers/PropertyValueSerializer.py: 89%

114 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2025-12-18 04:00 +0000

1from core.auxiliary.models.PropertyValue import PropertyValue 

2from rest_framework import serializers 

3from core.auxiliary.models.PropertyInfo import PropertyInfo, check_is_except_last 

4from core.auxiliary.models.PropertySet import PropertySet 

5from flowsheetInternals.unitops.config.config_base import configuration 

6from typing import List 

7from drf_spectacular.utils import extend_schema_field 

8 

9 

10from ..viewsets.compound_conversions import ( 

11 check_fully_defined, 

12 convert_to_molar_fractions, 

13 convert_to_raw_values, 

14) 

15 

16class PropertyValueSerializer(serializers.ModelSerializer): 

17 controlManipulated = serializers.IntegerField( 

18 source='controlManipulated.id', read_only=True) 

19 controlManipulatedName = serializers.CharField( 

20 source='controlManipulated.setPoint.property.displayName', read_only=True) 

21 controlManipulatedId = serializers.IntegerField( 

22 source='controlManipulated.setPoint.property.set.simulationObject.id', read_only=True) 

23 controlSetPoint = serializers.IntegerField( 

24 source='controlSetPoint.id', read_only=True) 

25 controlSetPointName = serializers.CharField( 

26 source='controlSetPoint.manipulated.property.displayName', read_only=True) 

27 controlSetPointId = serializers.IntegerField( 

28 source='controlSetPoint.manipulated.property.set.simulationObject.id', read_only=True) 

29 controlManipulatedObject = serializers.CharField( 

30 source='controlManipulated.setPoint.property.set.simulationObject.componentName', read_only=True) 

31 controlSetPointObject = serializers.CharField( 

32 source='controlSetPoint.manipulated.property.set.simulationObject.componentName', read_only=True) 

33 indexedSets = serializers.SerializerMethodField() 

34 indexedSetNames = serializers.SerializerMethodField() 

35 

36 @extend_schema_field(serializers.ListField(child=serializers.CharField())) 

37 def get_indexedSets(self, instance: PropertyValue) -> list: 

38 return instance.get_indexes() 

39 

40 @extend_schema_field(serializers.ListField(child=serializers.CharField())) 

41 def get_indexedSetNames(self, instance: PropertyValue) -> list: 

42 return instance.get_index_names() 

43 

44 class Meta: 

45 model = PropertyValue 

46 fields = "__all__" 

47 read_only_fields = ['id', 'controlManipulated', 'controlSetPoint'] 

48 

49 def update(self, instance: PropertyValue, validated_data: dict) -> None: 

50 if not instance.property.set.has_simulation_object: 50 ↛ 52line 50 didn't jump to line 52 because the condition on line 50 was never true

51 # eg. pinch property set 

52 return super().update(instance, validated_data) 

53 self.handle_update(instance, validated_data) 

54 return instance 

55 

56 def handle_save(self, instance, validated_data) -> None: 

57 value = validated_data["value"] 

58 displayValue = validated_data.get("displayValue", value) 

59 instance.value = value 

60 instance.displayValue = displayValue 

61 instance.save() 

62 

63 def handle_update(self, instance, validated_data) -> None: 

64 from idaes_factory.endpoints import build_state_request, BuildStateSolveError 

65 

66 if "formula" in validated_data: 

67 instance.formula = validated_data["formula"] 

68 instance.save() 

69 return 

70 

71 property_info: PropertyInfo = instance.property 

72 property_set: PropertySet = property_info.set 

73 simulation_object = property_set.simulationObject 

74 def handle_save(): return self.handle_save(instance, validated_data) 

75 

76 object_type = simulation_object.objectType 

77 config = configuration.get(object_type) 

78 

79 if simulation_object.objectType != "stream": 

80 handle_save() 

81 if check_is_except_last(property_info): 81 ↛ 104line 81 didn't jump to line 104 because the condition on line 81 was always true

82 # The last property should be calculated so that all of the last index set sums to 1. 

83 

84 # get the first index set 

85 # The last items in the first index set will be calculated. 

86 first_index_type = property_info.get_schema().indexSets[0] 

87 

88 # Get the all the indices for this PropertyValue 

89 indexed_items = list(instance.indexedItems.all()) 

90 indexed_item_ids = [index.id for index in indexed_items if index.type != first_index_type] 

91 # Get all the other property values that have the same indices 

92 filtered_properties = instance.property.values 

93 for index in indexed_item_ids: 

94 filtered_properties = filtered_properties.filter( 

95 indexedItems__id=index) 

96 other_property_values: List[PropertyValue] = list(filtered_properties.all()) 

97 

98 # Split off the last one, that will be calculated 

99 calculated_property_value = other_property_values[-1] 

100 known_property_values = other_property_values[:-1] 

101 total_ = sum([float(prop_val.value) for prop_val in known_property_values if prop_val.pk != instance.pk and prop_val.value != None]) + float(instance.value) 

102 calculated_property_value.value = 1 - total_ 

103 calculated_property_value.save() 

104 return 

105 

106 property_set.ContainedProperties.all().prefetch_related("values") 

107 

108 revert_values: dict[PropertyValue, float] = {} 

109 mole_frac_comp = property_set.get_property("mole_frac_comp") 

110 

111 def get_revert_values(): 

112 for prop in mole_frac_comp.values.all(): 

113 revert_values[prop] = prop.value 

114 

115 update_is_empty = validated_data["value"] in [None, ""] 

116 if property_info.key == "mole_frac_comp": 

117 fully_defined = check_fully_defined( 

118 property_set, check_none_empty=True) 

119 

120 if fully_defined: 

121 if update_is_empty: 121 ↛ 123line 121 didn't jump to line 123 because the condition on line 121 was never true

122 # we are becoming undefined, set all the properties to "raw" values 

123 convert_to_raw_values(property_set) 

124 handle_save() 

125 else: 

126 handle_save() 

127 mole_frac_comp.refresh_from_db() 

128 if check_fully_defined(property_set, check_fraction_sum=True): 128 ↛ 132line 128 didn't jump to line 132 because the condition on line 128 was always true

129 # previously had a value, staying as fully defined 

130 convert_to_molar_fractions(property_set) 

131 else: 

132 convert_to_raw_values(property_set) 

133 handle_save() 

134 else: 

135 # not fully defined 

136 handle_save() 

137 mole_frac_comp.refresh_from_db() 

138 if ( 

139 not update_is_empty 

140 and check_fully_defined(property_set, [mole_frac_comp]) 

141 ): 

142 # this could make us fully defined 

143 if check_fully_defined(property_set, check_fraction_sum=True): 

144 get_revert_values() 

145 convert_to_molar_fractions(property_set) 

146 

147 else: 

148 fully_defined = check_fully_defined( 

149 property_set, check_none_empty=True) 

150 if update_is_empty: 150 ↛ 151line 150 didn't jump to line 151 because the condition on line 150 was never true

151 if fully_defined: 

152 # we are becoming undefined, set all the properties to "raw" values 

153 convert_to_raw_values(property_set) 

154 handle_save() 

155 else: 

156 handle_save() 

157 else: 

158 handle_save() 

159 if ( 

160 not fully_defined 

161 and check_fully_defined(property_set, check_fraction_sum=True) 

162 ): 

163 # we are now fully defined 

164 get_revert_values() 

165 convert_to_molar_fractions(property_set) 

166 

167 simulation_object.refresh_from_db() 

168 if ( 

169 not property_set.disable_all # ie. outlet stream or recycle stream 

170 and check_fully_defined(property_set, check_fraction_sum=True) 

171 and all([not value.is_externally_controlled() 

172 for prop in PropertyInfo.objects.filter(set__simulationObject=simulation_object) 

173 for value in prop.values.all()]) 

174 ): 

175 # if stream and all properties are specified, solve the stream 

176 try: 

177 build_state_request(simulation_object) 

178 except BuildStateSolveError as e: 

179 # revert values if any 

180 value_objs = [] 

181 for prop, value in revert_values.items(): 

182 value_objs.append(prop) 

183 prop.value = value 

184 

185 PropertyValue.objects.bulk_update(value_objs, ["value"]) 

186 raise e