Documentation

Introduction

SimpleOpenServer (or SOS for short) is a group of Class Methods and Modules implemented in VBA, intended for the use of Petroleum Engineers that want to automatize tasks involving models.

Using SimpleOpenServer is easy, even for the users who did not have contact with OpenServer before. A basic understanding of Excel Macros is needed, in order to understand the inputs and outputs of the methods.

This documentation is divided into sections corresponding to each of the modules of the original SimpleOpenServer package:

  • ProsperCalculation, which is the object used to interact with PROSPER and perform calculations with Well models.
  • Vector Object, which is the object that encapsulates methods relative to curves and vectors.

The Prosper Calculation Object

The ProsperCalculation object is used to make calculations in PROSPER Well models. The ProsperCalculation object supports the following calculations:

  • System calculations
  • Gradient calculations
  • VLP calculations
  • IPR calculations

Please see the following sections regarding the Prosper Calculation Object:

Basic Use

In order to make calculations with this object, the user needs to do four things:

  1. Initialize the Object
  2. Set the value of any variables for the calculation
  3. Make the calculation
  4. Obtain the results in form of values, using solution(); or curves, using vector()

Example and Comparison with normal OpenServer

In this example we try to find the System solution for a Skin factor of 2.5, and obtain the Liquid Rate.

Dim myCalc as New ProsperCalculation
myCalc.calculationType = System
myCalc.setVar Skin, 2.5
myCalc.calculate
Range("B2") = myCalc.solution([Q Liquid])

Before making the calcualtions, the myCalc object is created, as a new ProsperCalculation. This object will hold the properties, methods and functions that will be used.

To start, we set the calculationType property to System, and set the Skin factor to the indicated value using the setVar method. To make the calculation, we run the calculate method. Finally, obtain the solution value using the solution function, and store the value in cell B2.

The basic syntax is very similar to common OpenServer syntax, replacing the DoGet, DoCmd and DoSet functions for other more representative of what is being done.

This is the OpenServer syntax for the above task:

DoSet "PROSPER.ANL.SYS.SENS.SENSDB.CLEAR", 1
DoSet "PROSPER.ANL.SYS.SENS.SENSDB.VARS[0]", 2
DoSet "PROSPER.ANL.SYS.SENS.SENSDB.SENS[27].VALS[0]", 2.5
DoCmd "PROSPER.ANL.SYS.CALC"
Range("B2") = DoGet("PROSPER.OUT.SYS.RESULTS[0].SOL.LIQRATE")

But, as you will notice, the OpenServer code is not as literal, easy to read, easy to understand or easy to debug as the SimpleOpenServer one.

What does the 2 stand for? And the 27? It is impossible to know beforehand that those values represent Skin factor.

Properties

The ProsperCalculation object has the following properties:

calculationType

List Variable. Defaults to System.

You can set or get the calculation type for a ProsperCalculation object using this property. The possible values, and the respective equivalent number are:

  • Inflow (0)
  • System (1)
  • VLP (2)
  • Gradient (3)

To Set this property, just assign its value. VBA will show the list of options.

myCalc.calculationType = System

You can also use the equal sign to Get the value of this property, but bear in mind that the output will be an integer.

myCalc.calculationType = Gradient
MsgBox myCalc.calculationType ' Will output 3

If you are testing for the value of this property, and do not want to use the indexes, you can use the osCalculationType enumerable, which will list all the possible calculation types:

myCalc.calculationType = Gradient
If myCalc.calculationType = osCalculationType.Gradient Then
  MsgBox "This calculation is a gradient calculation!"
Else
  MsgBox "This calculation is NOT a gradient calculation!"
End If

regressionStatus

List Variable. Initially, its value is No Regression Done.

This property is read-only. Used to know the status of convergence of a regression calculation, after performing a regression (such as find, maximize, etc...). The possible values are:

  • No Regression Done (0)
  • Converged (1)
  • Solution Not Found In Range (2)
  • Loops Exceeded (2)
  • No Solution Found (3)

To get the value, just use it as any other property of the object:

' Perform any regression here with the ProsperCalculation Object
If myCalc.regressionStatus = 1 Then
  MsgBox "Converged!"
Else
  MsgBox "Did not Converge"
End If

Instead of placing the number 1 in the conditional, you can use the auxiliary Enumerable list called osRegressionStatus:

If myCalc.regressionStatus = osRegressionStatus.Converged Then
' continue code ...

This property is useful to know what happened to the convergence algorithm. See each of the regression algorithms to learn more about what the convergence flags are in each case.

rememberSetVariables

Boolean. Defaults to True.

As the ProsperCalculation object can accept multiple calculations, it is possible that the user wants to set a property (e.g. Gas-to-oil ratio), and consistently use it along all calculations.

An example would be performing a System calculation first, to find the liquid rate, and then use the liquid rate to perform a Gradient calculation. In this case, the logical thing to do would be to maintain the same conditions for both calculations:

With myCalc
  .setVar GOR, 675 ' GOR set to 675
  .calculationType = System
  .calculate ' First calculation.
  
  [B5] = .solution([Q Liquid])
  
  .setVar [Flow Rate (Gradient)], [B5]
  
  .calculationType = Gradient
  .calculate ' Second calculation. (gradient calculation)
End With

If the rememberSetVariable flag is set to True, then the Gradient calculation will also be calculated with the GOR value of 675. There is no need to repeat the .setVar method.

This property can be Set by just changing its value:

myCalc.rememberSetVariables = False

To Get the value of this property, just use it as a normal property:

Range("B5") = myCalc.rememberSetVariables

resetSensitivities

Boolean. Defaults to True.

Before running any calculation in PROSPER, it is usually desirable to reset all the sensitivities. If this property is True (the default), then any sensitivities present will be reset, and only the variables set using setVar will be considered.

For now, this setting has not much impact as currently the ProsperCalculation object only deals with single solutions. But it will come in useful if the user wants to keep the sensitivities stored in each calculation.

This property can be Set by just changing its value:

myCalc.resetSensitivities = False

useRawValues

Boolean. Defaults to False.

If set to True, all values that are input to PROSPER will be considered as being in Oilfield units. Also, all values obtained from PROSPER will be always in Oilfield units.

If set to False, all values that are input to PROSPER will be considered to be in the same units than the variables in the current PROSPER model, and all the values obtained from PROSPER will be in the same unit system as the PROSPER model.

This setting is used when the units of the PROSPER models might not be always the same.

Example:

Setting the Reservoir Pressure of a PROSPER model that has BARg as the pressure unit will have a different result whether Raw values are used or not:

  • If Raw Values are used, and the value "230" is input, then the reservoir pressure will be changed to 230 psig.
  • If Raw Values are not used, and the value "230" is input, then the new Reservoir pressure will be "230 BARg"

The same happens if we use Raw values when getting the values out of PROSPER. Let's suppose that the Reservoir pressure in our model is 230BARg:

  • If Raw Values are used, and we ask for the reservoir pressure, then the value returned will be "3336", which corresponds to 3336 psig = 230 BARg.
  • If Raw Values are not used, then the value "230" will be returned.

Methods

The ProsperCalculation object has the following methods:

  • setVar, to set a variable prior to calculation
  • calculate, to run the calculation

setVar [variable], [value]

Parameters:

  • variable: Input variable to be changed / set
  • value: Value to which it will be set

This method will set the chosen input variable to the value entered.

Currently, only scalar values are accepted so, to avoid errors, Value should be an integer or decimal (double).

Advantages over doSet

For simple variables such as [Top node Pressure] or [GOR], the syntax in OpenServer is simple if you know the AccessString:

' Setting Top Node Press. in OpenServer
doSet "PROSPER.ANL.SYS.PRES", 250

However, for other variables such as [Permeability], or [Skin Factor], or [ESP Frequency], the syntax is more complicated for OpenServer:

' Example setting ESP Frequency = 60Hz in OpenServer (IPM9)
doSet "PROSPER.ANL.SYS.Sens.SensDB.Var[0]", 35
doSet "PROSPER.ANL.SYS.Sens.Sens[148].Var[0]", 60

This code is difficult to understand, because the variable is hidden inside an index (35), and that index inside another (148)!. Also, when adding more variables the indexes “[0]" must change accordingly, which further complicates the situation.

Using setVar, you will always use the same syntax:

myCalc.setVar [Top Node Pressure], 250
myCalc.setVar [Pump Operating Frequency (ESP)], 60

Which is clearer, easier to read, debug, and understand.

setVar and multiple Calculations

If you are going to make multiple calculations which are related, such as a System calculation followed by a Gradient calculation, you should make sure that the rememberSetVariables flag is set to true, to keep the values set using setVar in all the calculations.

setVar and previously existing Sensitivities

As setVar will sometimes modify the sensitivity section of the calculations, the resetSensitivities flag is used to either reset the current sensitivities or to keep them when making the calculations.

calculate

This method performs the calculation set in calculationType property of the ProsperCalculation object.

myCalc.calculate

Notice that the same method is called for any of the three different calculationTypes in PROSPER.

Functions

The ProsperCalculation object has several functions.

Some are to get results of calculations:

  • solution, to obtain any variable of the system calculation solution
  • vector, to obtain any curve resulting from a calculation (e.g. IPR Pressure, or Pressure Gradient vs Depth)

Other functions are used to make a regression using the PROSPER model, and obtaining the result of such regression:

  • find, to find the input variable that matches a condition
  • maximize, to find the input variable that maximizes a certain output variable
  • minimize, to find the input variable that minimizes a certain output variable
  • match, to match a certain curve to a set of points by changing an input variable.
  • rateOfChange, to find the rate of change of an output variable when an input variable is modified

solution (variable)

Parameters:

  • variable: Output variable to be obtained

The Solution function will output any of the variables corresponding to the result of a System calculation in PROSPER.

Dim myCalc as New ProsperCalculation
myCalc.calculationType = System
myCalc.calculate
Range("F3") = myCalc.solution([Q Gas])

This example code makes the system calculation and outputs the gas rate found to the F3 cell.

vector (variable)

Parameters:

  • variable: Output variable to be obtained

This function returns a vector object. Using this command you can obtain any curve generated by PROSPER in a calculation. For example, you can obtain the IPR curve by using:

Dim myCalc as New ProsperCalculation, theVector as New Vector
myCalc.calculationType = IPR
myCalc.calculate
Set theVector = myCalc.vector([IPR Pressure])
' Now theVector holds the ipr curve

or, for a gradient calculation, you can get the pressure gradient in the well:

Dim myCalc as New ProsperCalculation, theVector as New Vector
myCalc.calculationType = IPR
myCalc.calculate
Set theVector = myCalc.vector(Pressure)
' Now theVector holds the pressure gradient vs depth

To show the whole list of options, use the prefix rv (for rate vectors) and dv for depth vectors, as in this example:

Intellisense Shown using the appropriate rv prefix to show rate vectors

If you want to obtain the IPR curve, for eaxmple, you would request for a rate vector with the IPR pressures, as in the example above. Then, Simple OpenServer would obtain both the rates and the pressures for you to build the whole curve. You can see more about that in the Vector Object documentation.

Related Examples:

find (valueOf, thatMakes, equalTo, betweenValue, andValue, [precision])

Parameters:

  • valueOf: The Input Variable will be modified until the conditions are met
  • thatMakes: Target variable that will be set equal to the value of equalTo
  • equalTo: The Target value
  • betweenValue and andValue: Range of Search, defined by minimum and maximum values for the Input variable.
  • precision (optional): The precision, in terms of the target value, to which to adjust the match.

Usage:

[F2] = myCalc.find(valueOf:=[Top Node Pressure], _
                 thatMakes:=[Liquid Rate], _
                   equalTo:=2500, _
              betweenValue:=300, _
                  andValue:=600)

Which is equivalent to:

"We will look for the value of Top Node Pressure that will make the Liquid Rate of the well equal to 2500[STB/d], searching between Top Node Pressures of 300 and 600[psig]."

Remember: The units are implied in the PROSPER model, or depending on the setting of useRawValues.

This regression algorithm will only find a solution if the seeked value of the Input Variable is between the range given (defined by the betweenValue & andValue parameters).

The returned value is the value of the Input Variable that fulfills the condition: Target Variable = Target Value.

find and the regressionStatus flag

If the seeked value is outside the range given, the regressionStatus will be equal to [Solution Not Found in Range], and the value returned will be one of the two extremes of the Range provided, whichever is closest.

This might not be true for non-monotonous curves, such as pump efficiency, so caution in the selection of the ranges is advised.

If the seeked value is found, but after the iterations it did not converge to the required precision, then the regressionStatus will be equal to [Loops Exceeded]. The value returned will be the best guess so far.

If the seeked value is found, and the required precision is met, then the found value is returned, and the regressionStatus will be equal to [Converged].

maximize (variable, byChanging, betweenValue, andValue, [precision])

Parameters:

  • variable: Target variable that will try to be maximized
  • byChanging: The Input Variable will be modified until the maximum is found
  • betweenValue and andValue: Range of Search, defined by minimum and maximum values for the Input variable.
  • precision (optional): The precision, in terms of the target value, that dictates when to stop the algorithm.

Usage:

[F2] = myCalc.maximize(variable:=[Q Oil], _
                     byChanging:=[Gaslift Casing Pressure], _
                   betweenValue:=1000, _
                       andValue:=2500)

Which is equivalent to:

"What is the Casing Pressure that maximizes Oil Rate, searching between Casing Pressures of 1000 and 2500[psig]."

The returned value will be the value of the Input Variable that maximizes the Target Variable.

maximize and the regressionStatus flag

If the trend of the Target Variable shows no maximum point between the searched range, then one of the extremes will be returned, whatever one that makes the Target Variable higher, and the regressionStatus will be set to [No Solution Found].

If the trend of the Target Variable shows a maximum point, but that point seems to be outside the searched range, then one of the extremes will be returned, and the regressionStatus will be set to [Solution Not Found in Range].

If the trend of the Target Variable shows a maximum point, and seems to be inside the searched range, then the maximum point will be searched for.

After a certain number of iterations, if the solution has not been found within a certain tolerance (the precision variable), then the returned value will be the best guess so far, and the regressionStatus will be set to [Loops Exceeded].

If, however, the solution is found within the tolerance set by precision, then the returned value will be the value of the Input Variable that maximizes the Target Variable, and the regressionStatus will be set to [Converged].

minimize (variable, byChanging, betweenValue, andValue, [precision])

Parameters:

  • variable: Target variable that will try to be minimized
  • byChanging: The Input Variable will be modified until the minimum is found
  • betweenValue and andValue: Range of Search, defined by minimum and maximum values for the Input variable.
  • precision (optional): The precision, in terms of the target value, that dictates when to stop the algorithm.

Usage:

[F2] = myCalc.minimize(variable:=[Bottomhole Pressure], _
                     byChanging:=[Gaslift Injection Rate], _
                   betweenValue:=2, _
                       andValue:=10)

Which is equivalent to:

"What is the Gaslift Injection Rate that minimizes Bottomhole Pressure, searching between Injection Rates of 2 and 10[MMScfd]."

The returned value will be the value of the Input Variable that maximizes the Target Variable.

maximize and the regressionStatus flag

The same flag concepts described in the maximize function apply.

match (curve, toPoints, byChanging, betweenValue, andValue, [precision])

Parameters:

  • curve: The Curve that is going to be matched
  • toPoints: The Test Points that will be used to find the match
  • byChanging: The Input Variable that will be modified to meet the conditions
  • betweenValue and andValue: Range of Search, defined by minimum and maximum values for the Input variable
  • precision (optional): The precision, in terms of the target value, to which to adjust the match

Usage:

[F2] = myCalc.match(curve:=[IPR Pressure], _
                 toPoints:=testPoints, _
               byChanging:=Skin, _
             betweenValue:=0, _
                 andValue:=12)

Which is equivalent to:

"We will look for the Skin factor value that will make the IPR curve match our Test Points, searching between Skin factors 0 and 12."

The Curve parameter can be filled using intellisense, just by adding either the rate vector (rv) or depth vector (dv) prefixes. To show the whole list of options, use the prefix rv (for rate vectors) and dv for depth vectors, as in this example:

Intellisense Shown using the appropriate rv prefix to show rate vectors

Even though this example is showing the vector function, the prefixes work the same way here.

If you want to match the IPR curve, for exmple, you would choose to match the IPR Pressures, which is a rate vector. An example was created to exemplify in depth the use of this functionality: how to obtain curves from PROSPER.

The Test Points passed in to this function should be a vector object. Usually, the newFromRange method is used to grab the Test points from the worksheet directly, or the addPoint method to add points one at a time.

Remember: The units are implied in the PROSPER model, or depending on the setting of useRawValues.

This regression algorithm will only find a solution if the seeked value of the Input Variable is between the range given (defined by the betweenValue & andValue parameters).

The returned value is the value of the Input Variable that matches the provided curve within the tolerance.

match and the regressionStatus flag

The same flag concepts described in the maximize function apply.

Related Examples:

rateOfChange (of, whenChanging, atValue)

Parameters:

  • of: The Output Variable whose rate of change is evaluated
  • whenChanging: The Input Variable that will be modified
  • atValue: The rate of change returned corresponds to a certain value of the Input Variable. As rates of change are not constant, such value need to be informed.

Usage:

[F2] = myCalc.rateOfChange(of:=[Q Liquid], _
                 whenChanging:=[Top Node Pressure], _
                      atValue:=450)

Which is equivalent to:

"How sensible is the Liquid Rate of my well to WHP? Current WHP is 450[psig]."

This function will return the derivative of the Output Variable with respect to the Input Variable at the given point.

In the above example, the returned value will be in [STB/d per psi]. This function can be used for marginal decision making analysis.

The Vector Object

The vector object was designed to hold the curves obtained from PROSPER calculations, mainly from the .vector() function.

It provides enhanced functions and methods that facilitate the manipulation of curves obtained from PROSPER in Excel.

Please see the following sections regarding the Vector Object:

Properties

The Vector Object has the following Properties:

  • first and last, to get the first or last values of the curve
  • min and max, to get the extreme values of the curve
  • points, to get the number of points in the curve

first ([coordinate])

Parameter:

  • coordinate (optional): If the string "X" is passed, then the returned value will be the X coordinate. Otherwise, the Y coordinate is returned.

Returns the Y-coordinate of the first point in the vector. If the optional parameter passed is a string "X", then the X-coordinate of the first point in the vector is returned.

last ([coordinate])

Works really the same as first, only that it returns the last point.

min ([coordinate])

Parameter:

  • coordinate (optional): If the string "X" is passed, then the returned value will be the X coordinate. Otherwise, the Y coordinate is returned.

Returns the Y-coordinate of the minimum point in the vector/curve. The comparison is done using the Y-values. If the optional parameter passed is a string "X", then the X-coordinate of the minimum point in the vector is returned.

max ([coordinate])

Works really the same as min, only that it returns the maximum point.

points

Returns the number of points in the vector. Will return zero if the vector has no points assigned yet.

Methods

The Vector Object has the following Methods:

  • add, subtract and multiply, the vector operations, can perform operations with vectors or values
  • printInCell, to print a vector in a range of cells
  • transpose, exchanges the x and y coordinates of the vector
  • newFromRange, sets the values of the vector using the given range of cells

add (vectorOrValue)

Parameter:

  • vectorOrValue: A vector object or a number to be added to the vector.

Usage:

There is a usage example in the subtract section, which is totally compatible with the add method.

If the parameter passed is another vector, add will add the y-coordinates of two vectors. Both vectors must be equal in size, and the X-coordinates must be compatible.

In the case of scalar addition, all y-coordinates are subtracted the given scalar.

subtract (vectorOrValue)

Subtract works in the same way as add, only that it subtracts.

Usage:

Dim myCalc as New ProsperCalculation, PumpDp as New Vector, PIP as New Vector
myCalc.calculationType = System
myCalc.calculate

' PumpDp vector initially holds PDP
Set PumpDp = myCalc.vector([Pump Discharge Press.])
Set PIP = myCalc.vector([Pump Intake Press.])

' We subtract PIP to obtain Pump the DP
PumpDp.subtract PIP

' We can now print the results.. or do other calculations

The script above is equivalent to:

Make a System calculation, find the PDP and PIP curves, and subtract them to get the DP across the Pump.

multiply (vectorOrValue)

Parameter:

  • vectorOrValue: A vector object or a number to be multiplied with the vector.

Multiply will make the multiplication of two vectors' values or the multiplication of all values in the vector by the provided scalar.

In the case of vector multiplication, both vectors must be equal in size, and the Y-values are multiplied like this:

y_i = y_i * z_i, where y and z are the two vectors, and i the index.

In the case of scalar multiplication, all y-coordinates are multiplied by the given scalar.

printInCell (range, [direction], [printX])

Parameters:

  • inRange: The top-left cell where the data will be printed
  • direction (optional): The direction to print. Can be printDown or printRight. Defaults to printDown
  • printX (optional): Boolean. Choose to print the X-values or not. Defaults to True

Usage:

myVector.printInCell Range("B5")
' Will print the vector starting from B5 down, including the x-coordinates of myVector

You can pass othe optional values like this:

myVector.printInCell Range("B5"), printX:=False
' Will only print the Y-values of the vector

TIP: you can reference ranges in VBA with the shorter syntax:

Range("F15")
' is equivalent to
[F15]
' which makes
myVector.printInCell [F15]
' insanely simple

transpose

Transpose exchanges the X and Y coordinates of a vector.

newFromRange (rng)

Sets the vector equal to the values in the range of cells passed. The range must be a column-oriented range with the values you want to have inside the vector object.

Parameters:

  • rng: Range of cells to be converted to a vector, or name of range of cells.

Usage:

Dim matchingPoints as New Vector
matchingPoints.newFromRange Range("A2:B9")
' matchingPoints holds a vector from that range

The rng parameter can be a range or a string:

matchingPoints.newFromRange Range("A2:B9")
' is equivalent to
matchingPoints.newFromRange "A2:B9" 

Functions

Vector Object has the following Functions:

  • xFromY, to obtain the X value that corresponds to a given Y value
  • Y, to obtain the Y value that corresponds to a given X value
  • dYdX, to obtain the Y derivative at a given X value
  • MSE, returns the mean square error between the vector and matching points

xFromY (Y, [searchDirection])

Parameters:

  • Y: The Y value you will use to look for the X coordinate.
  • searchDirection (optional): can be either rightToLeft or leftToRight, and will determine the search direction of the algorithm

Usage:

Dim myCalc as New ProsperCalculation, IPR as as New Vector, LIQUID_RATE as as Double, BHP as Double

myCalc.calculationType = Inflow
myCalc.calculate
Set IPRcurve = myCalc.vector([IPR Pressure])

BHP = 600
LIQUID_RATE = IPR.xFromY(BHP)

Is equivalent to:

Once you have the IPR of the well, find the rate that will be produced if the BHP is equal to 600.

This function will try to find the X value that corresponds to the given Y value. The searchDirection can be used to modify the algorithm and condition the result found, particularly in non-monotonous curves, as the VLP curve.

The interpolation between the points is linear interpolation.

Y (X)

Parameter:

  • X: The X value you will use to look for the corresponding Y coordinate.

Usage:

Dim myCalc as New ProsperCalculation, Pres_gradient as New Vector, Gauge_D as Double, P_At_Gauge_D as Double

myCalc.calculationType = Gradient
myCalc.calculate
Set Pres_gradient = myCalc.vector(Pressure)

Gauge_D = 3540
P_At_Gauge_D = Pres_gradient(Gauge_D)

Is equivalent to:

Calculate the Flowing Pressure Gradient of the well, store it in the PressGradient variable, and find the pressure at the Gauge Depth.

The Y function returns the Y value that corresponds to a given X value. If the X value does not lie in the X-range of the vector, the last points will be used to extrapolate.

Linear interpolation/extrapolation is used in this function.

dYdX (X)

Parameter:

  • X: The X value you will use to look for the corresponding Y derivative.

The Usage is very similar to the Y function.

Returns the derivative value with respect to X of the curve, at the given X value.

MSE (Points)

Parameter:

  • Points: The Points to compare with the vector

MSE will return the Mean Squared error

Usage:

dim myCalc as New ProsperCalculation, IPRcurve as New Vector, matchingPoints as New Vector
myCalc.calculationType = Inflow
myCalc.calculate
Set IPRcurve = myCalc.vector([IPR Pressure])

matchingPoints.newFromRange("B4:C9")

[F3] = IPRcurve.MSE(matchingPoints)

Is equivalent to:

Calculate the IPR of the well, and record the Mean Squared Error in cell F3 when comparing the IPR to the matching points in the range B4:C9.

This function returns the Mean Squared Error that exists between the points and a given vector. To find the error, the vector is interpolated at each of the x-values of the points vector.

The Points vector must be a vector. To generate a vector from a range, the function to use is newFromRange.

This function can be used in matching algorithms, to match a curve to a set of points.

DOCUMENTATION LAST UPDATED: 14/6/2015