Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ' ####################################################
- ' # ProsperCalculation Class Module #
- ' ####################################################
- ' Auxiliary library to work with Petroleum Experts (TM) OpenServer.
- ' Part of the SimpleOpenServer package, developed by Patricio Panichelli.
- ' Some rights reserved (c) www.SimpleOpenServer.com/license
- ' For documentation, visit www.SimpleOpenServer.com/docs
- ' SOS Version: 1.0.0
- ' Developed & tested with: IPM 9.0
- '
- Option Explicit
- Option Base 0
- Private xCalculationType As osCalculationType, xFixedVars() As Variant, xFixedValues() As Variant, xFixedVarsCount As Long, _
- xResetSensitivities As Boolean, xRememberSetVariables As Boolean, xUseRawValues As Boolean, xRegressionStatus As osRegressionStatus, _
- xXvalues, xFluidType As osFluidType
- Enum osFluidType
- [Oil and Water]
- [Dry and Wet Gas]
- [Retrograde Condensate]
- End Enum
- Enum osRegressionStatus
- [No Regression Done]
- Converged
- [Solution Not Found In Range]
- [Loops Exceeded]
- [No Solution Found]
- End Enum
- Enum osInputVariable
- [Water Cut]
- GOR
- CGR
- WGR
- [Top Node Pressure]
- [Reservoir Pressure]
- [Reservoir Temperature]
- [Productivity Index]
- Permeability
- Skin
- [Tubing Correlation]
- [Surface Correlation]
- [Flow Rate (Gradient)]
- [Bottomhole Pressure (Gradient)]
- [Tubing Roughness]
- [Heat Transfer Coefficient]
- [_Sens DB]
- [Pump Operating Frequency (ESP)]
- [Pump Wear Factor (ESP)]
- [Pump MD (ESP)]
- [Pump Number of Stages (ESP)]
- [Pump Speed (SRP)]
- [Gaslift Gas Injection Rate]
- [Gaslift Injection Depth]
- [Gaslift Casing Pressure]
- End Enum
- Enum osSolutionVariable
- [_Exists]
- [Q Liquid]
- [Q Oil]
- [Q Water]
- [Q Gas]
- [Solution Node Pressure]
- [Bottomhole Pressure]
- [dP Friction]
- [dP Gravity]
- [Wellhead Pressure]
- [Wellhead Temperature]
- [First Node Pressure]
- [First Node Temperature]
- [Pump Intake Pressure]
- [Pump Discharge Pressure]
- [Average Rate Through Pump]
- [Pump Head Generated]
- [Pump Power Requirement]
- [Pump Efficiency]
- [Motor Amps Requirement]
- [Motor Power Generated]
- End Enum
- Enum rv
- [Liquid rate]
- [Oil rate]
- [Water rate]
- [Gas rate]
- [IPR Pressure]
- [VLP Pressure]
- [dP Frict.]
- [dP Grav.]
- [Pump Intake Press.]
- [Pump Discharge Press.]
- [Pump Power Req.]
- End Enum
- Enum dv
- [Label]
- [Measured Depth]
- [True Vertical Depth]
- [Pressure]
- [Temperature]
- [Pressure Gradient]
- [Holdup]
- [Flow Regime Number]
- [Static Gradient]
- [Friction Gradient]
- [Total NoSlip Velocity]
- [Turner Velocity]
- End Enum
- Enum osCalculationType
- Inflow
- System
- VLP
- Gradient
- End Enum
- ' ++++++++++++++++++++++++++++
- ' Private sub Class_Initialize
- ' ++++++++++++++++++++++++++++
- ' Initializes the class with the defaults
- Private Sub Class_Initialize()
- xCalculationType = System
- xResetSensitivities = True
- xRememberSetVariables = True
- xUseRawValues = False
- xFluidType = -1
- xRegressionStatus = [No Regression Done]
- xXvalues = 0
- End Sub
- ' +++++++++++++++++++++++++
- ' Private sub pGetFluidType
- ' +++++++++++++++++++++++++
- ' Sets the xFluidType variable
- Private Sub pGetFluidType()
- Debug.Print "GET " & "PROSPER.Sin.Sum.Fluid = " & DoGet("PROSPER.Sin.Sum.Fluid")
- xFluidType = CInt(DoGet("PROSPER.Sin.Sum.Fluid"))
- End Sub
- ' ++++++++++++++++++++++
- ' Public sub setVariable
- ' ++++++++++++++++++++++
- ' adds a variable to the xSensVars list
- ' parses its values using interpretValue
- ' and adds the values to xSensValues list
- ' checks for duplicate setVariable statements & overrites
- ' keeps track of xSensVarsCount
- Public Sub setVar(variable As osInputVariable, value As Variant)
- Dim index As Long
- index = pFindInArray(what:=variable, inArray:=xFixedVars)
- If index < 0 Then
- ReDim Preserve xFixedVars(xFixedVarsCount), xFixedValues(xFixedVarsCount)
- index = xFixedVarsCount
- xFixedVarsCount = xFixedVarsCount + 1
- End If
- ' Add to xFixedVars()
- xFixedVars(index) = variable
- ' Add values to xFixedValues
- xFixedValues(index) = value
- End Sub
- ' ++++++++++++++++++++++
- ' Public Function vector
- ' ++++++++++++++++++++++
- ' Returns an array with depths or rates in the (0) index, and the desired value in the (1) index
- ' Thus, the Variable can be either a depthVector variable (listed in the dv enumerable)
- ' or a rateVector variable (listed in the rv enumerable)
- Public Function Vector(variable As Long) As Vector
- Dim result As String, values, i As Integer, returnedVec() As Double
- If xCalculationType = Gradient Then
- result = pGet(Replace(accessString_osDepthVector(variable), "[i][j][k]", "[0][0][0]"))
- Else
- result = pGet(Replace(accessString_osRateVector(variable), "[#]", "[0]"))
- End If
- pGetXvalues
- values = pVectorize(result)
- ReDim returnedVec(0 To 1, 0 To UBound(values)) As Double
- For i = 0 To UBound(values)
- returnedVec(0, i) = xXvalues(i)
- returnedVec(1, i) = values(i)
- Next
- Dim V As New Vector
- V.newFromValues returnedVec
- Set Vector = V
- End Function
- ' +++++++++++++++++++++++++++
- ' Private Function pVectorize
- ' +++++++++++++++++++++++++++
- ' Splits a multi-value string returned by an $ access string
- ' Returns a variant array with the values.
- ' If values are Doubles, then returns Doubles
- Private Function pVectorize(st As String) As Variant
- Dim vec
- If Right(st, 1) = "|" Then st = Mid(st, 1, Len(st) - 1)
- vec = Split(st, "|")
- If IsNumeric(vec(0)) Then
- Dim dblVec() As Double, i As Long
- ReDim dblVec(0 To UBound(vec))
- For i = LBound(vec) To UBound(vec)
- dblVec(i) = CDbl(vec(i))
- Next
- pVectorize = dblVec
- Else
- pVectorize = vec
- End If
- End Function
- ' +++++++++++++++++++++++
- ' Private Sub pGetXvalues
- ' +++++++++++++++++++++++
- ' Ensures that the xXvalues vector is set
- Private Sub pGetXvalues()
- If TypeName(xXvalues) = "Integer" Then
- Dim result As String
- If calculationType = Gradient Then
- result = pGet(Replace(accessString_osDepthVector([Measured Depth]), "[i][j][k]", "[0][0][0]"))
- Else
- If fluidType = [Oil and Water] Then
- result = pGet(Replace(accessString_osRateVector([Liquid rate]), "[#]", "[0]"))
- Else
- result = pGet(Replace(accessString_osRateVector([Gas rate]), "[#]", "[0]"))
- End If
- End If
- xXvalues = pVectorize(result)
- End If
- End Sub
- ' ++++++++++++++++++++++++
- ' Public function solution
- ' ++++++++++++++++++++++++
- ' returns any of the solution values of SYSTEM calculation
- ' optional Index can obtain any index solution
- Public Function solution(variable As osSolutionVariable, Optional index As Variant) As Double
- If IsMissing(index) Then index = 0
- solution = CDbl(pGet(Replace(accessString_osSolution(variable), "#", CStr(index))))
- End Function
- ' ++++++++++++++++++++
- ' Public sub calculate
- ' ++++++++++++++++++++
- ' populates the xCombinations array first,
- ' then runs the calculations
- ' and saves the results in xRecordValues
- Public Sub calculate(Optional loops As Variant)
- If xResetSensitivities Then pResetSensDB
- pSetFixedVars
- pMakeCalculation
- End Sub
- ' ++++++++++++++++++++++++++++
- ' Private sub pMakeCalculation
- ' ++++++++++++++++++++++++++++
- ' Actually makes the doCmd for the calculation
- Private Sub pMakeCalculation()
- Select Case xCalculationType
- Case Is = osCalculationType.Gradient
- Debug.Print "CMD PROSPER.ANL.GRD.CALC"
- DoCmd "PROSPER.ANL.GRD.CALC"
- Case Is = osCalculationType.Inflow
- Debug.Print "CMD PROSPER.ANL.INF.CALC"
- DoCmd "PROSPER.ANL.INF.CALC"
- Case Is = osCalculationType.System
- Debug.Print "CMD PROSPER.ANL.SYS.CALC"
- DoCmd "PROSPER.ANL.SYS.CALC"
- Case Is = osCalculationType.VLP
- Debug.Print "CMD PROSPER.ANL.VLP.CALC"
- DoCmd "PROSPER.ANL.VLP.CALC"
- End Select
- xXvalues = 0
- End Sub
- ' +++++++++++++++++++++++++
- ' Private sub pSetFixedVars
- ' +++++++++++++++++++++++++
- ' Actually makes the doSet in the prosper file for all
- ' variables that were set before using setVar
- Private Sub pSetFixedVars()
- Dim i As Long, sensDBVars As Long, accstr As Variant, rv As String
- If xUseRawValues Then rv = ".RAWVAL"
- For i = 0 To xFixedVarsCount - 1
- accstr = accessString(CLng(xFixedVars(i)))
- If IsNumeric(accstr) Then
- Debug.Print "SET " & accessString(osInputVariable.[_Sens DB]) & ".Vars[" & CStr(sensDBVars) & "] to " & CStr(accstr)
- DoSet accessString(osInputVariable.[_Sens DB]) & ".Vars[" & CStr(sensDBVars) & "]", CStr(accstr)
- Debug.Print "SET " & accessString(osInputVariable.[_Sens DB]) & ".Sens[" & CStr(pIndexFromSensVar(CLng(accstr))) & "].Vals[0]" & rv & " to " & xFixedValues(i)
- DoSet accessString(osInputVariable.[_Sens DB]) & ".Sens[" & CStr(pIndexFromSensVar(CLng(accstr))) & "].Vals[0]" & rv, xFixedValues(i)
- sensDBVars = sensDBVars + 1
- ElseIf accstr <> "N/A" Then
- Debug.Print "SET " & accessString(CLng(xFixedVars(i))) & rv & " to " & xFixedValues(i)
- DoSet accessString(CLng(xFixedVars(i))) & rv, xFixedValues(i)
- End If
- Next
- End Sub
- ' +++++++++++++++++++
- ' Private sub pSetVar
- ' +++++++++++++++++++
- ' sets a variable to the given value for calculation
- ' does not reset the SensDB
- ' if variable is a SensDB variable, assumes that SensDB is prepared for receiving the variable
- ' used in regression calculations
- Private Sub pSetVar(accstr As String, value As Double)
- Dim rv As String
- If xUseRawValues Then rv = ".RAWVAL"
- If IsNumeric(accstr) Then
- Debug.Print "SET " & accessString(osInputVariable.[_Sens DB]) & ".Sens[" & CStr(pIndexFromSensVar(CLng(accstr))) & "].Vals[0]" & rv & " to " & value
- DoSet accessString(osInputVariable.[_Sens DB]) & ".Sens[" & CStr(pIndexFromSensVar(CLng(accstr))) & "].Vals[0]" & rv, value
- ElseIf accstr <> "N/A" Then
- Debug.Print "SET " & accstr & rv & " to " & value
- DoSet accstr & rv, value
- End If
- End Sub
- ' +++++++++++++++++++++
- ' Private function pGet
- ' +++++++++++++++++++++
- ' Performs the DoGet function, with the raw value if needed
- Private Function pGet(accstr As String) As String
- If xUseRawValues Then
- Debug.Print "GET " & accstr & ".RAWVAL"
- pGet = DoGet(accstr & ".RAWVAL")
- Else
- Debug.Print "GET " & accstr
- pGet = DoGet(accstr)
- End If
- End Function
- ' ++++++++++++++++++++++++
- ' Private sub pResetSensDB
- ' ++++++++++++++++++++++++
- ' Resets the sensitivity database
- Private Sub pResetSensDB()
- Dim accstr As String
- accstr = accessString(osInputVariable.[_Sens DB]) & ".Clear"
- Debug.Print "SET " & accstr & " to 1"
- DoSet accstr, 1
- End Sub
- ' ###############################################
- ' ################ PROPERTIES ###################
- ' ###############################################
- ' +++++++++++++++++++++++++++++++
- ' Public property calculationType
- ' +++++++++++++++++++++++++++++++
- ' defines what calculation is going to be done
- ' defaults to System, has getter and a setter
- Public Property Get calculationType() As osCalculationType
- calculationType = xCalculationType
- End Property
- Public Property Let calculationType(RHS As osCalculationType)
- xCalculationType = RHS
- End Property
- ' ++++++++++++++++++++++++++++++++++
- ' Public property resetSensitivities
- ' ++++++++++++++++++++++++++++++++++
- ' defines whether the sensDB is cleared every time
- ' defaults to true, has getter and setter
- Public Property Get resetSensitivities() As Boolean
- resetSensitivities = xResetSensitivities
- End Property
- Public Property Let resetSensitivities(RHS As Boolean)
- xResetSensitivities = RHS
- End Property
- ' ++++++++++++++++++++++++++++++++++++
- ' Public property rememberSetVariables
- ' ++++++++++++++++++++++++++++++++++++
- ' defines whether the set variables are remembered or cleared after calc
- ' defaults to true, has getter and setter
- Public Property Get rememberSetVariables() As Boolean
- rememberSetVariables = xRememberSetVariables
- End Property
- Public Property Let rememberSetVariables(RHS As Boolean)
- xRememberSetVariables = RHS
- End Property
- ' ++++++++++++++++++++++++++++
- ' Public property useRawValues
- ' ++++++++++++++++++++++++++++
- ' defines whether the all calls are done using Raw Values
- ' (both doSet and doGet)
- Public Property Get useRawValues() As Boolean
- useRawValues = xUseRawValues
- End Property
- Public Property Let useRawValues(RHS As Boolean)
- xUseRawValues = RHS
- End Property
- ' +++++++++++++++++++++++++
- ' Public property fluidType
- ' +++++++++++++++++++++++++
- ' read only. Returns the fluid type of the PROSPER model
- Public Property Get fluidType() As osFluidType
- If xFluidType < 0 Then pGetFluidType
- fluidType = xFluidType
- End Property
- ' ++++++++++++++++++++++++++++++++
- ' Public property regressionStatus
- ' ++++++++++++++++++++++++++++++++
- ' read only. exhibits the regression status after a regression call
- Public Property Get regressionStatus() As osRegressionStatus
- regressionStatus = xRegressionStatus
- End Property
- ' #########################################################
- ' ################ REGRESSION FUNCTIONS ###################
- ' #########################################################
- ' ++++++++++++++++++++
- ' Public function find
- ' ++++++++++++++++++++
- ' Regression Function
- ' Will try to match the desired objective variable to a target, with the specified precision
- ' by changing an input variable in PROSPER
- ' Precision defaults to 2% of target
- ' Works best for monotonic series (i.e. no local extremes)
- ' Needs the extremes to be in either side of the desired value
- ' Returns the matched value & updates the regressionStatus property of this object
- ' As all regression algorithms, this can be improved. If you want to contribute,
- ' see contact details in www.SimpleOpenServer.com
- Function find(valueOf As osInputVariable, thatMakes As osSolutionVariable, equalTo As Double, betweenValue As Double, andValue As Double, Optional precision As Variant) As Double
- If IsMissing(precision) Then precision = 0.02 * Abs(equalTo)
- Dim accstr As String, x0 As Double, x1 As Double, x2 As Double, y0 As Double, y1 As Double, y2 As Double, dx As Double, f As Double, loops As Integer
- accstr = accessString(CLng(valueOf))
- x0 = betweenValue
- setVar valueOf, x0
- calculate
- y0 = solution(thatMakes) - equalTo
- x2 = andValue
- pSetVar accstr, x2
- pMakeCalculation
- y2 = solution(thatMakes) - equalTo
- f = y0 / (y0 - y2)
- If f < 0 Or f > 1 Then
- ' Solution does not fall between extremes
- xRegressionStatus = [Solution Not Found In Range]
- If f < 0 Then
- find = x0
- Else
- find = x2
- End If
- Else
- ' Solution falls between extremes, start regression
- x1 = (x2 - x0) * f + x0
- pSetVar accstr, x1
- pMakeCalculation
- y1 = solution(thatMakes) - equalTo
- Do While Abs(y1) > precision And loops <= 8
- If Math.Sgn(y1) = Math.Sgn(y0) Then
- ' Sigo con x1 y x2
- x0 = x1
- y0 = y1
- Else
- ' Sigo con x0 y x1
- x2 = x1
- y2 = y1
- End If
- f = y0 / (y0 - y2)
- x1 = (x2 - x0) * f + x0
- pSetVar accstr, x1
- pMakeCalculation
- y1 = solution(thatMakes) - equalTo
- Loop
- If loops > 8 Then
- xRegressionStatus = [Loops Exceeded]
- Else
- xRegressionStatus = Converged
- End If
- find = x1
- End If
- End Function
- ' +++++++++++++++++++++
- ' Public function match
- ' +++++++++++++++++++++
- ' Regression Function
- ' Will try to match the desired vector, with the specified precision
- ' by changing an input variable in PROSPER
- ' Precision defaults to 2% of target
- ' As all regression algorithms, this can be improved. If you want to contribute,
- ' see contact details in www.SimpleOpenServer.com
- Function match(curve As Long, toPoints As Vector, byChanging As osInputVariable, betweenValue As Double, andValue As Double, Optional precision As Variant) As Double
- Dim X(4) As Double, Y(4) As Double, i As Integer, accstr As String, loopCount As Integer, x_min As Double, x_min_old As Double, estimationChange As Double, y_min As Double, y_min_old As Double, theVector As New Vector
- accstr = accessString(CLng(byChanging))
- loopCount = 0
- X(0) = betweenValue
- X(4) = andValue
- y_min = -1000
- ' Calcular los 5 puntos
- ' Calculo el 1ro
- setVar byChanging, X(0)
- calculate
- Set theVector = Me.Vector(curve)
- Y(0) = theVector.MSE(toPoints)
- ' Calculo los otros 4
- For i = 1 To 4
- X(i) = X(0) + (X(4) - X(0)) * i / 4
- pSetVar accstr, X(i)
- pMakeCalculation
- Set theVector = Me.Vector(Vector)
- Y(i) = theVector.MSE(toPoints)
- Next
- GoTo 1
- Do
- x_min_old = x_min
- ' Calculo los 3 pts que faltan
- For i = 1 To 3
- X(i) = X(0) + (X(4) - X(0)) * i / 4
- pSetVar accstr, X(i)
- pMakeCalculation
- Set theVector = Me.Vector(Vector)
- Y(i) = theVector.MSE(toPoints)
- Next
- 1
- ' Find the min
- i = 1
- Do
- If Y(i) > Y(i - 1) Then Exit Do
- i = i + 1
- Loop Until i = 5
- i = i - 1
- Dim coeffs As Variant
- If i = 0 Then
- i = 1
- ElseIf i = 4 Then
- i = 3
- End If
- coeffs = pFitQuad(X(i - 1), Y(i - 1), X(i), Y(i), X(i + 1), Y(i + 1))
- ' Prepare array for next run
- X(0) = X(i - 1)
- Y(0) = Y(i - 1)
- X(4) = X(i + 1)
- Y(4) = Y(i + 1)
- If coeffs(0) < 0 Then
- ' Tenemos un MAXIMO en vez de MINIMO.
- ' No se encontro resultado
- xRegressionStatus = [No Solution Found]
- match = -1
- Exit Function
- Else
- x_min = -coeffs(1) / 2 / coeffs(0)
- If x_min > X(4) Or x_min < X(0) Then
- ' El minimo esta afuera
- xRegressionStatus = [Solution Not Found In Range]
- match = X(0)
- If Y(4) < Y(0) Then match = X(4)
- Exit Function
- Else
- If y_min = -1000 Then
- y_min_old = Y(0)
- i = 1
- Do
- If Y(i) < Y(i - 1) Then y_min_old = Y(i)
- i = i + 1
- Loop Until i = 5
- If IsMissing(precision) Then precision = 0.02
- Else
- y_min_old = y_min
- End If
- pSetVar accstr, x_min
- pMakeCalculation
- y_min = theVector.MSE(toPoints)
- End If
- End If
- estimationChange = Abs(x_min - x_min_old) / x_min
- loopCount = loopCount + 1
- Loop While loopCount <= 3 And estimationChange > precision
- If estimationChange > precision Then
- xRegressionStatus = [Loops Exceeded]
- Else
- xRegressionStatus = Converged
- End If
- match = x_min
- End Function
- ' ++++++++++++++++++++++++
- ' Public function maximize
- ' ++++++++++++++++++++++++
- ' Regression Function
- ' Will try to maximize the desired objective variable, with the specified precision
- ' by changing an input variable in PROSPER
- ' Precision defaults to 2% of target
- ' Unpredictable when having multiple maximi
- ' Not recommended for discontinuous curves
- ' As all regression algorithms, this can be improved. If you want to contribute,
- ' see contact details in www.SimpleOpenServer.com
- Function maximize(variable As osSolutionVariable, byChanging As osInputVariable, betweenValue As Double, andValue As Double, Optional precision As Variant) As Double
- Dim X(4) As Double, Y(4) As Double, i As Integer, accstr As String, loopCount As Integer, x_max As Double, y_max As Double, y_max_old As Double, coeffs As Variant
- accstr = accessString(CLng(byChanging))
- loopCount = 0
- X(0) = betweenValue
- X(4) = andValue
- y_max = -1000
- ' Calcular los 5 puntos
- ' Calculo el 1ro, usando setVar y calculate
- setVar byChanging, X(0)
- calculate
- Y(0) = CDbl(solution(variable))
- ' Calculo los otros 4, usando pSetVar y pMakeCalculation
- For i = 1 To 4
- X(i) = X(0) + (X(4) - X(0)) * i / 4
- pSetVar accstr, X(i)
- pMakeCalculation
- Y(i) = CDbl(solution(variable))
- Next
- GoTo 1
- Do
- ' Calculo los 3 pts que faltan
- For i = 1 To 3
- X(i) = X(0) + (X(4) - X(0)) * i / 4
- pSetVar accstr, X(i)
- pMakeCalculation
- Y(i) = CDbl(solution(variable))
- Next
- 1
- ' Busco el max
- i = 1
- Do
- If Y(i) < Y(i - 1) Then Exit Do
- i = i + 1
- Loop Until i = 5
- i = i - 1
- If i = 0 Then
- i = 1
- ElseIf i = 4 Then
- i = 3
- End If
- coeffs = pFitQuad(X(i - 1), Y(i - 1), X(i), Y(i), X(i + 1), Y(i + 1))
- ' Prepare array for next run
- X(0) = X(i - 1)
- Y(0) = Y(i - 1)
- X(4) = X(i + 1)
- Y(4) = Y(i + 1)
- If coeffs(0) > 0 Then
- ' Tenemos un MINIMO en vez de MAXIMO.
- ' No se encontro resultado
- xRegressionStatus = [No Solution Found]
- maximize = -1
- Exit Function
- Else
- x_max = -coeffs(1) / 2 / coeffs(0)
- If x_max > X(4) Or x_max < X(0) Then
- ' El maximo esta afuera
- xRegressionStatus = [Solution Not Found In Range]
- maximize = X(0)
- If Y(4) > Y(0) Then maximize = X(4)
- Exit Function
- Else
- If y_max = -1000 Then
- y_max_old = Y(0)
- i = 1
- Do
- If Y(i) > Y(i - 1) Then y_max_old = Y(i)
- i = i + 1
- Loop Until i = 5
- If IsMissing(precision) Then precision = 0.02 * y_max_old
- Else
- y_max_old = y_max
- End If
- pSetVar accstr, x_max
- pMakeCalculation
- y_max = CDbl(solution(variable))
- End If
- End If
- loopCount = loopCount + 1
- Loop While Abs(y_max_old - y_max) > precision And loopCount <= 3
- If Abs(y_max_old - y_max) > precision Then
- xRegressionStatus = [Loops Exceeded]
- Else
- xRegressionStatus = Converged
- End If
- maximize = x_max
- End Function
- ' ++++++++++++++++++++++++
- ' Public function minimize
- ' ++++++++++++++++++++++++
- ' Regression Function
- ' Will try to minimize the desired objective variable, with the specified precision
- ' by changing an input variable in PROSPER
- ' Precision defaults to 2% of target
- ' Unpredictable when having multiple minimi
- ' Not recommended for discontinuous curves
- ' As all regression algorithms, this can be improved. If you want to contribute,
- ' see contact details in www.SimpleOpenServer.com
- Function minimize(variable As osSolutionVariable, byChanging As osInputVariable, betweenValue As Double, andValue As Double, Optional precision As Variant) As Double
- Dim X(4) As Double, Y(4) As Double, i As Integer, accstr As String, loopCount As Integer, x_min As Double, y_min As Double, y_min_old As Double
- accstr = accessString(CLng(byChanging))
- loopCount = 0
- X(0) = betweenValue
- X(4) = andValue
- y_min = -1000
- ' Calcular los 5 puntos
- ' Calculo el 1ro
- setVar byChanging, X(0)
- calculate
- Y(0) = CDbl(solution(variable))
- ' Calculo los otros 4
- For i = 1 To 4
- X(i) = X(0) + (X(4) - X(0)) * i / 4
- pSetVar accstr, X(i)
- pMakeCalculation
- Y(i) = CDbl(solution(variable))
- Next
- GoTo 1
- Do
- ' Calculo los 3 pts intermedios
- For i = 1 To 3
- X(i) = X(0) + (X(4) - X(0)) * i / 4
- pSetVar accstr, X(i)
- pMakeCalculation
- Y(i) = CDbl(solution(variable))
- Next
- 1
- ' Find the min
- i = 1
- Do
- If Y(i) > Y(i - 1) Then Exit Do
- i = i + 1
- Loop Until i = 5
- i = i - 1
- Dim coeffs As Variant
- If i = 0 Then
- i = 1
- ElseIf i = 4 Then
- i = 3
- End If
- coeffs = pFitQuad(X(i - 1), Y(i - 1), X(i), Y(i), X(i + 1), Y(i + 1))
- ' Prepare array for next run
- X(0) = X(i - 1)
- Y(0) = Y(i - 1)
- X(4) = X(i + 1)
- Y(4) = Y(i + 1)
- If coeffs(0) < 0 Then
- ' Tenemos un MAXIMO en vez de MINIMO.
- ' No se encontro resultado
- xRegressionStatus = [No Solution Found]
- minimize = -1
- Exit Function
- Else
- x_min = -coeffs(1) / 2 / coeffs(0)
- If x_min > X(4) Or x_min < X(0) Then
- ' El maximo esta afuera
- xRegressionStatus = [Solution Not Found In Range]
- minimize = X(0)
- If Y(4) < Y(0) Then minimize = X(4)
- Exit Function
- Else
- If y_min = -1000 Then
- y_min_old = Y(0)
- i = 1
- Do
- If Y(i) < Y(i - 1) Then y_min_old = Y(i)
- i = i + 1
- Loop Until i = 5
- If IsMissing(precision) Then precision = 0.02 * y_min_old
- Else
- y_min_old = y_min
- End If
- pSetVar accstr, x_min
- pMakeCalculation
- y_min = CDbl(solution(variable))
- End If
- End If
- loopCount = loopCount + 1
- Loop While Abs(y_min_old - y_min) > precision And loopCount <= 3
- If Abs(y_min_old - y_min) > precision Then
- xRegressionStatus = [Loops Exceeded]
- Else
- xRegressionStatus = Converged
- End If
- minimize = x_min
- End Function
- ' ++++++++++++++++++++++++++++
- ' Public function rateOfChange
- ' ++++++++++++++++++++++++++++
- ' Will evaluate the rate of change of one variable
- ' when changing another, around a center point (atValue)
- Function rateOfChange(of As osSolutionVariable, whenChanging As osInputVariable, atValue As Double)
- ' Generar un rango de valores, segun el X
- ' 3 valores. evaluar, sacar coeficientes quad y evaluar la derivada en el del medio
- Dim X(2) As Double, Y(2) As Double, i As Integer, accstr As String, dx As Double, coeffs As Variant
- dx = 0.02 * atValue
- accstr = accessString(CLng(whenChanging))
- X(0) = atValue - dx
- X(1) = atValue
- X(2) = atValue + dx
- ' Calcular los 3 puntos
- i = 0
- ' Calculo el 1ro
- setVar whenChanging, X(i)
- calculate
- Y(i) = CDbl(solution(of))
- ' Calculo los otros 4
- For i = 1 To 2
- pSetVar accstr, X(i)
- pMakeCalculation
- Y(i) = CDbl(solution(of))
- Next
- coeffs = pFitQuad(X(0), Y(0), X(1), Y(1), X(2), Y(2))
- rateOfChange = 2 * coeffs(0) * atValue + coeffs(1)
- End Function
- ' +++++++++++++++++++++++++++++
- ' Private function accessString
- ' +++++++++++++++++++++++++++++
- ' Used for INPUT variables.
- ' returns the access string that corresponds to the variable and the
- ' calculation type that is being performed. Will return N/A if the
- ' variable is not enabled for the set calculation type
- Private Function accessString(osVariable As Long) As String
- accessString = Array(Array("PROSPER.ANL.INF.WC", "PROSPER.ANL.INF.GOR", "PROSPER.ANL.INF.CGR", "N/A", "N/A", "1", "53", "3", "51", "2", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "PROSPER.ANL.INF.Sens.SensDB", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A"), _
- Array("PROSPER.ANL.SYS.WC", "PROSPER.ANL.SYS.GOR", "PROSPER.ANL.SYS.CGR", "PROSPER.ANL.SYS.WGR", "PROSPER.ANL.SYS.Pres", "1", "53", "3", "51", "2", "PROSPER.ANL.SYS.Tubing", "PROSPER.ANL.SYS.Pipe", "N/A", "N/A", "26", "334", "PROSPER.ANL.SYS.Sens.SensDB", "35", "37", "38", "41", "326", "22", "31", "29"), _
- Array("PROSPER.ANL.VL3.WC", "PROSPER.ANL.VL3.WC", "PROSPER.ANL.VL3.CGR", "PROSPER.ANL.VL3.WGR", "PROSPER.ANL.VL3.Pres", "N/A", "N/A", "N/A", "N/A", "N/A", "PROSPER.ANL.VL3.Tubing", "PROSPER.ANL.VL3.Pipe", "N/A", "N/A", "26", "334", "PROSPER.ANL.VL3.Sens.SensDB", "35", "37", "38", "41", "326", "22", "31", "29"), _
- Array("PROSPER.ANL.GRD.WC", "PROSPER.ANL.GRD.GOR", "PROSPER.ANL.GRD.CGR", "PROSPER.ANL.GRD.WGR", "PROSPER.ANL.GRD.Pres", "N/A", "N/A", "N/A", "N/A", "N/A", "PROSPER.ANL.GRD.Tubing", "PROSPER.ANL.GRD.Pipe", "PROSPER.ANL.GRD.Rate", "PROSPER.ANL.GRD.Pres", "26", "334", "PROSPER.ANL.GRD.Sens.SensDB", "35", "37", "38", "41", "326", "22", "31", "29")) _
- (xCalculationType)(osVariable)
- End Function
- ' ++++++++++++++++++++++++++++++++++++++++
- ' Private function accessString_osSolution
- ' ++++++++++++++++++++++++++++++++++++++++
- ' Used for SOLUTION variables
- ' returns the access string that corresponds to the variable.
- Private Function accessString_osSolution(osSolutionVar As Long) As String
- accessString_osSolution = Array("Exists", "PROSPER.OUT.SYS.Results[#].Sol.LiqRate", "PROSPER.OUT.SYS.Results[#].Sol.OilRate", "PROSPER.OUT.SYS.Results[#].Sol.WatRate", "PROSPER.OUT.SYS.Results[#].Sol.GasRate", "PROSPER.OUT.SYS.Results[#].Sol.BHP", "PROSPER.OUT.SYS.Results[#].Sol.BHP", "PROSPER.OUT.SYS.Results[#].Sol.PRFRIC", "PROSPER.OUT.SYS.Results[#].Sol.PRSTAT", "PROSPER.OUT.SYS.Results[#].Sol.WHPressure", "PROSPER.OUT.SYS.Results[#].Sol.WHTemperature", "PROSPER.OUT.SYS.Results[#].Sol.FNPressure", "PROSPER.OUT.SYS.Results[#].Sol.FNTemperature", "PROSPER.OUT.SYS.Results[#].Sol.PIP", _
- "PROSPER.OUT.SYS.Results[#].Sol.PDP", "PROSPER.OUT.SYS.Results[#].Sol.PumpAvRate", "PROSPER.OUT.SYS.Results[#].Sol.PumpHead", "PROSPER.OUT.SYS.Results[#].Sol.PumpPower", "PROSPER.OUT.SYS.Results[#].Sol.PumpEfficiency", "PROSPER.OUT.SYS.Results[#].Sol.MotorAmps", "PROSPER.OUT.SYS.Results[#].Sol.MotorPower") _
- (osSolutionVar)
- End Function
- ' ++++++++++++++++++++++++++++++++++++++++++
- ' Private function accessString_osRateVector
- ' ++++++++++++++++++++++++++++++++++++++++++
- ' Used for RATE VECTOR variables
- ' returns the access string that corresponds to the variable and the
- ' calculation type that is being performed. Will return N/A if the
- ' variable is not enabled for the set calculation type
- Private Function accessString_osRateVector(osVariable As Long) As String
- accessString_osRateVector = Array(Array("PROSPER.OUT.INF.RESULTS[#].LiqRate[$]", "PROSPER.OUT.INF.RESULTS[#].OilRate[$]", "PROSPER.OUT.INF.RESULTS[#].WatRate[$]", "PROSPER.OUT.INF.RESULTS[#].GasRate[$]", "PROSPER.OUT.INF.RESULTS[#].IPRPres[$]", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A"), _
- Array("PROSPER.OUT.SYS.RESULTS[#].LiqRate[$]", "PROSPER.OUT.SYS.RESULTS[#].OilRate[$]", "PROSPER.OUT.SYS.RESULTS[#].WatRate[$]", "PROSPER.OUT.SYS.RESULTS[#].GasRate[$]", "PROSPER.OUT.SYS.RESULTS[#].IPRPres[$]", "PROSPER.OUT.SYS.RESULTS[#].VLPPres[$]", "PROSPER.OUT.SYS.Results[#].PrFric[$]", "PROSPER.OUT.SYS.Results[#].PrStat[$]", "PROSPER.OUT.SYS.Results[#].PIP[$]", "PROSPER.OUT.SYS.Results[#].PDP[$]", "PROSPER.OUT.SYS.Results[#].POW[$]"), _
- Array("PROSPER.OUT.VLP.RESULTS[#].LiqRate[$]", "PROSPER.OUT.VLP.RESULTS[#].OilRate[$]", "PROSPER.OUT.VLP.RESULTS[#].WatRate[$]", "PROSPER.OUT.VLP.RESULTS[#].GasRate[$]", "N/A", "PROSPER.OUT.VLP.RESULTS[#].VLPPres[$]", "PROSPER.OUT.VLP.Results[#].PrFric[$]", "PROSPER.OUT.VLP.Results[#].PrStat[$]", "PROSPER.OUT.VLP.Results[#].PIP[$]", "PROSPER.OUT.VLP.Results[#].PDP[$]", "PROSPER.OUT.VLP.Results[#].POW[$]")) _
- (xCalculationType)(osVariable)
- End Function
- ' +++++++++++++++++++++++++++++++++++++++++++
- ' Private function accessString_osDepthVector
- ' +++++++++++++++++++++++++++++++++++++++++++
- ' Used for DEPTH VECTOR variables
- ' returns the access string that corresponds to the variable and the
- ' calculation type that is being performed. Will return N/A if the
- ' variable is not enabled for the set calculation type
- Private Function accessString_osDepthVector(osVariable As Long) As String
- accessString_osDepthVector = Array("PROSPER.OUT.GRD.RESULTS[i][j][k].LABEL[$]", "PROSPER.OUT.GRD.RESULTS[i][j][k].MSD[$]", "PROSPER.OUT.GRD.RESULTS[i][j][k].TVD[$]", "PROSPER.OUT.GRD.RESULTS[i][j][k].PRES[$]", "PROSPER.OUT.GRD.RESULTS[i][j][k].TEMP[$]", "PROSPER.OUT.GRD.RESULTS[i][j][k].GRAD[$]", "PROSPER.OUT.GRD.RESULTS[i][j][k].HOLDUP[$]", _
- "PROSPER.OUT.GRD.RESULTS[i][j][k].REGIME[$]", "PROSPER.OUT.GRD.RESULTS[i][j][k].GRSTAT[$]", "PROSPER.OUT.GRD.RESULTS[i][j][k].GRFRIC[$]", "PROSPER.OUT.GRD.RESULTS[i][j][k].VLTOTL[$]", "PROSPER.OUT.GRD.RESULTS[i][j][k].VLTURN[$]") _
- (osVariable)
- End Function
- ' +++++++++++++++++++++++++++++
- ' Private function pFindInArray
- ' +++++++++++++++++++++++++++++
- ' returns the first occurrance of "what" in "inArray"
- ' returns -1 otherwhise (e.g. inArray is not an array or not found)
- Private Function pFindInArray(what As Variant, inArray As Variant) As Long
- On Error GoTo err:
- Dim i As Long
- For i = 0 To UBound(inArray)
- If inArray(i) = what Then Exit For
- Next
- If i > UBound(inArray) Then
- err:
- pFindInArray = -1
- Else
- pFindInArray = i
- End If
- End Function
- ' +++++++++++++++++++++++++
- ' Private function pFitQuad
- ' +++++++++++++++++++++++++
- ' given three points 1,2,3: fits them using a quadratic function ax2 + bx + c
- ' returns [ a, b, c ]
- Private Function pFitQuad(x1 As Double, y1 As Double, x2 As Double, y2 As Double, x3 As Double, y3 As Double) As Variant
- Dim result(2), X(1 To 3, 1 To 3) As Double, Y(1 To 3, 1 To 1) As Double, c
- X(1, 1) = 1
- X(1, 2) = x1
- X(1, 3) = x1 * x1
- X(2, 1) = 1
- X(2, 2) = x2
- X(2, 3) = x2 * x2
- X(3, 1) = 1
- X(3, 2) = x3
- X(3, 3) = x3 * x3
- Y(1, 1) = y1
- Y(2, 1) = y2
- Y(3, 1) = y3
- c = Application.MMult(Application.MInverse(X()), Y())
- result(0) = c(3, 1)
- result(1) = c(2, 1)
- result(2) = c(1, 1)
- pFitQuad = result
- End Function
- ' ++++++++++++++++++++++++++++++++++
- ' Private function pIndexFromSensVar
- ' ++++++++++++++++++++++++++++++++++
- ' Index function to change the Sens Var number to a sens var index,
- ' due to the unexplicable logic behind sens vars and sens values in PROSPER.
- Private Function pIndexFromSensVar(num As Long) As Long
- Select Case num
- Case Is = 1
- pIndexFromSensVar = 1
- Case Is = 2
- pIndexFromSensVar = 27
- Case Is = 3
- pIndexFromSensVar = 3
- Case Is = 22
- pIndexFromSensVar = 138
- Case Is = 26
- pIndexFromSensVar = 144
- Case Is = 29
- pIndexFromSensVar = 142
- Case Is = 31
- pIndexFromSensVar = 140
- Case Is = 35
- pIndexFromSensVar = 148
- Case Is = 37
- pIndexFromSensVar = 150
- Case Is = 38
- pIndexFromSensVar = 151
- Case Is = 41
- pIndexFromSensVar = 157
- Case Is = 51
- pIndexFromSensVar = 7
- Case Is = 53
- pIndexFromSensVar = 2
- Case Is = 326
- pIndexFromSensVar = 187
- Case Is = 334
- pIndexFromSensVar = 195
- End Select
- End Function
Advertisement
Add Comment
Please, Sign In to add comment