Quintiq file version 2.0 
 | 
#parent: #root 
 | 
Method InitConstraintsForStockingPointInPeriods ( 
 | 
  CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program, 
 | 
  const RunContextForCapacityPlanning runcontext, 
 | 
  const RunContextMeta rcm, 
 | 
  const LibOpt_Scope scope, 
 | 
  const constcontent ProductInStockingPointInPeriodPlanningLeafs leafpispips 
 | 
) const 
 | 
{ 
 | 
  Description: 'Initialize hard constraints for stocking points' 
 | 
  TextBody: 
 | 
  [* 
 | 
    starttime := OS::PrecisionCounter();  
 | 
    constname := typeof( MPSPInPeriodInventoryLevelConstraint ); 
 | 
     
 | 
    scalefactor_spinvqty_const := this.ScaleConstraintTerm( typeof( MPSPInvQtyVariable ), constname ); 
 | 
    scalefactor_invqty_const := this.ScaleConstraintTerm( typeof( MPInvQtyVariable ), constname ); 
 | 
    scalefactor_stockingpointcapacityoverloaded_const := this.ScaleConstraintTerm( typeof( MPStockingPointCapacityOverloadedVariable ), constname ); 
 | 
     
 | 
    scalefactor_rhs_const := this.ScaleConstraintRHS( constname, 1.0 ); 
 | 
     
 | 
    spipstoconsider := selectset(  scope.GetStockingPointInPeriodInOptimizerRunConst(),  
 | 
                                   Elements,  
 | 
                                   spip, 
 | 
                                   not spip.IsPeriodFrozen() 
 | 
                                   and not spip.StockingPoint_MP().IsPlannedInfinite() ); 
 | 
     
 | 
     
 | 
    // Inventory of stocking point in period = sum of inventory of pispip + dead inventory 
 | 
     
 | 
    SelectorMeta::CheckNoGap( scope ); // debugmode check only 
 | 
     
 | 
    // first create constraints 
 | 
    traverse( spipstoconsider, Elements, spip )  
 | 
    { 
 | 
      // define overload - using same scaling factors as SPInPeriodInventoryLevelConstraint 
 | 
      constrlimit := program.SPInPeriodOverloadConstraints().New( spip );  
 | 
      constrlimit.Sense( '<=' );  
 | 
      constrlimit.RHSValue( spip.MaxCapacity() * scalefactor_rhs_const );  
 | 
      constrlimit.NewTerm( 1.0 * scalefactor_spinvqty_const, 
 | 
                     program.SPInvQtyVariables().Get( spip ) ); 
 | 
       
 | 
      constrlimit.NewTerm( -1.0 * scalefactor_stockingpointcapacityoverloaded_const, program.StockingPointCapacityOverloadedVariables().Get( spip ) ); 
 | 
     
 | 
      if ( runcontext.IsMetaIteration() )  
 | 
      { 
 | 
          // define overload for meta against slightly reduced capacity. Used to supress tiny overloads due to mismatches 
 | 
           
 | 
        restrictedcap := spip.MaxCapacity() * ( 1 - rcm.OptionRestrictedSPCapacityEpsilon() );  
 | 
        constrlimitmeta := program.SPInPeriodOverloadMetaConstraints().New( spip );  
 | 
        constrlimitmeta.Sense( '<=' );  
 | 
        constrlimitmeta.RHSValue( restrictedcap * scalefactor_rhs_const );  
 | 
        constrlimitmeta.NewTerm( 1.0 * scalefactor_spinvqty_const, 
 | 
                       program.SPInvQtyVariables().Get( spip ) ); 
 | 
         
 | 
        constrlimitmeta.NewTerm( -1.0 * scalefactor_stockingpointcapacityoverloaded_const, program.StockingPointCapacityOverloadedMetaVariables().Get( spip ) ); 
 | 
      } 
 | 
       
 | 
      // const UoM: SP 
 | 
      // define inventory level by summing pispips that contribute 
 | 
      const := program.SPInPeriodInventoryLevelConstraints().New( spip ); 
 | 
      const.Sense( '=' ); 
 | 
      // RHS UoM: SP 
 | 
      const.RHSValue( spip.InventoryLevelEnd() * scalefactor_rhs_const ); // we initialize like this, so we can reduce it each time we add a pispip. This way we can avoid having to traverse all pispips (only those in scope) 
 | 
      // Term UoM: SP 
 | 
      const.NewTerm( 1.0 * scalefactor_spinvqty_const, 
 | 
                     program.SPInvQtyVariables().Get( spip ) ); 
 | 
    } 
 | 
     
 | 
    // add constraint terms by traversing scope on  
 | 
    traverse( leafpispips, Elements, pispip )  
 | 
    { 
 | 
      // figure out which spip 'pispip' contributes to: if pispip.SPIP is in scope it is direct, otherwise of 'pispip' is the last pispip in scope for the pisp  
 | 
      pisp := pispip.ProductInStockingPoint_MP();  
 | 
      pisp_is_relevant := not pisp.IsNegativeInventoryAllowed() 
 | 
                  and not pisp.IsExcluded() 
 | 
                  and not pisp.StockingPoint_MP().IsPlannedInfinite(); 
 | 
      spip := pispip.AsStockingPointInPeriod();               
 | 
      if ( pisp_is_relevant and not spip.IsPeriodFrozen() )  
 | 
      { 
 | 
        const := program.SPInPeriodInventoryLevelConstraints().Get( spip ); 
 | 
        uomconversionfactor := pisp.UOMConversionForSPIPConstraint();    
 | 
        // Term: uomconversion * InvQty  
 | 
          // UoM:   [PISP to SP] * [PISP] 
 | 
        const.NewTerm( -uomconversionfactor * scalefactor_invqty_const, program.InvQtyVariables().Get( pispip ) ); 
 | 
                        
 | 
        // now reduce RHS for this term because we know it is in scope 
 | 
        newrhs := this.GetConstraintRHS( const, scalefactor_rhs_const ) - uomconversionfactor * pispip.InventoryLevelEnd();  
 | 
        const.RHSValue( newrhs * scalefactor_rhs_const );  
 | 
                                                                                                   
 | 
        if ( pisp.LatestPISPIPInScope() = pispip ) // special case, we also need to include the contibution to later spip 
 | 
        { 
 | 
          current := spip.NextSPIPPlanning();  
 | 
          currentpispip := pispip.NextPlanningPISPIP();  
 | 
           
 | 
          while ( not isnull( current ) )  
 | 
          { 
 | 
            if ( not current.IsPeriodFrozen() and scope.Contains( current.SPIPInOptimizerRun() ) )  
 | 
            { 
 | 
              const_current := program.SPInPeriodInventoryLevelConstraints().Get( current );  
 | 
              const_current.NewTerm( -uomconversionfactor * scalefactor_invqty_const, program.InvQtyVariables().Get( pispip ) ); 
 | 
               
 | 
              // Take *out* currentpispip.InventoryEnd from RHS contribution, but add in the delta = currentpispip.InventoryLevelEnd - pispip.InventoryLevelEnd. So net put in pispip.InventoryLevelEnd.   
 | 
              newrhs := this.GetConstraintRHS( const_current, scalefactor_rhs_const ) - uomconversionfactor * pispip.InventoryLevelEnd() 
 | 
              const_current.RHSValue( newrhs * scalefactor_rhs_const ); 
 | 
            } 
 | 
             
 | 
            current := current.NextSPIPPlanning();  
 | 
            currentpispip := currentpispip.NextPlanningPISPIP();  
 | 
          }  
 | 
        }                                                                                                                                                                                                                                                                                                  
 | 
      }  
 | 
    } 
 | 
     
 | 
       
 | 
    // final constraint modifications + deal with out of scope SPIP 
 | 
    traverse( spipstoconsider, Elements, spip )  
 | 
    {  
 | 
      const := program.SPInPeriodInventoryLevelConstraints().Get( spip );                                
 | 
      changeunscaledRHS := this.FilterCPLEXNoise( const, scalefactor_rhs_const ); // can consider this to be the change in the inventory level out of scope. Using it to compute existing violation for meta 
 | 
       
 | 
      varattrworkaround := program.NewVariable(  'UnscaledRHSModificationSPInPeriodInventoryLevelConstraints', spip );  
 | 
      varattrworkaround.Enabled( false );  
 | 
      this.StoreValueInVariable( varattrworkaround, changeunscaledRHS );  
 | 
                                                                                                               
 | 
      nextspip := spip.GetNextPlanningSPIP();                   
 | 
      if ( not runcontext.IsSmartPlan()  
 | 
           and not isnull( nextspip )  
 | 
           and not scope.Contains( nextspip.SPIPInOptimizerRun() ) )  
 | 
      { 
 | 
        spipblockafter_outofscope := nextspip.GetMaximalOutOfScope( scope );  
 | 
        mininventoryspaceleftafter := min( spipblockafter_outofscope,  
 | 
                                           Elements,  
 | 
                                           spipfuture,  
 | 
                                           spipfuture.Start() > spip.Start(),  
 | 
                                           maxvalue ( 0.0, spipfuture.MaxCapacity() - spipfuture.InventoryLevelEnd() ) );   
 | 
        // we should limit the increase in the last period by maxinventorydiffafter. We do this by changing the variable upper bound  
 | 
     
 | 
        restrictedcapacity := maxvalue( 0.0, spip.InventoryLevelEnd() + mininventoryspaceleftafter );  
 | 
        // We set the limit always not to make worse any violation in the plan after what is in scope.   
 | 
        // using same (mass) scaling factor as inventy define constraint 
 | 
        var := program.SPInvQtyVariables().Get( spip ); 
 | 
        restrictedmaxcap := program.SPRestrictedCapacityForOutOfScopeConstraints().New( spip ); // introduce this constraint because merging of constraints ignores the var bound (parallel cplex) 
 | 
        restrictedmaxcap.Sense( '<=' );  
 | 
        restrictedmaxcap.RHSValue( scalefactor_rhs_const * restrictedcapacity ); 
 | 
        restrictedmaxcap.NewTerm( 1.0 * scalefactor_spinvqty_const, var );   
 | 
        restrictedmaxcap.NewTerm( -1.0 * scalefactor_spinvqty_const, program.SPInvOutOfScopeSlackVariables().Get( spip ) );   
 | 
      } 
 | 
    } 
 | 
    endtime := OS::PrecisionCounter();  
 | 
    durationmethod := (endtime - starttime ) / OS::PrecisionCounterFrequency();  
 | 
    debuginfo(  'TIME FOR SP constraint = ', durationmethod , 'sec' ); 
 | 
  *] 
 | 
  InterfaceProperties { Accessibility: 'Module' } 
 | 
} 
 |