| Quintiq file version 2.0 | 
| #parent: #root | 
| Method InitConstraintsForBalanceNoShelfLife ( | 
|   CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program, | 
|   const constcontent ProductInStockingPointInPeriods smartplanpispips, | 
|   constcontent ProductInStockingPoint_MPs intermediatepisps, | 
|   const ProductInStockingPointInPeriodPlanningLeaf pispip, | 
|   const RunContextForCapacityPlanning runcontext, | 
|   const LibOpt_Scope scope, | 
|   Real scalefactor_demandslack_const, | 
|   Real scalefactor_tripnewsupply_const, | 
|   Real scalefactor_invqty_const, | 
|   Real scalefactor_salesdemandqty_const, | 
|   Real scalefactor_dependentdemandinpispip_const, | 
|   Real scalefactor_delayedsalesdemandqty_const, | 
|   Real scalefactor_periodtaskqty_const, | 
|   Real scalefactor_expired_const, | 
|   Real scalefactor_rhs_constr | 
| ) const | 
| { | 
|   Description: | 
|   [* | 
|     To balance the demands and supply in pispip | 
|     Dependent demands must be fulfilled in full quantity. Sales demands can be fulfilled halfly. | 
|   *] | 
|   TextBody: | 
|   [* | 
|     //   SUM( factor * relativeduration * PTQty ( operationoutput.operation, ptperiod ) | 
|     // + SUM( TripNewSupply ( newsupply.productintrip )  | 
|     // + InvQty ( Previous )  | 
|     // - SUM( SalesDemandQty ( leaf sales demand ) ) | 
|     // - SUM( DelayedSalesDemandQty ( delayed leaf sales demand ) ) | 
|     // - SUM( DisaggregatedSalesDemandQty ( disaggregated sales demand ) ) | 
|     // - SUM( DelayedDisaggregatedSalesDemandQty( delayed disaggregated sales demand ) ) | 
|     // - DependentDemandInPISPIP | 
|     // - TargetInvQty | 
|     // - UnallocQty  | 
|     // - Expiry (pispip)  | 
|     // = - InventorySupplyQuantity âˆ€ pispip where operationoutput, newsupply, sales demands   âˆˆ pispip | 
|      | 
|      | 
|      | 
|                                   | 
|     // unallocated supply = new supply + inventory supply + inventory carried forward - demands (sales demands ( Leaf sales demands and Disaggregated sales demands), dependent demand, inventory demand ) | 
|     // constr constraint UoM: PISP | 
|      | 
|      | 
|      | 
|     constr := program.BalanceConstraints().New( pispip ); | 
|     constr.Sense( '=' ); | 
|      | 
|     // RHS UoM: PISP | 
|     rhs := this.GetInventoryRHSForBalanceConstraint( pispip, runcontext, scope ); | 
|     rhs_scaled := rhs * scalefactor_rhs_constr | 
|     constr.RHSValue( rhs_scaled ); | 
|      | 
|     // Inventory end for pispip | 
|     // Term UoM: PISP | 
|     constr.NewTerm( -1.0 * scalefactor_invqty_const, program.InvQtyVariables().Get( pispip ) ); | 
|      | 
|     // Penalty for decreasing demand quantity in a pispip for balancing the constraint | 
|     // (A positive DemandSlack represents a supply that is "magically" created to even out the balance constraint) | 
|     // Term UoM: PISP | 
|     // Remove the slack in case we only plan 1 step upstream and it is an intermediary product.       | 
|     if( this.GetIsBalanceSlackAllowed( pispip, smartplanpispips, intermediatepisps, runcontext ) ) | 
|     {   | 
|       constr.NewTerm( 1.0 * scalefactor_demandslack_const, | 
|                      program.DemandSlackVariables().Get( pispip ) );                   | 
|     } | 
|      | 
|     // New supplies from operations | 
|     ispostprocessing := runcontext.IsPostProcessing();  | 
|     traverse( pispip,  | 
|               ProductInStockingPoint_MP.OperationOutputAvailableForOptimization,  | 
|               output,  | 
|               output.HasRegularProductforOptimizer() or  | 
|               output.GetIsProductInOptimizerRun( ispostprocessing ) ) | 
|     {              | 
|       // Term UoM: Output PISP | 
|       this.AddConstraintForOperationNewSupplies( output, pispip.Period_MP(), null( Period_MP ), | 
|                                                  program, 1.0, constr, scalefactor_periodtaskqty_const, scope ); | 
|     } | 
|      | 
|     // New supplies from trips, for those productintrip that are part of the optimizer run | 
|     traverse( pispip, NewSupplyTrip.ProductInTrip, productintrip ) | 
|     { | 
|       // Term UoM: Output PISP | 
|       pitnsvar := program.TripNewSupplyVariables().Find( productintrip ); | 
|       if ( not isnull( pitnsvar ) ) // if not isnull means in scope and vice-versa | 
|       {  | 
|         constr.NewTerm( scalefactor_tripnewsupply_const, pitnsvar ); | 
|       } | 
|     } | 
|      | 
|     // Inventory carried forward, if the previous pispip exists and is part of the optimizer run | 
|     previouspispip := pispip.PreviousPlanningPISPIP(); | 
|     if( not isnull( previouspispip ) | 
|         and previouspispip.Start() >= pispip.ProductInStockingPoint_MP().EarliestPISPIPInScope().Start() )  | 
|     { | 
|          // Term UoM: PISP | 
|         constr.NewTerm( scalefactor_invqty_const, | 
|                        program.InvQtyVariables().Get( previouspispip ) ); | 
|     } | 
|      | 
|     // Sales demands added to balance constraint pispip salesdemands | 
|     traverse( pispip.GetLeafSalesDemandInPeriod(), Elements, lsdip, not lsdip.IsPostponed() or lsdip.IsManuallyPostponed() ) // note GetLeafSalesDemandInPeriod can include postponed sd, but non manual postponed  | 
|     {                                                                                                      // sd is never added to scope (only the original) (*) | 
|       // Leaf sales demands added to balance constraint | 
|       constr.NewTerm( -1.0 * scalefactor_salesdemandqty_const, | 
|                      program.SalesDemandQtyVariables().Get( lsdip ) ); | 
|     } | 
|      | 
|     traverse( pispip.GetDisaggregatedSalesDemandInPeriod(),  | 
|               Elements,  | 
|               dsdip,  | 
|               not dsdip.IsPostponed() ) // similar remark as (*) above. Note disaggregates sales demand cannot be manually postponed | 
|     { | 
|       // Disaggregated sales demands added to balance constraint | 
|       constr.NewTerm( -1.0 * scalefactor_salesdemandqty_const, | 
|                      program.DisaggregatedSalesDemandQtyVariables().Get( dsdip ) ); | 
|     } | 
|      | 
|     // Dependent demands, with slack to prevent infeasibility | 
|     // Term UoM: PISP | 
|     constr.NewTerm( -1.0 * scalefactor_dependentdemandinpispip_const, | 
|                    program.DependentDemandInPISPIPVariables().Get( pispip ) ); | 
|      | 
|      | 
|     if ( pispip.ProductInStockingPoint_MP().IsOptShelfLife() ) // note we always include the unsplit balance constraint defined in the current method  | 
|     {                                                          // so pispip can still have shelf life defined | 
|       constr.NewTerm( -1.0 * scalefactor_expired_const, program.ExpiredVariables().Get( pispip ) ); | 
|     } | 
|      | 
|     // PISPs with allowed negative inventory | 
|     // Define positive inventory to allow inventory cost calculation | 
|     if( pispip.ProductInStockingPoint_MP().IsNegativeInventoryAllowed() ) | 
|     { | 
|       posinvconst := program.PositiveInventoryConstraints().New( pispip ); | 
|       posinvconst.Sense( '>=' ); | 
|       posinvconst.RHSValue( 0.0 ); | 
|        | 
|       posinvconst.NewTerm( scalefactor_invqty_const, program.PosInvQtyVariables().Get( pispip ) );   | 
|       posinvconst.NewTerm( -1.0 * scalefactor_invqty_const,program.InvQtyVariables().Get( pispip ) ); | 
|     } | 
|      | 
|     previouspispip := pispip.PreviousPlanningPISPIP(); | 
|      | 
|     maxnumberofpostponement := pispip.ProductInStockingPoint_MP().OptimizerMaxPostponementPeriod(); // set in init instance for performance  | 
|     for( i := 1; | 
|          i <= maxnumberofpostponement  // within the maximum number of postponement periods | 
|          and not isnull( previouspispip );             // the previous pispip exists | 
|          i++ ) | 
|     { | 
|       traverse( previouspispip.astype( ProductInStockingPointInPeriodPlanningLeaf ), PlanningBaseSalesDemandInPeriodForOptimizationPostponable, sd ) | 
|       { | 
|         var := null( MPVariable ); | 
|          | 
|         var := sd.GetDelayedSalesDemandQtyVariable( program, pispip.Period_MP() ); | 
|          | 
|         if( not isnull( var ) ) | 
|         { | 
|           // Term UoM: PISP | 
|           constr.NewTerm( -1.0 * scalefactor_delayedsalesdemandqty_const, var ); | 
|         } | 
|       } | 
|       previouspispip := previouspispip.PreviousPlanningPISPIP(); | 
|     } | 
|   *] | 
|   InterfaceProperties { Accessibility: 'Module' } | 
| } |