Coverage for backend/PinchAnalysis/models/OptionModels.py: 100%

86 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2025-11-06 23:27 +0000

1from django.db import models 

2from core.auxiliary.enums import uiEnums 

3from core.auxiliary.models.PropertyValue import PropertyValue 

4from core.auxiliary.models.PropertySet import PropertySet 

5from core.auxiliary.enums import pinchEnums 

6from django.db.models.signals import post_save 

7from django.dispatch import receiver 

8from core.auxiliary.models.PropertyInfo import PropertyInfo 

9 

10from typing import Literal 

11from common.config_types import * 

12from flowsheetInternals.unitops.config.config_methods import * 

13 

14from core.managers import AccessControlManager 

15 

16 

17 

18 

19# Main Options PropKey Enum 

20class MainOptionsPropKeys(models.TextChoices): 

21 TIT_BUTTON_SELECTED = "PROP_MOP_0" 

22 TS_BUTTON_SELECTED = "PROP_MOP_1" 

23 TURBINE_WORK_BUTTON = "PROP_MOP_2" 

24 AREA_BUTTON = "PROP_MOP_3" 

25 ENERGY_RETROFIT_BUTTON = "PROP_MOP_4" 

26 EXERGY_BUTTON = "PROP_MOP_5" 

27 PRINT_PTS = "PROP_MOP_6" 

28 PLOT_GRAPHS = "PROP_MOP_7" 

29 

30# Graph Options PropKey Enum 

31class GraphOptionsPropKeys(models.TextChoices): 

32 CC = "PROP_GOP_0" 

33 SCC = "PROP_GOP_1" 

34 BCC = "PROP_GOP_2" 

35 GCC = "PROP_GOP_3" 

36 GCC_NP = "PROP_GOP_4" 

37 GCCU = "PROP_GOP_5" 

38 LGCC = "PROP_GOP_6" 

39 TOTAL_SITE = "PROP_GOP_7" 

40 ERC = "PROP_GOP_8" 

41 NLC = "PROP_GOP_9" 

42 EC = "PROP_GOP_10" 

43 

44class TurbineOptionsPropKeys(models.TextChoices): 

45 TURBINEFORM_T_TURBINE_BOX = "PROP_TOP_0" 

46 TURBINEFORM_P_TURBINE_BOX = "PROP_TOP_1" 

47 TURBINEFORM_MIN_EFF = "PROP_TOP_2" 

48 TURBINEFORM_ELECTRICITY_PRICE = "PROP_TOP_3" 

49 TURBINEFORM_LOAD = "PROP_TOP_4" 

50 TURBINEFORM_MECH_EFF = "PROP_TOP_5" 

51 TURBINEFORM_COMBOBOX = "PROP_TOP_6" 

52 TURBINEFORM_ABOVE_PINCH_CHECKBOX = "PROP_TOP_7" 

53 TURBINEFORM_BELOW_PINCH_CHECKBOX = "PROP_TOP_8" 

54 TURBINEFORM_CONDESATE_FLASH_CORRECTION = "PROP_TOP_9" 

55 

56 

57 

58OptionSets = Literal["MainOptions", "TurbineOptions"] 

59 

60OptionsType = Dict[OptionSets, PropertiesType] 

61 

62pinch_options: OptionsType = { 

63 "MainOptions": PropertiesType.model_validate({ 

64 MainOptionsPropKeys.TIT_BUTTON_SELECTED: { "displayName": "Totally Integrated Site", "value": True, "unitType": "dimensionless", "type": "checkbox" }, 

65 MainOptionsPropKeys.TS_BUTTON_SELECTED: { "displayName": "Total Site Heat Integration", "value": True, "unitType": "dimensionless", "type": "checkbox" }, 

66 MainOptionsPropKeys.TURBINE_WORK_BUTTON: { "displayName": "Turbine Shaft Work", "value": False, "unitType": "dimensionless", "type": "checkbox" }, 

67 MainOptionsPropKeys.AREA_BUTTON: { "displayName": "Target Area and Cost", "value": False, "unitType": "dimensionless", "type": "checkbox" }, 

68 MainOptionsPropKeys.ENERGY_RETROFIT_BUTTON: { "displayName": "Energy Retrofit", "value": False, "unitType": "dimensionless", "type": "checkbox" }, 

69 MainOptionsPropKeys.EXERGY_BUTTON: { "displayName": "Thermal Exergy", "value": False, "unitType": "dimensionless", "type": "checkbox" }, 

70 MainOptionsPropKeys.PRINT_PTS: { "displayName": "Print Problem Tables", "value": False, "unitType": "dimensionless", "type": "checkbox" }, 

71 }), 

72 "TurbineOptions": PropertiesType.model_validate({ 

73 TurbineOptionsPropKeys.TURBINEFORM_T_TURBINE_BOX: { "displayName": "Inlet Temperature", "value": 450, "unitType": "temperature", "type": "numeric" }, 

74 TurbineOptionsPropKeys.TURBINEFORM_P_TURBINE_BOX: { "displayName": "Inlet Pressure", "value": 90, "unitType": "pressure", "type": "numeric" }, 

75 TurbineOptionsPropKeys.TURBINEFORM_MIN_EFF: { "displayName": "Minimum (Fixed)", "value": 0.1, "unitType": "dimensionless", "type": "numeric" }, 

76 TurbineOptionsPropKeys.TURBINEFORM_ELECTRICITY_PRICE: { "displayName": "Electricity Price", "value": 100, "unitType": "dimensionless", "type": "numeric" }, 

77 TurbineOptionsPropKeys.TURBINEFORM_LOAD: { "displayName": "Part Load Fraction", "value": 1.0, "unitType": "dimensionless", "type": "numeric" }, 

78 TurbineOptionsPropKeys.TURBINEFORM_MECH_EFF: { "displayName": "Mechanical Efficiency", "value": 1.0, "unitType": "dimensionless", "type": "numeric" }, 

79 TurbineOptionsPropKeys.TURBINEFORM_COMBOBOX: { "displayName": "Turbine Model", "value": pinchEnums.TurbineModel.MEDINA_FLORES, "unitType": "dimensionless", "type": "dropdown" }, 

80 TurbineOptionsPropKeys.TURBINEFORM_ABOVE_PINCH_CHECKBOX: { "displayName": "Above Pinch", "value": True, "unitType": "dimensionless", "type": "checkbox" }, 

81 TurbineOptionsPropKeys.TURBINEFORM_BELOW_PINCH_CHECKBOX: { "displayName": "Below Pinch", "value": False, "unitType": "dimensionless", "type": "checkbox" }, 

82 TurbineOptionsPropKeys.TURBINEFORM_CONDESATE_FLASH_CORRECTION: { "displayName": "High Pressure Condensate", "value": False, "unitType": "dimensionless", "type": "checkbox" }, 

83 }), 

84} 

85 

86propKeyMapping = { 

87 MainOptionsPropKeys.EXERGY_BUTTON: GraphOptionsPropKeys.EC, 

88 MainOptionsPropKeys.TIT_BUTTON_SELECTED: GraphOptionsPropKeys.TOTAL_SITE, 

89 MainOptionsPropKeys.ENERGY_RETROFIT_BUTTON: GraphOptionsPropKeys.ERC 

90} 

91 

92# Receiver for updating graph options on main options change 

93# Seems pretty expensive 

94# TODO: Get a better way of doing this 

95# @receiver(post_save, sender=PropertyInfo) 

96# def update_main_options(sender, instance, **kwargs): 

97# # Check if this PropertyInfo is related to MainOptions or GraphOptions 

98# if instance.propKey in [MainOptionsPropKeys.EXERGY_BUTTON, MainOptionsPropKeys.TIT_BUTTON_SELECTED, MainOptionsPropKeys.ENERGY_RETROFIT_BUTTON]: 

99# main_options = MainOptions.objects.get(selections=instance.set) 

100# value = instance.value 

101# property = main_options.graph_options.properties.ContainedProperties.get(propKey=propKeyMapping[instance.propKey]) 

102# property.access = uiEnums.PropertyType.RW if value else uiEnums.PropertyType.RO 

103# property.save() 

104# if instance.propKey == MainOptionsPropKeys.PLOT_GRAPHS: 

105# graph_options = MainOptions.objects.get(selections=instance.set).graph_options 

106# graph_options.is_active = instance.value 

107# graph_options.save() 

108# if instance.propKey == MainOptionsPropKeys.TURBINE_WORK_BUTTON: 

109# turbine_options = MainOptions.objects.get(selections=instance.set).turbine_options 

110# turbine_options.is_active = instance.value 

111# turbine_options.save() 

112 

113 

114 

115# Additional options for turbine shaft work 

116class TurbineOptions(models.Model): 

117 flowsheet = models.ForeignKey("core_auxiliary.Flowsheet", on_delete=models.CASCADE, related_name="TurbineOptions") 

118 properties = models.ForeignKey(PropertySet, on_delete=models.CASCADE, default=None, null=True) 

119 is_active = models.BooleanField(default=True) 

120 

121 created_at = models.DateTimeField(auto_now_add=True) 

122 objects = AccessControlManager() 

123 

124 

125 @classmethod 

126 def create(cls, flowsheet, **kwargs): 

127 # Create property set and options object 

128 property_set = create_property_set_options("TurbineOptions", flowsheet) 

129 instance = cls.objects.create(properties=property_set, flowsheet=flowsheet) 

130 instance.save() 

131 return instance 

132 

133# Main options for the system 

134class MainOptions(models.Model): 

135 flowsheet = models.ForeignKey("core_auxiliary.Flowsheet", on_delete=models.CASCADE, related_name="MainOptions") 

136 selections = models.ForeignKey(PropertySet, on_delete=models.CASCADE, default=None, null=True) 

137 turbine_options = models.ForeignKey(TurbineOptions, on_delete=models.CASCADE, default=None, null=True) 

138 project_owner = models.OneToOneField("PinchAnalysis.StreamDataProject", on_delete=models.CASCADE, related_name="Options", null=True) 

139 

140 created_at = models.DateTimeField(auto_now_add=True) 

141 objects = AccessControlManager() 

142 

143 

144 @classmethod 

145 def create(cls, project_owner, flowsheet, **kwargs): 

146 # Create property set and options object 

147 property_set = create_property_set_options("MainOptions", flowsheet) 

148 turbine_options = TurbineOptions.create(flowsheet) 

149 # graph_options = GraphOptions.create(flowsheet) 

150 instance = cls.objects.create(selections=property_set, turbine_options=turbine_options, project_owner=project_owner, flowsheet=flowsheet) 

151 instance.save() 

152 return instance 

153 

154 

155def create_property_set_options(option_set: OptionSets, flowsheet): 

156 property_set = PropertySet.objects.create(flowsheet=flowsheet) 

157 properties_to_create = [] 

158 properties_values_to_create = [] 

159 

160 for key, schema in pinch_options[option_set].items(): 

161 property_info_data = get_property_fields(key, schema, property_set) 

162 property_info, property_values = PropertyInfo.create(**property_info_data, flowsheet=flowsheet) 

163 properties_to_create.append(property_info) 

164 properties_values_to_create.extend(property_values) 

165 PropertyInfo.objects.bulk_create(properties_to_create) 

166 PropertyValue.objects.bulk_create(properties_values_to_create) 

167 

168 return property_set