Quintiq file version 2.0 
 | 
#parent: #root 
 | 
Method SetKPILowerBounds ( 
 | 
  CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program, 
 | 
  const RunContextForCapacityPlanning runcontext, 
 | 
  Boolean scopefrompreprod 
 | 
) const 
 | 
{ 
 | 
  TextBody: 
 | 
  [* 
 | 
    if ( runcontext.IsMetaIteration() and not this.IsFullPlanMetaPriorFocus() )  
 | 
    { 
 | 
      message := '';  
 | 
      debuginfo( ifexpr(  scopefrompreprod, 'Also fixing focus level because scope produced by pre-production selector', '' ) );   
 | 
      rcm := this.GetRunContextMeta();  
 | 
      if ( rcm.OptionCPLEXFixModelBoundsForGoals() )  
 | 
      { 
 | 
        size := counter(  this, MacroPlan.StrategyMacroPlan.StrategyLevelMacroPlan, slm, true, slm.Level() >= 1 ); // exclude 0 level for slack 
 | 
        bounds := RealVector::Construct( size );  
 | 
        usage := BooleanVector::Construct( size );  
 | 
         
 | 
        traverse( this,  
 | 
                  MacroPlan.StrategyMacroPlan.StrategyLevelMacroPlan,  
 | 
                  level,  
 | 
                  1 <= level.Level()  
 | 
                  and level.Level() <= this.FocusLevel() )  
 | 
        { 
 | 
         level_TotalBoundFromPlan := program.RetrieveReal( 'collect_values_model_TotalBoundFromPlan' + [String] level.Level() ); // workaround because cannot write to attribute  
 | 
           
 | 
          // workaround for not being able to use attributes  
 | 
          level_SetCPLEXBoundFromPlan := program.RetrieveReal( 'collect_values_model_SetCPLEXBoundFromPlan' + [String] level.Level() ) > 0.5;  
 | 
          level_TotalBoundFromPlan := program.RetrieveReal( 'collect_values_model_TotalBoundFromPlan' + [String] level.Level() );  
 | 
           
 | 
          bounds.Set( level.Level() - 1, level_TotalBoundFromPlan );  
 | 
          if ( level_SetCPLEXBoundFromPlan and level.Level() < this.FocusLevel() + ifexpr(  scopefrompreprod or runcontext.UseCampaignSequenceOptimizer(), 1, 0 ) ) // if scope is made by pre production selector then we also fix focus level  
 | 
          {                                                                                                                                                         // for campaign sequence optimizer we also fix, because the campaign level gets reoptimized each time 
 | 
            message := message +  'Setting bound for level=' +[String] level.Level() +  'kpi >= '+ [String]  level_TotalBoundFromPlan + String::NewLine();  
 | 
             
 | 
            usage.Set( level.Level() - 1, true );  
 | 
            goalvar := program.GoalForLevelVariables().Get( level );  
 | 
            totallotsizevar := program.TotalLotSizeVariables().Get();  
 | 
            totalspipcapvar := program.TotalStockingPointCapacityVariables().Get();  
 | 
            totalblendingvar := program.TotalBlendingVariables().Get();  
 | 
     
 | 
            constr := program.GoalLevelBoundForMetaConstraints().New( level );  
 | 
            constr.Sense( '>=' );  
 | 
            constr.RHSValue( level_TotalBoundFromPlan );  
 | 
            if ( level.NeedsMetaGoalSlack( this.FocusLevel() ) )  
 | 
            { 
 | 
               
 | 
              goalslackvar := program.GoalLevelSlackVariables().Get( level );  
 | 
              scalefactorforslackdefconstraint := this.ScaleConstraintTerm( typeofexpression( goalslackvar ), typeof( MPTotalSlackConstraint ) ); 
 | 
              goalslackvar.UpperBound( 0.01 );  
 | 
              constr.NewTerm( 1.0, program.GoalLevelSlackVariables().Get( level ) ); // deliberately omitting scale factor. 
 | 
              slackdefconstraint := program.TotalSlackConstraints().Get();  
 | 
              slackdefconstraint.NewTerm( -1.0 * scalefactorforslackdefconstraint, goalslackvar );  
 | 
            } 
 | 
             
 | 
            this.FilterCPLEXNoise( constr, 1.0 ); // this constraint is excluded from the parallel init, so need to do the filtering separate 
 | 
            goalcons := program.GoalConstraints().Get( level ); 
 | 
            traverse( goalcons.Terms(),  
 | 
                      Elements,  
 | 
                      t,  
 | 
                      not t.Variable() = goalvar 
 | 
                      and not typeofexpression( t.Variable() ) = typeof (MPGoalLevelSlackVariable ) 
 | 
                      and not typeofexpression( t.Variable() ) = typeof( MPTotalStockingPointCapacityMetaVariable ) ) 
 | 
            { 
 | 
              if ( t.Variable() = totallotsizevar )  
 | 
              { 
 | 
                c := program.UpperBoundForTotalLotSizeMetaConstraints().New(); 
 | 
                value_collect_values_model_TotalLotSizeVariables := program.RetrieveReal( 'collect_values_model_TotalLotSizeVariables' );  // workaround for attribute  
 | 
                c.RHSValue( value_collect_values_model_TotalLotSizeVariables );  
 | 
                c.Sense( '<=' );  
 | 
                c.NewTerm( 1.0, totallotsizevar );  
 | 
                this.FilterCPLEXNoise( c, 1.0 ); // this constraint is excluded from the parallel init, so need to do the filtering separate 
 | 
                message := message + 'Setting upper bound total lot size = ' + [String] c.RHSValue() + String::NewLine();  
 | 
              } 
 | 
              else if ( t.Variable() = totalspipcapvar ) 
 | 
              { 
 | 
                totalstockingpointviolation := program.RetrieveReal( 'collect_values_model_TotalStockingPointCapacityVariables' ); 
 | 
                c := program.UpperBoundForTotalSPIPCapacityMetaConstraints().New();  
 | 
                c.RHSValue( totalstockingpointviolation );  
 | 
                c.Sense( '<=' );  
 | 
                c.NewTerm( 1.0, totalspipcapvar );  
 | 
                this.FilterCPLEXNoise( c, 1.0 ); // this constraint is excluded from the parallel init, so need to do the filtering separate 
 | 
                message := message + 'Setting upper bound for spip cap variable = ' + [String] c.RHSValue() + String::NewLine();   
 | 
              } 
 | 
              else if ( t.Variable() = totalblendingvar )  
 | 
              { 
 | 
                value_collectvalues_model_TotalBlendingViolation := program.RetrieveReal( 'collectvalues_model_TotalBlendingViolation' );  
 | 
                c := program.UpperBoundForTotalBlendingMetaConstraints().New();  
 | 
                c.RHSValue( value_collectvalues_model_TotalBlendingViolation );  
 | 
                c.Sense( '<=' );  
 | 
                c.NewTerm( 1.0, totalblendingvar );  
 | 
                this.FilterCPLEXNoise( c, 1.0 ); // this constraint is excluded from the parallel init, so need to do the filtering separate 
 | 
                message := message + 'Setting upper bound total blending = ' + [String] c.RHSValue() + String::NewLine();  
 | 
              } 
 | 
              else 
 | 
              { 
 | 
                constr.NewTerm( t.Coefficient(), t.Variable() );  
 | 
              }  
 | 
            }  
 | 
          } 
 | 
        } 
 | 
      } 
 | 
      debuginfo( message );  
 | 
      program.StoreString( 'message_kpilowerbound', message ); // workaround because method needs to be const 
 | 
    } 
 | 
  *] 
 | 
  InterfaceProperties { Accessibility: 'Module' } 
 | 
} 
 |