Quintiq file version 2.0
|
#parent: #root
|
Method InitConstraintsForBalanceNoShelfLife (
|
CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program,
|
const constcontent ProductInStockingPointInPeriods smartplanpispips,
|
constcontent ProductInStockingPoint_MPs intermediatepisps,
|
const ProductInStockingPointInPeriodPlanningLeaf pispip,
|
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
|
Dependent demands must be fulfilled in full quantity. Sales demands can be fulfilled halfly.
|
*]
|
TextBody:
|
[*
|
// SUM( factor * relativeduration * PTQty ( operationoutput.operation, ptperiod )
|
// + SUM( TripNewSupply ( newsupply.productintrip )
|
// + InvQty ( Previous )
|
// - SUM( SalesDemandQty ( leaf sales demand ) )
|
// - SUM( DelayedSalesDemandQty ( delayed leaf sales demand ) )
|
// - SUM( DisaggregatedSalesDemandQty ( disaggregated sales demand ) )
|
// - SUM( DelayedDisaggregatedSalesDemandQty( delayed disaggregated sales demand ) )
|
// - DependentDemandInPISPIP
|
// - TargetInvQty
|
// - UnallocQty
|
// - Expiry (pispip)
|
// = - InventorySupplyQuantity ∀ pispip where operationoutput, newsupply, sales demands ∈ pispip
|
|
|
|
|
// unallocated supply = new supply + inventory supply + inventory carried forward - demands (sales demands ( Leaf sales demands and Disaggregated sales demands), dependent demand, inventory demand )
|
// constr constraint UoM: PISP
|
|
|
|
constr := program.BalanceConstraints().New( pispip );
|
constr.Sense( '=' );
|
|
// RHS UoM: PISP
|
rhs := this.GetInventoryRHSForBalanceConstraint( pispip, 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.InvQtyVariables().Get( pispip ) );
|
|
// 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.DemandSlackVariables().Get( pispip ) );
|
}
|
|
// New supplies from operations
|
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
|
traverse( pispip, NewSupplyTrip.ProductInTrip, productintrip )
|
{
|
// Term UoM: Output PISP
|
pitnsvar := program.TripNewSupplyVariables().Find( productintrip );
|
if ( not isnull( pitnsvar ) ) // if not isnull means in scope and vice-versa
|
{
|
constr.NewTerm( scalefactor_tripnewsupply_const, pitnsvar );
|
}
|
}
|
|
// 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() >= pispip.ProductInStockingPoint_MP().EarliestPISPIPInScope().Start() )
|
{
|
// Term UoM: PISP
|
constr.NewTerm( scalefactor_invqty_const,
|
program.InvQtyVariables().Get( previouspispip ) );
|
}
|
|
// Sales demands added to balance constraint pispip salesdemands
|
traverse( pispip.GetLeafSalesDemandInPeriod(), Elements, lsdip, not lsdip.IsPostponed() or lsdip.IsManuallyPostponed() ) // note GetLeafSalesDemandInPeriod can include postponed sd, but non manual postponed
|
{ // sd is never added to scope (only the original) (*)
|
// Leaf sales demands added to balance constraint
|
constr.NewTerm( -1.0 * scalefactor_salesdemandqty_const,
|
program.SalesDemandQtyVariables().Get( lsdip ) );
|
}
|
|
traverse( pispip.GetDisaggregatedSalesDemandInPeriod(),
|
Elements,
|
dsdip,
|
not dsdip.IsPostponed() ) // similar remark as (*) above. Note disaggregates sales demand cannot be manually postponed
|
{
|
// Disaggregated sales demands added to balance constraint
|
constr.NewTerm( -1.0 * scalefactor_salesdemandqty_const,
|
program.DisaggregatedSalesDemandQtyVariables().Get( dsdip ) );
|
}
|
|
// Dependent demands, with slack to prevent infeasibility
|
// Term UoM: PISP
|
constr.NewTerm( -1.0 * scalefactor_dependentdemandinpispip_const,
|
program.DependentDemandInPISPIPVariables().Get( pispip ) );
|
|
|
if ( pispip.ProductInStockingPoint_MP().IsOptShelfLife() ) // note we always include the unsplit balance constraint defined in the current method
|
{ // so pispip can still have shelf life defined
|
constr.NewTerm( -1.0 * scalefactor_expired_const, program.ExpiredVariables().Get( pispip ) );
|
}
|
|
// PISPs with allowed negative inventory
|
// Define positive inventory to allow inventory cost calculation
|
if( pispip.ProductInStockingPoint_MP().IsNegativeInventoryAllowed() )
|
{
|
posinvconst := program.PositiveInventoryConstraints().New( pispip );
|
posinvconst.Sense( '>=' );
|
posinvconst.RHSValue( 0.0 );
|
|
posinvconst.NewTerm( scalefactor_invqty_const, program.PosInvQtyVariables().Get( pispip ) );
|
posinvconst.NewTerm( -1.0 * scalefactor_invqty_const,program.InvQtyVariables().Get( pispip ) );
|
}
|
|
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 := null( MPVariable );
|
|
var := sd.GetDelayedSalesDemandQtyVariable( program, pispip.Period_MP() );
|
|
if( not isnull( var ) )
|
{
|
// Term UoM: PISP
|
constr.NewTerm( -1.0 * scalefactor_delayedsalesdemandqty_const, var );
|
}
|
}
|
previouspispip := previouspispip.PreviousPlanningPISPIP();
|
}
|
*]
|
InterfaceProperties { Accessibility: 'Module' }
|
}
|