Coverage for backend/django/core/auxiliary/models/Scenario.py: 100%

100 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2026-07-22 05:22 +0000

1from django.core.validators import MaxValueValidator, MinValueValidator 

2from django.db import models 

3from .PropertyInfo import PropertyInfo 

4from .PropertyValue import PropertyValue 

5from flowsheetInternals.unitops.models.SimulationObject import SimulationObject 

6 

7from core.managers import AccessControlManager, AllFlowsheetStatesManager 

8 

9class ScenarioTabTypeEnum(models.TextChoices): 

10 

11 SteadyState = "steady state" 

12 MultiSteadyState = "mss" 

13 Dynamic = "dynamic" 

14 

15class ScenarioInputModeEnum(models.TextChoices): 

16 Csv = "csv" 

17 ParameterSweep = "parameter_sweep" 

18 

19class ScenarioTimeSeriesUnitEnum(models.TextChoices): 

20 Seconds = "seconds" 

21 Minutes = "minutes" 

22 Hours = "hours" 

23 Days = "days" 

24 Months = "months" 

25 

26class ParameterSweepMethodEnum(models.TextChoices): 

27 Grid = "grid" 

28 MonteCarlo = "monte_carlo" 

29 Hammersley = "hammersley" 

30 HaltonZaremba = "halton_zaremba", "Halton" 

31 

32class SolverOptionEnum(models.TextChoices): 

33 Ipopt= "ipopt" 

34 Ipopt_v2 = "ipopt_v2" 

35 Ipopt_WaterTAP = "ipopt-watertap" 

36 Bomin = "bonmin" 

37 Petsc = "petsc" 

38 

39 

40# Bound user-configurable solve timeouts to a range that is useful in practice: 

41# short enough to stop obviously stuck solves quickly, but long enough to allow 

42# legitimate large solves to finish without leaving them unbounded. 

43SOLVE_TIMEOUT_MIN_SECONDS = 5 

44SOLVE_TIMEOUT_MAX_SECONDS = 60 * 60 

45SOLVE_TIMEOUT_DEFAULT_SECONDS = 300 

46 

47MSS_TIME_SERIES_INTERVAL_MIN = 1 

48MSS_TIME_SERIES_INTERVAL_MAX = 1000 

49MSS_TIME_SERIES_INTERVAL_DEFAULT = 1 

50 

51 

52 

53class Scenario(models.Model): 

54 """ 

55 Stores all relevant information about an optimization 

56 """ 

57 flowsheet_state = models.ForeignKey("FlowsheetState", on_delete=models.CASCADE, related_name="Optimizations") 

58 # owner of the optimization 

59 simulationObject = models.ForeignKey(SimulationObject, on_delete=models.CASCADE, related_name="optimizations", null=True) 

60 displayName = models.CharField(max_length=64, blank=True, default="Scenario") 

61 enable_optimization = models.BooleanField(default=False) 

62 enable_dynamics = models.BooleanField(default=False) 

63 state_name = models.CharField(max_length=64, blank=True, choices=ScenarioTabTypeEnum.choices, default=ScenarioTabTypeEnum.SteadyState) 

64 mss_input_mode = models.CharField( 

65 max_length=32, 

66 choices=ScenarioInputModeEnum.choices, 

67 default=ScenarioInputModeEnum.Csv, 

68 ) 

69 mss_time_series_enabled = models.BooleanField(default=False) 

70 mss_time_series_unit = models.CharField( 

71 max_length=16, 

72 choices=ScenarioTimeSeriesUnitEnum.choices, 

73 default=ScenarioTimeSeriesUnitEnum.Seconds, 

74 ) 

75 mss_time_series_interval = models.PositiveIntegerField( 

76 default=MSS_TIME_SERIES_INTERVAL_DEFAULT, 

77 validators=[ 

78 MinValueValidator(MSS_TIME_SERIES_INTERVAL_MIN), 

79 MaxValueValidator(MSS_TIME_SERIES_INTERVAL_MAX), 

80 ], 

81 ) 

82 num_time_steps = models.IntegerField(default=1) 

83 simulation_length = models.FloatField(default=1.0) 

84 simulation_length_units = models.CharField(max_length=32, blank=True) 

85 Uploaded_fileName = models.CharField(max_length=64, blank=True, default="No file Chosen") 

86 enable_rating = models.BooleanField(default=False) 

87 solver_option = models.CharField(max_length=64, blank=True, choices=SolverOptionEnum.choices, default=SolverOptionEnum.Ipopt) 

88 solve_timeout_seconds = models.PositiveIntegerField( 

89 default=SOLVE_TIMEOUT_DEFAULT_SECONDS, 

90 validators=[ 

91 MinValueValidator(SOLVE_TIMEOUT_MIN_SECONDS), 

92 MaxValueValidator(SOLVE_TIMEOUT_MAX_SECONDS), 

93 ], 

94 ) 

95 is_LiveData = models.BooleanField(default=False) 

96 disable_initialization = models.BooleanField(default=False) 

97 skip_initialization_for_units_with_initial_values = models.BooleanField(default=False) 

98 send_solve_complete_email = models.BooleanField(default=False) 

99 degreesOfFreedom : models.QuerySet["OptimizationDegreesOfFreedom"] 

100 

101 # expression to minimize or maximize 

102 objective = models.ForeignKey(PropertyInfo, on_delete=models.SET_NULL, null=True) 

103 # boolean to find minimum or maximum or the objective 

104 minimize = models.BooleanField(default=True) 

105 

106 created_at = models.DateTimeField(auto_now_add=True) 

107 economics_schedule_revision = models.UUIDField( 

108 null=True, 

109 editable=False, 

110 help_text=( 

111 "Persisted generation for economics schedule fingerprints. Legacy " 

112 "scenarios are promoted after their existing fingerprint is verified." 

113 ), 

114 ) 

115 

116 objects = AccessControlManager() 

117 all_states = AllFlowsheetStatesManager() 

118 

119 

120 

121 

122 

123class OptimizationDegreesOfFreedom(models.Model): 

124 flowsheet_state = models.ForeignKey("FlowsheetState", on_delete=models.CASCADE, related_name="OptimizationDegreesOfFreedoms") 

125 scenario = models.ForeignKey(Scenario, on_delete=models.CASCADE, related_name="degreesOfFreedom", null=True) 

126 propertyValue: PropertyValue = models.ForeignKey(PropertyValue, on_delete=models.CASCADE, null=True) 

127 upper_bound = models.FloatField(null=True, blank=True) 

128 lower_bound = models.FloatField(null=True, blank=True) 

129 created_at = models.DateTimeField(auto_now_add=True) 

130 objects = AccessControlManager() 

131 all_states = AllFlowsheetStatesManager() 

132 

133 

134class ParameterSweepDefinition(models.Model): 

135 """Editable sampling definition used to generate MSS scenario input rows.""" 

136 

137 flowsheet_state = models.ForeignKey( 

138 "FlowsheetState", 

139 on_delete=models.CASCADE, 

140 related_name="parameterSweepDefinitions", 

141 ) 

142 scenario = models.OneToOneField( 

143 Scenario, 

144 on_delete=models.CASCADE, 

145 related_name="parameterSweepDefinition", 

146 ) 

147 method = models.CharField( 

148 max_length=32, 

149 choices=ParameterSweepMethodEnum.choices, 

150 default=ParameterSweepMethodEnum.Grid, 

151 ) 

152 sample_count = models.PositiveIntegerField(null=True, blank=True) 

153 monte_carlo_seed = models.PositiveIntegerField(null=True, blank=True) 

154 created_at = models.DateTimeField(auto_now_add=True) 

155 updated_at = models.DateTimeField(auto_now=True) 

156 

157 objects = AccessControlManager() 

158 all_states = AllFlowsheetStatesManager() 

159 

160 

161class ParameterSweepParameter(models.Model): 

162 """One ordered target parameter within a generated MSS sweep definition.""" 

163 

164 flowsheet_state = models.ForeignKey( 

165 "FlowsheetState", 

166 on_delete=models.CASCADE, 

167 related_name="parameterSweepParameters", 

168 ) 

169 definition = models.ForeignKey( 

170 ParameterSweepDefinition, 

171 on_delete=models.CASCADE, 

172 related_name="parameters", 

173 ) 

174 property_value = models.ForeignKey( 

175 PropertyValue, 

176 on_delete=models.CASCADE, 

177 related_name="parameterSweepParameters", 

178 ) 

179 order = models.PositiveIntegerField() 

180 lower_bound = models.DecimalField(max_digits=24, decimal_places=12) 

181 upper_bound = models.DecimalField(max_digits=24, decimal_places=12) 

182 step = models.DecimalField(max_digits=24, decimal_places=12, null=True, blank=True) 

183 unit = models.CharField(max_length=32, blank=True) 

184 target_label = models.CharField(max_length=255, blank=True) 

185 created_at = models.DateTimeField(auto_now_add=True) 

186 

187 objects = AccessControlManager() 

188 all_states = AllFlowsheetStatesManager() 

189 

190 class Meta: 

191 ordering = ["order", "id"] 

192 constraints = [ 

193 models.UniqueConstraint( 

194 fields=["definition", "property_value"], 

195 name="unique_parameter_sweep_target", 

196 ), 

197 models.UniqueConstraint( 

198 fields=["definition", "order"], 

199 name="unique_parameter_sweep_order", 

200 ), 

201 ]