Example #1
0
def oneSidedStabCheck(iPhs, pRes, tRes, Z, fugZ, logK, clsEOS, clsIO):

    mSTB = 101
    nCom = clsEOS.nComp

    qP = False  #-- No Pres, Temp or Comp Derivatives Needed
    qT = False
    qX = False

    res0 = NP.zeros(nCom)

    iSTB = 0

    if clsIO.Deb["STAB1"] > 0:
        qDeb = True
        fDeb = clsIO.fDeb
    else:
        qDeb = False

    if qDeb > 0:
        sOut = "1-Sided SC at pRes,tRes {:10.3f} {:8.3f}\n".format(pRes, tRes)
        K = NP.exp(logK)
        WO.writeArrayDebug(fDeb, K, "1SidedStab: K")
        WO.writeArrayDebug(fDeb, Z, "1SidedStab: Z")
        fDeb.write(sOut)

#== Successive Substitution/GDEM Loop =================================

    while iSTB < mSTB:

        iSTB += 1

        #-- Mole Numbers ----------------------------------------------------

        K = NP.exp(logK)
        yMol = Z * K

        #-- Mole composition (normalised) -----------------------------------

        yNor, sumY = UT.NormSum(yMol)

        fugY,dumV,dumV,dumM = \
            CE.calcPhaseFugPTX(iPhs,qP,qT,qX,pRes,tRes,yNor,clsEOS)

        gStr = 1.0 - sumY

        #-- Residuals -------------------------------------------------------

        res1 = res0
        res0 = fugZ - fugY - logK

        tolR = NP.dot(res0, res0)
        gStr = gStr - NP.dot(yMol, res0)

        #-- GDEM Step? ------------------------------------------------------

        if iSTB % UT.mGDEM1 > 0: eigV = 1.0
        else: eigV = UT.GDEM1(res0, res1, clsIO)

        if eigV < 1.0: eigV = 1.0

        #-- Update logK with/without GDEM Acceleration ----------------------

        eVr0 = eigV * res0
        logK = logK + eVr0

        triV = NP.dot(logK, logK)

        if qDeb:
            sOut = "Stab1S: iSTB,sumY,gStr,tolR,triV,eigV {:3d} {:10.3e} {:10.3e} {:10.3e} {:10.3e} {:8.4f}\n" \
               .format(iSTB,sumY,gStr,tolR,triV,eigV)
            fDeb.write(sOut)
            #K = NP.exp(logK)
            #WO.writeArrayDebug(fDeb,K,"1SidedStab: K")

#-- Trivial or Converged? -------------------------------------------

        if triV < 1.0E-04:
            break
        elif tolR < 1.0E-12:
            break

#== Return the Gstar ==================================================

    if qDeb > 0:
        WO.writeArrayDebug(fDeb, K, "End 1S-SC: K")

    return iSTB, sumY, gStr, tolR, triV, logK
Example #2
0
def calcStepGRD(dDep, pDep, tRes, zRef, fRef, clsEOS, clsIO):

    mxSS = 50

    nCom = clsEOS.nComp
    iLiq = 0

    zDep = NP.zeros(nCom)  #-- Composition at this Depth
    yMol = NP.zeros(nCom)
    res0 = NP.zeros(nCom)
    res1 = NP.zeros(nCom)
    fBar = NP.zeros(nCom)

    #-- Gravity Correction: Whitson Eqn.(4.96) --------------------------

    grvC = dDep / (144.0 * UT.gasCon * tRes)

    #print("dDep,grvC {:10.3f} {:10.3e}".format(dDep,grvC))

    zDep = zRef  #-- Vec: initial z
    fBar = NP.multiply(fRef, NP.exp(grvC * clsEOS.Mw))  #-- Vec: W&B Eqn.(4.96)

    #======================================================================
    #  Main Iterative Loop
    #======================================================================

    iSS = 0  #-- Successive-Substitution Counter
    qConv = False

    while not qConv:

        iSS += 1

        if iSS > mxSS: break  #-- Not converged!

        #-- Fugacity Coefs and their P-Derivatives of New Fluid -------------

        fDep, dFdP = setupCalcGRDCoefsP(iLiq, pDep, tRes, zDep, clsEOS)

        #-- Mole Numbers: Whitson Eqn.(4.95) --------------------------------

        res1 = res0  #-- Vec: Might be used in GDEM
        res0 = fBar / fDep  #-- Vec
        yMol = zDep * res0  #-- Vec: W&B Eqn.(4.95)
        sumY = NP.sum(yMol)  #-- Scalar
        res0 = res0 / sumY  #-- Vec: W&B Eqn.(4.97)
        wrkQ = yMol * res0 * dFdP / fDep
        dQdP = NP.sum(wrkQ)  #-- Scalar: W&B Eqn.(4.100)

        qFun = 1.0 - sumY  #-- W&B Eqn.(4.94)
        dPrs = -qFun / dQdP  #-- W&B Eqn.(4.99a)
        pDep = pDep + dPrs  #-- W&B Eqn.(4.99b)

        #== Converged? ========================================================

        cWrk = res0 * zDep / yMol  #-- Vec
        cWrk = NP.log(cWrk)
        cTst = NP.sum(cWrk)
        cTst = cTst * cTst

        if cTst < 1.0E-12: break

        #== SS or GDEM Update? W&B Eqn.(4.83) =================================

        if iSS % UT.mGDEM1 > 0: eigV = 1.0
        else:

            res0 = NP.log(res0)  #-- Take logs of Residuals
            res1 = NP.log(res1)

            eigV = UT.GDEM1(res0, res1, clsIO)  #-- GDEM works on log-Residuals

            res0 = NP.exp(res0)  #-- Restore Residuals
            res1 = NP.exp(res1)

        #print("calcStepGRD: iSS,qFun,dQdP,eigV,dPrs,cTst {:2d} {:10.3e} {:10.3e} {:8.3f} {:10.3e} {:10.3e}".format(iSS,qFun,dQdP,eigV,dPrs,cTst))

        yMol = yMol * NP.power(res0, eigV)

        #-- Mole Numbers to Composition -------------------------------------

        zDep = UT.Norm(yMol)

#== Return the updated pressure and composition =======================

#print("calcStepGRD: iSS,pDep {:2d} {:10.3f}".format(iSS,pDep))

    return pDep, zDep
Example #3
0
def calcPsat(pObs,tRes,clsEOS,clsSAM,clsIO) :

    nCom = clsEOS.NC
    mPSA = 101

    if clsIO.Deb["PSAT"] > 0 :
        qDeb = True
        fDeb = clsIO.fDeb
    else :
        qDeb = False
    
#== Pre-Sweep; do we have approx phase env and/or observed Psat? ======

    qBub,p2PH,p1PH,logK = sweepPsat(pObs,tRes,clsEOS,clsSAM,clsIO)

    pSat = p2PH
    p2OK = p2PH
    
#========================================================================
#  Do we have a valid Pressure Interval to search?
#========================================================================

    if qDeb :
        sOut = "calcPsat: tRes,p2PH,p1PH {:8.3f} {:10.3f} {:10.3f}\n".format(tRes,p2PH,p1PH)
        fDeb.write(sOut)
        K = NP.exp(logK)
        WO.writeArrayDebug(fDeb,K,"Post-sweepPsat: K")

    pDIF = p1PH - p2PH

    if p2PH >= p1PH :
        print("calcSat: can't find valid search range - Error")
        Ksat = NP.zeros(nCom)
        pSat = -1.0
        return qBub,pSat,Ksat

#-- Load Feed Composition -------------------------------------------    

    Z = NP.zeros(nCom)
    
    for iC in range(nCom) : Z[iC] = clsSAM.gZI(iC)
    
#== Test the logK-values have the right sign! =========================
    
    logL = -1.0*logK

    tol21,yMol,res0,dFdP = calcFugDerv(qBub,pSat,tRes,Z,logK,clsEOS)
    tol22,yMol,res0,dFdP = calcFugDerv(qBub,pSat,tRes,Z,logL,clsEOS)

    if qDeb :
        sOut = "Initial tol21,tol22 {:10.3e} {:10.3e}\n".format(tol21,tol22)
        fDeb.write(sOut)

    if tol21 > tol22 :
        logK = logL
        K    = NP.exp(logK)
        if qDeb : WO.writeArrayDebug(fDeb,K,"Post-tol2: K")
    
#----------------------------------------------------------------------
#  Main Loop
#----------------------------------------------------------------------

    iPSA = 0

    while iPSA < mPSA :

        iPSA += 1

#-- Get Fugacity Coeffs and their Pressure-Derivatives --------------

        if iPSA > 1 : res1 = res0  #-- Copy 'last' residual for GDEM

        tol2,yMol,res0,dFdP = calcFugDerv(qBub,pSat,tRes,Z,logK,clsEOS)

        resX = NP.exp(res0)

#== Is this a GDEM Step?  If so, calculate Single Eigenvalue ==========            

        if iPSA % CO.mGDEM1 > 0 : eigV = 1.0
        else                    : eigV = UT.GDEM1(res0,res1,clsIO)

#== Perform Update; Calculate Various Sums ============================

        yMol = yMol*resX                #-- W&B Eqn.(4.83) with lambda=1
        dQdp = NP.dot(yMol,dFdP)        #-- W&B Eqn.(4.86)
        qFun = NP.sum(yMol)             #-- W&B Eqn.(4.87a) 
        wrk0 = eigV*res0                #-- W&B Eqn.(4.83) with any lambda
        logK = logK + wrk0

#-- Test for Trivial Solution [all K's -> 1] ------------------------            

        triV = NP.dot(logK,logK)        #-- W&B Eqn.(4.88)

#== SS or GDEM step?  If GDEM, re-compute Yi afresh ===================        
        
        if eigV == 1.0 :
            sumY = qFun
        else :
            K    = NP.exp(logK)
            yMol = Z*K
            sumY = NP.sum(yMol)
            if qDeb :
                WO.writeArrayDebug(fDeb,K,"Post-GDEM: K")

        qFun =     1.0 - qFun
        tol1 = abs(1.0 - sumY)          #-- W&B Eqn.(4.87a)

#== Pressure Update (Newton) ==========================================

        if abs(dQdp) < CO.macEPS :
            print("calcSat: Can't update Psat [dQdp = 0] - Error")
            Ksat = NP.zeros(nCom)
            pSat = -1.0
            return qBub,pSat,Ksat

        dPrs = - qFun/dQdp

        pOld = pSat
        pSat = pSat + dPrs              #-- W&B Eqn.(4.85)

        if qDeb :
            sOut = "iPSA,qFun,dQdp,to11,tol2,triV,eigV,dPrs,pSat {:3d} {:10.3e} {:10.3e} {:10.3e} {:10.3e} {:10.3e} {:10.3e} {:10.3e} {:10.4f}\n"\
                .format(iPSA,qFun,dQdp,tol1,tol2,triV,eigV,dPrs,pSat)
            fDeb.write(sOut)

        if pSat > p1PH or pSat < p2PH :
            #print("pSat>p1PH: p2PH,p1PH,pSat {:10.3f} {:10.3f} {:10.3f}".format(p2PH,p1PH,pSat))
            pSat,logK = rescuePsat(qBub,p2PH,p1PH,tRes,Z,clsEOS,clsIO)
            break

#== Converged? ========================================================

        if tol1 < 1.0E-12 and tol2 < 1.0E-08 :      #-- Hard to acheive 1E-13
            qCon = True
            break

#== Trivial Solution? =================================================

        if triV < 1.0E-04 :
            qTrv = True
            print("calcPsat: Trivial Solution?")
            break

#== Pressure-Step too big? ============================================

        """
        if   pSat > p1PH :
            #pSat = pOld + 0.001
            if qDeb :
                sOut = "p2PH,p1PH,pSat {:10.3f} {:10.3f} {:10.3f}\n".format(p2PH,p1PH,pSat)
                fDeb.write(sOut)
        elif pSat < p2PH :
            pSat = pOld + 0.5*pDIF
        else :
            p2PH = pSat
            pDIF = p1PH - p2PH
        """

#========================================================================
#  Converged: Calculate K-Values
#========================================================================

    Ksat = NP.exp(logK)

#== Ensure the K-Values are the 'Right-Way-Up' ========================

    if Ksat[nCom-1] > 1.0 :
        qBub = False
        #qBub = not qBub
        Ksat = NP.divide(1.0,Ksat)
        if qDeb :
            sOut = "End-calcPsat: K-Values Flipped\n"
            fDeb.write(sOut)
    else :
        qBub = True
        if qDeb :
            sOut = "End-calcPsat: K-Values OK\n"
            fDeb.write(sOut)

    return qBub,pSat,Ksat
Example #4
0
def calcTsat(pRes,clsEOS,clsSAM,clsIO) :

    nCom = clsEOS.NC
    mTSA = 101

    if clsIO.Deb["TSAT"] > 0 :
        qDeb = True
        fDeb = clsIO.fDeb
    else :
        qDeb = False

#-- Load Feed Composition -------------------------------------------    

    Z = NP.zeros(nCom)
    
    for iC in range(nCom) : Z[iC] = clsSAM.gZI(iC)
    
#== Pre-Sweep; 2-Phase/1-Phase Temperature Bounds =====================

    t2PH,t1PH,logK = boundTsat(pRes,Z,clsEOS,clsIO)

    tRes = t2PH     #-- This will be our iteration parameter

    if qDeb :
        sOut = "calcTsat: pRes,t2PH,t1PH {:8.3f} {:10.3f} {:10.3f}\n".format(pRes,t2PH,t1PH)
        fDeb.write(sOut)
        K = NP.exp(logK)
        WO.writeArrayDebug(fDeb,K,"Post-boundTsat: K")

#----------------------------------------------------------------------
#  Main Iterative Loop
#----------------------------------------------------------------------

    iTSA = 0
    iPhs = 0
    qPD  = False
    qTD  = True
    qXD  = False

    K    = NP.exp(logK)
    yMol = Z*K

    while iTSA < mTSA :

        iTSA += 1

        if iTSA > 1 : res1 = res0  #-- Copy 'last' residual for GDEM

#== Log Fug Coefs and their T-derivatives for Feed and Trial Phase ====

        fugZ,dZdP,dZdT,dumM = CE.calcPhaseFugPTX(iPhs,qPD,qTD,qXD,pRes,tRes,Z,clsEOS)

#-- Get Normalised Trial Composition --------------------------------

        yNor = UT.Norm(yMol)

        fugY,dYdP,dYdT,dumM = CE.calcPhaseFugPTX(iPhs,qPD,qTD,qXD,pRes,tRes,yNor,clsEOS)

#== Residual and Derivative Difference ================================

        res0 = fugZ - fugY - logK   #-- Vector
        dFdT = dYdT - dZdT          #-- Vector

#== Calculate tol2 =====================================================

        tol2 = calcTOL2(logK,res0)

        resX = NP.exp(res0)

#== Is this a GDEM Step?  If so, calculate Single Eigenvalue ==========            

        if iTSA % CO.mGDEM1 > 0 : eigV = 1.0
        else                    : eigV = UT.GDEM1(res0,res1,clsIO)

#== Perform Update; Calculate Various Sums ============================

        yMol = yMol*resX                #-- W&B Eqn.(4.83) with lambda=1
        dQdT = NP.dot(yMol,dFdT)        #-- W&B Eqn.(4.86)
        qFun = NP.sum(yMol)             #-- W&B Eqn.(4.87a) 
        wrk0 = eigV*res0                #-- W&B Eqn.(4.83) with any lambda
        logK = logK + wrk0

#-- Test for Trivial Solution [all K's -> 1] ------------------------            

        triV = NP.dot(logK,logK)        #-- W&B Eqn.(4.88)

#== SS or GDEM step?  If GDEM, re-compute Yi afresh ===================        
        
        if eigV == 1.0 :
            sumY = qFun
        else :
            K    = NP.exp(logK)
            yMol = Z*K
            sumY = NP.sum(yMol)
            if qDeb :
                WO.writeArrayDebug(fDeb,K,"Post-GDEM: K")

        qFun =     1.0 - qFun
        tol1 = abs(1.0 - sumY)          #-- W&B Eqn.(4.87a)

#== Pressure Update (Newton) ==========================================

        dTem = - qFun/dQdT

        tOld = tRes
        tRes = tRes + dTem              #-- W&B Eqn.(4.85)

        if qDeb :
            sOut = "iTSA,qFun,dQdT,to11,tol2,triV,eigV,dTem,tRes {:3d} {:10.3e} {:10.3e} {:10.3e} {:10.3e} {:10.3e} {:10.3e} {:10.3e} {:10.4f}\n"\
                .format(iTSA,qFun,dQdT,tol1,tol2,triV,eigV,dTem,tRes)
            fDeb.write(sOut)

#== Converged? ========================================================

        if tol1 < 1.0E-12 and tol2 < 1.0E-08 :      #-- Hard to acheive 1E-13
            qCon = True
            break

#== Trivial Solution? =================================================

        if triV < 1.0E-04 :
            qTrv = True
            print("calcPsat: Trivial Solution?")
            break

#========================================================================
#  Converged: Calculate K-Values
#========================================================================

    Ksat = NP.exp(logK)

#== Ensure the K-Values are the 'Right-Way-Up' ========================

    if Ksat[nCom-1] > 1.0 :
        qBub = False
        #qBub = not qBub
        #Ksat = NP.divide(1.0,Ksat)
        if qDeb :
            sOut = "End-calcTsat: K-Values NOT Flipped\n"
            fDeb.write(sOut)
    else :
        qBub = True
        if qDeb :
            sOut = "End-calcTsat: K-Values OK\n"
            fDeb.write(sOut)

#== Return values =====================================================

    return qBub,tRes,Ksat
Example #5
0
def calcStepGRD(dDep, pDep, tRes, zRef, fRef, clsEOS, clsIO):

    mxSS = 50

    nCom = clsEOS.NC
    iLiq = 0

    zDep = NP.zeros(nCom)  #-- Composition at this Depth
    yMol = NP.zeros(nCom)
    res0 = NP.zeros(nCom)
    res1 = NP.zeros(nCom)
    fBar = NP.zeros(nCom)

    #-- Gravity Correction: Whitson Eqn.(4.96) --------------------------

    grvC = dDep / (144 * CO.gasCon * tRes)

    #print("dDep,grvC {:10.3f} {:10.3e}".format(dDep,grvC))

    for iC in range(nCom):
        zDep[iC] = zRef[iC]
        fBar[iC] = fRef[iC] * exp(
            grvC * clsEOS.gPP("MW", iC))  #-- W&B Eqn.(4.96)

#======================================================================
#  Main Iterative Loop
#======================================================================

    iSS = 0  #-- Successive-Substitution Counter
    qConv = False

    while not qConv:

        iSS += 1

        if iSS > mxSS: break  #-- Not converged!

        #-- Fugacity Coefs and their P-Derivatives of New Fluid -------------

        fDep, dFdP = setupCalcGRDCoefsP(iLiq, pDep, tRes, zDep, clsEOS)

        #-- Mole Numbers: Whitson Eqn.(4.95) --------------------------------

        sumY = 0.0
        dQdP = 0.0
        for iC in range(nCom):
            res1[iC] = res0[iC]
            res0[iC] = fBar[iC] / fDep[iC]  #-- W&B Eqn.(4.97a)
            yMol[iC] = zDep[iC] * res0[iC]  #-- W&B Eqn.(4.95)
            sumY = sumY + yMol[iC]
            dQdP = dQdP + yMol[iC] * dFdP[iC] / fDep[
                iC]  #-- W&B Eqn.(4.100) - WRONG!!

        sumR = 1.0 / sumY
        for iC in range(nCom):
            res0[iC] = sumR * res0[iC]  #-- W&B Eqn.(4.97b)

        qFun = 1.0 - sumY  #-- W&B Eqn.(4.94)
        dPrs = -qFun / dQdP  #-- W&B Eqn.(4.99a)

        pDep = pDep + dPrs  #-- W&B Eqn.(4.99b)

        #== Converged? ========================================================

        cTst = 0.0
        for iC in range(nCom):
            cWrk = log(res0[iC] * zDep[iC] / yMol[iC])
            cTst = cTst + cWrk
        cTst = cTst * cTst

        if cTst < 1.0E-13 and abs(dPrs) < 1.0E-06: break

        #== SS or GDEM Update? W&B Eqn.(4.83) =================================

        if iSS % CO.mGDEM1 > 0: eigV = 1.0
        else:

            res0 = NP.log(res0)  #-- Take logs of Residuals
            res1 = NP.log(res1)

            eigV = UT.GDEM1(res0, res1, clsIO)  #-- GDEM works on log-Residuals

            res0 = NP.exp(res0)  #-- Restore Residuals
            res1 = NP.exp(res1)

        #print("calcStepGRD: iSS,qFun,dQdP,eigV,dPrs,cTst {:2d} {:10.3e} {:10.3e} {:8.3f} {:10.3e} {:10.3e}".format(iSS,qFun,dQdP,eigV,dPrs,cTst))

        for iC in range(nCom):
            yMol[iC] = yMol[iC] * pow(res0[iC], eigV)

        #-- Mole Numbers to Composition -------------------------------------

        sumY = 0.0
        for iC in range(nCom):
            sumY = sumY + yMol[iC]

        sumR = 1.0 / sumY
        for iC in range(nCom):
            zDep[iC] = sumR * yMol[iC]

#== Return the updated pressure and composition =======================

#print("calcStepGRD: iSS,pDep {:2d} {:10.3f}".format(iSS,pDep))

    return pDep, zDep