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

83 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2026-06-23 21:51 +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 

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 ParameterSweepMethodEnum(models.TextChoices): 

20 Grid = "grid" 

21 MonteCarlo = "monte_carlo" 

22 Hammersley = "hammersley" 

23 HaltonZaremba = "halton_zaremba", "Halton" 

24 

25class SolverOptionEnum(models.TextChoices): 

26 Ipopt= "ipopt" 

27 Ipopt_v2 = "ipopt_v2" 

28 Ipopt_WaterTAP = "ipopt-watertap" 

29 Bomin = "bonmin" 

30 Petsc = "petsc" 

31 

32 

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

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

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

36SOLVE_TIMEOUT_MIN_SECONDS = 5 

37SOLVE_TIMEOUT_MAX_SECONDS = 60 * 60 

38SOLVE_TIMEOUT_DEFAULT_SECONDS = 300 

39 

40 

41 

42class Scenario(models.Model): 

43 """ 

44 Stores all relevant information about an optimization 

45 """ 

46 flowsheet = models.ForeignKey("Flowsheet", on_delete=models.CASCADE, related_name="Optimizations") 

47 # owner of the optimization 

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

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

50 enable_optimization = models.BooleanField(default=False) 

51 enable_dynamics = models.BooleanField(default=False) 

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

53 mss_input_mode = models.CharField( 

54 max_length=32, 

55 choices=ScenarioInputModeEnum.choices, 

56 default=ScenarioInputModeEnum.Csv, 

57 ) 

58 num_time_steps = models.IntegerField(default=1) 

59 simulation_length = models.FloatField(default=1.0) 

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

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

62 enable_rating = models.BooleanField(default=False) 

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

64 solve_timeout_seconds = models.PositiveIntegerField( 

65 default=SOLVE_TIMEOUT_DEFAULT_SECONDS, 

66 validators=[ 

67 MinValueValidator(SOLVE_TIMEOUT_MIN_SECONDS), 

68 MaxValueValidator(SOLVE_TIMEOUT_MAX_SECONDS), 

69 ], 

70 ) 

71 is_LiveData = models.BooleanField(default=False) 

72 disable_initialization = models.BooleanField(default=False) 

73 skip_initialization_for_units_with_initial_values = models.BooleanField(default=False) 

74 send_solve_complete_email = models.BooleanField(default=False) 

75 degreesOfFreedom : models.QuerySet["OptimizationDegreesOfFreedom"] 

76 

77 # expression to minimize or maximize 

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

79 # boolean to find minimum or maximum or the objective 

80 minimize = models.BooleanField(default=True) 

81 

82 created_at = models.DateTimeField(auto_now_add=True) 

83 

84 objects = AccessControlManager() 

85 

86 

87 

88 

89 

90class OptimizationDegreesOfFreedom(models.Model): 

91 flowsheet = models.ForeignKey("Flowsheet", on_delete=models.CASCADE, related_name="OptimizationDegreesOfFreedoms") 

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

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

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

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

96 created_at = models.DateTimeField(auto_now_add=True) 

97 objects = AccessControlManager() 

98 

99 

100class ParameterSweepDefinition(models.Model): 

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

102 

103 flowsheet = models.ForeignKey( 

104 "Flowsheet", 

105 on_delete=models.CASCADE, 

106 related_name="parameterSweepDefinitions", 

107 ) 

108 scenario = models.OneToOneField( 

109 Scenario, 

110 on_delete=models.CASCADE, 

111 related_name="parameterSweepDefinition", 

112 ) 

113 method = models.CharField( 

114 max_length=32, 

115 choices=ParameterSweepMethodEnum.choices, 

116 default=ParameterSweepMethodEnum.Grid, 

117 ) 

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

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

120 created_at = models.DateTimeField(auto_now_add=True) 

121 updated_at = models.DateTimeField(auto_now=True) 

122 

123 objects = AccessControlManager() 

124 

125 

126class ParameterSweepParameter(models.Model): 

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

128 

129 flowsheet = models.ForeignKey( 

130 "Flowsheet", 

131 on_delete=models.CASCADE, 

132 related_name="parameterSweepParameters", 

133 ) 

134 definition = models.ForeignKey( 

135 ParameterSweepDefinition, 

136 on_delete=models.CASCADE, 

137 related_name="parameters", 

138 ) 

139 property_value = models.ForeignKey( 

140 PropertyValue, 

141 on_delete=models.CASCADE, 

142 related_name="parameterSweepParameters", 

143 ) 

144 order = models.PositiveIntegerField() 

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

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

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

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

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

150 created_at = models.DateTimeField(auto_now_add=True) 

151 

152 objects = AccessControlManager() 

153 

154 class Meta: 

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

156 constraints = [ 

157 models.UniqueConstraint( 

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

159 name="unique_parameter_sweep_target", 

160 ), 

161 models.UniqueConstraint( 

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

163 name="unique_parameter_sweep_order", 

164 ), 

165 ]