Quintiq file version 2.0 
 | 
#parent: #root 
 | 
Method InitConstraintsForBalanceSplitShelfLife ( 
 | 
  CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program, 
 | 
  const constcontent ProductInStockingPointInPeriods smartplanpispips, 
 | 
  constcontent ProductInStockingPoint_MPs intermediatepisps, 
 | 
  const ProductInStockingPointInPeriodPlanning pispip, 
 | 
  DateTime firstpispipforbalancestart, 
 | 
  DateTime lastpispipstart, 
 | 
  const RunContextForCapacityPlanning runcontext, 
 | 
  const LibOpt_Scope scope, 
 | 
  Real scalefactor_demandslack_const, 
 | 
  Real scalefactor_tripnewsupply_const, 
 | 
  Real scalefactor_invqty_const, 
 | 
  Real scalefactor_salesdemandqty_const, 
 | 
  Real scalefactor_dependentdemandinpispip_const, 
 | 
  Real scalefactor_delayedsalesdemandqty_const, 
 | 
  Real scalefactor_periodtaskqty_const, 
 | 
  Real scalefactor_expired_const, 
 | 
  Real scalefactor_rhs_constr 
 | 
) const 
 | 
{ 
 | 
  Description: 
 | 
  [* 
 | 
    To balance the demands and supply in pispip for a pispip that has IsOptShelfLife or IsOptMaturation 
 | 
    Dependent demands must be fulfilled in full quantity. Sales demands can be fulfilled halfly. 
 | 
  *] 
 | 
  TextBody: 
 | 
  [* 
 | 
    traverse( pispip, ProductInStockingPoint_MP.IncomingShelfLifeDay, islday )  
 | 
    { 
 | 
      constr := program.BalanceShelfLifeConstraints().New( pispip, islday ); 
 | 
      constr.Sense( '=' ); 
 | 
     
 | 
      // RHS UoM: PISP 
 | 
      rhs := this.GetInventoryRHSForShelfLifeSplitBalanceConstraint( pispip, islday, firstpispipforbalancestart, runcontext, scope );   
 | 
      rhs_scaled := rhs * scalefactor_rhs_constr 
 | 
     
 | 
      constr.RHSValue( rhs_scaled ); 
 | 
     
 | 
      // Inventory end for pispip 
 | 
      // Term UoM: PISP 
 | 
      constr.NewTerm( -1.0 * scalefactor_invqty_const, program.InvQtyShelfLifeVariables().Get( pispip, islday ) ); 
 | 
     
 | 
      // Penalty for decreasing demand quantity in a pispip for balancing the constraint 
 | 
      // (A positive DemandSlack represents a supply that is "magically" created to even out the balance constraint) 
 | 
      // Term UoM: PISP 
 | 
      // Remove the slack in case we only plan 1 step upstream and it is an intermediary product.       
 | 
      if( this.GetIsBalanceSlackAllowed( pispip, smartplanpispips, intermediatepisps, runcontext ) ) 
 | 
      {   
 | 
        constr.NewTerm( 1.0 * scalefactor_demandslack_const, 
 | 
                       program.DemandSlackShelfLifeVariables().Get( pispip, islday ) );                   
 | 
      } 
 | 
       
 | 
      // New supplies from operations added to shelflife 0  
 | 
      if ( islday.ShelfLifeDays() = 0 )  
 | 
      { 
 | 
        ispostprocessing := runcontext.IsPostProcessing();  
 | 
        traverse( pispip,  
 | 
                  ProductInStockingPoint_MP.OperationOutputAvailableForOptimization,  
 | 
                  output, 
 | 
                  output.HasRegularProductforOptimizer()  
 | 
                  or output.GetIsProductInOptimizerRun( ispostprocessing ) ) 
 | 
        {              
 | 
          // Term UoM: Output PISP 
 | 
          this.AddConstraintForOperationNewSupplies( output, pispip.Period_MP(), null( Period_MP ), 
 | 
                                                     program, 1.0, constr, scalefactor_periodtaskqty_const, scope ); 
 | 
        } 
 | 
      } 
 | 
       
 | 
       
 | 
      // New supplies from trips, for those productintrip that are part of the optimizer run and add islday.ShelfLifeDays to the shelf life 
 | 
      traverse( pispip, astype( ProductInStockingPointInPeriodPlanningLeaf ).NewSupply.ProductInTrip, productintrip, 
 | 
                scope.Contains(  productintrip.ProductInTripInOptimizerRun() )  
 | 
                and productintrip.Trip().GetShelfLifeAgeToAdd() = islday.ShelfLifeDays() )  
 | 
      { 
 | 
        // Term UoM: Output PISP 
 | 
        constr.NewTerm( 1.0 * scalefactor_tripnewsupply_const, program.TripNewSupplyVariables().Get( productintrip ) ); 
 | 
      } 
 | 
     
 | 
      // Inventory carried forward, if the previous pispip exists and is part of the optimizer run 
 | 
      previouspispip := pispip.PreviousPlanningPISPIP(); 
 | 
      if( not isnull( previouspispip ) and previouspispip.Start() >= firstpispipforbalancestart )  
 | 
      { 
 | 
           // Term UoM: PISP 
 | 
          constr.NewTerm( 1.0 * scalefactor_invqty_const,   program.InvQtyShelfLifeVariables().Get( previouspispip, islday ) ); 
 | 
      } 
 | 
     
 | 
      // Sales demands added to balance constraint pispip salesdemands 
 | 
      traverse( pispip.GetLeafSalesDemandInPeriod(), Elements, lsdip, not lsdip.IsPostponed() or lsdip.IsManuallyPostponed() ) // analogous to non-shelflife balance  
 | 
      { 
 | 
        // Leaf sales demands added to balance constraint 
 | 
        constr.NewTerm( -1.0 * scalefactor_salesdemandqty_const, 
 | 
                       program.SalesDemandShelfLifeQtyVariables().Get( lsdip, islday ) ); 
 | 
      } 
 | 
      traverse( pispip.GetDisaggregatedSalesDemandInPeriod(), Elements, dsdip, not dsdip.IsPostponed() ) // analogous to non-shelflife balance  
 | 
      { 
 | 
        // Disaggregated sales demands added to balance constraint 
 | 
        constr.NewTerm( -1.0 * scalefactor_salesdemandqty_const, 
 | 
                       program.DisaggregatedSalesDemandShelfLifeQtyVariables().Get( dsdip, islday ) ); 
 | 
      } 
 | 
     
 | 
      // Dependent demands, with slack to prevent infeasibility 
 | 
      // Term UoM: PISP 
 | 
      traverse( pispip, ProductInStockingPoint_MP.OutgoingShelfLifeDay, oslday )  
 | 
      { 
 | 
        constr.NewTerm( -1.0 * scalefactor_dependentdemandinpispip_const, 
 | 
                       program.DependentDemandInPISPIPShelfLifeVariables().Get( pispip, islday, oslday ) ); 
 | 
      }   
 | 
       
 | 
      //subtract the number of products that have expired in this pispip 
 | 
      if ( pispip.ProductInStockingPoint_MP().IsOptShelfLife() )  
 | 
      { 
 | 
        constr.NewTerm( -1.0 * scalefactor_expired_const, program.ExpiredForAgeVariables().Get( pispip, islday ) ); 
 | 
      } 
 | 
     
 | 
      // Postponed demands which are postponed to this period 
 | 
      previouspispip := pispip.PreviousPlanningPISPIP(); 
 | 
       
 | 
      maxnumberofpostponement := pispip.ProductInStockingPoint_MP().OptimizerMaxPostponementPeriod(); // set in init instance for performance  
 | 
      for( i := 1; 
 | 
           i <= maxnumberofpostponement // within the maximum number of postponement periods 
 | 
           and not isnull( previouspispip ); // the previous pispip exists 
 | 
           i++ ) 
 | 
      { 
 | 
        traverse( previouspispip.astype( ProductInStockingPointInPeriodPlanningLeaf ), PlanningBaseSalesDemandInPeriodForOptimizationPostponable, sd ) 
 | 
        {                                              
 | 
          var := sd.GetDelayedSalesDemandShelfLifeQtyVariable( program, pispip.Period_MP(), islday );  
 | 
          if( not isnull( var ) ) 
 | 
          { 
 | 
            // Term UoM: PISP 
 | 
            constr.NewTerm( -1.0 * scalefactor_delayedsalesdemandqty_const, var ); 
 | 
          } 
 | 
        } 
 | 
        previouspispip := previouspispip.PreviousPlanningPISPIP(); 
 | 
      } 
 | 
    } 
 | 
  *] 
 | 
  InterfaceProperties { Accessibility: 'Module' } 
 | 
} 
 |