Quintiq file version 2.0 
 | 
#parent: #root 
 | 
Method AdditionalConstraintMaxInventory ( 
 | 
  CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program, 
 | 
  const LibOpt_Scope scope, 
 | 
  const RunContextForCapacityPlanning runcontext, 
 | 
  const RunContextMeta runcontextmeta 
 | 
) const 
 | 
{ 
 | 
  TextBody: 
 | 
  [* 
 | 
    if ( runcontext.IsMetaIteration() and runcontextmeta.OptionUseAdditonalMaxInventoryConstraint() )  
 | 
    { 
 | 
      constname := typeof( MPMetaLimitMaxInventoryPastHorizonConstraint );  
 | 
      scalefactor_invqty_const := this.ScaleConstraintTerm( typeof( MPInvQtyVariable ), constname ); 
 | 
      scalefactor_slack_const := this.ScaleConstraintTerm( typeof( MPMetaLimitMaxInventoryPastHorizonSlackVariable ), constname ); 
 | 
      scalefactor_rhs_const := this.ScaleConstraintRHS( constname, 1.0 ); 
 | 
     
 | 
      traverse( scope.GetProductInStockingPointInOptimizerRunConst(), Elements.LatestPISPIPInScope, pispip )             
 | 
      { 
 | 
        smallestgap := pispip.GetSmallestMaxGap();  
 | 
         
 | 
        // we only allow the inventory level to increase by smallest gap at the pispip so we do not introduce additional constraints.  
 | 
        currentlevelincludesmaxinventorylevelgoal := runcontext.WeightLevelNonFinancial().MaximumInventoryLevel() <= this.FocusLevel() 
 | 
                                                     and runcontext.WeightLevelNonFinancial().MaximumInventoryLevelWeight() > 0.0;  
 | 
        if ( smallestgap.IsFinite() and currentlevelincludesmaxinventorylevelgoal )  
 | 
        { 
 | 
           
 | 
          constr := program.MetaLimitMaxInventoryPastHorizonConstraints().New( pispip ); 
 | 
          slackvar := program.MetaLimitMaxInventoryPastHorizonSlackVariables().New( pispip );  
 | 
          constr.Sense( '<=' ); 
 | 
          constr.NewTerm( -1.0 * scalefactor_slack_const, slackvar );  
 | 
           
 | 
           
 | 
          pispipinvend := pispip.InventoryLevelEnd(); 
 | 
          rhs := maxvalue( 0.0, pispipinvend + smallestgap );  
 | 
          // We only update the RHS if the quantity is larger than the feasibility tolerance to avoid numerical instability 
 | 
          rhs := ifexpr( abs( rhs * scalefactor_rhs_const ) >= this.SmallestFeasibilityTolerance(), rhs, 0.0 ) ; 
 | 
          constr.RHSValue( rhs * scalefactor_rhs_const ); 
 | 
           
 | 
          // Term UoM: PISP 
 | 
          if ( pispip.IsLeafPlanning() )  
 | 
          { 
 | 
            constr.NewTerm( 1.0 * scalefactor_invqty_const, program.InvQtyVariables().Get( pispip )  ); 
 | 
          } 
 | 
          else 
 | 
          { 
 | 
            this.AddTermsToInventorySpecificationHighLevelConstraint( program, constr, pispip, scope, scalefactor_invqty_const, scalefactor_rhs_const );  
 | 
          } 
 | 
           
 | 
          lowerlimitconstr := program.FindConstraint( CapacityPlanningSuboptimizer::ConstraintNameLowerBoundLastPeriodInventory(), pispip ); // need to be consistent with this lower bound due to pre solve numerical issues 
 | 
          if ( not isnull( lowerlimitconstr ) )  
 | 
          { 
 | 
            lowerlimit :=  -lowerlimitconstr.RHSValue();  
 | 
            upperlimit := constr.RHSValue();  
 | 
            if ( lowerlimit >= upperlimit )  
 | 
            { 
 | 
              lowerlimitconstr.RHSValue( 1000.0 ); // work around epsilon logic 
 | 
              lowerlimitconstr.RHSValue( -upperlimit );  
 | 
            } 
 | 
          } 
 | 
        } 
 | 
      } 
 | 
    } 
 | 
  *] 
 | 
  InterfaceProperties { Accessibility: 'Module' } 
 | 
} 
 |