haorenhui
2023-10-30 6d6cc10d9e8e242661da7fd655dec155a09d676c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
Quintiq file version 2.0
#parent: #root
Method OnDatasetConstructed
{
  TextBody:
  [*
    if( ( this.Task( relsize ) > 0 
          // When a run is requested to the LibOpt_OptimizerRunController, then no tasks have been started yet. 
          or this.Status() = LibOpt_RunStatus::Requested() )
        and MDSEditor::Editor().ObjectInfo( this.MDSID() ).State() <> DatasetState::Temporary().AsString() )     
    {
      this.Stop();
      
      traverse( this, Task, task, isnull( task.SnapshotComponent() ) )
      {
        task.Delete();
      }
        
      // Create the 'The dataset was unloaded. The run is stopped.' snapshot warning if the current dataset is unloaded during an optimizer run.
      // The warning is not created when a new dataset is created during a run.
      if( this.MDSID() = this.MDSIDRun() ) 
      {
        traverse( this, Task, task, task.ShouldHaveAbortMessage() )
        {
          LibOpt_SnapshotWarning::Throw( task, Translations::LibOpt_Run_OnDatasetConstructed_AbortingTasks(), LibOpt_Issue::Severity_2_Low() );
        }
        // If a dataset is unloaded and immediately loaded again, then we want to tell the run controller that the run has ended.
        // This ensures that the run controller no longer reserves any threads for this run.
        // (Datasets that are unloaded for a longer amount of time are handled by the DeleteInvalidOptimizerRuns daemon )
        if( this.Optimizer().IsRunControllerEnabled() )
        {
          LibOpt_OptimizerRunController::GetRunControllerDataset()->AbortRun( this.MDSID(), this.Key() );
        }
      }
      else
      {
        // We only reach this else block if a dataset copy of the current dataset is created during the run.
        // The copied dataset should support reruns, so all LibOpt_Scopes are changed to LibOpt_ScopeFats. 
        this.DebugScope( true ); // Should be set to true to keep the scopes after the tasks are deleted.
        traverse( this, Scope.astype( LibOpt_ScopeThin ), scope )
        {
          scope.ConvertToFat();
        }
        
        // We assume that most datasets that are copied during a run are datasets that are created with the 'replannable snapshots' functionality. 
        // The IsOptimizerDatasetCopy attribute is only used to enable/disable the 'Reload parent dataset' button in the 'Replannable snapshots' form. 
        // Therefore, it isn't an issue that the above assumption is sometimes incorrect.
        this.Optimization().IsOptimizerDatasetCopy( true );
      } 
      
      traverse( this, Task, task )
      {
        task.Delete();
      }
    }
    
    // Migrate data
    traverse( this, Scope.astype( LibOpt_ScopeFat ).ScopeElementOnScopeDEPRECATED, seos )
    {
      seos.ScopeElement().ScopeElementOnScope( relnew,
                                               Comment := seos.Comment(),
                                               Scope := seos.Scope(),
                                               ScopeAsActiveScopeElements := seos.ScopeAsActiveScopeElements(),
                                               ScopeAsDeletedScopeElements := seos.ScopeAsDeletedScopeElements() );
      seos.Delete();
    }
    traverse( this, Component.astype( LibOpt_IteratorUntil ), iterator_depr )
    {
      iterator_depr.OnDatasetConstructed();
    }
    
    traverse( this, Component.astype( LibOpt_Suboptimizer ).SnapshotComponent, snapshotcomponent )
    {
      if( exists( snapshotcomponent, Children.astype( LibOpt_SnapshotAlgorithm ), snapshotalgorithm,
                  snapshotalgorithm.ExecutionNr() = 0
                )
        )
      {   
        snapshotsalgorithm_sorted := selectsortedset( snapshotcomponent, Children.astype( LibOpt_SnapshotAlgorithm ), snapshotalgorithm,
                                                      // FILTER
                                                      true,
                                                      // VALUE
                                                      snapshotalgorithm.SequenceNr()
                                                    );
        
        executionnr := 1;
        traverse( snapshotsalgorithm_sorted, Elements, snapshotalgorithm )
        {
          snapshotalgorithm.ExecutionNr( executionnr );
          
          executionnr++;
        }
      }
    }
    
    traverse( this, Snapshot.astype( LibOpt_SnapshotSuboptimizer ), snapshotsuboptimizer,
              snapshotsuboptimizer.NrKPILevels() = 0
            )
    {
      snapshotsuboptimizer.NrKPILevels( RealVector::Construct( snapshotsuboptimizer.Improvement() ).Size() );
    }
    
    traverse( this, Snapshot.astype( LibOpt_SnapshotMP ), snapshot )
    {
      if( RealVector::Construct( snapshot.AbsoluteGaps() ).Size() = 0
          and RealVector::Construct( snapshot.Bounds() ).Size() = 0
          and RealVector::Construct( snapshot.GoalScores() ).Size() = 0
          and RealVector::Construct( snapshot.RelativeGaps() ).Size() = 0 )
      {
        vector := RealVector::Construct( 1 );
        
        vector.Set( 0, snapshot.AbsoluteGap() );
        snapshot.AbsoluteGaps( vector.AsBinaryValue() );
        
        vector.Set( 0, snapshot.Bound() );
        snapshot.Bounds( vector.AsBinaryValue() );
        
        vector.Set( 0, snapshot.GoalScore() );
        snapshot.GoalScores( vector.AsBinaryValue() );
        
        vector.Set( 0, snapshot.RelativeGap() );
        snapshot.RelativeGaps( vector.AsBinaryValue() );
      }
      
      if( snapshot.NrGoalLevels() = 0 )
      {
        snapshot.NrGoalLevels( RealVector::Construct( snapshot.GoalScores() ).Size() );
      }
    }
    //sort suboptimizer snapshots
    traverse( this, Component.astype( LibOpt_Suboptimizer ), subOpt )
    {
      if( subOpt.SnapshotSuboptimizer( relsize ) > 0 )
      {
        subOpt.SortSnapshotSuboptimizer( attribute( LibOpt_SnapshotSuboptimizer, SequenceNr ), true );
      }
      else
      {
        //collect the snapshots and add them to this relation
        snapshots := selectsortedset( subOpt, SnapshotComponent.Children.astype( LibOpt_SnapshotSuboptimizer ), ss, true, ss.SequenceNr() );
        traverse( snapshots, Elements, ss )
        {
          subOpt.SnapshotSuboptimizer( relinsert, ss );
        }
      }
    }
    // Create statistics and issues for this run, if they don't exist yet.
    Transaction::Transaction().Propagate( method( LibOpt_Run, CreateStatisticsAndIssuesPrecondition, Boolean ) );
    if( this.Statistic( relsize ) = 0
        and this.AutoAnalysisEnabled()
        and this.CreateStatisticsAndIssuesPrecondition( true /*is fail-fast check*/ )
      )
    {
      Transaction::Transaction().Propagate( method( LibOpt_Run, CreateStatisticsAndIssues ) );
      this.CreateStatisticsAndIssues();
    }
    
    // Link each `LibOpt_Issue` to its relevant `LibOpt_Run`.
    traverse( this, Statistic.Issue, issue,
              isnull( issue.Run() )
            )
    {
      issue.LinkToRun();
    }
    
    // Migrate the the PrecisionTimeStamp attribute to the PrecisionTimeStampStartComponent attribute, so that the LibOpt_SnapshotComponent.Duration attribute remains unchanged after a model upgrade. 
    traverse( this, Snapshot.astype( LibOpt_SnapshotComponent ), snapshot, snapshot.PrecisionTimeStampStartComponent() = 0 )
    {
      snapshot.PrecisionTimeStampStartComponent( snapshot.PrecisionTimeStamp() );
    }
  *]
  InterfaceProperties { Accessibility: 'Module' }
}