| Quintiq file version 2.0 | 
| #parent: #root | 
| Method SetPTQtyVariableProperties ( | 
|   const LibOpt_Scope scope, | 
|   const RunContextForCapacityPlanning runcontext, | 
|   const Operation operation, | 
|   const Period_MP period, | 
|   MPVariable var, | 
|   Boolean setstart, | 
|   CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program | 
| ) const | 
| { | 
|   TextBody: | 
|   [* | 
|     lowerbound := 0.0; | 
|     var.LowerBound( -100.0 );  | 
|     var.LowerBound( lowerbound );  | 
|     var.UpperBound( Real::MaxReal() ); | 
|      | 
|     // Minimum quantity on operation | 
|     if( runcontext.UseProcessMinimumQuantity() | 
|         and operation.HasMinimumQuantity() | 
|         and period.IsWithinLotSizeHorizon() | 
|         and ( not runcontext.IsSlidingWindowsRun() | 
|               or period.GetIsInSlidingWindow( scope ) ) ) | 
|     { | 
|       lowerbound := operation.MinimumQuantity() / operation.QuantityToProcessFactor();   // If PeriodTask.Quantity > 0, it must fulfill: PeriodTask.Quantity * Operation.QuantityToProcessFactor >= Operation.MinimumQuantity | 
|      | 
|       if ( lowerbound > 0 )  | 
|       { | 
|         scalefactor_timeconstbigm_rhs := this.ScaleConstraintRHS( typeof(  MPProcessMinQtyBIGMTimeConstraint ), 1.0 );  | 
|         scalefactor_quantityconstbigm_rhs := this.ScaleConstraintRHS( typeof(  MPProcessMinQtyBIGMQuantityConstraint ), 1.0 );  | 
|          | 
|         scalefactor_ptqty_bigmtime_const := this.ScaleConstraintTerm( typeof( MPPTQtyVariable ), typeof( MPProcessMinQtyBIGMTimeConstraint )  ); | 
|         scalefactor_ptqty_bigmquantity_const := this.ScaleConstraintTerm( typeof( MPPTQtyVariable ), typeof( MPProcessMinQtyBIGMQuantityConstraint )  ); | 
|      | 
|         unitperiod := UnitPeriod::FindUnitPeriodTypeIndex( operation.UnitID(), period.Start(), period.End() );  | 
|          | 
|         quantitycurrent := guard(  PeriodTaskOperation::FindPeriodTaskOperationTypeIndex( unitperiod.Start(), operation.ID() ).Quantity(), 0.0 );  | 
|         bigM := CapacityPlanningSuboptimizer::GetBigMProcessMinQty( operation, unitperiod, lowerbound, quantitycurrent );  // for time based capacity this is an upper bound on number of hours, for Quantity based an upper bound on quantity | 
|      | 
|         iszerovar := program.PTQtyIsZero_MinProcessBigMVariables().New( operation, period );  | 
|         iszerovar.StartValue( ifexpr( quantitycurrent = 0.0, 1.0, 0.0 ) );  | 
|         var.LowerBound( 0.0 ); // PTQY needs to be >= 0  | 
|      | 
|           //      | 
|           // scaledlowerbound <= ptqty + scaledlowerbound * iszerovar | 
|           // | 
|           c := program.ProcessMinQtyEnforceQuantityConstraints().New( operation, period );  | 
|           scalefactor_scaledforcplex := CapacityPlanningSuboptimizer::GetVariableScaleFactor( typeofexpression( var ) );  | 
|           scaledlowerbound := lowerbound / scalefactor_scaledforcplex;  | 
|           c.Sense( '<=' );  | 
|           c.RHSValue( -scaledlowerbound );  | 
|           c.NewTerm(  -1.0, var );  | 
|           c.NewTerm(  -1.0 * scaledlowerbound, iszerovar ); // no restriction if iszerovar=1, otherwise need to be at least lower bound | 
|           this.FilterCPLEXNoise( c, 1.0 ); // this constraint is excluded from the parallel init, so need to do the filtering separate    | 
|      | 
|         if ( operation.Unit().HasCapacityTypeTime() )  | 
|         { | 
|           capusqageperqty := operation.GetCapacityUsagePerQuantity( unitperiod ); | 
|      | 
|           d := program.ProcessMinQtyBIGMTimeConstraints().New( operation, period );  | 
|           d.Sense( '<=' );  | 
|           d.RHSValue( bigM * scalefactor_timeconstbigm_rhs );  | 
|           d.NewTerm( 1.0 * scalefactor_ptqty_bigmtime_const * capusqageperqty, var );  | 
|           d.NewTerm( 1.0 * bigM * scalefactor_timeconstbigm_rhs, iszerovar );    | 
|            | 
|           this.FilterCPLEXNoise( d, 1.0 ); // this constraint is excluded from the parallel init, so need to do the filtering separate | 
|         } | 
|         else | 
|         { | 
|           // | 
|           // ptyqty <= bigM - bigM*iszerovar | 
|           // | 
|           d := program.ProcessMinQtyBIGMQuantityConstraints().New( operation, period );  | 
|           d.Sense( '<=' );  | 
|           d.RHSValue( bigM * scalefactor_quantityconstbigm_rhs );  | 
|           d.NewTerm( 1.0 * scalefactor_ptqty_bigmquantity_const, var );  | 
|           d.NewTerm( 1.0 * bigM * scalefactor_quantityconstbigm_rhs, iszerovar );    | 
|            | 
|           this.FilterCPLEXNoise( d, 1.0 ); // this constraint is excluded from the parallel init, so need to do the filtering separate | 
|         } | 
|       } | 
|     } | 
|      | 
|      // Set feedback bounds that apply to the variable | 
|     if( operation.FeedbackPeriodTaskOperation( relsize ) > 0 ) | 
|     { | 
|       feedbackset := selectset(  operation,  | 
|                                  FeedbackPeriodTaskOperation,  | 
|                                  feedback, | 
|                                  true,  | 
|                                  feedback.GetIsValidFeedback() and feedback.UnitPeriod().Period_MP() = period );  | 
|                     | 
|       feedbackqty := sum( feedbackset, Elements, feedback, true, feedback.FeedbackQuantity() ); | 
|      | 
|       pto := PeriodTaskOperation::FindPeriodTaskOperationTypeIndex( period.Start(), operation.ID() );  | 
|      | 
|       islockedfeedback := guard( pto.IsFeedbackLocked(),  | 
|                                  exists( feedbackset, Elements, fb, true, fb.IsLocked() ) );  | 
|          | 
|       lowerboundfixedsofar := lowerbound;  | 
|      | 
|       if( feedbackqty > 0  | 
|           or islockedfeedback ) // if it is not locked setting lower bound >=0 & making continuous interfers with process min qty | 
|       { | 
|         iszerovar := program.FindVariable(  'PTQtyIsZero', operation, period );  | 
|         if ( not isnull( iszerovar ) )  | 
|         { | 
|           var.UpperBound( 0.0 );  | 
|           constr := program.ProcessMinQtyEnforceQuantityConstraints().Get( operation, period );  | 
|           constr.Enabled( false );  | 
|           if ( operation.Unit().HasCapacityTypeQuantity() )  | 
|           { | 
|             constr2 := program.ProcessMinQtyBIGMQuantityConstraints().Get( operation, period );  | 
|             constr2.Enabled( false ); | 
|           } | 
|           else if ( operation.Unit().HasCapacityTypeTime() )  | 
|           { | 
|             constr2 := program.ProcessMinQtyBIGMTimeConstraints().Get( operation, period );  | 
|             constr2.Enabled( false );  | 
|           }  | 
|         } | 
|         if ( islockedfeedback )  | 
|         { | 
|           this.FreezeVariableLowerUpperBound( var, feedbackqty, feedbackqty );  | 
|         } | 
|         else | 
|         { | 
|           this.FreezeVariableLowerBound( var, maxvalue(  feedbackqty, lowerboundfixedsofar ) );  | 
|         } | 
|       } | 
|     } | 
|      | 
|     // set start value for semi continuous variables | 
|     if ( setstart and var.VariableType() = 'SemiContinuous' )  | 
|     { | 
|       periodtask := select(  operation, PeriodTaskOperation, pto, true, pto.UnitPeriod().Period_MP() = period );  | 
|       startval := 0.0;  | 
|       if ( not isnull( periodtask )  ) | 
|       { | 
|         startval := periodtask.Quantity();  | 
|       } | 
|       var.StartValue( startval  );  | 
|     } | 
|      | 
|     contextisusecampaign := runcontext.UseCampaign();  | 
|     ismanualcampaignsequence := not runcontext.UseCampaignSequenceOptimizer() | 
|     if ( ismanualcampaignsequence and contextisusecampaign and period.GetIsInCampaignTypeHorizonUnit( operation.Unit() ) )  | 
|     { | 
|       unit := operation.Unit();  | 
|       up := select(  operation, Unit.UnitPeriod, uperiod, true, uperiod.Period_MP() = period );  | 
|       iscampaignunit := unit.Campaign_MP( relsize ) > 0;  | 
|        | 
|       if ( iscampaignunit  | 
|            and operation.OperationInCampaignType( relsize ) + operation.OperationInTransitionType( relsize ) = 0  // operation not in campaign or transition | 
|            and up.Period_MP().GetIsInCampaignTypeHorizonUnit( up.Unit() ) )                     // but it is in the campaign horizon  | 
|       {    | 
|          // set upper bound = 0 (for user period tasks exception is possible because set below) | 
|         debuginfo(  'Setting = 0', operation.ID(), period.Start() ) ; | 
|         ptqtyvar := program.PTQtyVariables().Get( operation, period );   | 
|         ptqtyvar.UpperBound( 0.0 );  | 
|         ptqtyvar.LowerBound( 0.0 ); | 
|       } | 
|     } | 
|   *] | 
|   InterfaceProperties { Accessibility: 'Module' } | 
| } |