Quintiq file version 2.0
|
#parent: #root
|
Method GetInventoryRHSForBalanceConstraint (
|
const ProductInStockingPointInPeriodPlanningLeaf pispip,
|
const RunContextForCapacityPlanning runcontext,
|
const LibOpt_Scope scope
|
) const as Real
|
{
|
Description: 'Calculate and returns the rhs of the balance constraints (=starting inventory of a pispip considering all decisions outside the optimizer horizon)'
|
TextBody:
|
[*
|
// The RHS of this constraint is the initial inventory based on all decisions outside the scope of the optimizer, it includes:
|
// Inventory supply that is greater than 0. If the supply is less than 0, it will be treated as a "must be fulfilled" demands
|
supplyquantity := ifexpr( pispip.InventorySupplyQuantity() > 0, pispip.InventorySupplyQuantity(), 0 );
|
|
// Inventory of the previous period if that period exists and is not part of the optimizer horizon
|
invstart := 0.0;
|
if( pispip.ProductInStockingPoint_MP().EarliestPISPIPInScope() = pispip
|
and not isnull( pispip.PreviousPlanningPISPIP() ) )
|
{
|
invstart := pispip.InventoryLevelStart(); // this ensures expired quantity is also taken out of the balance
|
}
|
|
|
// The sum of the new supply that starts outside the optimizer scope
|
sumnewsupply := 0.0;
|
// Add the new supply quantity if it has a dd on a pispip outside the optimizer scope
|
traverse( pispip, NewSupplyOperation, newsupply, not newsupply.Quantity() = 0.0 )
|
|
{
|
if ( ( isnull( newsupply.PeriodTaskOperation().UnitPeriodWhenInScope() ) // either the period task is not in scope
|
or not newsupply.GetHasAllDDInOptimizerScope( runcontext, scope) ) ) // or if it is check whether some dependent demand is taking from a pispip not in scope
|
{
|
sumnewsupply := sumnewsupply + newsupply.Quantity();
|
}
|
}
|
|
traverse( pispip, NewSupplyTrip.ProductInTrip, pit, not pit.Quantity() = 0.0 )
|
{
|
if ( not scope.Contains( pit.ProductInTripInOptimizerRun() ) )
|
{
|
sumnewsupply := sumnewsupply + pit.Quantity();
|
}
|
}
|
|
// Subtract any dependent demands that have a new supply outside the optimizer scope
|
sumdd := 0.0;
|
if ( this.GetPeriodsFromPeriodTaskOperation() )
|
{
|
traverse( pispip, DependentDemandOperation, dd, not dd.Quantity() = 0.0 )
|
{
|
if( ( isnull( dd.PeriodTaskOperation().UnitPeriodWhenInScope() ) ) ) // check if period task is not in scope,
|
{
|
sumdd := sumdd + dd.Quantity();
|
}
|
}
|
}
|
else
|
{
|
traverse( pispip, DependentDemandOperation, dd, not dd.Quantity() = 0.0 )
|
{
|
if( ( isnull( dd.PeriodTaskOperation().UnitPeriodWhenInScope() ) // either the period task is not in scope,
|
or not dd.GetHasAllNewSupplyInOptimizerScope( runcontext, scope ) ) ) // or if it is then check whether some new supply is delivering to a pispip not in scope
|
{
|
sumdd := sumdd + dd.Quantity();
|
}
|
}
|
}
|
|
traverse( pispip, DependentDemandTrip.ProductInTrip, pit, not pit.Quantity() = 0.0 )
|
{
|
if ( not scope.Contains( pit.ProductInTripInOptimizerRun() ) )
|
{
|
sumdd := sumdd + pit.Quantity();
|
}
|
}
|
|
// subtract any postponed sales demand with original demand not in scope. Note we both handle LeafSalesDemandInPeriod and AggregatedSalesDemandInPeriod here.
|
// if the original is not in scope the postponed sd will not be allowed to be replanned
|
postponedsd_outscope := 0.0;
|
traverse( pispip, PlanningBaseSalesDemandInPeriodIsPostponed.astype( SalesDemandInPeriod ),
|
sdip,
|
not sdip.GetInScope( scope )
|
and guard( not sdip.OriginalSalesDemand().astype( SalesDemandInPeriod ).GetInScope( scope ), false )
|
and not scope.Contains( sdip.OriginalSalesDemand().astype( SalesDemandInPeriod ).SDIPBeforeScopeInRun() ) )
|
|
{
|
assert( sdip.IsPostponed() and not sdip.IsManuallyPostponed(), 'sales demand taken out of balance must be postponed object and not mamually postponed' );
|
postponedsd_outscope := postponedsd_outscope + sdip.FulfilledQuantity();
|
}
|
|
// If the user runs a downstream smart plan, then the user may specify a total available supply
|
// This total available supply will overrule the real total supply of the pispip
|
// Therefore, we will have to update the RHS of the balance constraint to account for the difference
|
magicalusersupply := 0.0;
|
if( pispip.GetHasMisMatchAvailableUserSupply() )
|
{
|
magicalusersupply := pispip.TotalAvailableSupplyUser() - pispip.SupplyQuantity();
|
}
|
|
// Calculate the total RHS
|
rhs := -( supplyquantity + invstart + sumnewsupply - ( sumdd + postponedsd_outscope ) + magicalusersupply );
|
return rhs
|
*]
|
InterfaceProperties { Accessibility: 'Module' }
|
}
|