5 MBAL and the OpenServer
5.5 Direct Access OPENSERVER
5.5.3 High Level Example
The following example illustrates usage of the required functions to use to develop a Direct Access OpenServer macro starting with high level functions:
This example is a VBA macro in an Excel spreadsheet called DA1.XLS is installed with the program in the samples directory.
The purpose of the macro is to run a prediction similar to the standard macro except that it uses different manifold pressures for each well.
The first command MBAL.RL.ALLREST should be called at the start of all macros as it deletes any objects that might not have been cleaned up when running a previous macro.
DoCmd "MBAL.RL.ALLRESET"
The next step is to create and initialize the data objects i.e., tanks, wells, layers and the connections between them. In most cases, the simplest way to do this is to read the objects from an existing *.MBI file. Low level functions do exist, which allow the objects
to be created without reference to a *. MBI file, and the MBAL interface is obviously the most convenient way to set up the objects.
The MBAL.RL.INITIALISE function will read the objects from the *.MBI file specified in the command tag and create objects matching those in the file and connect them together as in the given *.MBI file. All the objects are now initialized and ready for calculations to be performed. MBAL will then run the history simulation up to the time specified in the ENDHISTORY data item, and if a value of -1 is used then MBAL will automatically run the history to the end of the production history in the tanks.
The USESUBSTEP data item must be set to indicate if sub-steps should be used in the history simulation, and if the value is set to zero, MBAL will only calculate at the times specified in the production history. Alternatively, if the value is set to one, then MBAL will also calculate sub-steps between the entered times.
After the INITIALISE function, we read and store the handle that MBAL gave to the file we just read in a VBA variable. This is needed in various commands used later in the macro.
Range("F12") = "Opening file and initialising the model"
DoSet "MBAL.RL.SMBDATA.USESUBSTEPS", 0 dEndHistory = -1
DoSet "MBAL.RL.SMBDATA.ENDHISTORY", dEndHistory
DoCmd "MBAL.RL.INITIALISE(""" + Range("B12") + """)"
iMBIHandle = DoGet("MBAL.RL.SMBDATA.HANDLE")
In the last command we asked MBAL to run the history simulation to the end of the tanks production history, but we do not know what that time was and therefore where to start the prediction. So the next code fragment gets the data of the 1st tank in the corresponding *.MBI file - the CUMTIM variable from the data block will indicate the start of the prediction. We can simply use the 1st tank as the value that will be the same for all of the tanks. We have to set the *.MBI file handle stored above, and the command ID=8 to get the tank data. Also, set the tank number to zero to indicate that we want the data from the 1st tank. After calling the RESCALC function, store the CUMTIM variable in the dEndHistory VBA variable.
DoSet "MBAL.RL.SMBRESDATA.HANDLE", iMBIHandle iCommand = 8 ' Get tank data command
DoSet "MBAL.RL.SMBRESDATA.COMMANDID", iCommand DoSet "MBAL.RL.SMBRESDATA.TANKNUM", 0
DoCmd "MBAL.RL.RESCALC"
dEndHistory = DoGet("MBAL.RL.SMBRESDATA.CUMTIM")
The macro defined the WellName() VBA variable at the top of the macro which lists the names of the wells in the MBI file.
WellName(0) = "OilWell"
WellName(1) = "GasLift"
WellName(2) = "WatInj"
WellName(3) = "GasWell"
The next section of the code finds the well model handle of the corresponding well object in MBAL for each of the wells in the VBA WellName() variable. It saves the well model handles in the VBA variable iWellModel() in the same order as the WellName() variable. If the macro is to do any special manipulation of wells such as using a particular WHP for WELLA-3, etc., then the calling macro has to know the handle of each well.
The first stage is to get the number of wells loaded in MBAL and set the Command ID=4 to get the number of well models. After calling the WELLDATA command, we can then get the number of well models from the INTDATA variable in the data block.
The next step is to loop round each well model in MBAL and find the name of each well.
When we find the matching name, we store the well handle. To find the name, we load the stored MBI file handle in the MBIHANDLE variable, and use the command ID=10 to get the well model name and the HANDLE variable with the MBI well model handle.
After the WELLDATA command the WELLNAME variable contains the name.
DoSet "MBAL.RL.SMBWELLDATA.COMMANDID", 4 ' Get well model count
DoCmd "MBAL.RL.WELLDATA"
iNumWellModels = DoGet("MBAL.RL.SMBWELLDATA.INTDATA") For i = 0 To iNumWells - 1
For j = 0 To iNumWellModels - 1
DoSet "MBAL.RL.SMBWELLDATA.MBIHANDLE", iMBIHandle
DoSet "MBAL.RL.SMBWELLDATA.COMMANDID", 10 ' Get well name of model
DoSet "MBAL.RL.SMBWELLDATA.HANDLE", j DoCmd "MBAL.RL.WELLDATA"
If (WellName(i) = DoGet("MBAL.RL.SMBWELLDATA.
WELLNAME")) Then
iWellModel(i) = j End If
Next j Next i
By default, the well model is created assuming there is one instance of the well model.
This next fragment shows how to model more than one well being drilled of the same type:
- Load the MBI handle as usual
- Load 2nd well model handle in the HANDLE variable as we wish to modify the Gas Lift well
- Load the number of wells to drill in NUMWELL
- Load –1 in the variable IPRNUM (this indicates that the command is not specific to a particular layer)
The following code example illustrates the above:
DoSet "MBAL.RL.SMBWELLDATA.MBIHANDLE", iMBIHandle DoSet "MBAL.RL.SMBWELLDATA.HANDLE", iWellModel(1) DoSet "MBAL.RL.SMBWELLDATA.NUMWELL", 2
DoSet "MBAL.RL.SMBWELLDATA.IPRNUM", -1 iCommand = 13 ' Set number of wells
DoSet "MBAL.RL.SMBWELLDATA.COMMAND", iCommand DoCmd "MBAL.RL.WELLDATA"
The next sub-section shows how to set a downtime factor for the 1st well, the Oil Well. A downtime of zero means that the well is always producing, where a downtime of 1.0 means that the well is never producing. The method is much the same as for setting the number of wells.
DoSet "MBAL.RL.SMBWELLDATA.MBIHANDLE", iMBIHandle DoSet "MBAL.RL.SMBWELLDATA.HANDLE", iWellModel(0) DoSet "MBAL.RL.SMBWELLDATA.DOWNTIME", 0.2
DoSet "MBAL.RL.SMBWELLDATA.IPRNUM", -1 iCommand = 12 ' Set downtime command
DoSet "MBAL.RL.SMBWELLDATA.COMMAND", iCommand DoCmd "MBAL.RL.WELLDATA"
This next section shows how to set a start and end time for a well model. This code fragment also shows an important point concerning the use of times. In the Direct Access OpenServer, times are in internal units which are the number of days since 1900. Obviously these are not very convenient units, and if calendar dates i.e., 01/01/1994 aare being used a command to convert calendar dates to internal times (and back again) is provided. To do this set the DATE variable to the calendar date required, then call the DATETOTIME command. The answer can then be retrieved from the TIME variable. To do the reverse calculation use the command TIMETODATE.
We first convert the two calendar dates required to internal times, and then set the STARTTIME and ENDTIME variables to these two internal time values. We set the HANDLE to the well model handle for the third well (Gas Well) and finally set the Command ID=14 to set the start and end times.
DoSet "MBAL.RL.DATE", "31/01/1990"
DoCmd "MBAL.RL.DATETOTIME"
dStartTime = DoGet("MBAL.RL.TIME") DoSet "MBAL.RL.DATE", "02/03/1990"
DoCmd "MBAL.RL.DATETOTIME"
dEndTime = DoGet("MBAL.RL.TIME")
DoSet "MBAL.RL.SMBWELLDATA.MBIHANDLE", iMBIHandle DoSet "MBAL.RL.SMBWELLDATA.HANDLE", iWellModel(3) DoSet "MBAL.RL.SMBWELLDATA.STARTTIME", dStartTime DoSet "MBAL.RL.SMBWELLDATA.ENDTIME", dEndTime DoSet "MBAL.RL.SMBWELLDATA.IPRNUM", -1
iCommand = 14 ' Set start and end time command DoSet "MBAL.RL.SMBWELLDATA.COMMAND", iCommand DoCmd "MBAL.RL.WELLDATA"
We have now completed the initialization and are ready to go into the prediction loop.
The rest of the source code listings are within the main prediction loop which does a time step for each time through the loop.
The first fragment from within the loop is used to update the layers to the current tank conditions. The UPDATELAYERS command only needs the well model handle. The command will loop through each layer in the specifed well model and for each layer it will update the PVT properties from the tank calculated at the current pressure. It then calculates the WCT, GOR, CGR, and WGR for each layer from the relative permeabilities and breakthroughs.
NOTE: This command must be called, or the initial tank conditions will always be used! No command ID is needed.
For iWellNo = 0 To iNumWellModels - 1
DoSet "MBAL.RL.SMBWELLDATA.HANDLE", iWellModel (iWellNo)
DoCmd "MBAL.RL.UPDATELAYERS"
Next iWellNo
The next section is used to calculate the performance of the wells using the IPR/VLP intersection calculation. In this macro we apply a different FWHP for each well. Much of this part of the macro is repeated for each well so only a relevant fragment for the gas lift well is shown.
The first step is to set the well model handle. The next variable to set (TOL) is used to control if intersections are allowed on the negative slope section of the lift curve. The normal situation is where they are not allowed in which case use 0.0. If negative VLP intersections are allowed, the value will be set to a large value i.e., a value of -1e10 will allow any size of negative slope solution.
We then set the extrapolation flag. This specifies whether the lift curves should be extrapolated beyond the upper and lower values of the sensitivity variables. In general, the lift curves should be calculated over all the expected ranges of sensitivity variables.
However limited extrapolation will broaden the range of the lift curves.
NOTE: VLP extrapolation is undesirable as unpredictable behaviour may occur. It is always recommended to regenerate the VLP if lift curve extrapolation has been reported in the well results Status column.
The next step is setting the sensitivity variables for the lift curves, and the required variables will depend on the well type and include:
GLRINJ – Gas lift injected for gas lift wells FREQ – Frequency for ESPs
WHP – Well head pressure
The next step is to call the command IPRVLPCALC. No command ID is needed.
The results of the calculation are the total rate, GOR, WCT etc., which can be retrieved from the data block.
Note that the total rate is liquid rate for oil or water wells and gas rate for gas or condensate wells.
DoSet "MBAL.RL.SMBIPRVLPCALC.HANDLE", iWellModel (iWellNo)
DoSet "MBAL.RL.SMBIPRVLPCALC.TOL", 0#
DoSet "MBAL.RL.SMBIPRVLPCALC.EXTRAP", 1#
If (iWellNo = 1) Then GLRInj = 240#
DoSet "MBAL.RL.SMBIPRVLPCALC.GLRINJ", GLRInj DoSet "MBAL.RL.SMBIPRVLPCALC.WHP", fWHP(iWellNo) DoCmd "MBAL.RL.IPRVLPCALC"
iErrorCode = DoGet("MBAL.RL.SMBERRORDATA.CODE") Range("F" + CStr(17 + iStep)) = fWHP(iWellNo) Range("G" + CStr(17 + iStep)) = GLRInj
If (iErrorCode = 120) Then
Range("H" + CStr(17 + iStep)) = NoSolutionStr Range("I" + CStr(17 + iStep)) = NoSolutionStr Range("J" + CStr(17 + iStep)) = NoSolutionStr Else
Range("H" + CStr(17 + iStep)) = DoGet("MBAL.RL.