| Quintiq file version 2.0 | 
| #parent: #root | 
| Method InitConstraintsForUserTotalSupply ( | 
|   CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program, | 
|   const RunContextForCapacityPlanning runcontext, | 
|   const LibOpt_Scope scope, | 
|   const constcontent ProductInStockingPointInPeriodPlannings pispipsinrun | 
| ) const | 
| { | 
|   Description: | 
|   [* | 
|     Initialize the constraint related to the total (user) supply in a base PISPIP | 
|     This constraint is used in the Smart plan functionality. | 
|   *] | 
|   TextBody: | 
|   [* | 
|     // For each PISPIP, if it has a total user supply and it should be considered in this run | 
|     // Then the sum of all supply into this pispip ( Inventory Supply, TripNewSupply, OperationNewSupply and InvQty of the previous period) | 
|     // should be equal to the total supply user | 
|      | 
|     if( runcontext.GetConsiderTotalUserSupply( scope ) ) | 
|     { | 
|       pispipsforconstraint := runcontext.GetPISPISPForUserSupplyConstraint( scope, pispipsinrun );  | 
|        | 
|       constrname := typeof( MPUserTotalSupplyConstraint ); | 
|        | 
|       scalefactor_invqty_constr := this.ScaleConstraintTerm( typeof( MPInvQtyVariable ), constrname ); | 
|       scalefactor_tripnewsupply_constr := this.ScaleConstraintTerm( typeof( MPTripNewSupplyVariable ), constrname ); | 
|       scalefactor_usertotalsupplyover_constr := this.ScaleConstraintTerm( typeof( MPUserTotalSupplyOverVariable ), constrname ); | 
|       scalefactor_usertotalsupplyunder_constr := this.ScaleConstraintTerm( typeof( MPUserTotalSupplyUnderVariable ), constrname ); | 
|       scalefactor_periodtaskqty_constr := this.ScaleConstraintTerm( typeof( MPPTQtyVariable ), constrname ); | 
|        | 
|       scalefactor_rhs_constr := this.ScaleConstraintRHS( constrname, 1.0 ); | 
|        | 
|       traverse( pispipsforconstraint, Elements, pispip )  | 
|       { | 
|         // constr constraint UoM: PISP | 
|         constr := program.UserTotalSupplyConstraints().New( pispip ); | 
|         constr.Sense( '=' ); | 
|        | 
|         rhs := pispip.TotalSupplyUser() - pispip.InventorySupplyQuantity(); | 
|         // RHS UoM: PISP | 
|         constr.RHSValue( rhs * scalefactor_rhs_constr ); | 
|        | 
|         previouspispip := pispip.PreviousPlanningPISPIP(); | 
|        | 
|         // Inventory end of the previous period | 
|         if( not isnull( previouspispip ) ) | 
|           { | 
|           // If the previous pipsip is part of the optimizer run, add the inventory quantity variable to the constraint | 
|           if( scope.Contains( previouspispip.PISPIPInOptimizerRun() ) ) | 
|           { | 
|             // Term UoM: PISP | 
|             constr.NewTerm( scalefactor_invqty_constr, | 
|                             program.InvQtyVariables().Get( previouspispip ) ); | 
|             if ( pispip.ProductInStockingPoint_MP().IsOptShelfLife() )  | 
|             { | 
|               constr.NewTerm( -scalefactor_invqty_constr, program.ExpiredVariables().Get( pispip ) );  | 
|             }                         | 
|           } | 
|           // Otherwise update the RHS to include the frozen inventory end | 
|           else | 
|           { | 
|             newrhs := this.GetConstraintRHS( constr, scalefactor_rhs_constr ) - previouspispip.InventoryLevelEnd(); | 
|             constr.RHSValue( newrhs * scalefactor_rhs_constr ); | 
|           } | 
|         } | 
|        | 
|         // New supplies from trips | 
|         traverse( pispip, astype(ProductInStockingPointInPeriodPlanningLeaf ).NewSupply.ProductInTrip, productintrip ) | 
|         { | 
|           // If the productintrip is part of the optimizer run, add its tripnewsupply quantity variable to the constraint | 
|           if( scope.Contains( productintrip.ProductInTripInOptimizerRun() ) )  | 
|           { | 
|             // Term UoM: Output PISP | 
|             constr.NewTerm( scalefactor_tripnewsupply_constr, program.TripNewSupplyVariables().Get( productintrip ) ); | 
|           } | 
|           // Otherwise update the RHS with the frozen productintrip supply quantity | 
|           else | 
|           { | 
|             newrhs := this.GetConstraintRHS( constr, scalefactor_rhs_constr ) - productintrip.Quantity(); | 
|             constr.RHSValue( newrhs * scalefactor_rhs_constr ); | 
|           } | 
|         } | 
|        | 
|         // New supplies from operations | 
|         traverse( pispip, ProductInStockingPoint_MP.OperationOutputAvailableForOptimization, output ) | 
|         { | 
|           // Term UoM: Output PISP | 
|           this.AddConstraintForOperationNewSupplies( output, pispip.Period_MP(), null( Period_MP ), | 
|                                                      program, 1.0, constr, scalefactor_periodtaskqty_constr, scope ); | 
|        | 
|           // If there is a new supply of this output in this pispips that is not part of the optimization run, then this new supply should be subtracted from the RHS | 
|           // Comment from MvE: this should follow the summing of RHS new supply in GetInventoryRHSForBalanceConstraint | 
|           traverse( output, NewSupply, newsupply, | 
|                     newsupply.PeriodTask_MP().UnitPeriod().Period_MP() = pispip.Period_MP()                 | 
|                     and( not scope.Contains(  newsupply.PeriodTaskOperation().PeriodTaskOperationInOptimizerRun() ) | 
|                          and not scope.Contains( newsupply.PeriodTask_MP().UnitPeriod().UnitPeriodInOptimizerRun() ) ) // If this is a regular optimizer run, the PTOperations are not added to the algorithm run | 
|                     or ( ifexpr( runcontext.IsSmartPlanForPeriodTask(), not newsupply.GetHasAllDDInOptimizerScope( runcontext, scope ), false ) ) // Only check this for period task smart plan | 
|                     )   | 
|           { | 
|             newrhs := this.GetConstraintRHS( constr, scalefactor_rhs_constr ) - newsupply.Quantity(); | 
|             constr.RHSValue( newrhs * scalefactor_rhs_constr ); | 
|           } | 
|         } | 
|        | 
|         // Add slack variables | 
|         // Term UoM: Output PISP | 
|         constr.NewTerm( -1.0 * scalefactor_usertotalsupplyover_constr, program.UserTotalSupplyOverVariables().Get( pispip ) ); | 
|         constr.NewTerm( scalefactor_usertotalsupplyunder_constr, program.UserTotalSupplyUnderVariables().Get( pispip ) ); | 
|       } | 
|     } | 
|   *] | 
|   InterfaceProperties { Accessibility: 'Module' } | 
| } |