Quintiq file version 2.0 
 | 
#parent: #root 
 | 
Method InitConstraintsForDemandFulfillmentInPISPIP ( 
 | 
  CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program, 
 | 
  const RunContextForCapacityPlanning runcontext, 
 | 
  const LibOpt_Scope scope, 
 | 
  const constcontent ProductInStockingPointInPeriodPlannings pispipsinrun, 
 | 
  Number threadnr 
 | 
) const 
 | 
{ 
 | 
  Description: 'Calculate the total demand fulfillment for a pispip' 
 | 
  TextBody: 
 | 
  [* 
 | 
    //   SUM( OperationDemandQty ( operationinput, period ) ) 
 | 
    // + SUM( TripDemandQty(dependentdemand.productintrip) ) 
 | 
    // + SUM( SalesDemandQty ( leaf sales demand ) ) 
 | 
    // + SUM( DelayedSalesDemandQty(delayed leaf sales demand ) ) 
 | 
    // + SUM( DisaggregatedSalesDemandQty ( disaggregated sales demand ) ) 
 | 
    // + SUM( DelayedDisaggregatedSalesDemandQty( delayed disaggregated sales demand ) ) 
 | 
    // – DemandFulfillmentInPISPIP 
 | 
    // = 0   ∀ pispip where operationinput, period, sales demands, dependentdemand, ∈ pispip 
 | 
     
 | 
    constname := typeof( MPDemandFulfillmentInPISPIPConstraint ); 
 | 
     
 | 
    scalefactor_demandfulfillmentinpispip_const := this.ScaleConstraintTerm( typeof( MPDemandFulfillmentInPISPIPVariable ), constname ); 
 | 
    scalefactor_operationdemandqty_const := this.ScaleConstraintTerm( typeof( MPOperationDemandQtyVariable ), constname ); 
 | 
    scalefactor_tripdemandqty_const := this.ScaleConstraintTerm( typeof( MPTripDemandQtyVariable ), constname ); 
 | 
    scalefactor_salesdemandqty_const := this.ScaleConstraintTerm( typeof( MPSalesDemandQtyVariable ), constname ); 
 | 
    scalefactor_delayedsalesdemandqty_const := this.ScaleConstraintTerm( typeof( MPDelayedSalesDemandQtyVariable ), constname ); 
 | 
     
 | 
    scalefactor_rhs_const := this.ScaleConstraintRHS( constname, 1.0 ); 
 | 
     
 | 
    // The demand fulfillment constraint should be specified for all pispips whose inventory specification in days is considered 
 | 
    pispips := this.GetPISPIPsForDemandFulfillment( scope, pispipsinrun ); 
 | 
     
 | 
    // Calculate the total demand fulfillment for used in inventory specification in days. 
 | 
    traverse( pispips, Elements, pispip, CapacityPlanningSuboptimizer::GetThreadNr( this.ThreadAParameter(), this.ThreadBParameter(), pispip.PreThreadNr() ) = threadnr  ) 
 | 
    { 
 | 
      // const constraint UoM: PISP 
 | 
      const := program.DemandFulfillmentInPISPIPConstraints().New( pispip ); 
 | 
      const.Sense( '=' ); 
 | 
      const.RHSValue( 0.0 * scalefactor_rhs_const ); 
 | 
     
 | 
      // Term UoM: PISP 
 | 
      const.NewTerm( -1.0 * scalefactor_demandfulfillmentinpispip_const, 
 | 
                     program.DemandFulfillmentInPISPIPVariables().Get( pispip ) ); 
 | 
     
 | 
      traverse( pispip.GetLeavesOfProductDimensionConst(),  
 | 
                Elements.astype( ProductInStockingPointInPeriodPlanningLeaf ),  
 | 
                activepispip, 
 | 
                pispip.IsLeafPlanning() or not activepispip.ProductInStockingPoint_MP().IsNegativeInventoryAllowed()  ) 
 | 
      { 
 | 
        // The leaf pispip only have variables if they are part of this optimizer run 
 | 
        if( activepispip = pispip // we know pispip is in scope so we can skip the check (for leaves this will be the only activepispip) 
 | 
            or scope.Contains( activepispip.PISPIPInOptimizerRun() ) )  
 | 
        { 
 | 
          // Dependent demands for operations 
 | 
          traverse( activepispip, ProductInStockingPoint_MP.OperationInputAvailableForOptimization, input ) 
 | 
          { 
 | 
            var := program.OperationDemandQtyVariables().Find( input, pispip.Period_MP() ); 
 | 
            // The OperationDemandQty variable will be null if this combination of operation and period are not part of this optimizer run 
 | 
            // In that case, this variable is not relevant and should not be added to this constraint 
 | 
            // Also if the product is not part of the optimizer run, we should not add this term 
 | 
            if( not isnull( var ) 
 | 
                and ( input.HasRegularProductforOptimizer()  
 | 
                      or input.GetIsProductInOptimizerRun( runcontext.IsPostProcessing() ) ) ) 
 | 
            { 
 | 
              // Term UoM: PISP 
 | 
              const.NewTerm( 1.0 * scalefactor_operationdemandqty_const, 
 | 
                             var ); 
 | 
            } 
 | 
            // If the variable is null (and the decision is thus out of scope of the optimizer ), then we need to update the RHS to reflect this frozen quantity 
 | 
            else 
 | 
            { 
 | 
              ptoperation := PeriodTaskOperation::FindPeriodTaskOperationTypeIndex( pispip.Period_MP().Start(), input.Operation().ID() ); 
 | 
              dependentdemand := select( ptoperation, DependentDemand, dd, dd.ProcessInput() = input ); 
 | 
              if( not isnull( dependentdemand ) ) 
 | 
              { 
 | 
                newrhs := this.GetConstraintRHS( const, scalefactor_rhs_const ) - dependentdemand.FulfilledQuantity(); 
 | 
                const.RHSValue( newrhs * scalefactor_rhs_const ); 
 | 
              } 
 | 
            } 
 | 
          } 
 | 
       
 | 
          // Dependent demands for trips 
 | 
          traverse( activepispip, DependentDemandTrip.ProductInTrip, productintrip ) 
 | 
          { 
 | 
            if( scope.Contains( productintrip.ProductInTripInOptimizerRun() ) )  
 | 
            { 
 | 
              // Term UoM: PISP 
 | 
              const.NewTerm( 1.0 * scalefactor_tripdemandqty_const, program.TripDemandQtyVariables().Get( productintrip ) ); 
 | 
            } 
 | 
            else if( productintrip.Quantity() > 0.0 ) 
 | 
            { 
 | 
              fulfilledqty := guard(  productintrip.DependentDemand().FulfilledQuantity(), 0.0 );  
 | 
              newrhs := this.GetConstraintRHS( const, scalefactor_rhs_const ) - fulfilledqty; 
 | 
              const.RHSValue( newrhs * scalefactor_rhs_const ); 
 | 
            } 
 | 
          } 
 | 
     
 | 
          // Sales demands 
 | 
          traverse( activepispip, PlanningBaseSalesDemandInPeriodForOptimization, sd ) 
 | 
          { 
 | 
            if( sd.istype( LeafSalesDemandInPeriod ) ) 
 | 
            { 
 | 
              // Term UoM: PISP 
 | 
              const.NewTerm( 1.0 * scalefactor_salesdemandqty_const, program.SalesDemandQtyVariables().Get( sd.astype( LeafSalesDemandInPeriod ) ) ); 
 | 
            } 
 | 
            else if( sd.istype( DisaggregatedSalesDemandInPeriod ) ) 
 | 
            { 
 | 
              const.NewTerm( 1.0 * scalefactor_salesdemandqty_const, program.DisaggregatedSalesDemandQtyVariables().Get( sd.astype( DisaggregatedSalesDemandInPeriod ) ) ); 
 | 
            }                     
 | 
          } 
 | 
           
 | 
          // Calculating the postponed sales demand fulfillment 
 | 
          // E.g., if the current period is period 11, max postponment period = 3, this retrieves postponed sales demands to period 11 from period 10, 9, 8. 
 | 
          maxpostponedperiod := pispip.ProductInStockingPoint_MP().OptimizerMaxPostponementPeriod(); // set in in init instance per pisp for performance  
 | 
          previouspispip := activepispip.PreviousPlanningPISPIP(); 
 | 
     
 | 
          for( i := 1; 
 | 
               i <= maxpostponedperiod                     // within the maximum number of postponement periods 
 | 
               and not isnull( previouspispip );            // the next pispip exists 
 | 
               i++ ) 
 | 
          { 
 | 
            traverse( previouspispip.astype( ProductInStockingPointInPeriodPlanningLeaf ), PlanningBaseSalesDemandInPeriodForOptimizationPostponable, sd ) 
 | 
            { 
 | 
              var := sd.GetDelayedSalesDemandQtyVariable( program, activepispip.Period_MP() ); 
 | 
     
 | 
              if( not isnull( var ) ) 
 | 
              { 
 | 
                // Term UoM: PISP 
 | 
                const.NewTerm( 1.0 * scalefactor_delayedsalesdemandqty_const, var ); 
 | 
              } 
 | 
            } 
 | 
            previouspispip := previouspispip.PreviousPlanningPISPIP(); 
 | 
          } 
 | 
        } 
 | 
        // If the leaf pispip is not in the optimizer run we still need to update the RHS 
 | 
        else 
 | 
        { 
 | 
          // The RHS should be updated for the dependent demands that are related to the pispip that is out of scope of this optimizer run 
 | 
          traverse( activepispip, DependentDemandOperation, dependentdemand ) 
 | 
          { 
 | 
            newrhs := this.GetConstraintRHS( const, scalefactor_rhs_const ) - dependentdemand.FulfilledQuantity(); 
 | 
            const.RHSValue( newrhs * scalefactor_rhs_const ); 
 | 
          } 
 | 
           
 | 
          traverse( activepispip, DependentDemandTrip.ProductInTrip, pit, not scope.Contains( pit.ProductInTripInOptimizerRun() ) ) 
 | 
          { 
 | 
            newrhs := this.GetConstraintRHS( const, scalefactor_rhs_const ) - pit.Quantity() 
 | 
            const.RHSValue( newrhs * scalefactor_rhs_const ); 
 | 
          } 
 | 
        } 
 | 
      } 
 | 
    } 
 | 
  *] 
 | 
  InterfaceProperties { Accessibility: 'Module' } 
 | 
} 
 |