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
Quintiq file version 2.0
#parent: #root
Method InitConstraintsForMaturation (
  CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program,
  const RunContextForCapacityPlanning runcontext,
  const LibOpt_Scope scope,
  const constcontent ProductInStockingPoint_MPs pispsinrun
) const
{
  TextBody:
  [*
    cpconstname := typeof( MPCumulativeDemandMaturationConstraint );
    scalefactor_mass := this.ScaleConstraintTerm( typeof( MPCumulativeDemandMaturationVariable ), cpconstname ); // just use same scaling everywhere
    scalefactor_rhs_const := this.ScaleConstraintRHS( cpconstname, 1.0 );
    
    traverse( pispsinrun, Elements, pisp, pisp.IsOptMaturation() ) 
    {
      initpispips := pisp.GetPISPIPForShelfLifeOptimizer( scope ); 
      datecutoffhistorical := pisp.GetCutOffDateHistoricalForOptimizerShelfLife(); 
      traverse( initpispips, Elements, pispip )
      {
        ishistorical := pispip.IsPeriodFrozen(); 
        previouspispip := pispip.PreviousPlanningPISPIP(); 
        // define CumulativeDemandMaturation
        traverse( pispip, ProductInStockingPoint_MP.OutgoingShelfLifeDay, oslday ) 
        {
          constr := program.CumulativeDemandMaturationConstraints().New( pispip, oslday ); 
          constr.NewTerm( -1.0 * scalefactor_mass, program.CumulativeDemandMaturationVariables().Get( pispip, oslday )  ); 
         
          
          var := program.CumulativeDemandMaturationVariables().Find( previouspispip, oslday ); 
          isfirstpispip := isnull( var );      
          if ( not isfirstpispip ) //we assume we always have enough historical periods for maturation duration - for the very first period we can ignore what is before then 
          {
             constr.NewTerm( 1.0 * scalefactor_mass, var ); 
          }
          
          // now add all outgoing trips 
          if ( oslday.ShelfLifeDays() > 0 or oslday.IsZeroShelfLifeDaysForTrips() ) 
          {
            computeonlynewfromprevious := not isfirstpispip; 
            newoutgoingtrips := pispip.GetOutgoingProductInTripsForMaturation( computeonlynewfromprevious, oslday ) // these are all trips departing up to current pispip with oslday leadtime for shelf life
            
            // next add the variables for each outgoing trip once
            traverse( newoutgoingtrips, 
                      Elements, 
                      outgoingtrip, 
                      not ( ishistorical and outgoingtrip.Trip().Departure().Date() <= datecutoffhistorical ) )  // exclude demand prior to actual) 
            {
              if ( scope.Contains( outgoingtrip.ProductInTripInOptimizerRun() ) ) 
              {
                constr.NewTerm( 1.0 * scalefactor_mass,
                               program.TripDemandQtyVariables().Get( outgoingtrip ) );  
              }
              else
              {
                demandfromtrip := outgoingtrip.DependentDemand().Quantity(); 
                constr.RHSValue( constr.RHSValue() - scalefactor_rhs_const * demandfromtrip ); 
              }
            }
          }
          
          // sales and non trip dependent demand applicable for CP(pispip, *) 
          if ( oslday.ShelfLifeDays() = 0 and not oslday.IsZeroShelfLifeDaysForTrips() ) 
          {
            if ( not ishistorical or pispip.Start().Date() > datecutoffhistorical ) 
            {
              traverse( pispip.GetLeafSalesDemandInPeriod(), Elements, lsdip )
              {
                if ( scope.Contains( pispip.PISPIPInOptimizerRun() ) ) // same transaction, equivalent to scope.Contains( pispip.PISPIPInOptimizerRun() ) ) 
                {
                  constr.NewTerm( 1.0 * scalefactor_mass, program.SalesDemandQtyVariables().Get( lsdip ) );
                }
                else
                {
                  constr.RHSValue( constr.RHSValue() - scalefactor_rhs_const * lsdip.FulfilledQuantity() ); 
                }
              }
              // non trip dependent demand 
              traverse( pispip, 
                        ProductInStockingPoint_MP.OperationInputAvailableForOptimization, 
                        input,
                        guard( scope.Contains( input.Operation().OperationInOptimizerRun() ), false )
                        and input.HasRegularProductforOptimizer() or input.GetIsProductInOptimizerRun( runcontext.IsPostProcessing() ) )
              {
                operationdemandqtyvar := program.OperationDemandQtyVariables().Find( input, pispip.Period_MP() )
            
                // If the variable does not exists, it indicates that this operation-period combination is not included in the optimizer run
                // Therefore, this variable should then also not be added to this constraint
                if( not isnull( operationdemandqtyvar ) )
                {
                  constr.NewTerm( 1.0 * scalefactor_mass, operationdemandqtyvar );
                }
              }
              
              // non trip dependent demand in case pispip is not in run but part of extra pispips prior to horizon
              traverse( pispip, astype( ProductInStockingPointInPeriodPlanningLeaf ).DependentDemand, dd ) 
              {
                if ( dd.IsDependentDemandOfOperation()
                    and ( isnull( dd.PeriodTaskOperation().UnitPeriodWhenInScope() ) ) ) 
                {          
                  constr.RHSValue( constr.RHSValue() - scalefactor_rhs_const * dd.Quantity() ); 
                }
              }
            }
          } // endif oslday = 0
          
          // Define maturation slack [pispip, oslday] 
          // sum all smaller oslday 'o' CDMat[pispip, o ] <= 'production that has arrived' + mat slack [ pispip, oslday] 
          //
          matconstr := program.MaturationSlackConstraints().New( pispip, oslday ); 
          matconstr.NewTerm( -1.0 * scalefactor_mass, program.MaturationSlackVariables().Get( pispip, oslday ) ); 
          
          osldayatmost := selectset( pisp, OutgoingShelfLifeDay, 
                                     osld, 
                                     true, 
                                     osld.ShelfLifeDays() <= oslday.ShelfLifeDays() 
                                     and osld.IsZeroShelfLifeDaysForTrips() = oslday.IsZeroShelfLifeDaysForTrips() ); 
          traverse( osldayatmost, Elements, osltoaddd ) 
          {
            matconstr.NewTerm( 1.0 * scalefactor_mass, program.CumulativeDemandMaturationVariables().Get( pispip, osltoaddd ) ); 
          }
          
          ismaturationforarrival := true; 
          this.AddProductionTermMaturationSlackConstraint( program, matconstr, pisp, pispip, oslday, scalefactor_mass, scalefactor_rhs_const, ismaturationforarrival ); 
        } // traverse oslday
      } // traverse pispip
    } // traverse pisp
  *]
  InterfaceProperties { Accessibility: 'Module' }
}