| Quintiq file version 2.0 | 
| #parent: #root | 
| Method InitConstraintsSequentialAtEnd ( | 
|   CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program, | 
|   const RunContextForCapacityPlanning runcontext, | 
|   const LibOpt_Scope scope, | 
|   const constcontent ProductInStockingPointInPeriodPlanningLeafs leafplanningpispips | 
| ) const | 
| { | 
|   Description: 'method to be executed after parallel cplex constraint init has taken places ( used for initialzing items that need data from multiple threads)' | 
|   TextBody: | 
|   [* | 
|      | 
|     // Define the goals for each level | 
|     this.InitConstraintsForGoalsForLevelGoal( program,runcontext, scope ); // lkeep last because for meta we obtain values from existing plan before this | 
|      | 
|     if ( runcontext.IsMetaIteration()  | 
|          and this.FocusLevel() > 0  | 
|          and this.GetRunContextMeta().OptionFixDemandSlackVar()  | 
|          and this.DoLevelCollapse( runcontext ) ) | 
|     { | 
|       traverse( leafplanningpispips, Elements, pispip )  | 
|       { | 
|         boundforvar := pispip.DependentDemandUnfulfilledQuantity() | 
|         this.FreezeSlackVariableMeta( program, pispip, boundforvar, program.DemandSlackVariables().Get( pispip ), program.TotalSlackConstraints().Get() ); | 
|       }  | 
|        | 
|       if( runcontext.GetConsiderTotalUserSupply( scope ) ) | 
|       { | 
|         pispipsforconstraint := runcontext.GetPISPISPForUserSupplyConstraint( scope, leafplanningpispips );  | 
|          | 
|         traverse( pispipsforconstraint, Elements.astype( ProductInStockingPointInPeriodPlanningLeaf ), pispip )  | 
|         { | 
|           // constr constraint UoM: PISP | 
|           constr := program.TotalSlackUserSupplyConstraints().Get();  | 
|           varover := program.UserTotalSupplyOverVariables().Get( pispip );  | 
|           varunder := program.UserTotalSupplyUnderVariables().Get( pispip );  | 
|           oversupply := maxvalue( 0.0, pispip.SupplyQuantity()  - pispip.TotalSupplyUser() );  | 
|           undersupply := maxvalue( 0.0, pispip.TotalSupplyUser() - pispip.SupplyQuantity() );  | 
|           this.FreezeSlackVariableMeta( program, pispip, oversupply, varover, constr ); | 
|           this.FreezeSlackVariableMeta( program, pispip, undersupply, varunder, constr ); | 
|         } | 
|       } | 
|     } | 
|      | 
|     if ( runcontext.UseCampaignSequenceOptimizer() and runcontext.RunWithDebugCampaignCombis() )  | 
|     { | 
|       // for running with manual fixed combis (debugging) it easy not to have selected a combi for a unit period, so we add a slack variable to safeguard against it | 
|       level_zero := select(  this, MacroPlan.StrategyMacroPlan.StrategyLevelMacroPlan, slm, true, slm.Level() = 0 );  | 
|       traverse( scope.GetUnitPeriodInOptimizerRunConst(), Elements.OptCampaignUnitSubPeriod, ocusp ) | 
|       { | 
|         constr := program.CalcDurationOfOptCampaignUnitSubPeriodConstraints().Get( ocusp ); | 
|         debuginfo( 'Warning - running with fixed campaign combis. Adding slack variable ', constr.Name() );   | 
|         slackvar := program.SlackDebugCampaignCombisVariables().New( ocusp );  | 
|         c := program.GoalConstraints().Get( level_zero );   | 
|         c.NewTerm( -1000.0, slackvar );  | 
|         constr.NewTerm( 1.0, slackvar );    | 
|       } | 
|     } | 
|      | 
|     // Define PosInvPastLast variable in case inventory holding needs to be computed | 
|     if ( runcontext.IsMetaIteration() and this.GetInitializeFinancialConstraints( runcontext ) )  | 
|     { | 
|         constname :=  typeof( MPDefinePosInvPastLastConstraint ); | 
|      | 
|         scalefactor_posinvpastlast_const := this.ScaleConstraintTerm( typeof( MPPosInvQtyPastLastVariable ), constname ); | 
|         scalefactor_invqty_const := this.ScaleConstraintTerm( typeof( MPInvQtyVariable ), constname ); | 
|         scalefactor_rhs_constr := this.ScaleConstraintRHS( constname, 1.0 ); | 
|      | 
|       traverse( scope.GetProductInStockingPointInOptimizerRunConst(), Elements, pisp )  | 
|       { | 
|      | 
|      | 
|      | 
|         last := pisp.LatestPISPIPInScope();  | 
|         current := guard( last.Next().astype(  ProductInStockingPointInPeriodPlanningLeaf ), null(  ProductInStockingPointInPeriodPlanningLeaf ) );  | 
|          | 
|         while ( not isnull( current ) )  | 
|         { | 
|           var := program.PosInvQtyPastLastVariables().Get( current );  | 
|            | 
|           // PosInvPastLast_current >= current.InventoryLevelEnd + (InvQty_last - last.InventoryLevelEnd )  | 
|           // | 
|           // example: if we decrease the inventory of last by 5 this says PosInvPastLast_current >= current.InventoryLevelEnd - 5.  | 
|           //          meaning if current.InventoryLevelEnd is <= 5, we can avoid inventory holding cost | 
|           // similarly if we increase by 5, posInvPastLast_current >= current.InventoryLevelEnd + 5 and we collect inventory holding cost in case previous inventory was bigger than 5 | 
|            | 
|           c := program.DefinePosInvPastLastConstraints().New( current );  | 
|           c.Sense( '>=' );  | 
|           c.RHSValue( ( current.InventoryLevelEnd() - last.InventoryLevelEnd() ) * scalefactor_rhs_constr );   | 
|           c.NewTerm( 1.0 * scalefactor_posinvpastlast_const, var ); | 
|           c.NewTerm( -1.0 * scalefactor_invqty_const, program.InvQtyVariables().Get( last ) );   | 
|            | 
|           this.FilterCPLEXNoise( c, 1.0 );  | 
|            | 
|           current := current.NextPlanningPISPIP().astype(  ProductInStockingPointInPeriodPlanningLeaf );  | 
|         } | 
|       } | 
|     } | 
|      | 
|     traverse( runcontext, UserPeriodTask, pt, pt.HasUserQuantity() and pt.HasDependentDemandUserQuantity() ) // deal with potential infeasible manual fixed planning, where both  | 
|     {                                                                                                        // periodtask dependent demand and new supply quantity are set | 
|       slackconstr := program.TotalSlackConstraints().Get();  | 
|       period := pt.UnitPeriod().Period_MP();  | 
|        | 
|       constddqtyname := typeof( MPOperationDependentDemandQtyConstraint ); | 
|       constddpartialname := typeof( MPPartialOperationDependentDemandQtyConstraint ); | 
|       constslack := typeof( MPTotalSlackConstraint );  | 
|      | 
|       scalefactor_slack_constpartial := this.ScaleConstraintTerm( typeof( MPPartialOperationDependentDemandQtySlackNegVariable ), constddpartialname ); | 
|       scalefactor_partialslack_slackconst := this.ScaleConstraintTerm( typeof( MPPartialOperationDependentDemandQtySlackNegVariable ), constslack ); | 
|       scalefactor_slack_slackconst := this.ScaleConstraintTerm( typeof( MPOperationDependentDemandQtySlackNegVariable ), constslack ); | 
|       scalefactor_slack_constdd := this.ScaleConstraintTerm( typeof( MPOperationDependentDemandQtySlackNegVariable ), constddqtyname ); | 
|      | 
|      | 
|       traverse( pt, DependentDemand, dd, dd.HasUserQuantity() ) | 
|       { | 
|         pispipperiod := dd.ProductInStockingPointInPeriodPlanningLeaf().Period_MP();  | 
|         input := dd.ProcessInput().astype( OperationInput );  | 
|         if ( pt.Operation().HasLeadTime() )  | 
|         { | 
|           c := program.PartialOperationDependentDemandQtyConstraints().Find( input, pispipperiod, period ); | 
|           if ( not isnull( c ) )  | 
|           { | 
|             slacknegvar := program.PartialOperationDependentDemandQtySlackNegVariables().New( input, pispipperiod, period );  | 
|             slackposvar := program.PartialOperationDependentDemandQtySlackPosVariables().New( input, pispipperiod, period );  | 
|             c.NewTerm( 1.0 * scalefactor_slack_constpartial, slackposvar );  | 
|             c.NewTerm( -1.0 * scalefactor_slack_constpartial, slacknegvar );  | 
|              | 
|             slackconstr.NewTerm( -1.0 * scalefactor_partialslack_slackconst, slacknegvar );  | 
|             slackconstr.NewTerm( -1.0 * scalefactor_partialslack_slackconst, slackposvar );  | 
|           } | 
|         }  | 
|         else | 
|         { | 
|           c := program.OperationDependentDemandQtyConstraints().Find( input, period ); | 
|           if ( not isnull( c ) )  | 
|           { | 
|             slackposvar := program.OperationDependentDemandQtySlackPosVariables().New( input, period );  | 
|             slacknegvar := program.OperationDependentDemandQtySlackNegVariables().New( input, period );  | 
|             c.NewTerm( 1.0 * scalefactor_slack_constdd, slackposvar );  | 
|             c.NewTerm( -1.0 * scalefactor_slack_constdd, slacknegvar );  | 
|              | 
|             slackconstr.NewTerm( -1.0 * scalefactor_slack_slackconst, slacknegvar );  | 
|             slackconstr.NewTerm( -1.0 * scalefactor_slack_slackconst, slackposvar );  | 
|           } | 
|         }  | 
|       }     | 
|     } | 
|      | 
|     program.GenerateNames(); // need to otherwise .sav files are anonymized | 
|   *] | 
|   InterfaceProperties { Accessibility: 'Module' } | 
| } |