| Quintiq file version 2.0 | 
| #parent: #root | 
| Method GetNonFinancialKPI ( | 
|   Number level, | 
|   Boolean includeintbased, | 
|   Boolean intbasedonly, | 
|   output String msg_o, | 
|   const WeightLevelNonFinancial weightlevels, | 
|   output Real minweightused, | 
|   output Real maxweightused | 
| ) as Real | 
| { | 
|   TextBody: | 
|   [* | 
|     // Storing of goal value to instances | 
|      | 
|     msg := '';  | 
|     dummy1 := 0.0;  | 
|     dummy2 := 0.0;  | 
|     dummy3 := 0.0;  | 
|     value := 0.0;  | 
|     subopt := this.Suboptimizer().astype( CapacityPlanningSuboptimizer );  | 
|     mp := subopt.Run().Optimization().astype( Optimization ).MacroPlan();  | 
|     if ( not isnull( weightlevels ) )  | 
|     { | 
|       eis := mp.OptimizerMetaEIS();  | 
|       if ( not eis.IsNeedEstimatedImprovementScores()  ) // used so we can also write scores to snapshot in smartplan , full optimizer | 
|       { | 
|         eis.TemporaryForScoreWriting( true );  | 
|         Transaction::Transaction().Propagate( attribute( OptimizerMetaEIS, KPIBalanceViolation ) );  | 
|         Transaction::Transaction().Propagate( attribute( OptimizerMetaEIS, KPILotSizeTotal ) );  | 
|         Transaction::Transaction().Propagate( attribute( OptimizerMetaEIS, KPIMaximumInventory ) );  | 
|         Transaction::Transaction().Propagate( attribute( OptimizerMetaEIS, KPIMinimumInventory ) );  | 
|         Transaction::Transaction().Propagate( attribute( OptimizerMetaEIS, KPITargetInventory ) );  | 
|         Transaction::Transaction().Propagate( attribute( OptimizerMetaEIS, KPISalesDemandPriority ) );                                                                                                                       | 
|         eis.TemporaryForScoreWriting( false );  | 
|       } | 
|        | 
|       if ( intbasedonly )  | 
|       { | 
|         valuelotsize :=  ifexpr( level = weightlevels.LotSizeLevel(), -eis.KPILotSizeTotal() * this.AdjustMinMax( minweightused, maxweightused, weightlevels.LotSizeWeight() ), 0.0  ) | 
|         msg := msg + 'KPILotSize=' + [String]valuelotsize + String::NewLine(); | 
|         valueprocessminqty :=  ifexpr( level = weightlevels.SlackLevel(), // note process min qty is implemented with BIGM. It should be score on the hidden slack level  | 
|                                        -mp.GetKPIProcessMinimumQuantity(this.CutOffProcessMinQtyKPI() ) * this.AdjustMinMax( minweightused, maxweightused, weightlevels.ProcessMinimumQuantityWeight() ),  0.0 )  | 
|         msg := msg + 'KPIProcessMinQty=' + [String] valueprocessminqty + String::NewLine(); | 
|         value := valuelotsize + valueprocessminqty;  | 
|       } | 
|       else | 
|       {  | 
|         valuelotsize :=  ifexpr( includeintbased and level = weightlevels.LotSizeLevel(), -eis.KPILotSizeTotal() * this.AdjustMinMax( minweightused, maxweightused, weightlevels.LotSizeWeight() ), 0.0  ) | 
|         msg := msg + 'KPILotSize=' + [String]valuelotsize + String::NewLine(); | 
|         valueprocessminqty :=  ifexpr( includeintbased and level =weightlevels.SlackLevel(), // note process min qty is implemented with BIGM. It should be score on the hidden slack level  | 
|                                        -mp.GetKPIProcessMinimumQuantity( this.CutOffProcessMinQtyKPI()) * this.AdjustMinMax( minweightused, maxweightused, weightlevels.ProcessMinimumQuantityWeight() ),  0.0 )  | 
|         msg := msg + 'KPIProcessMinQty=' + [String] valueprocessminqty + String::NewLine(); | 
|          | 
|         valuecampaign := ifexpr( level = weightlevels.CampaignLevel(),  | 
|                                  -RollbackKPIMeta::GetCampaignScore( weightlevels.RunContextForCapacityPlanning(), mp, dummy1, dummy2, dummy3 ) * this.AdjustMinMax( minweightused, maxweightused, weightlevels.CampaignWeight() ),  0.0 );  | 
|         msg := msg + 'KPICampagin=' + [String]valuecampaign + String::NewLine();  | 
|         valuefulfillment :=  ifexpr( level = weightlevels.FulfillmentLevel(), mp.GetKPIFulfillment() * this.AdjustMinMax( minweightused, maxweightused, weightlevels.FulfillmentWeight() ), 0.0 );  | 
|         msg := msg + 'KPIfulfillment=' + [String]valuefulfillment + String::NewLine(); | 
|         valueinventorymix :=  ifexpr( level = weightlevels.InventoryMixBalancingLevel(), -mp.GetKPIInventoryMixBalancing() * this.AdjustMinMax( minweightused, maxweightused, weightlevels.InventoryMixBalancingWeight() ), 0.0  )   | 
|         msg := msg + 'KPIInventoryMixBalancing=' + [String]valueinventorymix + String::NewLine(); | 
|         valuemaxinventory :=  ifexpr( level = weightlevels.MaximumInventoryLevel(),  -eis.KPIMaximumInventory() * this.AdjustMinMax( minweightused, maxweightused, weightlevels.MaximumInventoryLevelWeight() ), 0.0  )  | 
|         msg := msg + 'KPIMaxInventoryLevel=' + [String] valuemaxinventory + String::NewLine(); | 
|         valuemininventory := ifexpr( level = weightlevels.MinimumInventoryLevel(), -eis.KPIMinimumInventory() * this.AdjustMinMax( minweightused, maxweightused, weightlevels.MinimumInventoryLevelWeight() ), 0.0  ) | 
|         msg := msg + 'KPIMinInventoryLevel=' + [String] valuemininventory + String::NewLine(); | 
|         valuesupplytarget :=  ifexpr( level = weightlevels.SupplyTargetLevel(), -mp.GetKPISupplyTarget() * this.AdjustMinMax( minweightused, maxweightused, weightlevels.SupplyTargetWeight() ),  0.0 ) | 
|         msg := msg + 'KPISupplyTarget=' + [String]valuesupplytarget + String::NewLine(); | 
|         valueminsupply :=  ifexpr( level = weightlevels.MinimumSupplyLevel(),  -mp.GetKPIMinimumSupply() * this.AdjustMinMax( minweightused, maxweightused, weightlevels.MinimumSupplyWeight() ), 0.0  )  | 
|         msg := msg + 'KPIMinSupply=' + [String] valueminsupply + String::NewLine(); | 
|         valuemaxsupply :=  ifexpr( level = weightlevels.MaximumSupplyLevel(),  -mp.GetKPIMaximumSupply() * this.AdjustMinMax( minweightused, maxweightused, weightlevels.MaximumSupplyWeight() ), 0.0  )  | 
|         msg := msg + 'KPIMaxSupply=' + [String] valuemaxsupply + String::NewLine(); | 
|         valueminunitcap :=  ifexpr( level = weightlevels.MinimumUnitCapacityLevel(), -mp.GetKPIUnitCapacityNotMet() * this.AdjustMinMax( minweightused, maxweightused, weightlevels.MinimumUnitCapacityWeight() ), 0.0 )  | 
|         msg := msg + 'KPIMinUnitCapacity=' + [String] valueminunitcap + String::NewLine(); | 
|         valuepostpone :=  ifexpr( level = weightlevels.PostponementPenaltyLevel(),  -mp.GetKPIPostponementPenalty() * this.AdjustMinMax( minweightused, maxweightused, weightlevels.PostponementPenaltyWeight() ), 0.0  )  | 
|         msg := msg + 'KPIPostponementPenalty=' + [String] valuepostpone + String::NewLine(); | 
|         valueprocessmaxqty :=  ifexpr( level = weightlevels.ProcessMaximumQuantityLevel(),  -mp.GetKPIProcessMaximumQuantity() * this.AdjustMinMax( minweightused, maxweightused, weightlevels.ProcessMaximumQuantityWeight() ), 0.0  )  | 
|         msg := msg + 'KPIProcessMaxQty=' + [String] valueprocessmaxqty + String::NewLine(); | 
|        | 
|         valuesalesdemandprio :=  ifexpr( level = weightlevels.SalesDemandPriorityLevel(), eis.KPISalesDemandPriority() * this.AdjustMinMax( minweightused, maxweightused, weightlevels.SalesDemandPriorityWeight() ), 0.0   ) // use attribute to avoid expensive kpi method | 
|         msg := msg + 'KPISalesDemandPrio=' + [String] valuesalesdemandprio + String::NewLine(); | 
|         valuefftarget :=  ifexpr( level = weightlevels.FulfillmentTargetLevel(), mp.GetKPIFulfillmentTargetOpt() * this.AdjustMinMax( minweightused, maxweightused, weightlevels.FulfillmentTargetWeight() ),   0.0  )  | 
|         msg := msg + 'KPIFulfillmentTarget=' + [String] valuefftarget + String::NewLine(); // note KPIFulfillmentTarget is a poor KPI to gauge convergence for  | 
|         valueservice :=  ifexpr( level = weightlevels.ServiceLevelLevel(), mp.GetKPIServiceLevel() * this.AdjustMinMax( minweightused, maxweightused, weightlevels.ServiceLevelWeight() ), 0.0  ) | 
|         msg := msg + 'KPIServiceLevel' + [String] valueservice + String::NewLine(); | 
|         valuespcap :=  ifexpr( level = weightlevels.StockingPointCapacityLevel(), -mp.GetKPIStockingPointCapacity() * this.AdjustMinMax( minweightused, maxweightused, weightlevels.StockingPointCapacityWeight() ), 0.0 )  | 
|         msg := msg + 'KPISPCapacity=' + [String] valuespcap + String::NewLine(); | 
|         valuetinvlevel :=  ifexpr( level = weightlevels.TargetInventoryLevel(), -eis.KPITargetInventory() * this.AdjustMinMax( minweightused, maxweightused, weightlevels.TargetInventoryLevelWeight() ), 0.0 )  | 
|         msg := msg + 'KPITargetInvLevel=' + [String] valuetinvlevel + String::NewLine(); | 
|         valueunitcap :=  ifexpr( level = weightlevels.UnitCapacityLevel(), -mp.GetKPIUnitCapacity() * this.AdjustMinMax( minweightused, maxweightused, weightlevels.UnitCapacityWeight() ), 0.0 ) | 
|         msg := msg + 'KPIUnitCap=' + [String] valueunitcap + String::NewLine(); | 
|         valuebalance := ifexpr ( level = weightlevels.SlackLevel(), -eis.KPIBalanceViolation() * this.AdjustMinMax( minweightused, maxweightused, weightlevels.SlackWeight() ), 0.0 ); // hidden balance KPI in level 1 | 
|         msg := msg + 'KPIBalanceViolation=' + [String] valuebalance + String::NewLine();  | 
|         valuecampaigncombislack := ifexpr( level = weightlevels.SlackLevel(), -RollbackKPIMeta::GetCampaignCombiSlackScore( mp, dummy1, dummy2, weightlevels.RunContextForCapacityPlanning().UseCampaignSequenceOptimizer() ), 0.0 );  | 
|         msg := msg + 'CampaignCombiSlack=' + [String] valuecampaigncombislack + String::NewLine();  | 
|         valueshiftmindurqationslack := ifexpr( level = weightlevels.SlackLevel(), -RollbackKPIMeta::GetShiftOptimizerMinDurationSlackScore( mp, subopt ), 0.0 );  | 
|         msg := msg + 'ShiftOptimizerMinDurationSlack=' + [String] valueshiftmindurqationslack + String::NewLine();  | 
|         valueblending := ifexpr(  level = weightlevels.BlendingLevel(), -mp.GetKPIBlending( this.AccuracyBlendingKPI() ) * this.AdjustMinMax( minweightused, maxweightused, weightlevels.BlendingWeight() ), 0.0 );  | 
|         msg := msg + 'KPIblending=' + [String] valueblending + String::NewLine();  | 
|         valuetotalexpired := ifexpr(  level = weightlevels.ExpiredQtyLevel(), -mp.GetKPITotalExpiredQuantity() * this.AdjustMinMax( minweightused, maxweightused, weightlevels.ExpiredQtyWeight() ), 0.0 );  | 
|         msg := msg + 'KPITotalExpiredQuantity=' + [String] valuetotalexpired + String::NewLine();  | 
|         valueco2emission := ifexpr( level = weightlevels.CO2EmissionLevel(), -mp.GetKPICO2Emission() * this.AdjustMinMax( minweightused, maxweightused, weightlevels.CO2EmissionWeight() ), 0.0 ); | 
|         msg := msg + 'KPICO2Emission=' + [String] valueco2emission + String::NewLine(); | 
|          | 
|         value := valuecampaign  | 
|                  + valuefulfillment  | 
|                  + valueinventorymix  | 
|                  + valuelotsize  | 
|                  + valuemaxinventory  | 
|                  + valuemininventory  | 
|                  + valuesupplytarget  | 
|                  + valueminsupply  | 
|                  + valuemaxsupply  | 
|                  + valueminunitcap  | 
|                  + valuepostpone  | 
|                  + valueprocessmaxqty  | 
|                  + valueprocessminqty  | 
|                  + valuesalesdemandprio  | 
|                  + valuefftarget  | 
|                  + valueservice  | 
|                  + valuespcap  | 
|                  + valuetinvlevel  | 
|                  + valueunitcap  | 
|                  + valuebalance  | 
|                  + valuecampaigncombislack | 
|                  + valueshiftmindurqationslack | 
|                  + valueblending  | 
|                  + valuetotalexpired | 
|                  + valueco2emission;  | 
|          | 
|         msg_o := msg;           | 
|       } | 
|     } | 
|     value := ifexpr( this.RoundPuzzleScoreDecimal() >= 0, value.Round( this.RoundPuzzleScoreDecimal() ), value ); // negative means no round | 
|      | 
|     return value; | 
|   *] | 
|   InterfaceProperties { Accessibility: 'Module' } | 
| } |