| 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' } | 
| } |