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' } 
 | 
} 
 |