Quintiq file version 2.0
|
#parent: #root
|
Method SelectOptimizerInputForSmartPlan (
|
ProductInStockingPointInPeriodPlannings pispipsmartplan,
|
LaneLegs lanelegsforoptimization,
|
Period_MPs periods,
|
Boolean isusingselectedunits,
|
Units units,
|
Boolean skipgapfillfinalrelations,
|
Process_MP process,
|
LibOpt_Scope scope,
|
RunContextForCapacityPlanning runcontext,
|
Boolean resetvisited
|
)
|
{
|
Description: 'Selects the pispips that should be used in the Smart plan'
|
TextBody:
|
[*
|
|
startingpispips := construct( ProductInStockingPointInPeriods );
|
this.RemoveAllSidePISPIPs(); // collect all side products here and add those later, so we do explore onward during the recursive method.
|
this.ResetRelationsStoredVisited( resetvisited );
|
this.PISPIPNewlyVisited( relflush ); // to keep track of what has been visited in this method call
|
|
// Select the starting pispips based on the user input
|
// The starting pispips are the selected pispips plus their previous n-1 pispips
|
isupstream := this.GetIsUpstream();
|
|
traverse( pispipsmartplan, Elements, pispip )
|
{
|
for( n := 1;
|
n <= this.NumberOfSmartPlanPeriods()
|
and not isnull( pispip );
|
n++ )
|
{
|
if ( not runcontext.IsMetaIteration() or pispip.Period_MP().IsInOptimizerPuzzle() )
|
{
|
startingpispips.Add( pispip );
|
}
|
if( isupstream )
|
{
|
pispip := pispip.PreviousPlanningPISPIP();
|
}
|
else
|
{
|
pispip := pispip.NextPlanningPISPIP();
|
}
|
}
|
}
|
|
// The optimization is performed on planning / leaf pispips, so we should make sure we have selected those
|
// Assuming that all starting pispips are planning pispips
|
traverse( startingpispips, Elements, pispip,
|
not pispip.IsLeafPlanning() )
|
{
|
startingpispips.Remove( pispip );
|
traverse( pispip.GetLeafPISPIPs(), Elements, leafpispip )
|
{
|
startingpispips.Add( leafpispip );
|
}
|
}
|
|
startingpispips := startingpispips.Unique();
|
|
if ( not runcontext.IsMetaIteration() )
|
{
|
totalnumberofpispips := counter( this,
|
MacroPlan.LeafProductInStockingPoint.ProductInStockingPointInPeriodPlanning,
|
pispip,
|
not pispip.IsPeriodFrozen() );
|
|
|
// If the user has selected more than X% of the PISPIPs, it is faster to create all trips upfront
|
// Otherwise, the trips will be created as they are needed in the algorithm.SetOptimizerInputSmartPlan method
|
if( totalnumberofpispips > 0
|
and ( ( startingpispips.Elements( relsize ) / totalnumberofpispips ) > this.SmartPlanPISPIPThreshold() ) )
|
{
|
updatedtrips := construct( Trips );
|
// Create all possible combi of trips as optimizer input
|
this.CreateTrips( lanelegsforoptimization, periods, updatedtrips );
|
|
// Without the Transaction.Propagate() the trips will not have the required relations for the SetOptimizerInput methods
|
Transaction::Transaction().Propagate( relation( Trip, PeriodTaskLaneLeg ) );
|
Transaction::Transaction().Propagate( relation( ProductInTrip, DependentDemand ) );
|
Transaction::Transaction().Propagate( relation( ProductInTrip, NewSupply ) );
|
}
|
}
|
|
// Get the routings related to the starting PISPIPs that are viable for the optimizer run.
|
if( runcontext.IsOnlyPlanOneStepUpstream() )
|
{
|
this.SetPISPIPRoutings( startingpispips, guard( process.astype( Operation ), null( Operation ) ), scope, runcontext );
|
this.SetPISPIPLaneLegs( startingpispips, guard( process.astype( LaneLeg ), null( LaneLeg ) ), scope, runcontext );
|
}
|
|
// Select all pispips, operations, trips, etc based on the starting pispips
|
traverse( startingpispips,
|
Elements.astype( ProductInStockingPointInPeriodPlanningLeaf ),
|
pispip,
|
pispip.IsPlanning()
|
and pispip.IsLeafPlanning()
|
and not pispip.IsPeriodFrozen()
|
and not pispip.Period_MP().IsHistorical() )
|
{
|
this.SetOptimizerInputSmartPlan( pispip,
|
isusingselectedunits,
|
units,
|
0, // depth
|
scope,
|
runcontext );
|
}
|
|
this.AddAllSidePISPIPsToScope( scope, runcontext ); // now make sure to add the side pispips
|
|
if ( not skipgapfillfinalrelations )
|
{
|
// We need to make sure we optimize over a continuous horizon
|
// Therefore we need to add the missing pispips
|
// Adding these pispips and their upstream pispips could introduce new gaps in the horizon
|
// So we have to iterate until we have no more gaps
|
// The 100 is used as an upperbound to prevent an infinite loop (in practice we should terminate after a couple iterations)
|
|
this.SmartPlanGapFill( isusingselectedunits, units, scope, runcontext );
|
|
this.SmartPlanSetFinalRunRelations( isupstream, scope, runcontext );
|
|
this.SmartPlanGapFill( isusingselectedunits, units, scope, runcontext ); // need to gapfill one more time because previous method can create gaps again
|
}
|
*]
|
InterfaceProperties { Accessibility: 'Module' }
|
}
|