Quintiq file version 2.0 
 | 
#parent: #root 
 | 
Method InitConstraintsForShelfLife ( 
 | 
  CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program, 
 | 
  const RunContextForCapacityPlanning runcontext, 
 | 
  const LibOpt_Scope scope, 
 | 
  const constcontent ProductInStockingPoint_MPs pispsinrun 
 | 
) const 
 | 
{ 
 | 
  Description: 'Initialize the constraints that are related to shelf life' 
 | 
  TextBody: 
 | 
  [* 
 | 
    cpconstname := typeof( MPCumulativeProductionConstraint ); 
 | 
    scalefactor_mass := this.ScaleConstraintTerm( typeof( MPCumulativeProductionVariable ), cpconstname ); // just use same scaling everywhere 
 | 
    scalefactor_rhs_const := this.ScaleConstraintRHS( cpconstname, 1.0 ); 
 | 
     
 | 
    traverse( pispsinrun, Elements, pisp, pisp.IsOptMaturation() or pisp.IsOptShelfLife() )  
 | 
    { 
 | 
      pispipsforstockingpoint_shelflifeormaturation := pisp.PISPInOptimizerRun().GetPISPIPForShelfLifeOptimizer( scope ); // also include extra objects up to shelf life prior to optimizer horizon (possibly historical)  
 | 
       
 | 
      lastpispipstart := DateTime::MaxDateTime() // set in method call    
 | 
      firstpispipstart := DateTime::MinDateTime()  // set in method call 
 | 
      firstafteractualstart := DateTime::MinDateTime()  // set in method call 
 | 
      pisp.GetScopeShelfLifeForPISP( pispipsforstockingpoint_shelflifeormaturation, firstpispipstart, lastpispipstart, firstafteractualstart );  
 | 
       
 | 
      traverse( pispipsforstockingpoint_shelflifeormaturation, Elements, pispip ) 
 | 
      { 
 | 
        traverse( pispip, ProductInStockingPoint_MP.IncomingShelfLifeDay, islday ) 
 | 
        {  
 | 
          this.InitConstraintsForShelfLifeCumulativeProduction( program, pispip, firstpispipstart, lastpispipstart, firstafteractualstart, islday, runcontext, scope );  
 | 
          if ( pisp.IsOptShelfLife() )  
 | 
          { 
 | 
            this.InitConstraintsForShelfLifeCumulativeDemand( program, pispip, lastpispipstart, firstafteractualstart, islday, scope );  
 | 
             
 | 
            { // scope on purpose, define cumulative waste CW[pispip, islday] 
 | 
              constr := program.CumulativeWasteConstraints().New( pispip, islday );    
 | 
              constr.NewTerm( -1.0 * scalefactor_mass, program.CumulativeDemandVariables().Get( pispip, islday ) );  
 | 
              constr.NewTerm( 1.0 * scalefactor_mass, program.CumulativeProductionVariables().Get( pispip, islday) ); 
 | 
              constr.NewTerm( -1.0 * scalefactor_mass, program.CumulativeWasteVariables().Get( pispip, islday ) );  
 | 
            } // end define cumulative waste 
 | 
       
 | 
            { // scope on purpose, upperbound CW[pispip, islday] <= CP[pispip, islday] 'no more waste than is produced'  
 | 
              constr := program.CumulativeWasteUpperBoundByProductionConstraints().New( pispip, islday );  
 | 
              constr.NewTerm(  1.0 * scalefactor_mass, program.CumulativeWasteVariables().Get( pispip, islday ) );  
 | 
              constr.NewTerm( -1.0 * scalefactor_mass, program.CumulativeProductionVariables().Get( pispip, islday ) );  
 | 
            }  
 | 
       
 | 
            { // scope on purpose define Waste[pispip, islday]  
 | 
              constr := program.WasteConstraints().New( pispip, islday );  
 | 
              constr.NewTerm( -1.0 * scalefactor_mass, program.WasteVariables().Get( pispip, islday ) );  
 | 
              constr.NewTerm(  1.0 * scalefactor_mass, program.CumulativeWasteVariables().Get( pispip, islday ) );  
 | 
               
 | 
              var := program.CumulativeWasteVariables().Find( pispip.PreviousPlanningPISPIP(), islday );  
 | 
              if ( not isnull( var ) ) // once var = null then we are at the 1st period of extra pispip prior to opt horizon (for which we make sure we always have enough via method ShelfLifeExtendHistoricalPeriods 
 | 
              { 
 | 
                constr.NewTerm( -1.0 * scalefactor_mass, var );  
 | 
              } 
 | 
            } // end define waste 
 | 
             
 | 
            { // scope intentional, define ExpiredForAge, add terms below 
 | 
              constr := program.ExpiredForAgeConstraints().New( pispip, islday );  
 | 
              constr.NewTerm( -1.0 * scalefactor_mass, program.ExpiredForAgeVariables().Get( pispip, islday ) );  
 | 
            } 
 | 
          } 
 | 
        } // end travers islday   
 | 
         
 | 
        if ( pisp.IsOptShelfLife() )  
 | 
        { 
 | 
          { // scope intentional - define InvQty blocked 
 | 
            constr := program.InventoryQtyBlockedConstraints().New( pispip );  
 | 
            constr.NewTerm( -1.0 * scalefactor_mass, program.InvQtyBlockedVariables().Get( pispip ) );  
 | 
            // add terms below 
 | 
             
 | 
            // set lower bound InvQty[pispip] >= InvQtyBlocked[pispip] 
 | 
            if ( scope.Contains( pispip.PISPIPInOptimizerRun() ) )  
 | 
            // can avoid scope.Contains(  pispip.PISPIPInOptimizerRun() ) ) - same transaction 
 | 
            // we only have InvQty for the optimizer scope and not the extra pispip prior to optimizer scope 
 | 
            { 
 | 
              blockconstr := program.InventoryQtyBlockedLowerBoundConstraints().New( pispip );  
 | 
              blockconstr.NewTerm( -1.0 * scalefactor_mass, program.InvQtyVariables().Get( pispip ) );  
 | 
              blockconstr.NewTerm( 1.0 * scalefactor_mass, program.InvQtyBlockedVariables().Get( pispip ) );                                                    
 | 
               
 | 
              // remove block on inventory supply with manufacturing date = pispip. This is production that is not yet in inventory so we should not block it 
 | 
              // inventory supply in future period with manufacture date = current period start is considered production for the current period 
 | 
              nextpsipipstoconsider := pispip.GetNextPISPIPWithinShelfLife( lastpispipstart );  
 | 
              traverse( nextpsipipstoconsider, Elements.Supply_MP.astype( InventorySupply ), invsup, invsup.Quantity() > 0.0 and invsup.GetManufacturingPISPIP() = pispip )  
 | 
              { 
 | 
                constr.RHSValue( constr.RHSValue() + scalefactor_rhs_const * invsup.Quantity() );  
 | 
              } 
 | 
            }  
 | 
          } // end define InvQtyBlocked  
 | 
        } 
 | 
      } // end traverse pispip 
 | 
       
 | 
      if ( pisp.IsOptShelfLife() )  
 | 
      { 
 | 
        // 
 | 
        // ExpiredForAge[pispip, age], InvQtyBlocked[pispip] - adding variable terms 
 | 
        // 
 | 
        traverse( pispipsforstockingpoint_shelflifeormaturation, Elements, pispip ) 
 | 
        { 
 | 
          // add terms to expired for age constraint 
 | 
          expirepispip := pispip.GetExpirePISPIPShelfLife();   
 | 
               
 | 
          if ( guard( expirepispip.Start() <= lastpispipstart, false ) )  
 | 
          { 
 | 
            traverse( pispip, ProductInStockingPoint_MP.IncomingShelfLifeDay, islday  )  
 | 
            { 
 | 
              constr := program.ExpiredForAgeConstraints().Get( expirepispip, islday );  
 | 
              constr.NewTerm( 1.0 * scalefactor_mass, program.WasteVariables().Get( pispip, islday ) );  
 | 
            } 
 | 
          } 
 | 
           
 | 
          // make sure inventory is blocked from pispip to lastusablepispip by adding to InvQtyBlocked 
 | 
          currentpispip := pispip;  
 | 
          done := currentpispip = expirepispip or guard( currentpispip.Start() > lastpispipstart, true );  
 | 
          while ( not done )  
 | 
          { 
 | 
            traverse( pispip, ProductInStockingPoint_MP.IncomingShelfLifeDay, islday )  
 | 
            { 
 | 
              if ( currentpispip.Start() >= pispip.Start() + islday.ShelfLifeAsDuration() )  
 | 
              { 
 | 
                constr := program.InventoryQtyBlockedConstraints().Get( currentpispip );  
 | 
                constr.NewTerm( 1.0 * scalefactor_mass, program.WasteVariables().Get( pispip, islday ) );   
 | 
              } 
 | 
            } 
 | 
            currentpispip := currentpispip.NextPlanningPISPIP();  
 | 
            done := currentpispip = expirepispip or guard( currentpispip.Start() > lastpispipstart, true ); 
 | 
          } 
 | 
        } // end traverse pispip 
 | 
      } 
 | 
    } // end traverse PISP 
 | 
     
 | 
    this.InitConstraintsForDependentDemandsInPISPIPForShelfLife( program, runcontext, scope, pispsinrun ); 
 | 
  *] 
 | 
  InterfaceProperties { Accessibility: 'Module' } 
 | 
} 
 |