skyfx
skyfx

Reputation: 29

Reproducing Excel Solver GRG Nonlinear Optimization in Visual Basic .NET

I am trying to re-produce the following Excel Solver GRG Nonlinear optimization using the Microsoft Solver Foundation in VB.NET (numbers are simplified for the sake of this example):

  1. Objective: Total Gas Rate = 100000
  2. Variable: Well 1 Oil Rate
  3. Constraints: 0 <= Well 1 Gas Rate <= 1000, Well 2 Gas Rate = 2000

This optimization is subject to the following relationships:

  1. Well 1 Gas Rate = Well 1 Oil Rate * 5
  2. Total Gas Rate = Well 1 Gas Rate + Well 2 Gas Rate

Is it possible to solve such a problem using Solver Foundation? When trying to implement this, the two things I struggled with are:

  1. It appears that Solver Foundation models only have two GoalKind's: minimum and maximum. In my case, I am trying to optimize for a specific value. Is there any way to do this?
  2. How do I define the above relationships? I would think the latter would be defined as part of the goal definition (e.g., model.AddGoal("total_gas_rate", GoalKind.[not sure what goes here], Well1PGasRate + Well2PGasRate), but how do I define the other one?

Thanks!

Upvotes: 1

Views: 1568

Answers (2)

Budi Zhu
Budi Zhu

Reputation: 1

Answer in C#:

    static void SolverGasRate()
    {
        Console.WriteLine("\nBegin Solver Gas Rate using Solver Context MSF\n");

        var solver = SolverContext.GetContext();
        var model = solver.CreateModel();

        var decisionWell1OilRate = new Decision(Domain.IntegerNonnegative, "Well1OilRate");
        model.AddDecision(decisionWell1OilRate);
        var decisionWell2GasRate = new Decision(Domain.IntegerNonnegative, "Well2GasRate");
        model.AddDecision(decisionWell2GasRate);

        Goal goal = model.AddGoal("Goal", GoalKind.Maximize, TotalGasRateTerm(decisionWell1OilRate, decisionWell2GasRate));

        model.AddConstraint("Objective", TotalGasRateTerm(decisionWell1OilRate, decisionWell2GasRate) <= 100000);
        model.AddConstraint("Constraint1", decisionWell1OilRate * 5 >= 0);
        model.AddConstraint("Constraint2", decisionWell1OilRate * 5 <= 1000);
        model.AddConstraint("Constraint3", decisionWell2GasRate <= 2000);

        var solution = solver.Solve();
        double Well1OilRate = decisionWell1OilRate.GetDouble();
        double Well2GasRate = decisionWell2GasRate.GetDouble();

        Console.WriteLine("Well1OilRate: " + (Well1OilRate).ToString());
        Console.WriteLine("Well1GasRate: " + (Well1OilRate*5).ToString());
        Console.WriteLine("Well2GasRate: " + (Well2GasRate).ToString());
        Console.WriteLine("TotalGasRate: " + TotalGasRate(Well1OilRate, Well2GasRate).ToString());

        Console.WriteLine("\nEnd Solver demo\n");
    }

    static Term TotalGasRateTerm(Decision decisionWell1OilRate, Decision decisionWell2GasRate)
    {
        return (decisionWell1OilRate * 5) + decisionWell2GasRate;
    }

    static double TotalGasRate(double Well1OilRate, double Well2GasRate)
    {
        return (Well1OilRate * 5) + Well2GasRate;
    }

Output:

Begin Solver Gas Rate using Solver Context MSF

Well1OilRate: 200
Well1GasRate: 1000
Well2GasRate: 2000
TotalGasRate: 3000

End Solver demo

Upvotes: 0

DirtStats
DirtStats

Reputation: 599

This answer only addresses part 1 of your question and in a conceptual manner, but hopefully it is helpful. If you're trying to optimize for a specific value target and the output of your function is output then you could try something like this pseudocode:

minimize(absolute_value(output/target-1))

Effectively, this will give you a value that reaches zero as the output of your function nears the target value. So you can still use an optimization engine that minimizes the final output of your function.

Upvotes: 0

Related Questions