Quintiq file version 2.0
|
#parent: #root
|
Method InitConstraintsForBalanceSplitShelfLife (
|
CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program,
|
const constcontent ProductInStockingPointInPeriods smartplanpispips,
|
constcontent ProductInStockingPoint_MPs intermediatepisps,
|
const ProductInStockingPointInPeriodPlanning pispip,
|
DateTime firstpispipforbalancestart,
|
DateTime lastpispipstart,
|
const RunContextForCapacityPlanning runcontext,
|
const LibOpt_Scope scope,
|
Real scalefactor_demandslack_const,
|
Real scalefactor_tripnewsupply_const,
|
Real scalefactor_invqty_const,
|
Real scalefactor_salesdemandqty_const,
|
Real scalefactor_dependentdemandinpispip_const,
|
Real scalefactor_delayedsalesdemandqty_const,
|
Real scalefactor_periodtaskqty_const,
|
Real scalefactor_expired_const,
|
Real scalefactor_rhs_constr
|
) const
|
{
|
Description:
|
[*
|
To balance the demands and supply in pispip for a pispip that has IsOptShelfLife or IsOptMaturation
|
Dependent demands must be fulfilled in full quantity. Sales demands can be fulfilled halfly.
|
*]
|
TextBody:
|
[*
|
traverse( pispip, ProductInStockingPoint_MP.IncomingShelfLifeDay, islday )
|
{
|
constr := program.BalanceShelfLifeConstraints().New( pispip, islday );
|
constr.Sense( '=' );
|
|
// RHS UoM: PISP
|
rhs := this.GetInventoryRHSForShelfLifeSplitBalanceConstraint( pispip, islday, firstpispipforbalancestart, runcontext, scope );
|
rhs_scaled := rhs * scalefactor_rhs_constr
|
|
constr.RHSValue( rhs_scaled );
|
|
// Inventory end for pispip
|
// Term UoM: PISP
|
constr.NewTerm( -1.0 * scalefactor_invqty_const, program.InvQtyShelfLifeVariables().Get( pispip, islday ) );
|
|
// Penalty for decreasing demand quantity in a pispip for balancing the constraint
|
// (A positive DemandSlack represents a supply that is "magically" created to even out the balance constraint)
|
// Term UoM: PISP
|
// Remove the slack in case we only plan 1 step upstream and it is an intermediary product.
|
if( this.GetIsBalanceSlackAllowed( pispip, smartplanpispips, intermediatepisps, runcontext ) )
|
{
|
constr.NewTerm( 1.0 * scalefactor_demandslack_const,
|
program.DemandSlackShelfLifeVariables().Get( pispip, islday ) );
|
}
|
|
// New supplies from operations added to shelflife 0
|
if ( islday.ShelfLifeDays() = 0 )
|
{
|
ispostprocessing := runcontext.IsPostProcessing();
|
traverse( pispip,
|
ProductInStockingPoint_MP.OperationOutputAvailableForOptimization,
|
output,
|
output.HasRegularProductforOptimizer()
|
or output.GetIsProductInOptimizerRun( ispostprocessing ) )
|
{
|
// Term UoM: Output PISP
|
this.AddConstraintForOperationNewSupplies( output, pispip.Period_MP(), null( Period_MP ),
|
program, 1.0, constr, scalefactor_periodtaskqty_const, scope );
|
}
|
}
|
|
|
// New supplies from trips, for those productintrip that are part of the optimizer run and add islday.ShelfLifeDays to the shelf life
|
traverse( pispip, astype( ProductInStockingPointInPeriodPlanningLeaf ).NewSupply.ProductInTrip, productintrip,
|
scope.Contains( productintrip.ProductInTripInOptimizerRun() )
|
and productintrip.Trip().GetShelfLifeAgeToAdd() = islday.ShelfLifeDays() )
|
{
|
// Term UoM: Output PISP
|
constr.NewTerm( 1.0 * scalefactor_tripnewsupply_const, program.TripNewSupplyVariables().Get( productintrip ) );
|
}
|
|
// Inventory carried forward, if the previous pispip exists and is part of the optimizer run
|
previouspispip := pispip.PreviousPlanningPISPIP();
|
if( not isnull( previouspispip ) and previouspispip.Start() >= firstpispipforbalancestart )
|
{
|
// Term UoM: PISP
|
constr.NewTerm( 1.0 * scalefactor_invqty_const, program.InvQtyShelfLifeVariables().Get( previouspispip, islday ) );
|
}
|
|
// Sales demands added to balance constraint pispip salesdemands
|
traverse( pispip.GetLeafSalesDemandInPeriod(), Elements, lsdip, not lsdip.IsPostponed() or lsdip.IsManuallyPostponed() ) // analogous to non-shelflife balance
|
{
|
// Leaf sales demands added to balance constraint
|
constr.NewTerm( -1.0 * scalefactor_salesdemandqty_const,
|
program.SalesDemandShelfLifeQtyVariables().Get( lsdip, islday ) );
|
}
|
traverse( pispip.GetDisaggregatedSalesDemandInPeriod(), Elements, dsdip, not dsdip.IsPostponed() ) // analogous to non-shelflife balance
|
{
|
// Disaggregated sales demands added to balance constraint
|
constr.NewTerm( -1.0 * scalefactor_salesdemandqty_const,
|
program.DisaggregatedSalesDemandShelfLifeQtyVariables().Get( dsdip, islday ) );
|
}
|
|
// Dependent demands, with slack to prevent infeasibility
|
// Term UoM: PISP
|
traverse( pispip, ProductInStockingPoint_MP.OutgoingShelfLifeDay, oslday )
|
{
|
constr.NewTerm( -1.0 * scalefactor_dependentdemandinpispip_const,
|
program.DependentDemandInPISPIPShelfLifeVariables().Get( pispip, islday, oslday ) );
|
}
|
|
//subtract the number of products that have expired in this pispip
|
if ( pispip.ProductInStockingPoint_MP().IsOptShelfLife() )
|
{
|
constr.NewTerm( -1.0 * scalefactor_expired_const, program.ExpiredForAgeVariables().Get( pispip, islday ) );
|
}
|
|
// Postponed demands which are postponed to this period
|
previouspispip := pispip.PreviousPlanningPISPIP();
|
|
maxnumberofpostponement := pispip.ProductInStockingPoint_MP().OptimizerMaxPostponementPeriod(); // set in init instance for performance
|
for( i := 1;
|
i <= maxnumberofpostponement // within the maximum number of postponement periods
|
and not isnull( previouspispip ); // the previous pispip exists
|
i++ )
|
{
|
traverse( previouspispip.astype( ProductInStockingPointInPeriodPlanningLeaf ), PlanningBaseSalesDemandInPeriodForOptimizationPostponable, sd )
|
{
|
var := sd.GetDelayedSalesDemandShelfLifeQtyVariable( program, pispip.Period_MP(), islday );
|
if( not isnull( var ) )
|
{
|
// Term UoM: PISP
|
constr.NewTerm( -1.0 * scalefactor_delayedsalesdemandqty_const, var );
|
}
|
}
|
previouspispip := previouspispip.PreviousPlanningPISPIP();
|
}
|
}
|
*]
|
InterfaceProperties { Accessibility: 'Module' }
|
}
|