Coverage for backend/core/auxiliary/serializers/PropertyValueSerializer.py: 89%
105 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
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
9from ..viewsets.compound_conversions import (
10 check_fully_defined,
11 convert_to_molar_fractions,
12 convert_to_raw_values,
13)
15class PropertyValueSerializer(serializers.ModelSerializer):
16 controlManipulated = serializers.IntegerField(
17 source='controlManipulated.id', read_only=True)
18 controlManipulatedName = serializers.CharField(
19 source='controlManipulated.setPoint.property.displayName', read_only=True)
20 controlManipulatedId = serializers.IntegerField(
21 source='controlManipulated.setPoint.property.set.simulationObject.id', read_only=True)
22 controlSetPoint = serializers.IntegerField(
23 source='controlSetPoint.id', read_only=True)
24 controlSetPointName = serializers.CharField(
25 source='controlSetPoint.manipulated.property.displayName', read_only=True)
26 controlSetPointId = serializers.IntegerField(
27 source='controlSetPoint.manipulated.property.set.simulationObject.id', read_only=True)
28 controlManipulatedObject = serializers.CharField(
29 source='controlManipulated.setPoint.property.set.simulationObject.componentName', read_only=True)
30 controlSetPointObject = serializers.CharField(
31 source='controlSetPoint.manipulated.property.set.simulationObject.componentName', read_only=True)
33 class Meta:
34 model = PropertyValue
35 fields = "__all__"
36 read_only_fields = ['id', 'controlManipulated', 'controlSetPoint']
38 def update(self, instance: PropertyValue, validated_data: dict) -> None:
39 if not instance.property.set.has_simulation_object: 39 ↛ 41line 39 didn't jump to line 41 because the condition on line 39 was never true
40 # eg. pinch property set
41 return super().update(instance, validated_data)
42 self.handle_update(instance, validated_data)
43 return instance
45 def handle_save(self, instance, validated_data) -> None:
46 value = validated_data["value"]
47 displayValue = validated_data.get("displayValue", value)
48 instance.value = value
49 instance.displayValue = displayValue
50 instance.save()
52 def handle_update(self, instance, validated_data) -> None:
53 from idaes_factory.endpoints import build_state_request, BuildStateSolveError
55 if "formula" in validated_data:
56 instance.formula = validated_data["formula"]
57 instance.save()
58 return
60 property_info: PropertyInfo = instance.property
61 property_set: PropertySet = property_info.set
62 simulation_object = property_set.simulationObject
63 def handle_save(): return self.handle_save(instance, validated_data)
65 object_type = simulation_object.objectType
66 config = configuration.get(object_type)
68 if simulation_object.objectType != "stream":
69 handle_save()
70 if check_is_except_last(property_info): 70 ↛ 93line 70 didn't jump to line 93 because the condition on line 70 was always true
71 # The last property should be calculated so that all of the last index set sums to 1.
73 # get the first index set
74 # The last items in the first index set will be calculated.
75 first_index_type = property_info.get_schema().indexSets[0]
77 # Get the all the indices for this PropertyValue
78 indexed_items = list(instance.indexedItems.all())
79 indexed_item_ids = [index.id for index in indexed_items if index.type != first_index_type]
80 # Get all the other property values that have the same indices
81 filtered_properties = instance.property.values
82 for index in indexed_item_ids:
83 filtered_properties = filtered_properties.filter(
84 indexedItems__id=index)
85 other_property_values: List[PropertyValue] = list(filtered_properties.all())
87 # Split off the last one, that will be calculated
88 calculated_property_value = other_property_values[-1]
89 known_property_values = other_property_values[:-1]
90 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)
91 calculated_property_value.value = 1 - total_
92 calculated_property_value.save()
93 return
95 property_set.ContainedProperties.all().prefetch_related("values")
97 revert_values: dict[PropertyValue, float] = {}
98 mole_frac_comp = property_set.get_property("mole_frac_comp")
100 def get_revert_values():
101 for prop in mole_frac_comp.values.all():
102 revert_values[prop] = prop.value
104 update_is_empty = validated_data["value"] in [None, ""]
105 if property_info.key == "mole_frac_comp":
106 fully_defined = check_fully_defined(
107 property_set, check_none_empty=True)
109 if fully_defined:
110 if update_is_empty: 110 ↛ 112line 110 didn't jump to line 112 because the condition on line 110 was never true
111 # we are becoming undefined, set all the properties to "raw" values
112 convert_to_raw_values(property_set)
113 handle_save()
114 else:
115 handle_save()
116 mole_frac_comp.refresh_from_db()
117 if check_fully_defined(property_set, check_fraction_sum=True): 117 ↛ 121line 117 didn't jump to line 121 because the condition on line 117 was always true
118 # previously had a value, staying as fully defined
119 convert_to_molar_fractions(property_set)
120 else:
121 convert_to_raw_values(property_set)
122 handle_save()
123 else:
124 # not fully defined
125 handle_save()
126 mole_frac_comp.refresh_from_db()
127 if (
128 not update_is_empty
129 and check_fully_defined(property_set, [mole_frac_comp])
130 ):
131 # this could make us fully defined
132 if check_fully_defined(property_set, check_fraction_sum=True):
133 get_revert_values()
134 convert_to_molar_fractions(property_set)
136 else:
137 fully_defined = check_fully_defined(
138 property_set, check_none_empty=True)
139 if update_is_empty: 139 ↛ 140line 139 didn't jump to line 140 because the condition on line 139 was never true
140 if fully_defined:
141 # we are becoming undefined, set all the properties to "raw" values
142 convert_to_raw_values(property_set)
143 handle_save()
144 else:
145 handle_save()
146 else:
147 handle_save()
148 if (
149 not fully_defined
150 and check_fully_defined(property_set, check_fraction_sum=True)
151 ):
152 # we are now fully defined
153 get_revert_values()
154 convert_to_molar_fractions(property_set)
156 simulation_object.refresh_from_db()
157 if (
158 not property_set.disable_all # ie. outlet stream or recycle stream
159 and check_fully_defined(property_set, check_fraction_sum=True)
160 and all([not value.is_externally_controlled()
161 for prop in PropertyInfo.objects.filter(set__simulationObject=simulation_object)
162 for value in prop.values.all()])
163 ):
164 # if stream and all properties are specified, solve the stream
165 try:
166 build_state_request(simulation_object)
167 except BuildStateSolveError as e:
168 # revert values if any
169 value_objs = []
170 for prop, value in revert_values.items():
171 value_objs.append(prop)
172 prop.value = value
174 PropertyValue.objects.bulk_update(value_objs, ["value"])
175 raise e