Quintiq file version 2.0
|
#parent: #root
|
Method InitConstraintsForDemandFulfillmentInPISPIP (
|
CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program,
|
const RunContextForCapacityPlanning runcontext,
|
const LibOpt_Scope scope,
|
const constcontent ProductInStockingPointInPeriodPlannings pispipsinrun,
|
Number threadnr
|
) const
|
{
|
Description: 'Calculate the total demand fulfillment for a pispip'
|
TextBody:
|
[*
|
// SUM( OperationDemandQty ( operationinput, period ) )
|
// + SUM( TripDemandQty(dependentdemand.productintrip) )
|
// + SUM( SalesDemandQty ( leaf sales demand ) )
|
// + SUM( DelayedSalesDemandQty(delayed leaf sales demand ) )
|
// + SUM( DisaggregatedSalesDemandQty ( disaggregated sales demand ) )
|
// + SUM( DelayedDisaggregatedSalesDemandQty( delayed disaggregated sales demand ) )
|
// – DemandFulfillmentInPISPIP
|
// = 0 ∀ pispip where operationinput, period, sales demands, dependentdemand, ∈ pispip
|
|
constname := typeof( MPDemandFulfillmentInPISPIPConstraint );
|
|
scalefactor_demandfulfillmentinpispip_const := this.ScaleConstraintTerm( typeof( MPDemandFulfillmentInPISPIPVariable ), constname );
|
scalefactor_operationdemandqty_const := this.ScaleConstraintTerm( typeof( MPOperationDemandQtyVariable ), constname );
|
scalefactor_tripdemandqty_const := this.ScaleConstraintTerm( typeof( MPTripDemandQtyVariable ), constname );
|
scalefactor_salesdemandqty_const := this.ScaleConstraintTerm( typeof( MPSalesDemandQtyVariable ), constname );
|
scalefactor_delayedsalesdemandqty_const := this.ScaleConstraintTerm( typeof( MPDelayedSalesDemandQtyVariable ), constname );
|
|
scalefactor_rhs_const := this.ScaleConstraintRHS( constname, 1.0 );
|
|
// The demand fulfillment constraint should be specified for all pispips whose inventory specification in days is considered
|
pispips := this.GetPISPIPsForDemandFulfillment( scope, pispipsinrun );
|
|
// Calculate the total demand fulfillment for used in inventory specification in days.
|
traverse( pispips, Elements, pispip, CapacityPlanningSuboptimizer::GetThreadNr( this.ThreadAParameter(), this.ThreadBParameter(), pispip.PreThreadNr() ) = threadnr )
|
{
|
// const constraint UoM: PISP
|
const := program.DemandFulfillmentInPISPIPConstraints().New( pispip );
|
const.Sense( '=' );
|
const.RHSValue( 0.0 * scalefactor_rhs_const );
|
|
// Term UoM: PISP
|
const.NewTerm( -1.0 * scalefactor_demandfulfillmentinpispip_const,
|
program.DemandFulfillmentInPISPIPVariables().Get( pispip ) );
|
|
traverse( pispip.GetLeavesOfProductDimensionConst(),
|
Elements.astype( ProductInStockingPointInPeriodPlanningLeaf ),
|
activepispip,
|
pispip.IsLeafPlanning() or not activepispip.ProductInStockingPoint_MP().IsNegativeInventoryAllowed() )
|
{
|
// The leaf pispip only have variables if they are part of this optimizer run
|
if( activepispip = pispip // we know pispip is in scope so we can skip the check (for leaves this will be the only activepispip)
|
or scope.Contains( activepispip.PISPIPInOptimizerRun() ) )
|
{
|
// Dependent demands for operations
|
traverse( activepispip, ProductInStockingPoint_MP.OperationInputAvailableForOptimization, input )
|
{
|
var := program.OperationDemandQtyVariables().Find( input, pispip.Period_MP() );
|
// The OperationDemandQty variable will be null if this combination of operation and period are not part of this optimizer run
|
// In that case, this variable is not relevant and should not be added to this constraint
|
// Also if the product is not part of the optimizer run, we should not add this term
|
if( not isnull( var )
|
and ( input.HasRegularProductforOptimizer()
|
or input.GetIsProductInOptimizerRun( runcontext.IsPostProcessing() ) ) )
|
{
|
// Term UoM: PISP
|
const.NewTerm( 1.0 * scalefactor_operationdemandqty_const,
|
var );
|
}
|
// If the variable is null (and the decision is thus out of scope of the optimizer ), then we need to update the RHS to reflect this frozen quantity
|
else
|
{
|
ptoperation := PeriodTaskOperation::FindPeriodTaskOperationTypeIndex( pispip.Period_MP().Start(), input.Operation().ID() );
|
dependentdemand := select( ptoperation, DependentDemand, dd, dd.ProcessInput() = input );
|
if( not isnull( dependentdemand ) )
|
{
|
newrhs := this.GetConstraintRHS( const, scalefactor_rhs_const ) - dependentdemand.FulfilledQuantity();
|
const.RHSValue( newrhs * scalefactor_rhs_const );
|
}
|
}
|
}
|
|
// Dependent demands for trips
|
traverse( activepispip, DependentDemandTrip.ProductInTrip, productintrip )
|
{
|
if( scope.Contains( productintrip.ProductInTripInOptimizerRun() ) )
|
{
|
// Term UoM: PISP
|
const.NewTerm( 1.0 * scalefactor_tripdemandqty_const, program.TripDemandQtyVariables().Get( productintrip ) );
|
}
|
else if( productintrip.Quantity() > 0.0 )
|
{
|
fulfilledqty := guard( productintrip.DependentDemand().FulfilledQuantity(), 0.0 );
|
newrhs := this.GetConstraintRHS( const, scalefactor_rhs_const ) - fulfilledqty;
|
const.RHSValue( newrhs * scalefactor_rhs_const );
|
}
|
}
|
|
// Sales demands
|
traverse( activepispip, PlanningBaseSalesDemandInPeriodForOptimization, sd )
|
{
|
if( sd.istype( LeafSalesDemandInPeriod ) )
|
{
|
// Term UoM: PISP
|
const.NewTerm( 1.0 * scalefactor_salesdemandqty_const, program.SalesDemandQtyVariables().Get( sd.astype( LeafSalesDemandInPeriod ) ) );
|
}
|
else if( sd.istype( DisaggregatedSalesDemandInPeriod ) )
|
{
|
const.NewTerm( 1.0 * scalefactor_salesdemandqty_const, program.DisaggregatedSalesDemandQtyVariables().Get( sd.astype( DisaggregatedSalesDemandInPeriod ) ) );
|
}
|
}
|
|
// Calculating the postponed sales demand fulfillment
|
// E.g., if the current period is period 11, max postponment period = 3, this retrieves postponed sales demands to period 11 from period 10, 9, 8.
|
maxpostponedperiod := pispip.ProductInStockingPoint_MP().OptimizerMaxPostponementPeriod(); // set in in init instance per pisp for performance
|
previouspispip := activepispip.PreviousPlanningPISPIP();
|
|
for( i := 1;
|
i <= maxpostponedperiod // within the maximum number of postponement periods
|
and not isnull( previouspispip ); // the next pispip exists
|
i++ )
|
{
|
traverse( previouspispip.astype( ProductInStockingPointInPeriodPlanningLeaf ), PlanningBaseSalesDemandInPeriodForOptimizationPostponable, sd )
|
{
|
var := sd.GetDelayedSalesDemandQtyVariable( program, activepispip.Period_MP() );
|
|
if( not isnull( var ) )
|
{
|
// Term UoM: PISP
|
const.NewTerm( 1.0 * scalefactor_delayedsalesdemandqty_const, var );
|
}
|
}
|
previouspispip := previouspispip.PreviousPlanningPISPIP();
|
}
|
}
|
// If the leaf pispip is not in the optimizer run we still need to update the RHS
|
else
|
{
|
// The RHS should be updated for the dependent demands that are related to the pispip that is out of scope of this optimizer run
|
traverse( activepispip, DependentDemandOperation, dependentdemand )
|
{
|
newrhs := this.GetConstraintRHS( const, scalefactor_rhs_const ) - dependentdemand.FulfilledQuantity();
|
const.RHSValue( newrhs * scalefactor_rhs_const );
|
}
|
|
traverse( activepispip, DependentDemandTrip.ProductInTrip, pit, not scope.Contains( pit.ProductInTripInOptimizerRun() ) )
|
{
|
newrhs := this.GetConstraintRHS( const, scalefactor_rhs_const ) - pit.Quantity()
|
const.RHSValue( newrhs * scalefactor_rhs_const );
|
}
|
}
|
}
|
}
|
*]
|
InterfaceProperties { Accessibility: 'Module' }
|
}
|