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

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 

7 

8class _PropertyInfoNotSetException(Exception): 

9 def __init__(self, message: str = ""): 

10 if message == "": 

11 message = "PropertyInfo value not set" 

12 super().__init__(message) 

13 

14 

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 

40 

41 

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 """ 

46 

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 

74 

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 

91 

92 elif ctx.is_dynamic() and is_indexed: 

93 return [float(value) for _ in ctx.time_steps] 

94 

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")