| Quintiq file version 2.0 | 
| #parent: #root | 
| Method InitConstraintsForBalance ( | 
|   CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program, | 
|   const constcontent ProductInStockingPointInPeriods smartplanpispips, | 
|   const RunContextForCapacityPlanning runcontext, | 
|   const LibOpt_Scope scope, | 
|   const constcontent ProductInStockingPointInPeriodPlanningLeafs leafpispipsinrun, | 
|   const constcontent ProductInStockingPoint_MPs pispsinrun, | 
|   Number threadnr | 
| ) 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: | 
|   [* | 
|     //If we only want to plan 1 step up stream we need to find the intermediate products of the involved routings. | 
|     //They are needed so we can remove the slack from those intermediate making sure the violations if any are created on the input. | 
|      | 
|      | 
|     balance_constname :=  typeof( MPBalanceConstraint ); | 
|      | 
|     scalefactor_demandslack_const := this.ScaleConstraintTerm( typeof( MPDemandSlackVariable ), balance_constname ); | 
|     scalefactor_tripnewsupply_const := this.ScaleConstraintTerm( typeof( MPTripNewSupplyVariable ), balance_constname ); | 
|     scalefactor_invqty_const := this.ScaleConstraintTerm( typeof( MPInvQtyVariable ), balance_constname ); | 
|     scalefactor_salesdemandqty_const := this.ScaleConstraintTerm( typeof( MPSalesDemandQtyVariable ), balance_constname ); | 
|     scalefactor_dependentdemandinpispip_const := this.ScaleConstraintTerm( typeof( MPDependentDemandInPISPIPVariable ), balance_constname ); | 
|     scalefactor_delayedsalesdemandqty_const := this.ScaleConstraintTerm( typeof( MPDelayedSalesDemandQtyVariable ), balance_constname ); | 
|     scalefactor_periodtaskqty_const := this.ScaleConstraintTerm( typeof( MPPTQtyVariable ), balance_constname ); | 
|     scalefactor_expired_const := this.ScaleConstraintTerm( typeof( MPExpiredVariable ), balance_constname ); | 
|      | 
|     scalefactor_rhs_constr := this.ScaleConstraintRHS( balance_constname, 1.0 ); | 
|      | 
|     intermediatepisps := construct( ProductInStockingPoint_MPs, constcontent );  | 
|     if ( runcontext.IsOnlyPlanOneStepUpstream() )  | 
|     { | 
|       intermediatepisps := selectset( scope.GetRoutingOfSmartPlanPISPIPsConst(), Elements.OperationInput.ProductInStockingPoint_MP, pisp,  | 
|                                            exists( scope.GetRoutingOfSmartPlanPISPIPsConst(), Elements.OperationOutput.ProductInStockingPoint_MP, pisp2, pisp2 = pisp ) ); | 
|         | 
|       // we need the unsplit balance equation always. For this small planning case we dont spread over threads  | 
|       if ( threadnr = 0 )  | 
|       { | 
|         traverse( leafpispipsinrun, Elements, pispip )  | 
|         { | 
|           this.InitConstraintsForBalanceNoShelfLife( program,  | 
|                                                      smartplanpispips,  | 
|                                                      intermediatepisps,  | 
|                                                      pispip,  | 
|                                                      runcontext,  | 
|                                                      scope,  | 
|                                                      scalefactor_demandslack_const,  | 
|                                                      scalefactor_tripnewsupply_const,  | 
|                                                      scalefactor_invqty_const,  | 
|                                                      scalefactor_salesdemandqty_const,  | 
|                                                      scalefactor_dependentdemandinpispip_const,  | 
|                                                      scalefactor_delayedsalesdemandqty_const,  | 
|                                                      scalefactor_periodtaskqty_const,  | 
|                                                      scalefactor_expired_const,  | 
|                                                      scalefactor_rhs_constr );  | 
|         } | 
|       } | 
|     } | 
|     else | 
|     { | 
|       // right now pispip.PreThreadNr is 0, 1, ..., 999. We use thread param to balance the workload  | 
|      | 
|       // we need the unsplit balance equation always | 
|       traverse( leafpispipsinrun, Elements, pispip, CapacityPlanningSuboptimizer::GetThreadNr( this.ThreadAParameter(), this.ThreadBParameter(), pispip.PreThreadNr() ) = threadnr )  | 
|       { | 
|         this.InitConstraintsForBalanceNoShelfLife( program,  | 
|                                                    smartplanpispips,  | 
|                                                    intermediatepisps,  | 
|                                                    pispip,  | 
|                                                    runcontext,  | 
|                                                    scope,  | 
|                                                    scalefactor_demandslack_const,  | 
|                                                    scalefactor_tripnewsupply_const,  | 
|                                                    scalefactor_invqty_const,  | 
|                                                    scalefactor_salesdemandqty_const,  | 
|                                                    scalefactor_dependentdemandinpispip_const,  | 
|                                                    scalefactor_delayedsalesdemandqty_const,  | 
|                                                    scalefactor_periodtaskqty_const,  | 
|                                                    scalefactor_expired_const,  | 
|                                                    scalefactor_rhs_constr );  | 
|       } | 
|     } | 
|      | 
|      | 
|     if ( threadnr = 0 ) // put all in thread 'A'  | 
|     { | 
|       // if shelf life is active we also need to create balances that are split per incoming lead time  | 
|       traverse( pispsinrun, Elements, pisp, pisp.IsOptShelfLife() )  | 
|       { | 
|         pispips := pisp.GetPISPIPForShelfLifeOptimizer( scope ); // this includes extra periods prior to the optimizer scope spanning at least the shelf life (this is a super set of what is in algorithmrun.PISPIPInOptimizerRun) | 
|          | 
|         firststart := DateTime::MinDateTime(); // set in method call - will be the first pispip.start from among 'pispips' | 
|         laststart := DateTime::MinDateTime(); // set in method call - will be the last pispip.start from among 'pispips' | 
|         firstafteractualstart := DateTime::MinDateTime(); // set in method call - will be the first pispip.start after the last actual (if any) | 
|         pisp.GetScopeShelfLifeForPISP( pispips, firststart, laststart, firstafteractualstart ); // set above three variables  | 
|         firstpispipforbalancestart := maxvalue( firststart, firstafteractualstart ); // we will initialize the split balance constraint after the last actual, or for any of the elements of 'pispips' if there are no actuals | 
|         traverse( pispips, Elements.astype( ProductInStockingPointInPeriodPlanningLeaf ), pispip )  | 
|         {    | 
|             if ( pispip.Start() >= firstpispipforbalancestart )  | 
|             { | 
|               this.InitConstraintsForBalanceSplitShelfLife( program,  | 
|                                                             smartplanpispips,  | 
|                                                             intermediatepisps,  | 
|                                                             pispip,  | 
|                                                             firstpispipforbalancestart,  | 
|                                                             laststart,  | 
|                                                             runcontext,  | 
|                                                             scope, | 
|                                                             scalefactor_demandslack_const,  | 
|                                                             scalefactor_tripnewsupply_const,  | 
|                                                             scalefactor_invqty_const,  | 
|                                                             scalefactor_salesdemandqty_const,  | 
|                                                             scalefactor_dependentdemandinpispip_const,  | 
|                                                             scalefactor_delayedsalesdemandqty_const,  | 
|                                                             scalefactor_periodtaskqty_const,  | 
|                                                             scalefactor_expired_const,  | 
|                                                             scalefactor_rhs_constr ); // additional split balance constraint in case shelf life is optimized | 
|             } | 
|             this.InitConstraintsForShelfLifeSumConstraints( program,  | 
|                                                             smartplanpispips,  | 
|                                                             intermediatepisps,  | 
|                                                             pispip,  | 
|                                                             firststart,  | 
|                                                             laststart,  | 
|                                                             scope,  | 
|                                                             scalefactor_invqty_const,  | 
|                                                             scalefactor_rhs_constr ); // sum constraints taking care of consisteny between split and unsplit versions of a variable | 
|         } | 
|       } | 
|     } | 
|   *] | 
|   InterfaceProperties { Accessibility: 'Module' } | 
| } |