Quintiq file version 2.0 
 | 
#parent: #root 
 | 
Method InitConstraintsGoalsForUnitPeriods ( 
 | 
  CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program, 
 | 
  const RunContextForCapacityPlanning runcontext, 
 | 
  const LibOpt_Scope scope, 
 | 
  const constcontent ProductInTrips pitinrun 
 | 
) const 
 | 
{ 
 | 
  Description: 'Init constraints goals for unit periods' 
 | 
  TextBody: 
 | 
  [* 
 | 
    collectvaluesmodel := runcontext.IsMetaIteration();  
 | 
     
 | 
    totalminimumcapacity := 0.0;  
 | 
    totalminimumcapacitysecondary := 0.0;  
 | 
    totalmaximumcapacity := 0.0;  
 | 
    totalmaximumcapacitysecondary := 0.0;  
 | 
    totalprocesssmax := 0.0; 
 | 
    totallotsize := 0.0;  
 | 
    totalco2emission := 0.0; 
 | 
    scalefactoroverloaded := CapacityPlanningSuboptimizer::GetVariableScaleFactor( typeof( MPUnitCapacityOverloadedQuantityVariable ) );  
 | 
    scalefactoroverloadedtime := CapacityPlanningSuboptimizer::GetVariableScaleFactor( typeof( MPUnitCapacityOverloadedTimeVariable ) );  
 | 
    scalefactoroverloadedsecondary := CapacityPlanningSuboptimizer::GetVariableScaleFactor( typeof( MPUnitSecondaryCapacityOverloadedVariable ) );  
 | 
    scalefactorunderloadedquantity := CapacityPlanningSuboptimizer::GetVariableScaleFactor( typeof( MPUnitCapacityNotMetQuantityVariable ) );  
 | 
    scalefactorunderloadedtime := CapacityPlanningSuboptimizer::GetVariableScaleFactor( typeof( MPUnitCapacityNotMetTimeVariable ) );  
 | 
    scalefactormaxptqtyover := CapacityPlanningSuboptimizer::GetVariableScaleFactor( typeof( MPMaxPTQtyOverVariable ) );  
 | 
     
 | 
    // minimum capacity 
 | 
    // mcconst constraint UoM: Unit --> Please note that this means that if different units have a different UoM, 
 | 
    //                                  their UnitCapacityNotMet will have a different weight in the goal 
 | 
    mcconst := program.TotalMinUnitCapacityConstraints().New();  
 | 
    mcconst.Sense( '=' ); 
 | 
    mcconst.RHSValue( this.ScaleConstraintRHS( typeofexpression( mcconst ), 0.0 ) ); 
 | 
    // Term UoM: Unit 
 | 
    mcconst.NewTerm( 1.0 * this.ScaleConstraintTerm( typeof( MPTotalMinimumUnitCapacityVariable ), typeofexpression( mcconst ) ) 
 | 
                     , program.TotalMinimumUnitCapacityVariables().Get()); 
 | 
     
 | 
    // smcconst constraint UoM: TransportCapacity --> Please note that this means that if different units have a different UoM, 
 | 
    //                                                their UnitSecondaryCapacityNotMet will have a different weight in the goal 
 | 
    smcconst := program.TotalMinUnitSecondaryCapacityConstraints().New(); 
 | 
    smcconst.Sense( '=' ); 
 | 
    smcconst.RHSValue( this.ScaleConstraintRHS( typeofexpression( smcconst ), 0.0 ) ); 
 | 
    // Term UoM: TransportCapacity 
 | 
    smcconst.NewTerm( 1.0 * this.ScaleConstraintTerm( typeof( MPTotalMinimumUnitSecondaryCapacityVariable ) 
 | 
                                                      , typeofexpression( smcconst ) ), program.TotalMinimumUnitSecondaryCapacityVariables().Get()); 
 | 
     
 | 
    // unit capacity overloaded 
 | 
    // ucoconst constraint UoM: Unit --> Please note that this means that if different units have a different UoM, 
 | 
    //                                   their UnitCapacityOverloaded will have a different weight in the goal 
 | 
    ucoconst := program.TotalUnitCapacityConstraints().New(); 
 | 
    ucoconst.Sense( '=' ); 
 | 
    ucoconst.RHSValue( this.ScaleConstraintRHS( typeofexpression( ucoconst ), 0.0 ) ); 
 | 
    // Term UoM: Unit 
 | 
    ucoconst.NewTerm( 1.0 * this.ScaleConstraintTerm( typeof( MPTotalUnitCapacityVariable ), typeofexpression( ucoconst ) ) 
 | 
                      , program.TotalUnitCapacityVariables().Get()); 
 | 
     
 | 
    // sucoconst constraint UoM: TransportCapacity --> Please note that this means if different units have a different UoM, 
 | 
    //                                                 their UnitSecondaryCapacityOverloaded will have a different weight in the goal 
 | 
    sucoconst := program.TotalUnitSecondaryCapacityConstraints().New(); 
 | 
    sucoconst.Sense( '=' ); 
 | 
    sucoconst.RHSValue( this.ScaleConstraintRHS( typeofexpression( sucoconst ), 0.0 ) ); 
 | 
    // Term UoM: TransportCapacity 
 | 
    sucoconst.NewTerm( 1.0 * this.ScaleConstraintTerm( typeof( MPTotalUnitSecondaryCapacityVariable ) 
 | 
                                                       , typeofexpression( sucoconst ) ), program.TotalUnitSecondaryCapacityVariables().Get()); 
 | 
     
 | 
    // Maximum quantity 
 | 
    // maxquantityconst constraint UoM: Unit --> Please note that this means that if different units have a different UoM, 
 | 
    //                                           their MaxPTQtyOver will have a different weight in the goal 
 | 
    maxquantityconst := program.TotalProcessMaximumQuantityConstraints().New(); 
 | 
    maxquantityconst.Sense( '=' ); 
 | 
    maxquantityconst.RHSValue( this.ScaleConstraintRHS( typeofexpression( maxquantityconst ), 0.0 ) ); 
 | 
    // Term UoM: Unit 
 | 
    maxquantityconst.NewTerm( 1.0 * this.ScaleConstraintTerm( typeof( MPTotalProcessMaximumQuantityVariable ), typeofexpression( maxquantityconst ) ) 
 | 
                                                              , program.TotalProcessMaximumQuantityVariables().Get()); 
 | 
     
 | 
    scalefactor_unitcapacitynotmet_mcconst := this.ScaleConstraintTerm( typeof( MPUnitCapacityNotMetQuantityVariable ), typeofexpression( mcconst ) ); 
 | 
    scalefactor_unitcapacitynotmettime_mcconst := this.ScaleConstraintTerm( typeof( MPUnitCapacityNotMetTimeVariable ), typeofexpression( mcconst ) ); 
 | 
    scalefactor_unitcapacityoverloaded_ucoconst := this.ScaleConstraintTerm( typeof( MPUnitCapacityOverloadedQuantityVariable ), typeofexpression( ucoconst ) ); 
 | 
    scalefactor_unitcapacityoverloadedtime_ucoconst := this.ScaleConstraintTerm( typeof( MPUnitCapacityOverloadedTimeVariable ), typeofexpression( ucoconst ) ); 
 | 
     
 | 
    scalefactor_unitsecondarycapacitynotmet_smcconst := this.ScaleConstraintTerm( typeof( MPUnitSecondaryCapacityNotMetVariable ), typeofexpression( smcconst ) ); 
 | 
    scalefactor_unitsecondarycapacityoverloaded_sucoconst := this.ScaleConstraintTerm( typeof( MPUnitSecondaryCapacityOverloadedVariable ), typeofexpression( sucoconst ) ); 
 | 
     
 | 
    unitperiods := construct( UnitPeriods, constcontent ); 
 | 
    traverse( scope.GetUnitPeriodInOptimizerRunConst(), Elements, up ) 
 | 
    { 
 | 
      unitperiods.Add( up ); 
 | 
      parentunitperiods := up.GetAllParentsOfUnitDimension(); 
 | 
      traverse( parentunitperiods, Elements, parentup )  
 | 
      {  
 | 
        unitperiods.Add(  parentup );  
 | 
      } 
 | 
    } 
 | 
     
 | 
    unitperiods := unitperiods.Unique(); 
 | 
    // The variables are not defined for parent units with infinite capacity 
 | 
    traverse( unitperiods, Elements, unitperiod, not ( unitperiod.Unit().HasChild() and unitperiod.Unit().HasCapacityTypeInfinite() ) ) 
 | 
    { 
 | 
      // Penalty for not meeting minimum capacity 
 | 
      // Term UoM: Unit 
 | 
      coefmincap := ifexpr(  unitperiod.IsTimeBasedCapacityUsage(), scalefactor_unitcapacitynotmettime_mcconst, scalefactor_unitcapacitynotmet_mcconst );  
 | 
      mcconst.NewTerm( -1.0 * coefmincap, unitperiod.GetCapacityNotMetVariable( program ) ); 
 | 
     
 | 
      // Penalty for overloading the unit capacity 
 | 
      // Term UoM: Unit 
 | 
      coefmaxcap :=  ifexpr(  unitperiod.IsTimeBasedCapacityUsage(), scalefactor_unitcapacityoverloadedtime_ucoconst, scalefactor_unitcapacityoverloaded_ucoconst);  
 | 
      coefmincapsecondary := scalefactor_unitsecondarycapacitynotmet_smcconst;  
 | 
      coefmaxcapsecondary := scalefactor_unitsecondarycapacityoverloaded_sucoconst;  
 | 
       
 | 
      ucoconst.NewTerm( -1.0 * coefmaxcap, unitperiod.GetCapacityOverloadedVariable( program ) );  
 | 
       
 | 
      processsecondary := unitperiod.istype( UnitPeriodTransportQuantity ) and unitperiod.astype( UnitPeriodTransportQuantity ).HasSecondaryCapacityDefinition();  
 | 
      if( processsecondary ) 
 | 
      { 
 | 
        // Penalty for not meeting minimum secondary capacity 
 | 
        // Term UoM: TransportCapacity 
 | 
        smcconst.NewTerm( -1.0 * coefmincapsecondary, program.UnitSecondaryCapacityNotMetVariables().Get( unitperiod ) ); 
 | 
         
 | 
        // Penalty for overloading the unit secondary capacity 
 | 
        // Term UoM: TransportCapacity 
 | 
        sucoconst.NewTerm( -1.0 * coefmaxcapsecondary, program.UnitSecondaryCapacityOverloadedVariables().Get( unitperiod ) ); 
 | 
      } 
 | 
       
 | 
      if ( collectvaluesmodel )  
 | 
      { 
 | 
        factoroverloaded := ifexpr( unitperiod.IsTimeBasedCapacityUsage(), scalefactoroverloadedtime, scalefactoroverloaded );  
 | 
        factorunderloaded := ifexpr(  unitperiod.IsTimeBasedCapacityUsage(), scalefactorunderloadedtime, scalefactorunderloadedquantity );  
 | 
        totalmaximumcapacity := totalmaximumcapacity + coefmaxcap * (unitperiod.OverloadCapacity() ) / factoroverloaded; 
 | 
        totalminimumcapacity := totalminimumcapacity + coefmincap * (unitperiod.CapacityNotMet() ) / factorunderloaded;  
 | 
        if (  processsecondary )  
 | 
        { 
 | 
          totalmaximumcapacitysecondary := totalmaximumcapacitysecondary  
 | 
                                           + coefmaxcapsecondary * unitperiod.astype(  UnitPeriodTransportQuantity ).SecondaryOverloadCapacity() / scalefactoroverloadedsecondary;  
 | 
                                            
 | 
          totalminimumcapacitysecondary := totalminimumcapacitysecondary  
 | 
                                           + coefmincapsecondary * unitperiod.astype(  UnitPeriodTransportQuantity ).CapacityNotMetSecondary() / scalefactor_unitsecondarycapacitynotmet_smcconst;                                     
 | 
        } 
 | 
      } 
 | 
    } 
 | 
     
 | 
    // workaround because cannot use attribute 
 | 
    this.StoreValueInProgram( program, 'collect_values_model_MPTotalUnitCapacityVariable', totalmaximumcapacity );  
 | 
    this.StoreValueInProgram( program, 'collect_values_model_MPTotalUnitSecondaryCapacityVariable', totalmaximumcapacitysecondary );  
 | 
    this.StoreValueInProgram( program, 'collect_values_models_MPTotalMinimumUnitCapacityVariable', totalminimumcapacity );  
 | 
    this.StoreValueInProgram( program, 'collect_values_models_MPTotalMinimumUnitSecondaryCapacityVariable', totalminimumcapacitysecondary );  
 | 
     
 | 
     
 | 
     
 | 
    // Penalty for overloading the campaign and transition time capacity  
 | 
    ismanualcampaignsequence := not runcontext.UseCampaignSequenceOptimizer() 
 | 
    if( ismanualcampaignsequence and runcontext.UseCampaign() ) 
 | 
    { 
 | 
      scalefactor_campaignoverloaded_uconst := this.ScaleConstraintTerm( typeof( MPCampaignPeriodOverloadedVariable ), typeofexpression( ucoconst ) );  
 | 
      traverse( scope.GetUnitInOptimizerRunConst(), Elements.CampaignType_MP, type ) 
 | 
      { 
 | 
        // Only consider this campaign if at least one of its operations is part of this optimizer run 
 | 
        traverse( type, Campaign_MP, campaign, 
 | 
                  exists( campaign, OperationInCampaign.Operation, operation, 
 | 
                          scope.Contains( operation.OperationInOptimizerRun() ) ) ) 
 | 
        { 
 | 
          // Only consider the campaingperiod if its unit period is part of this optimizer run 
 | 
          traverse( campaign, PlanningCampaignPeriod, cp, 
 | 
                    guard( scope.Contains( cp.UnitPeriod().UnitPeriodInOptimizerRun() ), false ) ) 
 | 
          { 
 | 
            if ( not cp.UnitPeriod().Unit().IsPlannedInfinite() )  
 | 
            { 
 | 
              ucoconst.NewTerm( -scalefactor_campaignoverloaded_uconst, program.CampaignPeriodOverloadedVariables().Get( cp ) ); 
 | 
               
 | 
              if ( collectvaluesmodel )  
 | 
              { 
 | 
                // created backlog issue 2386 for meta optimizer cmt____ := 'collect here';  
 | 
              } 
 | 
            } 
 | 
          } 
 | 
        } 
 | 
      } 
 | 
       
 | 
      scalefactor_transitionoverloaded_uconst := this.ScaleConstraintTerm( typeof( MPTransitionPeriodOverloadedVariable ), typeofexpression( ucoconst ) );  
 | 
      traverse( scope.GetUnitInOptimizerRunConst(),  
 | 
                Elements.TransitionType_MP.Transition_MP.TransitionPeriod_MP,  
 | 
                tperiod,  
 | 
                exists( tperiod, Transition_MP.OperationInTransition.OperationInTransitionType.Operation, operation, scope.Contains( operation.OperationInOptimizerRun() ) ) ) 
 | 
      { 
 | 
        if ( not tperiod.UnitPeriod().Unit().IsPlannedInfinite() )  
 | 
        { 
 | 
          ucoconst.NewTerm( -scalefactor_transitionoverloaded_uconst, program.TransitionPeriodOverloadedVariables().Get( tperiod ) );  
 | 
           
 | 
            if ( collectvaluesmodel )  
 | 
            { 
 | 
              // created backlog issue 2386 for meta optimizer cmt____ := 'collect here';  
 | 
            } 
 | 
        } 
 | 
      } 
 | 
     
 | 
      // campaign + transition output 
 | 
      
 | 
      // TotalCampaignTransitionOutput = SUM[PTTransitionQtyVariables] 
 | 
      transconst := program.TotalCampaignTransitionOutputConstraints().New(); 
 | 
      transconst.Sense( '=' ); 
 | 
      transconst.RHSValue( this.ScaleConstraintRHS( typeofexpression( transconst ), 0.0 ) ); 
 | 
      // Term UoM: Unit 
 | 
      transconst.NewTerm( 1.0 * this.ScaleConstraintTerm( typeof( MPTotalCampaignTransitionOutputVariable ), typeofexpression( transconst ) ), program.TotalCampaignTransitionOutputVariables().Get()); 
 | 
         
 | 
      traverse( scope.GetOperationInOptimizerRunConst(), Elements, operation, operation.OperationInCampaign( relsize ) + operation.OperationInTransitionType( relsize ) > 0 ) 
 | 
      { 
 | 
        periods := this.GetPeriodsForOperation( scope, operation );   
 | 
        traverse( periods, Elements, period, period.GetIsInCampaignTypeHorizonUnit( operation.Unit() ) ) 
 | 
        { 
 | 
          traverse( operation,  
 | 
                    OperationInTransitionType.OperationInTransition,  
 | 
                    oit,  
 | 
                    exists( oit, Transition_MP.TransitionPeriod_MP, tperiod, tperiod.UnitPeriod().Period_MP() = period ) ) 
 | 
          { 
 | 
            pttransvar := program.PTTransitionQtyVariables().Get( oit, period );  
 | 
            transconst.NewTerm(  -1.0 * this.ScaleConstraintTerm( typeof( MPPTTransitionQtyVariable ), typeofexpression( transconst)), pttransvar );  
 | 
          } 
 | 
        } 
 | 
      } 
 | 
       
 | 
      // camconst constraint UoM: Unit --> Please note that this means that if different units have a different UoM, 
 | 
      //                                   their MinCampaignQtyUnder/MaxCampaignQtyOver will have a different weight in the goal 
 | 
      // 
 | 
      // TotalCampaignVariables = SUM[MinCampaignQtyUnderVariables] + SUM[MaxCampaignQtyOverVariables] - TotalCampaignTransitionOutputVariables 
 | 
      // 
 | 
      camconst := program.TotalCampaignConstraints().New(); 
 | 
      camconst.Sense( '=' ); 
 | 
      camconst.RHSValue( this.ScaleConstraintRHS( typeofexpression( camconst ), 0.0 ) ); 
 | 
      // Term UoM: Unit 
 | 
      camconst.NewTerm( 1.0 * this.ScaleConstraintTerm( typeof( MPTotalCampaignVariable ), typeofexpression( camconst ) ), program.TotalCampaignVariables().Get()); 
 | 
       
 | 
      scalefactor_mincampaignqtyunder_camconst := this.ScaleConstraintTerm( typeof(  MPMinCampaignQtyUnderVariable ), typeofexpression( camconst ) ); 
 | 
      scalefactor_maxcampaignqtyover_camconst := this.ScaleConstraintTerm( typeof(  MPMaxCampaignQtyOverVariable ), typeofexpression( camconst ) ); 
 | 
     
 | 
      traverse( scope.GetUnitInOptimizerRunConst(), Elements.CampaignType_MP, type ) 
 | 
      { 
 | 
        // Only consider this campaign if at least one of its operations is part of this optimizer run 
 | 
        traverse( type, Campaign_MP, campaign, 
 | 
                  exists( campaign, OperationInCampaign.Operation, operation,  
 | 
                          scope.Contains( operation.OperationInOptimizerRun() ) ) ) 
 | 
        { 
 | 
          // Penalty for planning under the minimum quantity of campaign 
 | 
          // Term UoM: Unit 
 | 
          camconst.NewTerm( -1.0 * scalefactor_mincampaignqtyunder_camconst, program.MinCampaignQtyUnderVariables().Get( campaign ) ); 
 | 
     
 | 
          // Penalty for overloading the maximum quantity of campaign 
 | 
          // Term UoM: Unit 
 | 
          camconst.NewTerm( -1.0 * scalefactor_maxcampaignqtyover_camconst, program.MaxCampaignQtyOverVariables().Get( campaign ) ); 
 | 
        } 
 | 
      } 
 | 
      camconst.NewTerm( this.ScaleConstraintTerm( typeof( MPTotalCampaignTransitionOutputVariable ), typeofexpression( camconst ) ), program.TotalCampaignTransitionOutputVariables().Get() );  
 | 
    } 
 | 
     
 | 
    usemaxlotsize := runcontext.UseProcessMaximumQuantity(); 
 | 
    uselotsize := runcontext.UseLotSize(); 
 | 
    needlotcost := runcontext.UseLotCost(); 
 | 
     
 | 
    if( usemaxlotsize or uselotsize or needlotcost ) 
 | 
    { 
 | 
      // Lot size 
 | 
      // lotsizeconst constraint UoM: Unit --> Please note that this means that if different units have a different UoM, 
 | 
      //                                       their PTLotSizeUnder and TripLotSizeUnder will have a different weight in the goal 
 | 
       
 | 
      lotsizeconst := program.TotalLotSizeConstraints().New();  
 | 
      lotsizeconst.Sense( '=' ); 
 | 
      lotsizeconst.RHSValue( this.ScaleConstraintRHS( typeofexpression( lotsizeconst ), 0.0 ) ); 
 | 
      // Term UoM: Unit 
 | 
      lotsizeconst.NewTerm( 1.0 * this.ScaleConstraintTerm( typeof( MPTotalLotSizeVariable ), typeofexpression( lotsizeconst ) ) 
 | 
                            , program.TotalLotSizeVariables().Get()); 
 | 
                           
 | 
      scalefactor_maxptqtyover_maxquantityconst := this.ScaleConstraintTerm( typeof( MPMaxPTQtyOverVariable ), typeofexpression( maxquantityconst ) ); 
 | 
      scalefactor_ptlotsizeunder_lotsizeconst := this.ScaleConstraintTerm( typeof( MPPTLotSizeUnderVariable ), typeofexpression( lotsizeconst ) ); 
 | 
      scalefactor_triplotsizeunder_lotsizeconst := this.ScaleConstraintTerm( typeof( MPTripLotSizeUnderVariable ), typeofexpression( lotsizeconst ) ); 
 | 
      scalefactor_operationinputlotsizeunder_inputlotsizeconst := this.ScaleConstraintTerm( typeof( MPOperationInputLotSizeUnderVariable ), typeofexpression( lotsizeconst ) ); 
 | 
      scalefactor_lotsizeundervar := CapacityPlanningSuboptimizer::GetVariableScaleFactor( typeof( MPPTLotSizeUnderVariable ) );  
 | 
      scalefactor_inputlotsizeundervar := CapacityPlanningSuboptimizer::GetVariableScaleFactor( typeof( MPOperationInputLotSizeUnderVariable ) );  
 | 
      scalefactor_lotsizeundertripvar := CapacityPlanningSuboptimizer::GetVariableScaleFactor( typeof( MPTripLotSizeUnderVariable ) );  
 | 
       
 | 
      // Only those operations with a maximum quantity or lotsize should be considered 
 | 
      traverse( scope.GetOperationInOptimizerRunConst(), Elements, operation, 
 | 
                operation.HasMaximumQuantity() 
 | 
                or operation.HasLotSize() 
 | 
                or operation.HasInputLotSize() ) 
 | 
      { 
 | 
        periods := this.GetPeriodsForOperation( scope, operation ); 
 | 
        periodsfordd := construct( Period_MPs, constcontent ); // periods for dependent demand. Only need these for the input lot sizes - so will not compute if we do not have those 
 | 
     
 | 
        traverse( periods, Elements, period ) 
 | 
        { 
 | 
          pt := constnull( PeriodTaskOperation ); // for efficiency only use type index at most once in loop - but must set to null at start of each loop 
 | 
          coeffmaxprocess := scalefactor_maxptqtyover_maxquantityconst;  
 | 
          if( usemaxlotsize 
 | 
              and operation.HasMaximumQuantity() ) 
 | 
          { 
 | 
            // Penalty for exceeding the maximum quantity of operation 
 | 
            // Term UoM: Unit 
 | 
            maxquantityconst.NewTerm( -1.0 * coeffmaxprocess, program.MaxPTQtyOverVariables().Get( operation, period ) ); 
 | 
           
 | 
            if ( collectvaluesmodel )  
 | 
            { 
 | 
              pt := PeriodTaskOperation::FindPeriodTaskOperationTypeIndex( period.Start(), operation.ID() );  
 | 
              totalprocesssmax := totalprocesssmax  + coeffmaxprocess * guard( maxvalue(  operation.MinimumQuantity() - pt.Quantity(), 0.0 ), 0.0 ) / scalefactormaxptqtyover 
 | 
            } 
 | 
          } 
 | 
     
 | 
          if( ( uselotsize or needlotcost )  
 | 
                and operation.HasLotSize() 
 | 
                and period.IsWithinLotSizeHorizon() ) 
 | 
          { 
 | 
            // Penalty for having additional quantity to reach the lot size multiples 
 | 
            // Term UoM: Unit 
 | 
            coefflotsizeunderterm := scalefactor_ptlotsizeunder_lotsizeconst;  
 | 
            lotsizeconst.NewTerm( -1.0 * coefflotsizeunderterm, program.PTLotSizeUnderVariables().Get( operation, period ) ); 
 | 
            lotsizeconst.NewTerm( -1.0 * coefflotsizeunderterm, program.PTLotSizeOverVariables().Get( operation, period ) ); 
 | 
             
 | 
            if ( collectvaluesmodel )  
 | 
            { 
 | 
              if ( isnull( pt ) ) // for efficiency checking if already set in this loop iteration (above call to type index) 
 | 
              { 
 | 
                pt := PeriodTaskOperation::FindPeriodTaskOperationTypeIndex( period.Start(), operation.ID() ); 
 | 
              }  
 | 
              viol := pt.GetViolationLotsizeForOptimizer( this.SmallestIntegralityTolerance() );  
 | 
              totallotsize := totallotsize + coefflotsizeunderterm * viol / scalefactor_lotsizeundervar;  
 | 
            } 
 | 
          } 
 | 
           
 | 
          // Consider all relevant periods for the dependent demand 
 | 
          if ( operation.HasInputLotSize() and not this.GetPeriodsFromPeriodTaskOperation() ) //Only need periodsfordd for the input lot sizes - so will not compute if we do not have those 
 | 
          { 
 | 
            CapacityPlanningSuboptimizer::GetOperationDependentDemandPeriods( period, operation, &periodsfordd, this.GetPeriodsFromPeriodTaskOperation() ); // membership may not be unique. Output = periodsfordd 
 | 
          } 
 | 
        } // end traverse periods 
 | 
         
 | 
         // Calculate the additional quantity required to reach a multiple of the input lot size. 
 | 
        if( ( uselotsize or needlotcost ) 
 | 
            and operation.HasInputLotSize() ) 
 | 
        { 
 | 
          if ( this.GetPeriodsFromPeriodTaskOperation() )  
 | 
          { 
 | 
            traverse( operation, PeriodTaskOperationInScope.DependentDemand.ProductInStockingPointInPeriodPlanningLeaf.Period_MP, ddperiod )  
 | 
            { 
 | 
              periodsfordd.Add( ddperiod ); // not using above method CapacityPlanningSuboptimizer::GetOperationDependentDemandPeriods for performance 
 | 
            } 
 | 
          } 
 | 
           
 | 
          periodsfordd := periodsfordd.Unique(); 
 | 
          traverse( periodsfordd, Elements, period, 
 | 
                    period.IsWithinLotSizeHorizon() ) 
 | 
          { 
 | 
            traverse( operation,  
 | 
                      OperationInput,  
 | 
                      input, 
 | 
                      input.ProductInStockingPoint_MP().HasInputLotSize() 
 | 
                      and ( input.HasRegularProductforOptimizer() or input.GetIsProductInOptimizerRun( runcontext.IsPostProcessing() ) ) ) 
 | 
            { 
 | 
              // Penalty for having additional quantity to fulfil the input lot size multiples 
 | 
              // Term UoM: Unit 
 | 
              lotsizeconst.NewTerm( -1.0 * scalefactor_operationinputlotsizeunder_inputlotsizeconst, 
 | 
                                    program.OperationInputLotSizeUnderVariables().Get( input, period ) ); 
 | 
              lotsizeconst.NewTerm( -1.0 * scalefactor_operationinputlotsizeunder_inputlotsizeconst, 
 | 
                          program.OperationInputLotSizeOverVariables().Get( input, period ) );                                 
 | 
                                     
 | 
              if ( collectvaluesmodel )  
 | 
              { 
 | 
                inputlotsize := input.ProductInStockingPoint_MP().PISPSpecification().InputLotSize(); 
 | 
                dds := selectset( input, DependentDemand, dd, true, dd.ProductInStockingPointInPeriodPlanningLeaf().Period_MP() = period );  
 | 
                quantitytotal := sum( dds, Elements, dd, true, dd.Quantity() );  
 | 
                 
 | 
                requiredlot := guard( Util::Ceil( quantitytotal / inputlotsize ), 0.0 );  
 | 
                violationinput := CapacityPlanningSuboptimizer::GetLotSizeViolationForVariable( inputlotsize, requiredlot, quantitytotal, this.SmallestIntegralityTolerance() );  
 | 
                totallotsize := totallotsize + ( scalefactor_operationinputlotsizeunder_inputlotsizeconst * violationinput / scalefactor_inputlotsizeundervar );  
 | 
              } 
 | 
            } 
 | 
          } 
 | 
        } 
 | 
      } 
 | 
     
 | 
      traverse( scope.GetTripInOptimizerRun(), Elements, trip, 
 | 
                trip.DepartureUnitPeriod().Period_MP().IsWithinLotSizeHorizon() ) 
 | 
      { 
 | 
        unitperiod := trip.DepartureUnitPeriod(); 
 | 
     
 | 
        if( ( uselotsize or needlotcost ) 
 | 
              and guard( unitperiod.HasLotSize(), false ) ) 
 | 
        { 
 | 
          // Penalty for having additional quantity to reach the lot size multiples 
 | 
          // Term UoM: Unit 
 | 
          coefflotsizeunderterm := scalefactor_triplotsizeunder_lotsizeconst;  
 | 
          lotsizeconst.NewTerm( -1.0 * coefflotsizeunderterm, program.TripLotSizeUnderVariables().Get( trip ) ); 
 | 
          lotsizeconst.NewTerm( -1.0 * coefflotsizeunderterm, program.TripLotSizeOverVariables().Get( trip ) ); 
 | 
          if ( collectvaluesmodel )  
 | 
          { 
 | 
            totallotsize := totallotsize + coefflotsizeunderterm * trip.GetViolationForOptimizer( this.SmallestIntegralityTolerance() ) / scalefactor_lotsizeundertripvar;  
 | 
          } 
 | 
        } 
 | 
      } 
 | 
    } 
 | 
     
 | 
    // workaround because cannot write to attribute 
 | 
    this.StoreValueInProgram( program, 'collect_values_model_TotalLotSizeVariables', totallotsize );  
 | 
    this.StoreValueInProgram( program, 'collect_values_model_TotalProcessMaximumQuantityVariables', totalprocesssmax );  
 | 
     
 | 
    // Calculate the total blending constraint violation 
 | 
    if( runcontext.UseBlending() ) 
 | 
    {    
 | 
      blendingconstr := program.TotalBlendingConstraints().New(); 
 | 
      blendingconstr.Sense( '=' ); 
 | 
      blendingconstr.RHSValue( 0.0 ); 
 | 
     
 | 
      // Term UoM: Unit 
 | 
      blendingconstr.NewTerm( 1.0 * this.ScaleConstraintTerm( typeof( MPTotalBlendingVariable ), typeofexpression( blendingconstr ) ) 
 | 
                              , program.TotalBlendingVariables().Get()); 
 | 
     
 | 
      scalefactor_blendingmaxover_blendingconstr := this.ScaleConstraintTerm( typeof( MPBlendingMaxOverVariable ), typeofexpression( blendingconstr ) ); 
 | 
      scalefactor_blendingminunder_blendingconstr := this.ScaleConstraintTerm( typeof( MPBlendingMinUnderVariable ), typeofexpression( blendingconstr ) ); 
 | 
       
 | 
      traverse( scope.GetOperationInOptimizerRunConst(), Elements, operation, operation.IsBlending() ) 
 | 
      { 
 | 
        periods := this.GetPeriodsForOperation( scope, operation ); 
 | 
        traverse( periods, Elements, period ) 
 | 
        { 
 | 
          // Term UoM: Unit 
 | 
          blendingconstr.NewTerm( -1.0 * scalefactor_blendingmaxover_blendingconstr, program.BlendingMaxOverVariables().Get( operation, period ) ); 
 | 
          blendingconstr.NewTerm( -1.0 * scalefactor_blendingminunder_blendingconstr, program.BlendingMinUnderVariables().Get(  operation, period ) ); 
 | 
        } 
 | 
      } 
 | 
    } 
 | 
     
 | 
    // Calculate the total CO2 emission 
 | 
    totalco2emissionconstr := program.TotalCO2EmissionConstraints().New(); 
 | 
    totalco2emissionconstr.Sense( '=' ); 
 | 
    totalco2emissionconstr.RHSValue( 0.0 ); 
 | 
     
 | 
    // Term UoM: CO2 
 | 
    totalco2emissionconstr.NewTerm( 1.0 * this.ScaleConstraintTerm( typeof( MPTotalCO2EmissionVariable ), typeofexpression( totalco2emissionconstr ) ) 
 | 
                                    , program.TotalCO2EmissionVariables().Get() ); 
 | 
     
 | 
    scalefactor_ptqty_totalco2emissionconstr := this.ScaleConstraintTerm( typeof( MPPTQtyVariable ), typeofexpression( totalco2emissionconstr ) ); 
 | 
    scalefactor_tripnewsupply_totalco2emissionconstr := this.ScaleConstraintTerm( typeof( MPTripNewSupplyVariable ), typeofexpression( totalco2emissionconstr ) ); 
 | 
     
 | 
    co2uom := this.MacroPlan().DefaultCO2ProcessUoM(); 
 | 
     
 | 
    // CO2 emission for operations 
 | 
    traverse( scope.GetOperationInOptimizerRunConst(), Elements, operation ) 
 | 
    { 
 | 
      uomconversionfactor := operation.Unit().UnitOfMeasure_MP().GetConversionFactor( co2uom, null( Product_MP ) ); 
 | 
      co2emission := operation.CO2Emission(); 
 | 
      coeff := uomconversionfactor * co2emission; 
 | 
       
 | 
      periods := this.GetPeriodsForOperation( scope, operation ); 
 | 
       
 | 
      traverse( periods, Elements, period ) 
 | 
      { 
 | 
        // Term UoM: Unit 
 | 
        totalco2emissionconstr.NewTerm( -1.0 * coeff * scalefactor_ptqty_totalco2emissionconstr, program.PTQtyVariables().Get( operation, period ) ); 
 | 
      } 
 | 
       
 | 
      traverse( operation, PeriodTaskOperationInScope, periodtask ) 
 | 
      { 
 | 
        totalco2emission := totalco2emission + coeff * scalefactor_ptqty_totalco2emissionconstr * periodtask.Quantity(); 
 | 
      } 
 | 
    } 
 | 
     
 | 
    // CO2 emission for trips 
 | 
    traverse( pitinrun, Elements, productintrip ) 
 | 
    { 
 | 
      laneleg := productintrip.Trip().LaneLeg(); 
 | 
       
 | 
      uomconversionfactor := laneleg.Lane().Unit().UnitOfMeasure_MP().GetConversionFactor( co2uom, null( Product_MP ) ); 
 | 
      co2emission := laneleg.CO2Emission(); 
 | 
      coeff := uomconversionfactor * co2emission; 
 | 
       
 | 
      // Term UoM: Unit 
 | 
      totalco2emissionconstr.NewTerm( -1.0 * uomconversionfactor * co2emission * scalefactor_tripnewsupply_totalco2emissionconstr, program.TripNewSupplyVariables().Get( productintrip ) ); 
 | 
       
 | 
      totalco2emission := totalco2emission + coeff * scalefactor_tripnewsupply_totalco2emissionconstr * productintrip.Quantity(); 
 | 
    } 
 | 
     
 | 
    // workaround because cannot use attribute 
 | 
    this.StoreValueInProgram( program, 'collect_values_model_MPTotalCO2EmissionVariable', totalco2emission ) 
 | 
  *] 
 | 
  InterfaceProperties { Accessibility: 'Module' } 
 | 
} 
 |