yanweiyuan3
2023-08-09 588bc7829387dfc761cc25f06f77d4c81818bd10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
Quintiq file version 2.0
#parent: #root
Method GetUpstreamPISPIPs (
  Number depth,
  ProductInStockingPointInPeriods pispips_o
)
{
  Description:
  [*
    Selects all upstream PISPIPs related to this pispip. 
    Please note that this will create the required PeriodTaskOperations/Trips to be able to follow the dependent demand. 
    Therefore, it is recommended to delete any unused PeriodTaskOperations/Trips after calling this method
  *]
  TextBody:
  [*
    // Martijn Oct-18-2016 (created)
    // Martijn: I think we could remove some code duplication between this method and the SetOptimizerInputSmartPlan methods
    
    depth := depth - 1;
    
    if( depth > 0 )
    {
      pispips_o.Add( this );
      period := this.Period_MP();
      // Traverse over the operations that produce this product as an output
      // If this product is a byproduct, we do not want to add its operations, unless they only produce byproduct.
      // This is to avoid adding products to the smart plan that are only related to the smart plan input pispips because they are produced together with the same byproduct
      traverse( this, ProductInStockingPoint_MP.OperationOutput.Operation, operation,
                operation.GetIsAvailableForOptimization()                                     // The operation must be available
                and PeriodTaskOperation::GetIsValidPeriodTask( operation, period )  // The resulting period task must be valid
                and ( not this.ProductInStockingPoint_MP().Product_MP().IsByProduct()       // This product is not a byproduct
                      or forall( operation, OperationOutput.ProductInStockingPoint_MP.Product_MP, product, product.IsByProduct() ) ) )  // or all outputs are byproducts
      {
        // Create/Select the related periodtaskoperation
        periodtaskoperation := PeriodTaskOperation::FindPeriodTaskOperationTypeIndex( period.Start() , operation.ID() );
    
        if( isnull( periodtaskoperation ) )
        {
          unit := operation.Unit();
          unitperiod := UnitPeriod::FindUnitPeriodTypeIndex( unit.ID(), period.Start(), period.End() );
          periodtaskoperation := PeriodTaskOperation::Create( operation, unitperiod, 0.0, false );
          // I think this transaction propagate is necessary, we need to get the dependent demand from the newly created periodtask
          Transaction::Transaction().Propagate( relation( PeriodTaskOperation, DependentDemand ) )
        }
        
        traverse( periodtaskoperation, DependentDemand.ProductInStockingPointInPeriodPlanningLeaf, newpispip )
        {
          if( pispips_o.Find( newpispip ) < 0 )  //PISPIP not already added to the set
          {
            newpispip.GetUpstreamPISPIPs( depth, pispips_o );
          }
        }
      }
    
    
      // Traverse over the lanelegs that supply this PISPIP
      traverse( this, ProductInStockingPoint_MP.LaneLegOutput.LaneLeg, laneleg, laneleg.GetIsAvailableForOptimization() )
      {    
        unit := laneleg.Lane().Unit();
        unitperiod := UnitPeriod::FindUnitPeriodTypeIndex( unit.ID(), period.Start(), period.End() );
    
        // Select the existing trips of this laneleg on this unit period
        // Normally there should only be a single trip, but the user may have created multiple trips for a single unit period
        trips := selectset( laneleg, Trip, trip, trip.ArrivalUnitPeriod() = unitperiod );
        
        // If no such trip exists and it would be a valid nonfrozen trip, then create a new trip
        if( trips.Elements( relsize ) = 0
            and Trip::GetIsValidNonFrozenTrip( laneleg, period ) )
        {
          trips.Add( Trip::Create( laneleg, period ) );
          // Without the Transaction.Propagate() the trips will not have the required relations
          Transaction::Transaction().Propagate( relation( Trip, PeriodTaskLaneLeg ) );
        }
    
        // Add the current product to the trips (if it is not yet part of these trips)
        traverse( trips, Elements, trip,
                  not exists( trip, ProductInTrip.Product_MP, product,
                              product = this.ProductInStockingPoint_MP().Product_MP() ) )
        {
          trip.AddProduct( this.ProductInStockingPoint_MP().Product_MP(), 0.0, false );
          
          // Without the Transaction.Propagate() the trips will not have the required relations
          Transaction::Transaction().Propagate( relation( ProductInTrip, DependentDemand ) );
        }
       
        // Add the trips to the optimizer run
        traverse( trips, Elements, trip, trip.GetIsValidNonFrozenTrip() )
        {
          // Add the related productintrip to productintripsforoptimization
          traverse( trip, ProductInTrip, productintrip,
                    productintrip.ProductID() = this.ProductInStockingPoint_MP().ProductID() )
          {
            newpispip := null(ProductInStockingPointInPeriod )
            newpispip := guard( productintrip.DependentDemand().ProductInStockingPointInPeriodPlanningLeaf(), null(ProductInStockingPointInPeriodPlanningLeaf) );
            if( isnull( newpispip ) )
            {
              newpispip := this;
            }
            if( pispips_o.Find( newpispip ) < 0 )  //PISPIP not already added to the set
            {
              newpispip.GetUpstreamPISPIPs( depth, pispips_o );
            }
          }
        }
      }
    }
  *]
}