Quintiq file version 2.0
|
#parent: #root
|
Method InitConstraintsForBalance (
|
CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program,
|
const constcontent ProductInStockingPointInPeriods smartplanpispips,
|
const RunContextForCapacityPlanning runcontext,
|
const LibOpt_Scope scope,
|
const constcontent ProductInStockingPointInPeriodPlanningLeafs leafpispipsinrun,
|
const constcontent ProductInStockingPoint_MPs pispsinrun,
|
Number threadnr
|
) 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:
|
[*
|
//If we only want to plan 1 step up stream we need to find the intermediate products of the involved routings.
|
//They are needed so we can remove the slack from those intermediate making sure the violations if any are created on the input.
|
|
|
balance_constname := typeof( MPBalanceConstraint );
|
|
scalefactor_demandslack_const := this.ScaleConstraintTerm( typeof( MPDemandSlackVariable ), balance_constname );
|
scalefactor_tripnewsupply_const := this.ScaleConstraintTerm( typeof( MPTripNewSupplyVariable ), balance_constname );
|
scalefactor_invqty_const := this.ScaleConstraintTerm( typeof( MPInvQtyVariable ), balance_constname );
|
scalefactor_salesdemandqty_const := this.ScaleConstraintTerm( typeof( MPSalesDemandQtyVariable ), balance_constname );
|
scalefactor_dependentdemandinpispip_const := this.ScaleConstraintTerm( typeof( MPDependentDemandInPISPIPVariable ), balance_constname );
|
scalefactor_delayedsalesdemandqty_const := this.ScaleConstraintTerm( typeof( MPDelayedSalesDemandQtyVariable ), balance_constname );
|
scalefactor_periodtaskqty_const := this.ScaleConstraintTerm( typeof( MPPTQtyVariable ), balance_constname );
|
scalefactor_expired_const := this.ScaleConstraintTerm( typeof( MPExpiredVariable ), balance_constname );
|
|
scalefactor_rhs_constr := this.ScaleConstraintRHS( balance_constname, 1.0 );
|
|
intermediatepisps := construct( ProductInStockingPoint_MPs, constcontent );
|
if ( runcontext.IsOnlyPlanOneStepUpstream() )
|
{
|
intermediatepisps := selectset( scope.GetRoutingOfSmartPlanPISPIPsConst(), Elements.OperationInput.ProductInStockingPoint_MP, pisp,
|
exists( scope.GetRoutingOfSmartPlanPISPIPsConst(), Elements.OperationOutput.ProductInStockingPoint_MP, pisp2, pisp2 = pisp ) );
|
|
// we need the unsplit balance equation always. For this small planning case we dont spread over threads
|
if ( threadnr = 0 )
|
{
|
traverse( leafpispipsinrun, Elements, pispip )
|
{
|
this.InitConstraintsForBalanceNoShelfLife( program,
|
smartplanpispips,
|
intermediatepisps,
|
pispip,
|
runcontext,
|
scope,
|
scalefactor_demandslack_const,
|
scalefactor_tripnewsupply_const,
|
scalefactor_invqty_const,
|
scalefactor_salesdemandqty_const,
|
scalefactor_dependentdemandinpispip_const,
|
scalefactor_delayedsalesdemandqty_const,
|
scalefactor_periodtaskqty_const,
|
scalefactor_expired_const,
|
scalefactor_rhs_constr );
|
}
|
}
|
}
|
else
|
{
|
// right now pispip.PreThreadNr is 0, 1, ..., 999. We use thread param to balance the workload
|
|
// we need the unsplit balance equation always
|
traverse( leafpispipsinrun, Elements, pispip, CapacityPlanningSuboptimizer::GetThreadNr( this.ThreadAParameter(), this.ThreadBParameter(), pispip.PreThreadNr() ) = threadnr )
|
{
|
this.InitConstraintsForBalanceNoShelfLife( program,
|
smartplanpispips,
|
intermediatepisps,
|
pispip,
|
runcontext,
|
scope,
|
scalefactor_demandslack_const,
|
scalefactor_tripnewsupply_const,
|
scalefactor_invqty_const,
|
scalefactor_salesdemandqty_const,
|
scalefactor_dependentdemandinpispip_const,
|
scalefactor_delayedsalesdemandqty_const,
|
scalefactor_periodtaskqty_const,
|
scalefactor_expired_const,
|
scalefactor_rhs_constr );
|
}
|
}
|
|
|
if ( threadnr = 0 ) // put all in thread 'A'
|
{
|
// if shelf life is active we also need to create balances that are split per incoming lead time
|
traverse( pispsinrun, Elements, pisp, pisp.IsOptShelfLife() )
|
{
|
pispips := pisp.GetPISPIPForShelfLifeOptimizer( scope ); // this includes extra periods prior to the optimizer scope spanning at least the shelf life (this is a super set of what is in algorithmrun.PISPIPInOptimizerRun)
|
|
firststart := DateTime::MinDateTime(); // set in method call - will be the first pispip.start from among 'pispips'
|
laststart := DateTime::MinDateTime(); // set in method call - will be the last pispip.start from among 'pispips'
|
firstafteractualstart := DateTime::MinDateTime(); // set in method call - will be the first pispip.start after the last actual (if any)
|
pisp.GetScopeShelfLifeForPISP( pispips, firststart, laststart, firstafteractualstart ); // set above three variables
|
firstpispipforbalancestart := maxvalue( firststart, firstafteractualstart ); // we will initialize the split balance constraint after the last actual, or for any of the elements of 'pispips' if there are no actuals
|
traverse( pispips, Elements.astype( ProductInStockingPointInPeriodPlanningLeaf ), pispip )
|
{
|
if ( pispip.Start() >= firstpispipforbalancestart )
|
{
|
this.InitConstraintsForBalanceSplitShelfLife( program,
|
smartplanpispips,
|
intermediatepisps,
|
pispip,
|
firstpispipforbalancestart,
|
laststart,
|
runcontext,
|
scope,
|
scalefactor_demandslack_const,
|
scalefactor_tripnewsupply_const,
|
scalefactor_invqty_const,
|
scalefactor_salesdemandqty_const,
|
scalefactor_dependentdemandinpispip_const,
|
scalefactor_delayedsalesdemandqty_const,
|
scalefactor_periodtaskqty_const,
|
scalefactor_expired_const,
|
scalefactor_rhs_constr ); // additional split balance constraint in case shelf life is optimized
|
}
|
this.InitConstraintsForShelfLifeSumConstraints( program,
|
smartplanpispips,
|
intermediatepisps,
|
pispip,
|
firststart,
|
laststart,
|
scope,
|
scalefactor_invqty_const,
|
scalefactor_rhs_constr ); // sum constraints taking care of consisteny between split and unsplit versions of a variable
|
}
|
}
|
}
|
*]
|
InterfaceProperties { Accessibility: 'Module' }
|
}
|