yanweiyuan3
2023-08-09 588bc7829387dfc761cc25f06f77d4c81818bd10
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
Quintiq file version 2.0
#parent: #root
Method InitConstraintsForBalance (
  CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program,
  const constcontent ProductInStockingPointInPeriods smartplanpispips,
  const RunContextForCapacityPlanning runcontext,
  const LibOpt_Scope scope,
  const constcontent ProductInStockingPointInPeriodPlanningLeafs leafpispipsinrun,
  const constcontent ProductInStockingPoint_MPs pispsinrun,
  Number threadnr
) const
{
  Description:
  [*
    To balance the demands and supply in pispip
    Dependent demands must be fulfilled in full quantity. Sales demands can be fulfilled halfly.
  *]
  TextBody:
  [*
    //If we only want to plan 1 step up stream we need to find the intermediate products of the involved routings.
    //They are needed so we can remove the slack from those intermediate making sure the violations if any are created on the input.
    
    
    balance_constname :=  typeof( MPBalanceConstraint );
    
    scalefactor_demandslack_const := this.ScaleConstraintTerm( typeof( MPDemandSlackVariable ), balance_constname );
    scalefactor_tripnewsupply_const := this.ScaleConstraintTerm( typeof( MPTripNewSupplyVariable ), balance_constname );
    scalefactor_invqty_const := this.ScaleConstraintTerm( typeof( MPInvQtyVariable ), balance_constname );
    scalefactor_salesdemandqty_const := this.ScaleConstraintTerm( typeof( MPSalesDemandQtyVariable ), balance_constname );
    scalefactor_dependentdemandinpispip_const := this.ScaleConstraintTerm( typeof( MPDependentDemandInPISPIPVariable ), balance_constname );
    scalefactor_delayedsalesdemandqty_const := this.ScaleConstraintTerm( typeof( MPDelayedSalesDemandQtyVariable ), balance_constname );
    scalefactor_periodtaskqty_const := this.ScaleConstraintTerm( typeof( MPPTQtyVariable ), balance_constname );
    scalefactor_expired_const := this.ScaleConstraintTerm( typeof( MPExpiredVariable ), balance_constname );
    
    scalefactor_rhs_constr := this.ScaleConstraintRHS( balance_constname, 1.0 );
    
    intermediatepisps := construct( ProductInStockingPoint_MPs, constcontent ); 
    if ( runcontext.IsOnlyPlanOneStepUpstream() ) 
    {
      intermediatepisps := selectset( scope.GetRoutingOfSmartPlanPISPIPsConst(), Elements.OperationInput.ProductInStockingPoint_MP, pisp, 
                                           exists( scope.GetRoutingOfSmartPlanPISPIPsConst(), Elements.OperationOutput.ProductInStockingPoint_MP, pisp2, pisp2 = pisp ) );
       
      // we need the unsplit balance equation always. For this small planning case we dont spread over threads 
      if ( threadnr = 0 ) 
      {
        info( leafpispipsinrun.Size() );
        traverse( leafpispipsinrun, Elements, pispip ) 
        {
          this.InitConstraintsForBalanceNoShelfLife( program, 
                                                     smartplanpispips, 
                                                     intermediatepisps, 
                                                     pispip, 
                                                     runcontext, 
                                                     scope, 
                                                     scalefactor_demandslack_const, 
                                                     scalefactor_tripnewsupply_const, 
                                                     scalefactor_invqty_const, 
                                                     scalefactor_salesdemandqty_const, 
                                                     scalefactor_dependentdemandinpispip_const, 
                                                     scalefactor_delayedsalesdemandqty_const, 
                                                     scalefactor_periodtaskqty_const, 
                                                     scalefactor_expired_const, 
                                                     scalefactor_rhs_constr ); 
        }
      }
    }
    else
    {
      // right now pispip.PreThreadNr is 0, 1, ..., 999. We use thread param to balance the workload 
      info( leafpispipsinrun.Size() );
      // we need the unsplit balance equation always
      traverse( leafpispipsinrun, Elements, pispip, CapacityPlanningSuboptimizer::GetThreadNr( this.ThreadAParameter(), this.ThreadBParameter(), pispip.PreThreadNr() ) = threadnr ) 
      {
        info( pispip.ProductInStockingPoint_MP().ProductID(), pispip.ProductInStockingPoint_MP().StockingPointID(), pispip.Start() );
        info( guard( program.InvQtyVariables().Get( pispip ).OptimalValue(), 0 ) );
        this.InitConstraintsForBalanceNoShelfLife( program, 
                                                   smartplanpispips, 
                                                   intermediatepisps, 
                                                   pispip, 
                                                   runcontext, 
                                                   scope, 
                                                   scalefactor_demandslack_const, 
                                                   scalefactor_tripnewsupply_const, 
                                                   scalefactor_invqty_const, 
                                                   scalefactor_salesdemandqty_const, 
                                                   scalefactor_dependentdemandinpispip_const, 
                                                   scalefactor_delayedsalesdemandqty_const, 
                                                   scalefactor_periodtaskqty_const, 
                                                   scalefactor_expired_const, 
                                                   scalefactor_rhs_constr ); 
      }
    }
    
    
    if ( threadnr = 0 ) // put all in thread 'A' 
    {
      // if shelf life is active we also need to create balances that are split per incoming lead time 
      traverse( pispsinrun, Elements, pisp, pisp.IsOptShelfLife() ) 
      {
        pispips := pisp.GetPISPIPForShelfLifeOptimizer( scope ); // this includes extra periods prior to the optimizer scope spanning at least the shelf life (this is a super set of what is in algorithmrun.PISPIPInOptimizerRun)
        
        firststart := DateTime::MinDateTime(); // set in method call - will be the first pispip.start from among 'pispips'
        laststart := DateTime::MinDateTime(); // set in method call - will be the last pispip.start from among 'pispips'
        firstafteractualstart := DateTime::MinDateTime(); // set in method call - will be the first pispip.start after the last actual (if any)
        pisp.GetScopeShelfLifeForPISP( pispips, firststart, laststart, firstafteractualstart ); // set above three variables 
        firstpispipforbalancestart := maxvalue( firststart, firstafteractualstart ); // we will initialize the split balance constraint after the last actual, or for any of the elements of 'pispips' if there are no actuals
        traverse( pispips, Elements.astype( ProductInStockingPointInPeriodPlanningLeaf ), pispip ) 
        {   
            if ( pispip.Start() >= firstpispipforbalancestart ) 
            {
              this.InitConstraintsForBalanceSplitShelfLife( program, 
                                                            smartplanpispips, 
                                                            intermediatepisps, 
                                                            pispip, 
                                                            firstpispipforbalancestart, 
                                                            laststart, 
                                                            runcontext, 
                                                            scope,
                                                            scalefactor_demandslack_const, 
                                                            scalefactor_tripnewsupply_const, 
                                                            scalefactor_invqty_const, 
                                                            scalefactor_salesdemandqty_const, 
                                                            scalefactor_dependentdemandinpispip_const, 
                                                            scalefactor_delayedsalesdemandqty_const, 
                                                            scalefactor_periodtaskqty_const, 
                                                            scalefactor_expired_const, 
                                                            scalefactor_rhs_constr ); // additional split balance constraint in case shelf life is optimized
            }
            this.InitConstraintsForShelfLifeSumConstraints( program, 
                                                            smartplanpispips, 
                                                            intermediatepisps, 
                                                            pispip, 
                                                            firststart, 
                                                            laststart, 
                                                            scope, 
                                                            scalefactor_invqty_const, 
                                                            scalefactor_rhs_constr ); // sum constraints taking care of consisteny between split and unsplit versions of a variable
        }
      }
    }
  *]
  InterfaceProperties { Accessibility: 'Module' }
}