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
« 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
7from core.managers import AccessControlManager, AllFlowsheetStatesManager
9class ScenarioTabTypeEnum(models.TextChoices):
11 SteadyState = "steady state"
12 MultiSteadyState = "mss"
13 Dynamic = "dynamic"
15class ScenarioInputModeEnum(models.TextChoices):
16 Csv = "csv"
17 ParameterSweep = "parameter_sweep"
19class ScenarioTimeSeriesUnitEnum(models.TextChoices):
20 Seconds = "seconds"
21 Minutes = "minutes"
22 Hours = "hours"
23 Days = "days"
24 Months = "months"
26class ParameterSweepMethodEnum(models.TextChoices):
27 Grid = "grid"
28 MonteCarlo = "monte_carlo"
29 Hammersley = "hammersley"
30 HaltonZaremba = "halton_zaremba", "Halton"
32class SolverOptionEnum(models.TextChoices):
33 Ipopt= "ipopt"
34 Ipopt_v2 = "ipopt_v2"
35 Ipopt_WaterTAP = "ipopt-watertap"
36 Bomin = "bonmin"
37 Petsc = "petsc"
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
47MSS_TIME_SERIES_INTERVAL_MIN = 1
48MSS_TIME_SERIES_INTERVAL_MAX = 1000
49MSS_TIME_SERIES_INTERVAL_DEFAULT = 1
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"]
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)
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 )
116 objects = AccessControlManager()
117 all_states = AllFlowsheetStatesManager()
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()
134class ParameterSweepDefinition(models.Model):
135 """Editable sampling definition used to generate MSS scenario input rows."""
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)
157 objects = AccessControlManager()
158 all_states = AllFlowsheetStatesManager()
161class ParameterSweepParameter(models.Model):
162 """One ordered target parameter within a generated MSS sweep definition."""
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)
187 objects = AccessControlManager()
188 all_states = AllFlowsheetStatesManager()
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 ]