Coverage for backend/idaes_factory/adapters/property_value_adapter.py: 74%
57 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.PropertyInfo import PropertyInfo, check_is_except_last
2from core.auxiliary.models.PropertyValue import PropertyValue, sort_indexes
3from core.auxiliary.enums.uiEnums import DisplayType
4from common.config_types import *
5from core.auxiliary.models.SolveState import SolveValue
6from ..idaes_factory_context import IdaesFactoryContext
8class _PropertyInfoNotSetException(Exception):
9 def __init__(self, message: str = ""):
10 if message == "":
11 message = "PropertyInfo value not set"
12 super().__init__(message)
15# Property info operator
16def check_fixed(ctx:IdaesFactoryContext, property_info: PropertyInfo, property_value: PropertyValue, is_tear: bool = False) -> bool:
17 """
18 Check that the property is fixed
19 Raise an error if not, or return False if variables are not required to be fixed
20 """
21 if is_tear and not property_value.is_control_set_point() and not property_value.has_value():
22 # recycle guess, allowed to be empty
23 return False
24 # Property must be fixed, and have a value
25 if not property_value.has_value():
26 if property_value.is_control_manipulated():
27 # this value is a guess variable, and allowed to be empty
28 return False
29 indexed_items = [x for x in property_value.indexedItems.all()]
30 property_values = [x for x in property_info.values.all()]
31 pv_ii = [[x for x in y.indexedItems.all()] for y in property_values]
32 # error, property should be fixed and have a value
33 if ctx.require_variables_fixed: 33 ↛ 34line 33 didn't jump to line 34 because the condition on line 33 was never true
34 raise _PropertyInfoNotSetException(f"Property `{property_info.displayName}` is not set")
35 else:
36 # RequireVariablesFixed is a context variable that can be set to False to allow for properties to be unset
37 # Allow this to pass for testing purposes only.
38 return False
39 return True
42def serialise_property_value(ctx:IdaesFactoryContext, property_info: PropertyInfo, property_value: PropertyValue, is_indexed: bool = True, is_tear: bool = False):
43 """
44 Serialise a property info object
45 """
47 # TODO: add time step handling: get the value at the given time step
48 match property_info.type:
49 case DisplayType.dropdown: 49 ↛ 50line 49 didn't jump to line 50 because the pattern on line 49 never matched
50 raise NotImplementedError("Dropdown properties are not yet supported in idaes_factory")
51 case DisplayType.checkbox: 51 ↛ 52line 51 didn't jump to line 52 because the pattern on line 51 never matched
52 return value # return True or False
53 case DisplayType.numeric_arg: 53 ↛ 54line 53 didn't jump to line 54 because the pattern on line 53 never matched
54 raise NotImplementedError("Dropdown properties are not yet supported in idaes_factory")
55 case DisplayType.segmented: 55 ↛ 56line 55 didn't jump to line 56 because the pattern on line 55 never matched
56 raise NotImplementedError("Segmented properties are not yet supported in idaes_factory")
57 case DisplayType.numeric: 57 ↛ 101line 57 didn't jump to line 101 because the pattern on line 57 always matched
58 if is_tear:
59 # tear properties are disabled, but we still need to serialise the recycle guesses
60 if not (
61 property_info.is_recycle_var()
62 or property_value.is_control_set_point()
63 ):
64 # skip, not enabled
65 return None
66 else:
67 if not property_value.is_enabled() and not property_value.is_control_manipulated():
68 # property is disabled (and not a guess), so don't serialise it
69 return None
70 # check that the property is fixed, and raise an error if not
71 if not check_fixed(ctx, property_info, property_value, is_tear):
72 # variables are not required to be fixed, so don't serialise this property
73 return None
75 value = property_value.value
76 # We are no longer supporting parsing expressions here, becuase that functionality
77 # is possible with specification and control blocks.
78 if property_info.expression is not None:
79 if ctx.solve_index is not None: # if index is given for a value from the csv 79 ↛ 84line 79 didn't jump to line 84 because the condition on line 79 was always true
80 value = SolveValue.objects.get(
81 expression = property_info.expression,
82 solve = ctx.solve_index,
83 ).value
84 elif ctx.is_dynamic() and is_indexed: # only use MSS for dynamics if the property is indexed, because otherwise it will be a single value.
85 # We want to get all the solve values, and use as many solve values as there are timesteps
86 # (We are using the CSV data as input data)
87 # Note: assuming solveValue.objects.all() returns the values in the correct order
88 value = [i.value for i in SolveValue.objects.filter(expression=property_info.expression).all()]
89 value = value[0:len(ctx.time_steps)]
90 return value
92 elif ctx.is_dynamic() and is_indexed:
93 return [float(value) for _ in ctx.time_steps]
95 # we used to use the dynamic results as the input but we aren't doing that any more
96 # so just return the one value, idaes_service will assume it's constant.
97 if is_indexed:
98 return [float(value)]
99 else:
100 return float(value)
101 case _:
102 raise ValueError(f"Property type {property_info.type} is not supported in idaes_factory")