chenqinghong
2024-05-07 3ec06a830367465068963156dcc1d8e522571c13
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
Quintiq file version 2.0
#parent: #root
Method ShelfLifeCompleteSimple (
  LibOpt_Scope scope,
  RunContextForCapacityPlanning runcontext
)
{
  TextBody:
  [*
    if ( this.Optimization().astype( Optimization ).MacroPlan().HasShelfLifeOrMaturation() ) 
    {
      pispipsadded := construct( ProductInStockingPointInPeriodPlanningLeafs ); 
      
      
      pisps := selectset(  scope.GetPISPIPInOptimizerRun(), 
                           Elements.ProductInStockingPoint_MP, 
                           pisp, 
                           true, 
                           pisp.IsOptShelfLife() or pisp.IsOptMaturation()  ); // don't have pisp in scope yet, so get them via the pispips 
      
      debuginfo(  'Completing dependent demand for ', pisps.Size(), ' pisp(s)' ); 
    
      // first complete the horizon at the end, because we don't know how to add constraints to deal with expiration past the scope
      traverse( pisps, Elements, pisp ) 
      {
          current := pisp.LatestPISPIPInScope().astype( ProductInStockingPointInPeriodPlanningLeaf ); 
          while ( not isnull( current) ) 
          {
            scope.Add( current ); 
            pisp.LatestPISPIPInScope( relset, current ); 
            current := current.NextPlanningPISPIP().astype( ProductInStockingPointInPeriodPlanningLeaf ); 
          }
      }
      
      traverse( pisps, Elements, pisp ) 
      {
          current := pisp.EarliestPISPIPInScope().astype( ProductInStockingPointInPeriodPlanningLeaf ); 
          
          while ( not isnull( current) and not current.Period_MP().IsHistorical() ) 
          {
            scope.Add( current ); 
            pisp.EarliestPISPIPInScope( relset, current ); 
            current := current.PreviousPlanningPISPIP().astype( ProductInStockingPointInPeriodPlanningLeaf ); 
          }
      }
      
      // add in all trip & operation demand, becuase in the curren implementation we cannot take it out in a RHS of the constraints
      // note it suffices to add pispips, pit, trip, periodtaskoperation, operation. Other object are added via pispips in method .CompleteFor_PISPIP()
      traverse( pisps, Elements, pisp ) 
      {
          current := pisp.EarliestPISPIPInScope().astype( ProductInStockingPointInPeriodPlanningLeaf ); 
          laststart := pisp.LatestPISPIPInScope().Start(); 
          while ( not isnull( current) and current.Start() <= laststart ) 
          {
            // add trip demand
            traverse( current, DependentDemandTrip.ProductInTrip, pit ) 
            {
              arrivalpispip := pit.ArrivalPISPIP(); 
              scope.Add( pit ); 
              scope.Add( pit.Trip() ); 
              scope.Add(  arrivalpispip );
              scope.Add( arrivalpispip.Period_MP() );  
              pispipsadded.Add( arrivalpispip ); 
            }
            
            // add operation demand
            traverse( current, DependentDemandOperation.PeriodTaskOperation, pto, PeriodTaskOperation::GetIsValidPeriodTask( pto.Operation(), pto.UnitPeriod().Period_MP() ) ) 
            {
              scope.Add( pto.Operation() ); 
              scope.Add( pto ); 
              traverse( pto, NewSupply.ProductInStockingPointInPeriodPlanningLeaf, nspispip ) 
              {
                scope.Add( nspispip ); 
                pispipsadded.Add( nspispip);  
              }
            }
            
            current := current.NextPlanningPISPIP().astype( ProductInStockingPointInPeriodPlanningLeaf ); 
          }
      }
      
      // now repair gapfilling due to having added arrival pispips                                                      
      
      // recompute earliest latest pispip relation on pisp ( current method is called after gapfill)                     
      changed := construct( ProductInStockingPoint_MPs ); 
      traverse( pispipsadded, Elements, pispip ) 
      {
        pisp := pispip.ProductInStockingPoint_MP(); 
        
        if ( guard( pispip.Start() > pisp.LatestPISPIPInScope().Start(), true ) )
        {
          pisp.LatestPISPIPInScope( relset, pispip );
          changed.Add( pisp );  
        }
        if ( guard( pispip.Start() < pisp.EarliestPISPIPInScope().Start(), true ) )
        {
          pisp.EarliestPISPIPInScope( relset, pispip ); 
          changed.Add( pisp ); 
        }
      }
      
      changed := changed.Unique(); 
      debuginfo(  'Repairing gapsfill property for :', changed.Size(), ' pisp(s)' ); 
    
      traverse( changed, Elements, pisp )
      {
        firstpispip := pisp.EarliestPISPIPInScope(); 
        lastpispip := pisp.LatestPISPIPInScope(); 
      
        currentpispip := firstpispip; 
        while( not isnull( currentpispip ) 
               and currentpispip.Start() < lastpispip.Start() ) 
        {
          if ( not scope.Contains( currentpispip.PISPIPInOptimizerRun() ) ) 
          {
            scope.Add( currentpispip ); // we want to avoid calling this if the pispip is already in scope for performance
          } 
          currentpispip := currentpispip.NextPlanningPISPIP();
        }
      }
    }
  *]
  InterfaceProperties { Accessibility: 'Module' }
}