Quintiq file version 2.0
|
#parent: #root
|
Method InitConstraintsForOperationDependentDemandInputGroup_Add (
|
CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program,
|
const RunContextForCapacityPlanning runcontext,
|
const LibOpt_Scope scope,
|
const OperationInputGroup group,
|
const Period_MP period,
|
const PeriodTaskOperation pto,
|
Real scalefactor_periodtask_constddqty,
|
Real scalefactor_periodtask_constupper,
|
Real scalefactor_operationinputgroupover_constupper,
|
Real scalefactor_periodtask_constlower,
|
Real scalefactor_operationinputgroupunder_constlower,
|
Real scalefactor_partialoperationdemandqty_constddqty,
|
Real scalefactor_partialoperationdemandqty_constupper,
|
Real scalefactor_partialoperationdemandqty_constlower,
|
Real scalefactor_partialoperationdemandqty_constrelative,
|
Real scalefactor_operationdemandqty_constddqty,
|
Real scalefactor_operationdemandqty_constupper,
|
Real scalefactor_operationdemandqty_constlower,
|
Boolean usingproportionalleadtimelogic
|
) const
|
{
|
Description: 'Initialize constraints for dependent demands which is part of an input group'
|
TextBody:
|
[*
|
operation := group.Operation();
|
|
// Input group fulfilled quantity = sum of all dependent demand fulfilled quantity of the group
|
// constddqty constraint UoM: Unit
|
constddqty := program.OperationInputGroupDependentDemandQtyConstraints().New( group, period );
|
constddqty.Sense( '=' );
|
// using default RHS 0.0 for comstddqty
|
|
// Term: -group.Factor * PTQty variable
|
// UoM: [-] * [Unit]
|
constddqty.NewTerm( -group.Factor() * scalefactor_periodtask_constddqty,
|
program.PTQtyVariables().Get( operation, period ) );
|
|
// Step 1: Upper and lower bound of DD, must be according to min quantity and max quantity of operation input
|
// Step 2: Relative duration
|
// Only select the input where the product is included.
|
traverse( group, OperationInput, oi, oi.HasRegularProductforOptimizer() or oi.GetIsProductInOptimizerRun( runcontext.IsPostProcessing() ) )
|
{
|
maxfactor := oi.MaxQuantityFactor();
|
minfactor := oi.MinQuantityFactor();
|
|
// If the dependent demand is part of a user period task, we use the factor that is currently used
|
traverse( oi, DependentDemand, dd,
|
dd.PeriodTaskOperation().HasUserQuantity()
|
and dd.PeriodTask_MP().UnitPeriod().Period_MP() = period )
|
{
|
usedfactor := guard( dd.Quantity() / dd.DependentDemandInputGroup().GetGroupQuantity(), 0.0 );
|
maxfactor := usedfactor;
|
minfactor := usedfactor;
|
}
|
|
// constupper constraint UoM: Unit
|
constupper := program.OperationInputGroupUpperBoundConstraints().New( oi, period );
|
constupper.Sense( '<=' );
|
// using default RHS 0.0 for constupper
|
|
// Term: -maxfactor * PTQty variable
|
// UoM: [-] * [Unit]
|
constupper.NewTerm( -maxfactor * scalefactor_periodtask_constupper, program.PTQtyVariables().Get( operation, period ) );
|
|
// Term UoM: Unit
|
constupper.NewTerm( -1.0 * scalefactor_operationinputgroupover_constupper, program.OperationInputGroupOverVariables().Get( oi, period ) );
|
|
// constlower constraint UoM: Unit
|
constlower := program.OperationInputGroupLowerBoundConstraints().New( oi, period );
|
constlower.Sense( '>=' );
|
// using default RHS 0.0 for constlower
|
|
// Term: -minfactor * PTQty variable
|
// UoM: [-] * [Unit]
|
constlower.NewTerm( -minfactor * scalefactor_periodtask_constlower, program.PTQtyVariables().Get( operation, period ) );
|
|
// Term UoM: Unit
|
constlower.NewTerm( scalefactor_operationinputgroupunder_constlower, program.OperationInputGroupUnderVariables().Get( oi, period ) );
|
|
fac := 1.0;
|
sourceuom := oi.PISPUnitOfMeasurement();
|
targetuom := operation.Unit().UnitOfMeasure_MP();
|
uomconversion := guard( sourceuom.GetConversionFactor( targetuom, null( Product_MP ) ), 1.0 );
|
|
if( operation.HasLeadTime() )
|
{
|
pispipperiods := construct( Period_MPs, constcontent );
|
if ( this.GetPeriodsFromPeriodTaskOperation() ) // avoid call to below method which just (re)finds pto and then returns dd periods
|
{
|
traverse( pto, DependentDemand.ProductInStockingPointInPeriodPlanningLeaf.Period_MP, ddperiod )
|
{
|
pispipperiods.Add( ddperiod );
|
}
|
pispipperiods := pispipperiods.Unique();
|
}
|
else
|
{
|
CapacityPlanningSuboptimizer::GetOperationDependentDemandPeriods( period, operation, &pispipperiods, this.GetPeriodsFromPeriodTaskOperation() );
|
}
|
ddstart := Process_MP::GetDependentDemandEarliestStart( period, operation.LeadTime(), operation.Unit().MacroPlan().GlobalParameters_MP(), operation );
|
ddend := Process_MP::GetOperationEnd( period, ddstart );
|
|
traverse( pispipperiods, Elements, pispipperiod )
|
{
|
|
|
// Term: conversion factor * PartialOperationDemandQty variable
|
// UoM: [Conversion from Input PISP to Unit] * [Input PISP]
|
varpodqty := program.PartialOperationDemandQtyVariables().Get( oi, pispipperiod, period );
|
constddqty.NewTerm( uomconversion * scalefactor_partialoperationdemandqty_constddqty, varpodqty );
|
constupper.NewTerm( uomconversion * scalefactor_partialoperationdemandqty_constupper, varpodqty );
|
constlower.NewTerm( uomconversion * scalefactor_partialoperationdemandqty_constlower, varpodqty );
|
|
// Only enable if the DD spans across period, meaning, 1 period task has 2 dependent demands for the same operation input
|
// Calculate the quantity that span at current period and previous period
|
// For example, dependent demand span across Jan and Feb.
|
// The relative duration of Jan = 0.6, Feb = 0.4
|
// Then, they must be adhered to: ( fulfilled demand on Jan / 0.6 ) = ( fulfilled demand on Feb / 0.4 )
|
// The constraint is defined for the pispipperiod and the next period
|
// If the pispipperiod ends after the dependent demand ends, the next period is not relevant and we do not need the constraint
|
|
if( pispipperiod.End() < ddend and usingproportionalleadtimelogic )
|
{
|
// constrelative constraint UoM: Input PISP
|
constrelative := program.RelativeDurationConstraints().New( oi, operation, period, pispipperiod );
|
constrelative.Sense( '=' );
|
// using default RHS 0.0 for constrelative
|
|
start := Process_MP::GetDependentDemandStart( ddstart, pispipperiod );
|
end := Process_MP::GetDependentDemandEnd( ddend, pispipperiod );
|
relativeduration := Process_MP::GetRelativeDuration( start, end, period );
|
|
// Term: factor/relative duration * PartialOperationDemandQty variable
|
// UoM: [-] * [Input PISP]
|
constrelative.NewTerm( ( fac / relativeduration ) * scalefactor_partialoperationdemandqty_constrelative,
|
program.PartialOperationDemandQtyVariables().Get( oi, pispipperiod, period ) );
|
nextpispipperiod := pispipperiod.NextPlanningPeriod();
|
startnext := Process_MP::GetDependentDemandStart( ddstart, nextpispipperiod );
|
endnext := Process_MP::GetDependentDemandEnd( ddend, nextpispipperiod );
|
relativedurationnext := Process_MP::GetRelativeDuration( startnext, endnext, period )
|
|
// Term: -factor/relative duration * PartialOperationDemandQty variable
|
// UoM: [-] * [Input PISP]
|
constrelative.NewTerm( ( -fac / relativedurationnext ) * scalefactor_partialoperationdemandqty_constrelative,
|
program.PartialOperationDemandQtyVariables().Get( oi, nextpispipperiod, period ) );
|
}
|
}
|
}
|
else // operation does not have lead time logic
|
{
|
// Term: conversion factor * OperationDemandQty variable
|
// UoM: [Conversion from Input PISP to Unit] * [Input PISP]
|
varoperationdemandqty := program.OperationDemandQtyVariables().Get( oi, period );
|
constddqty.NewTerm( uomconversion * scalefactor_operationdemandqty_constddqty, varoperationdemandqty );
|
constupper.NewTerm( uomconversion * scalefactor_operationdemandqty_constupper, varoperationdemandqty );
|
constlower.NewTerm( uomconversion * scalefactor_operationdemandqty_constlower, varoperationdemandqty );
|
}
|
} // end traverse OperationInput oi
|
*]
|
InterfaceProperties { Accessibility: 'Module' }
|
}
|