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