Quintiq file version 2.0 
 | 
#parent: #root 
 | 
Method InitConstraintsGoalsForDriverInventoryHolding ( 
 | 
  CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program, 
 | 
  const RunContextForCapacityPlanning runcontext, 
 | 
  const LibOpt_Scope scope, 
 | 
  const constcontent ProductInStockingPoint_MPs pispsinrun 
 | 
) const 
 | 
{ 
 | 
  Description: 'Init constraints goals for PISPIPs' 
 | 
  TextBody: 
 | 
  [* 
 | 
    // Inventory holding accounts 
 | 
     
 | 
    icconstname := typeof( MPDriverInventoryHoldingConstraint ); 
 | 
    driverinventoryholding_varname := typeof( MPDriverInventoryHoldingVariable ); 
 | 
    invqty_varname := typeof( MPInvQtyVariable ); 
 | 
    partialoperationdemandqty_varname := typeof( MPPartialOperationDemandQtyVariable ); 
 | 
    tripdemandqty_varname := typeof( MPTripDemandQtyVariable ); 
 | 
     
 | 
    scalefactor_driver_icconst := this.ScaleConstraintTerm( driverinventoryholding_varname, icconstname ); 
 | 
    scalefactor_invqty_icconst := this.ScaleConstraintTerm( invqty_varname, icconstname ); 
 | 
    scalefactor_partialoperationdemandqty_icconst := this.ScaleConstraintTerm( partialoperationdemandqty_varname, icconstname ); 
 | 
    scalefactor_tripdemandqty_icconst := this.ScaleConstraintTerm( tripdemandqty_varname, icconstname ); 
 | 
     
 | 
    scalefactor_rhs_icconst := this.ScaleConstraintRHS( icconstname, 1.0 ); 
 | 
     
 | 
    ispostprocessing := runcontext.IsPostProcessing();  
 | 
     
 | 
    driver := select( this, MacroPlan.AccountCostDriver, driver, driver.Name() = Translations::MP_AccountAssignmentCostDriverInventoryHolding() ); // unique 
 | 
    traverse( scope.GetAccountsInOptimizerRunConst(), Elements, account, account.HasInventoryHoldingAssignment() ) // condition holds implies driver not null 
 | 
    { 
 | 
      // Inventory cost of each account = inventory quantity * cost + pre-processing quantity * day * cost per day + post-processing quantity * day * cost per day 
 | 
      // icconst UoM: Monetary 
 | 
      icconst := program.DriverInventoryHoldingConstraints().New( account, driver ); 
 | 
      icconst.Sense( '=' );  
 | 
      icconst.RHSValue( 0.0 * scalefactor_rhs_icconst ); 
 | 
      // Term UoM: Monetary 
 | 
      icconst.NewTerm( 1.0 * scalefactor_driver_icconst, program.DriverInventoryHoldingVariables().Get( account, driver ) ); 
 | 
     
 | 
      traverse( pispsinrun, Elements, pisp )  
 | 
      { 
 | 
        traverse( pisp, PISPAccountForInventoryHoldingOptimizer, aa, aa.AccountCostDriver() = driver and aa.Account_MP() = account )  
 | 
        // Only consider those pispips that are part of this optimizer run 
 | 
        // Only include those pispips where the product is included. 
 | 
        {  
 | 
          if ( runcontext.IsMetaIteration() )  
 | 
          { 
 | 
            // correction for pispip past scope 
 | 
            last := pisp.LatestPISPIPInScope();  
 | 
            current := guard( last.Next().astype(  ProductInStockingPointInPeriodPlanningLeaf ), null(  ProductInStockingPointInPeriodPlanningLeaf ) );  
 | 
             
 | 
            while ( not isnull( current ) )  
 | 
            { 
 | 
              var := program.PosInvQtyPastLastVariables().Get(  current );  
 | 
              icconst.NewTerm( -current.GetBaseInventoryHoldingCostPerQuantity( aa ) * scalefactor_invqty_icconst,  
 | 
                                 var );               // Inventory cost  
 | 
              current := current.NextPlanningPISPIP().astype( ProductInStockingPointInPeriodPlanningLeaf );                             
 | 
            }   
 | 
          } 
 | 
              
 | 
          traverse( aa.GetLeafPISPIPsInScope(),  
 | 
                    Elements,  
 | 
                    pispip )  
 | 
          { 
 | 
       
 | 
            if( pispip.ProductInStockingPoint_MP().IsNegativeInventoryAllowed() ) 
 | 
            { 
 | 
              // Negative inventory allowed case: only consider positive inventory 
 | 
              // Term: -holdingcostperqty * (Pos)InvQty variable 
 | 
              // UoM:    [Monetary/PISP]    *   [PISP] 
 | 
              icconst.NewTerm( -pispip.GetBaseInventoryHoldingCostPerQuantity( aa ) * scalefactor_invqty_icconst,  
 | 
                               program.PosInvQtyVariables().Get( pispip ) );               // Inventory cost  
 | 
            } 
 | 
            else 
 | 
            { 
 | 
              // Regular case: no negative inventory 
 | 
              icconst.NewTerm( -pispip.GetBaseInventoryHoldingCostPerQuantity( aa ) * scalefactor_invqty_icconst,  
 | 
                                program.InvQtyVariables().Get( pispip ) );               // Inventory cost    
 | 
            } 
 | 
         
 | 
            pispipperiod := pispip.Period_MP(); 
 | 
       
 | 
            // Dependent demands WIP cost for operations that are part of this optimizer run 
 | 
            if ( this.GetPeriodsFromPeriodTaskOperation() )  
 | 
            {  
 | 
              traverse( pispip, DependentDemandOperation, dd ) // better path for performance 
 | 
              { 
 | 
                pto := dd.PeriodTaskOperation();  
 | 
                operation := pto.Operation();  
 | 
                if ( operation.HasLeadTime() )  
 | 
                { 
 | 
                  input := dd.ProcessInput().astype( OperationInput );  
 | 
                  if ( ( input.HasRegularProductforOptimizer() or input.GetIsProductInOptimizerRun( ispostprocessing ) ) 
 | 
                       and not isnull( input.PISPwhenAvailableForOptimization() )  
 | 
                       and scope.Contains( pto.PeriodTaskOperationInOptimizerRun() ) )   
 | 
                  { 
 | 
                    cost := pispip.GetBaseWIPCostPerQuantityPerDay( aa ) * operation.LeadTime().DaysAsReal(); 
 | 
                    traverse( pto, NewSupply.ProductInStockingPointInPeriodPlanningLeaf.Period_MP, nsperiod, not nsperiod = pispipperiod )  
 | 
                    { 
 | 
                      partialoperationdemandqtyvar := program.PartialOperationDemandQtyVariables().Find( input, pispipperiod, nsperiod ); 
 | 
                      // If the variable does not exist, then this combination of operation and period is not considered by the optimizer 
 | 
                      // Therefore, this term should then also not exist 
 | 
                      if( not isnull( partialoperationdemandqtyvar ) ) 
 | 
                      { 
 | 
                        // Term:    -cost      * PartialOperationDemandQty variable 
 | 
                        // UoM:  [Monetary/PISP] *           [PISP] 
 | 
                        icconst.NewTerm( -cost * scalefactor_partialoperationdemandqty_icconst, partialoperationdemandqtyvar ); 
 | 
                      } 
 | 
                    } 
 | 
                  } 
 | 
                } 
 | 
              } 
 | 
            } 
 | 
            else 
 | 
            { 
 | 
              traverse( pispip,  
 | 
                        ProductInStockingPoint_MP.OperationInputAvailableForOptimization,  
 | 
                        input, 
 | 
                        guard( scope.Contains( input.Operation().OperationInOptimizerRun() ), false ) 
 | 
                        and input.HasRegularProductforOptimizer() or input.GetIsProductInOptimizerRun( ispostprocessing ) ) 
 | 
              { 
 | 
                operation := input.Operation(); 
 | 
         
 | 
                if( operation.HasLeadTime() ) 
 | 
                { 
 | 
                  cost := pispip.GetBaseWIPCostPerQuantityPerDay( aa ) 
 | 
                          * operation.LeadTime().DaysAsReal(); 
 | 
                           
 | 
                  ptperiods := CapacityPlanningSuboptimizer::GetOperationPeriodTaskPeriodsForPreprocessing( pispipperiod, operation); 
 | 
                               
 | 
                  traverse( ptperiods, Elements, ptperiod, 
 | 
                            ptperiod <> pispipperiod )              // WIP cost incurred for dependent demand that happens earlier than the period task. 
 | 
                  { 
 | 
                    partialoperationdemandqtyvar := program.PartialOperationDemandQtyVariables().Find( input, pispipperiod, ptperiod ); 
 | 
                    // If the variable does not exist, then this combination of operation and period is not considered by the optimizer 
 | 
                    // Therefore, this term should then also not exist 
 | 
                    if( not isnull( partialoperationdemandqtyvar ) ) 
 | 
                    { 
 | 
                      // Term:    -cost      * PartialOperationDemandQty variable 
 | 
                      // UoM:  [Monetary/PISP] *           [PISP] 
 | 
                      icconst.NewTerm( -cost * scalefactor_partialoperationdemandqty_icconst, partialoperationdemandqtyvar ); 
 | 
                    } 
 | 
                  } 
 | 
                } 
 | 
              } 
 | 
            } 
 | 
       
 | 
            // Inventory cost for trips that are part of this optimizer run 
 | 
            pits := selectset(  pispip, DependentDemandTrip.ProductInTrip, productintrip,  
 | 
                      scope.Contains( productintrip.ProductInTripInOptimizerRun() ) ) ;  
 | 
            basecostperquantityperday := ifexpr(  pits.Size() > 0, pispip.GetBaseWIPCostPerQuantityPerDay( aa ),  0.0 );  
 | 
                                    
 | 
            traverse( pits, Elements, productintrip ) 
 | 
            { 
 | 
              cost := basecostperquantityperday * productintrip.Trip().LeadTime().DaysAsReal(); 
 | 
              // Term:   -cost      * TripDemandQty variable 
 | 
              // UoM: [Monetary/PISP] *         [PISP] 
 | 
              icconst.NewTerm( -cost * scalefactor_tripdemandqty_icconst, program.TripDemandQtyVariables().Get( productintrip ) ); 
 | 
            } 
 | 
          } // end traverse leaf pispips 
 | 
        } // end traverse account assignment (PISPAccount) 
 | 
      } // end traverse pisp in scope 
 | 
    } // end traverse accounts 
 | 
  *] 
 | 
  InterfaceProperties { Accessibility: 'Module' } 
 | 
} 
 |