hongji.li
2023-11-07 1a1ba3ad5ed9e4380185aa1ccad20204a0e5f115
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
Quintiq file version 2.0
#parent: #root
Method InitVariablesForOperationPeriodTask (
  CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program,
  const constcontent PeriodTaskOperations userperiodtasks,
  const LibOpt_Scope scope
) const
{
  Description: 'Initialize all variables related to period task operation, including lot sizes, campaign, etc'
  TextBody:
  [*
    // create period task related variables for operations
    // 1. Init variables for all period tasks, freeze the lowerbounds for operations with a min quantity or feedback.
    // 2. Freeze the user period tasks
    
    start := OS::PrecisionCounter(); 
    runcontext := this.GetRunContextConst(); 
    mycount := 0; 
    // Operation: Init variables for all period tasks
    traverse( scope.GetOperationInOptimizerRunConst(), Elements, operation )
    {
      periods := this.GetPeriodsForOperation( scope, operation );
      periodsfordd := construct( Period_MPs, constcontent ); // periods for dependent demand
      unit := operation.Unit();
    
      iscapacitytypetime := unit.HasCapacityTypeTime();
      
      traverse( periods, Elements, period )
      {
        // PTQty variable UoM: Unit
        var := program.PTQtyVariables().New( operation, period );
        var.VariableType( 'Continuous' );
        mycount++; 
    
        if ( runcontext.UseOneTimeCost() and operation.HasOneTimeCost()  ) 
        {
          isusedvar := program.PTIsUsedVariables().New( operation, period );
          this.SetStartSolutionPTIsUsedVar( isusedvar, operation, period ); 
        }
        if( unit.HasToolOperations() and iscapacitytypetime )
        {
          unitperiod := UnitPeriod::FindUnitPeriodTypeIndex( unit.ID(), period.Start(), period.End() ); 
          
          traverse( unitperiod, ToolInUnitPeriod.Tool, t)
          {       
            if ( isnull( program.UnitPeriodToolIsUsedVariables().Find( unitperiod, t) ))
            {
              toolvar := program.UnitPeriodToolIsUsedVariables().New( unitperiod, t);
              this.SetStartSolutionToolIsUsedVar( toolvar, unitperiod, t ); 
            }
          }
        }  
    
        // Slack variables for the blending constraint
        if( runcontext.UseBlending() and operation.IsBlending() )
        {
          program.BlendingMaxOverVariables().New( operation, period );
          program.BlendingMinUnderVariables().New( operation, period );
        }
        
        // Maximum quantity on operation
        if( runcontext.UseProcessMaximumQuantity()
            and operation.HasMaximumQuantity() )
        {
          // MaxPTQtyOver variable UoM: Unit
          program.MaxPTQtyOverVariables().New( operation, period );   // Penalty of overloading the process maximum quantity
        }
    
        // Lot size
        if( ( runcontext.UseLotSize() or runcontext.UseLotCost() )
              and operation.HasLotSize()
              and period.IsWithinLotSizeHorizon() )
        {
          // PTNrOfLots variable UoM: Number
          ptnroflotsvar := program.PTNrOfLotsVariables().New( operation, period );
    
          // If this is a sliding windows run and the period is not in the sliding window, then relax the integer variable
          if( runcontext.IsSlidingWindowsRun()
              and not period.GetIsInSlidingWindow( scope ) )
          {
            ptnroflotsvar.VariableType( 'Continuous' );
          }
          
          // PTLotSizeUnder variable UoM: Unit
          program.PTLotSizeUnderVariables().New( operation, period );     // Additional quantity required to reach the multiples of lot size
          // PTLotSizeOver variable UoM: Unit
          program.PTLotSizeOverVariables().New( operation, period );     // Quantity to be reduced in order to reach the multiples of lot size
    
        }
    
        // OperationInputSet slack variables UoM: Unit
        traverse( operation, OperationInputSet, set )
        {
          program.OperationInputSetOverVariables().New( set, period );
          program.OperationInputSetUnderVariables().New( set, period );
        }
    
        traverse( operation, OperationInput, input, input.HasRegularProductforOptimizer() or input.GetIsProductInOptimizerRun( runcontext.IsPostProcessing() ) )
        {
          // OperationInputGroup slack variables UoM: Unit
          if ( not isnull( input.OperationInputGroup() ) ) 
          {
            program.OperationInputGroupOverVariables().New( input, period );
            program.OperationInputGroupUnderVariables().New( input, period );
          }
        }
              
        // create variables for dependent demand
        // Only include inputs where the product is included.
        if ( operation.HasLeadTime() and not this.GetPeriodsFromPeriodTaskOperation() ) // case when we can use period tasks is below (for efficiency)
        {
          traverse( operation, OperationInput, input, input.HasRegularProductforOptimizer() or input.GetIsProductInOptimizerRun( runcontext.IsPostProcessing() ) )
          {
            // Dependent demand that spans multiple periods when relative duration < 1
            
            // Traverse over all operation dependent demand periods
            // If any of these periods would be frozen or outside the horizon, the SelectPeriodsForOperation would not have included this operation/period combination
            pispipperiods := construct( Period_MPs, constcontent );
            CapacityPlanningSuboptimizer::GetOperationDependentDemandPeriods( period, operation, &pispipperiods, this.GetPeriodsFromPeriodTaskOperation() );
            
            traverse( pispipperiods, Elements, pispipperiod )
            {
              // PartialOperationDemandQty variable UoM: Input PISP
              program.PartialOperationDemandQtyVariables().New( input, pispipperiod, period );     // identify by: input, the dd period, and pt period
            }
          }
        }
    
       // Campaign, only define the PTQtyCampaign variable if this period is within the campaign type period related to this unit
       // and there is a campaign period of the related campaign in this period
        contextisusecampaign := runcontext.UseCampaign(); 
        ismanualcampaignsequence := not runcontext.UseCampaignSequenceOptimizer()
        if ( ismanualcampaignsequence and contextisusecampaign and period.GetIsInCampaignTypeHorizonUnit( operation.Unit() ) ) 
        {
          traverse( operation, 
                    OperationInCampaign, 
                    oic,
                    exists( oic, Campaign_MP.PlanningCampaignPeriod, cperiod,
                                cperiod.UnitPeriod().Period_MP() = period ) )
          {
            // PTQtyCampaign variable UoM: Unit
            ptcampaignqtyvar := program.PTCampaignQtyVariables().New( oic, period );
      
            // oceaned 09/02/2016
            // Freeze if corresponding PTiC has user set quantity
            ptcampaign := select( oic, 
                                  PeriodTaskInCampaign, 
                                  ptic,
                                  guard( ptic.CampaignPeriod_MP().UnitPeriod().Period_MP() = period, false )
                                  and ptic.HasQuantitySetByUser() );
            if( not( isnull( ptcampaign ) ) )
            {
              this.FixVariableStyleGuide( ptcampaignqtyvar, ptcampaign.Quantity() );
            }
          }
          
          
          traverse( operation, 
                    OperationInTransitionType.OperationInTransition, 
                    oit, 
                    exists( oit, Transition_MP.TransitionPeriod_MP, tperiod, tperiod.UnitPeriod().Period_MP() = period ) )
          {
            pttransvar := program.PTTransitionQtyVariables().New( oit, period ); 
            pttrans := select(  oit, 
                                PeriodTaskInTransition, 
                                ptit, 
                                guard( ptit.TransitionPeriod_MP().UnitPeriod().Period_MP() = period, false ) 
                                and ptit.HasQuantitySetByUser() ); 
                                
            if ( not ( isnull( pttrans ) ) ) 
            {
              this.FixVariableStyleGuide( pttransvar, pttrans.Quantity() ); 
            }                        
          }
          
          
        }
    
        // Consider all relevant periods for the dependent demand
        if ( not this.GetPeriodsFromPeriodTaskOperation() ) 
        {
          CapacityPlanningSuboptimizer::GetOperationDependentDemandPeriods( period, operation, &periodsfordd, this.GetPeriodsFromPeriodTaskOperation() ); // simply adding to periodsfordd - nonunique
        }
      } // end traverse over period
    
      
      if ( this.GetPeriodsFromPeriodTaskOperation() ) // instead of above (more expensive method) 
      {
        traverse( operation, PeriodTaskOperationInScope.DependentDemand, dd ) 
        {
          periodsfordd.Add( dd.ProductInStockingPointInPeriodPlanningLeaf().Period_MP() ); 
        }
      }
      
      periodsfordd := periodsfordd.Unique();
      traverse( periodsfordd, Elements, ddperiod )
      {
        // create variables for dependent demand
        // Only include those inputs where the product is included.
        traverse( operation, OperationInput, input, input.GetIsProductInOptimizerRun( runcontext.IsPostProcessing() ) )
        {
          this.InitVariablesForOperationPeriodTask_AddDemandVar( program, runcontext, scope, input, ddperiod ); 
        }
      } // end travere over periodfordd
      
      // create variables for dependent demand in case we can use period tasks ( efficiency) - case where we cannot use periodtasks is above
      // Only include inputs where the product is included.
      if ( operation.HasLeadTime() and this.GetPeriodsFromPeriodTaskOperation() ) 
      {
        traverse( operation, PeriodTaskOperationInScope.DependentDemand, dd ) 
        {
          input := dd.ProcessInput().astype( OperationInput ); 
          if ( input.HasRegularProductforOptimizer() or input.GetIsProductInOptimizerRun( runcontext.IsPostProcessing() ) )
          {
            pispipperiod := dd.ProductInStockingPointInPeriodPlanningLeaf().Period_MP(); 
            
            // PartialOperationDemandQty variable UoM: Input PISP
            program.PartialOperationDemandQtyVariables().New( input, pispipperiod,  dd.PeriodTask_MP().UnitPeriod().Period_MP() );     // identify by: input, the dd period, and pt period
          }
        }
      } //end if 
    } //end operation traverse
    
    
    end := OS::PrecisionCounter(); 
    durationptoinit := (end - start) /OS::PrecisionCounterFrequency(); 
    debuginfo( '========>> number of pt vars = ', mycount ); 
    debuginfo(  'Duration pto init =', durationptoinit );
  *]
  InterfaceProperties { Accessibility: 'Module' }
}