예제 #1
0
def calcFLS(iExp, qDif, clsEOS, dicSAM, clsEXP, clsIO):

    nCom = clsEOS.nComp
    nSam = clsEXP.nSamp
    nPrs = clsEXP.nRow

    iLiq = 1
    iVap = -1

    sNam = dicSAM[nSam].sNam

    #print("calcFLS: nCom,nSam,nRow ",nCom,nSam,nPrs)

    typIND = AP.classLIB().INDshrt.get("FLS")
    typOBS = AP.classLIB().OBSshrt.get("FLS")

    iPR = typIND.index("PRES")
    iTR = typIND.index("TEMP")

    iZF = typOBS.index("ZFAC")
    iDO = typOBS.index("DENO")
    iVF = typOBS.index("VFRC")

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

    Z = NP.zeros(nCom)
    for iC in range(nCom):
        Z[iC] = dicSAM[nSam].gZI(iC)

    #======================================================================
    #  Loop over user defined 'stages'
    #======================================================================

    for iPrs in range(nPrs):

        pRes = clsEXP.dInd[iPR][iPrs]
        tRes = clsEXP.dInd[iTR][iPrs]

        #-- 2-Phase Flash ---------------------------------------------------

        vEst = 0.5
        V, K, X, Y = CF.calcFlash(pRes, tRes, Z, vEst, clsEOS, clsIO)

        #-- Properties of the Liquid and Vapour Output of this stage --------

        Moil, Vliq, Doil, Zoil, Uoil, dumS, dumS = CE.calcProps(
            iLiq, pRes, tRes, X, clsEOS)
        Mgas, Vvap, Dgas, Zgas, Ugas, dumS, dumS = CE.calcProps(
            iVap, pRes, tRes, Y, clsEOS)

        clsEXP.dCal[iZF][iPrs] = Zgas
        clsEXP.dCal[iDO][iPrs] = Doil
        clsEXP.dCal[iVF][iPrs] = V

#======================================================================
#  End of Module
#======================================================================

    return
예제 #2
0
def isLibComp(iC, cName, clsEOS, clsIO):

    #fLog = clsIO.fLog

    clsLIB = AP.classLIB()

    Pcrit = clsLIB.lPcrt[cName]
    Vcrit = clsLIB.lVcrt[cName]
    Tcrit = clsLIB.lTcrt[cName] + UT.dF2dR  #-- Want this stored in degR

    Zcrit = Pcrit * Vcrit / (UT.gasCon * Tcrit)

    clsEOS.sNM(iC, cName)

    clsEOS.sPP("MW", iC, clsLIB.lMolW[cName])
    clsEOS.sPP("TC", iC, Tcrit)
    clsEOS.sPP("PC", iC, Pcrit)
    clsEOS.sPP("VC", iC, Vcrit)
    clsEOS.sPP("ZC", iC, Zcrit)
    clsEOS.sPP("AF", iC, clsLIB.lAcnF[cName])
    clsEOS.sPP("SG", iC, clsLIB.lSpcG[cName])
    clsEOS.sPP("TB", iC,
               clsLIB.lTboi[cName] + UT.dF2dR)  #-- Want this stored in degR
    clsEOS.sPP("PA", iC, clsLIB.lPara[cName])
    clsEOS.sPP("MA", iC, 1.0)
    clsEOS.sPP("MB", iC, 1.0)

    if clsEOS.EOS == "SRK": clsEOS.sPP("SS", iC, clsLIB.lVSRK[cName])
    else: clsEOS.sPP("SS", iC, clsLIB.lVSPR[cName])

    clsEOS.sPP("CA", iC, clsLIB.lCpAI[cName])
    clsEOS.sPP("CB", iC, clsLIB.lCpBI[cName])
    clsEOS.sPP("CC", iC, clsLIB.lCpCI[cName])
    clsEOS.sPP("CD", iC, clsLIB.lCpDI[cName])

    sLog = "Component ({:2d}) = {:4s} is in Internal Library - Properties Assigned".format(
        iC + 1, cName)
    print(sLog)

    #======================================================================
    #  End of Routine
    #======================================================================

    return
예제 #3
0
def calcGRD(iExp, qDif, clsEOS, dicSAM, clsEXP, clsIO):

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

    qSat = True

    #-- Various dimensions ----------------------------------------------

    nCom = clsEOS.nComp
    nSam = clsEXP.nSamp
    nDep = clsEXP.nRow - 1  #-- Extra Row for GOC, if present
    nRef = clsEXP.nDref

    nGOC = nDep

    #-- Pointers into the potential observed data (for calculated data) -

    typIND = AP.classLIB().INDshrt.get("GRD")
    typOBS = AP.classLIB().OBSshrt.get("GRD")

    iHG = typIND.index("HEIG")

    iPR = typOBS.index("PRES")
    iPS = typOBS.index("PSAT")
    iDN = typOBS.index("DENS")
    iC1 = typOBS.index("ZC1")
    iCP = typOBS.index("ZC7+")

    #-- Sample Name -----------------------------------------------------

    clsSAM = dicSAM[nSam]
    sNam = clsSAM.sNam

    clsWRK = AD.classSample("GRDwrk")
    clsWRK.setIntComp(nCom, nCom)

    #-- Load Reference Composition --------------------------------------

    zRef = NP.zeros(nCom)
    for iC in range(nCom):
        zRef[iC] = clsSAM.gZI(iC)

    #-- Reference Depth & Pressure --------------------------------------

    pRef = clsEXP.Pref
    hRef = clsEXP.Dref

    #-- Reservoir Temperature -------------------------------------------

    tRes = clsEXP.Tres

    #== Saturation Pressure at Reference Depth ============================

    pSatO = clsEXP.PsatO

    if pSatO > 0.0: pObs = 0.95 * pSatO
    else: pObs = -1.0

    qBub = None
    pSat = None
    logK = NP.empty(nCom)

    qBub, pSat, Ksat = CS.calcPsat(pObs, tRes, qBub, pSat, logK, clsEOS,
                                   clsSAM, clsIO)

    if qBub: iRef = 1  #-- Ref-State is BUB
    else: iRef = -1  #--              DEW

    iNeu = 0
    iLiq = 1
    iVap = -1

    mSat, vSat, dSat, zSat, uSat, dumS, dumS = CE.calcProps(
        iNeu, pSat, tRes, zRef, clsEOS)

    zC1, zC7 = calcMoleFracGRD(zRef, clsEOS)

    clsEXP.dCal[iPR][nRef] = pRef
    clsEXP.dCal[iPS][nRef] = pSat
    clsEXP.dCal[iDN][nRef] = dSat
    clsEXP.dCal[iC1][nRef] = zC1
    clsEXP.dCal[iCP][nRef] = zC7

    for iC in range(nCom):
        clsEXP.zCal[nRef][iC] = zRef[iC]

    #-- Get Reference (log) Fugacity Coeffs -----------------------------

    fRef, dumP = setupCalcGRDCoefsP(iNeu, pRef, tRes, zRef,
                                    clsEOS)  #-- Dont need Ref dlnPhi/dP

    #======================================================================
    #  GOC Search, if appropriate
    #======================================================================

    iTop = 0
    iBot = 0

    if nRef > 0:

        hTop = clsEXP.dInd[iHG][0]
        dTop = hTop - hRef
        zTyp = "Top"

        #-- Calculate a Pressure & Composition at Top Depth -----------------

        pTop,zTop,qTop,sTop = \
            calcTopBottom(zTyp,dTop,pRef,tRes,zRef,fRef,clsEOS,clsIO)

        if not qTop: iTop = -1  #-- Is DEW point

    else: hTop = None

    if nRef < nDep:

        hBot = clsEXP.dInd[iHG][nDep - 1]
        dBot = hBot - hRef
        zTyp = "Bot"

        #-- Calculate a Pressure & Composition at Bottom Depth --------------

        pBot,zBot,qBot,sBot = \
            calcTopBottom(zTyp,dBot,pRef,tRes,zRef,fRef,clsEOS,clsIO)

        if qBot: iBot = 1  #-- Is BUB point

    else: hBot = None

    #--------------------------------------------------------------------
    #  Search for Gas-Oil-Contact?
    #--------------------------------------------------------------------

    if iTop * iBot < 0:

        if iRef == iTop: hTop = hRef
        else: hBot = hRef

        print("Gas-Oil-Contact Detected in Depth Interval")

        hGOC,pGOC,sGOC,dGOC,zC1,zC7,zDew,zBub = \
            calcGOC(hTop,hBot,tRes,hRef,pRef,zRef,fRef,clsEOS,clsIO)
    else:
        print("No Gas-Oil-Contact Detected in Depth Interval")
        hGOC = 0.0
        pGOC = 0.0
        sGOC = 0.0
        dGOC = 0.0
        zC1 = 0.0
        zC7 = 0.0
        zDew = NP.zeros(nCom)
        zBub = NP.zeros(nCom)

    clsEXP.dInd[iHG][nGOC] = hGOC

    clsEXP.dCal[iPR][nGOC] = pGOC
    clsEXP.dCal[iPS][nGOC] = sGOC
    clsEXP.dCal[iDN][nGOC] = dGOC
    clsEXP.dCal[iC1][nGOC] = zC1
    clsEXP.dCal[iCP][nGOC] = zC7

    for iC in range(nCom):
        clsEXP.zCal[nGOC][iC] = zDew[iC]

    #-- Above and Below any Possible GOC --------------------------------

    hAbv = None
    hBel = None

    #--------------------------------------------------------------------
    #  Above Reference Depth
    #--------------------------------------------------------------------

    zTyp = "Abv"

    for iDep in range(nRef - 1, -1, -1):

        hDep = clsEXP.dInd[iHG][iDep]
        dDep = hDep - hRef

        #print("Above: iDep,hDep ",iDep,hDep)

        pDep,zDep,qDep,sDep = \
            calcTopBottom(zTyp,dDep,pRef,tRes,zRef,fRef,clsEOS,clsIO)

        mDep, vDep, yDep, gDen, uDep, dumS, dumS = CE.calcProps(
            iNeu, pDep, tRes, zDep, clsEOS)
        zC1, zC7 = calcMoleFracGRD(zDep, clsEOS)

        clsEXP.dCal[iPR][iDep] = pDep
        clsEXP.dCal[iPS][iDep] = sDep
        clsEXP.dCal[iDN][iDep] = yDep
        clsEXP.dCal[iC1][iDep] = zC1
        clsEXP.dCal[iCP][iDep] = zC7

        for iC in range(nCom):
            clsEXP.zCal[iDep][iC] = zDep[iC]

        if qDeb:
            if qBub: isBub = 1
            else: isBub = -1
            sOut = "Above: iDep,hDep,pDep,pSat,Bub,zC1,zC7+,Dens {:2d} {:10.3f} {:10.3f} {:10.3f} {:2d} {:6.4f} {:6.4f} {:7.3f}\n".format(
                iDep, hDep, pDep, pSat, isBub, zC1, zC7, yDep)
            fDeb.write(sOut)
            WO.writeArrayDebug(fDeb, zDep, "zDep")

#--------------------------------------------------------------------
#  Below Reference Depth
#--------------------------------------------------------------------

    zTyp = "Bel"

    for iDep in range(nRef + 1, nDep):

        hDep = clsEXP.dInd[iHG][iDep]
        dDep = hDep - hRef

        #print("Below: iDep,hDep ",iDep,hDep)

        pDep,zDep,qDep,sDep = \
            calcTopBottom(zTyp,dDep,pRef,tRes,zRef,fRef,clsEOS,clsIO)

        mDep, vDep, yDep, gDen, uDep, dumS, dumS = CE.calcProps(
            iNeu, pDep, tRes, zDep, clsEOS)
        zC1, zC7 = calcMoleFracGRD(zDep, clsEOS)

        clsEXP.dCal[iPR][iDep] = pDep
        clsEXP.dCal[iPS][iDep] = sDep
        clsEXP.dCal[iDN][iDep] = yDep
        clsEXP.dCal[iC1][iDep] = zC1
        clsEXP.dCal[iCP][iDep] = zC7

        for iC in range(nCom):
            clsEXP.zCal[iDep][iC] = zDep[iC]

        if qDeb:
            if qBub: isBub = 1
            else: isBub = -1
            sOut = "Below: iDep,hDep,pDep,pSat,Bub,zC1,zC7+,Dens {:2d} {:10.3f} {:10.3f} {:10.3f} {:2d} {:6.4f} {:6.4f} {:7.3f}\n".format(
                iDep, hDep, pDep, pSat, isBub, zC1, zC7, yDep)
            fDeb.write(sOut)
            WO.writeArrayDebug(fDeb, zDep, "zDep")

#======================================================================
#  End of Routine
#======================================================================

    return
예제 #4
0
def assignBIPs(clsEOS):

    clsLIB = AP.classLIB()

    nComp = clsEOS.nComp

    #-- Initially, set all values to Zero -------------------------------

    for iC in range(nComp):
        for jC in range(nComp):
            clsEOS.sIJ(iC, jC, 0.0)

#-- Then set Library/Other Components -------------------------------

    for iC in range(nComp):

        cINam = clsEOS.gNM(iC)

        #print("iC,cINam ",iC,cINam)

        if cINam.upper() == "N2":

            for jC in range(iC + 1, nComp):

                cJNam = clsEOS.gNM(jC)
                typJC = clsLIB.typeC.get(cJNam)  #-- Other Lib Compor Not?

                if typJC == "L":
                    if clsEOS.EOS == "SRK": KIJ = clsLIB.lKN2S[cJNam]
                    else: KIJ = clsLIB.lKN2P[cJNam]
                else:
                    if clsEOS.EOS == "SRK": KIJ = 0.080
                    else: KIJ = 0.115

                #print("N2 :jC,cJNam,typJC,KIJ ",jC,cJNam,typJC,KIJ)

                clsEOS.sIJ(iC, jC, KIJ)
                clsEOS.sIJ(jC, iC, KIJ)

        elif cINam.upper() == "CO2":

            for jC in range(iC + 1, nComp):

                cJNam = clsEOS.gNM(jC)
                typJC = clsLIB.typeC.get(cJNam)  #-- Other Lib Comp or Not?

                if typJC == "L":
                    if clsEOS.EOS == "SRK": KIJ = clsLIB.lKCOS[cJNam]
                    else: KIJ = clsLIB.lKCOP[cJNam]
                else:
                    if clsEOS.EOS == "SRK": KIJ = 0.150
                    else: KIJ = 0.115

                #print("CO2:jC,cJNam,typJC,KIJ ",jC,cJNam,typJC,KIJ)

                clsEOS.sIJ(iC, jC, KIJ)
                clsEOS.sIJ(jC, iC, KIJ)

        elif cINam.upper() == "H2S":

            for jC in range(iC + 1, nComp):

                cJNam = clsEOS.gNM(jC)
                typJC = clsLIB.typeC.get(cJNam)  #-- Other Lib Comp or Not?

                if typJC == "L":
                    if clsEOS.EOS == "SRK": KIJ = clsLIB.lKHSS[cJNam]
                    else: KIJ = clsLIB.lKHSP[cJNam]
                else:
                    if clsEOS.EOS == "SRK": KIJ = 0.030
                    else: KIJ = 0.055

                #print("H2S:jC,cJNam,typJC,KIJ ",jC,cJNam,typJC,KIJ)

                clsEOS.sIJ(iC, jC, KIJ)
                clsEOS.sIJ(jC, iC, KIJ)

        elif cINam.upper() == "C1":

            for jC in range(iC + 1, nComp):

                cJNam = clsEOS.gNM(jC)
                typJC = clsLIB.typeC.get(cJNam)  #-- Other Lib Comp or Not?

                if typJC == "L":
                    if clsEOS.EOS == "SRK": KIJ = clsLIB.lKC1S[cJNam]
                    else: KIJ = clsLIB.lKC1P[cJNam]
                else:
                    if clsEOS.EOS == "SRK": KIJ = 0.000
                    else:
                        mWJ = clsEOS.gPP("MW", jC)
                        if mWJ > 90.0:
                            KIJ = 0.14 * clsEOS.gPP("SG", jC) - 0.0668
                        else:
                            KIJ = 0.000

                #print("C1 :iC,jC,cJNam,typJC,KIJ ",iC,jC,cJNam,typJC,KIJ)

                clsEOS.sIJ(iC, jC, KIJ)
                clsEOS.sIJ(jC, iC, KIJ)

        else:
            pass

#=======================================================================
#  End of Routine
#=======================================================================

    return
예제 #5
0
def allProps(clsEOS, dicSAM, clsUNI, clsIO):

    iERR = 0

    clsLIB = AP.classLIB()

    nComp = clsEOS.nComp
    nUser = clsEOS.nUser
    nSplt = clsEOS.nPseu
    nSamp = len(dicSAM)

    #print("allProps: nComp,nUser,nSplt,nSamp ",nComp,nUser,nSplt,nSamp)

    print("allProps: Attempting to assign Component Properties")

    #-- Find the type (Library or SCN) of first Nc-1 components ---------

    for iC in range(nUser - 1):

        cName = clsEOS.gNM(iC)
        typC = clsLIB.typeC.get(cName)

        if typC == None:
            print("allProps: Component " + str(iC + 1, cName) +
                  " is not Library or SCN - Error")
            iERR = -1
            return iERR

#== Library Components ================================================

        if typC == 'L':

            isLibComp(iC, cName, clsEOS, clsIO)

#== SCN Components ====================================================

        elif typC == 'S':  #-- SCN     Component

            molWt = clsLIB.scnMW[cName]

            heavyComp(molWt, -1.0, iC, clsEOS)

            sLog = "Component ({:2d}) = {:4s} is assumed to be a SCN - Properties Assigned/Calculated".format(
                iC + 1, cName)
            print(sLog)

#== Not Library or SCN ================================================

        else:

            print("Component Name " + cName + " Not Recognised - Error")
            iERR = -1

#=======================================================================
#  Process the Plus Fraction(s)
#  If more than one sample, split using Whitson Quadrature Method
#=======================================================================

#-- Mole Weight of Penultimate Component: 'Last' component = nComp-1 --

    cPlus = clsEOS.gNM(nUser - 1)  #-- Name of the User Plus Fraction

    if nSamp > 1 or nSplt > 1:

        sLog = "Component ({:2d}) = {:4s} is Plus Fraction to be Split into {:1d} Pseudos".format(
            nUser, cPlus, nSplt)
        print(sLog)

        iERR = splitPlus(dicSAM, clsEOS, clsIO)

        if iERR < 0:
            return iERR

        print("Plus Fraction Splitting Completed")

    else:

        molWt = dicSAM[0].mPlus
        specG = dicSAM[0].sPlus

        sLog = "Component ({:2d}) = {:4s} is Plus Fraction with No Split Requested - Properties Calculated".format(
            nUser + 1, cPlus)
        print(sLog)

        heavyComp(molWt, specG, nUser - 1, clsEOS)

#=======================================================================
#  Sort the Binary Interaction Parameters
#=======================================================================

    nComp = clsEOS.nComp

    #print("compProps: Set BICs, N = ",nComp)

    assignBIPs(clsEOS)

    print("Binary Interaction Parameters (BIPs) Assigned/Calculated")

    #========================================================================
    #  Do we need to sort the components?  Most to Least Volatility
    #========================================================================

    clsEOS, dicSAM = sortComponents(clsEOS, dicSAM)

    #========================================================================
    #  Output the data
    #========================================================================

    sTit = "Initialisation"

    WO.outputProps(sTit, clsEOS, dicSAM, clsIO)

    #========================================================================
    #  Write Fluid Description to the SAV file
    #========================================================================

    WO.outputSave(sTit, clsEOS, dicSAM, clsIO)

    #======================================================================
    #  Generate (Approximate) Phase Plots
    #======================================================================

    #CP.allSamplesPhasePlot(clsEOS,dicSAM,clsIO)

    #======================================================================
    #  End of Routine
    #======================================================================

    return iERR
예제 #6
0
def calcSWL(iExp, qDif, clsEOS, dicSAM, clsEXP, clsIO):

    nCom = clsEOS.nComp
    nSam = clsEXP.nSamp
    nInj = clsEXP.nSinj
    nAdd = clsEXP.nRow

    sNam = dicSAM[nSam].sNam

    #print("calcSEP: nCom,nSam,nRow ",nCom,nSam,nPrs)

    typIND = AP.classLIB().INDshrt.get("SWL")
    typOBS = AP.classLIB().OBSshrt.get("SWL")

    iMO = typIND.index("MOLE")

    iPS = typOBS.index("PSAT")
    iVS = typOBS.index("VSWL")

    #-- Reservoir Temperature -------------------------------------------

    tRes = clsEXP.Tres

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

    clsSAM = dicSAM[nSam]
    clsINJ = dicSAM[nInj]

    clsWRK = AD.classSample("SWLwrk")
    clsWRK.setIntComp(nCom, nCom)

    Z = NP.zeros(nCom)
    for iC in range(nCom):
        Z[iC] = clsSAM.gZI(iC)

    #-- Load Injection Composition --------------------------------------

    Y = NP.zeros(nCom)
    for iC in range(nCom):
        Y[iC] = clsINJ.gZI(iC)

    #-- Composition Array to be used ------------------------------------

    W = NP.zeros(nCom)

    mTot = 1.0
    mInj = 0.0

    #======================================================================
    #  Loop over user defined 'stages'
    #======================================================================

    for iAdd in range(nAdd):

        mInj = clsEXP.dInd[iMO][iAdd]

        mTot = mInj + 1.0

        #print("calcSWL: iAdd,mAdd,mInj,mTot ",iAdd,mThs,mInj,mTot)

        wDiv = 1.0 / mTot
        for iC in range(nCom):
            W[iC] = (Z[iC] + mInj * Y[iC]) * wDiv
            clsWRK.sZI(iC, W[iC])

        pSatO = clsEXP.dObs[iPS][iAdd]

        if pSatO > 0.0: pEst = 0.95 * pSatO
        else: pEst = -1.0

        qBub = None
        pSat = None
        logK = NP.empty(nCom)

        qBub,pSat,Ksat = \
            CS.calcPsat(pEst,tRes,qBub,pSat,logK,clsEOS,clsWRK,clsIO)

        iLiq = 0
        MPs, VPs, DPs, ZPs, UPs, dmS, dmS = CE.calcProps(
            iLiq, pSat, tRes, W, clsEOS)

        if iAdd == 0: Vref = VPs

        Vswl = mTot * VPs / Vref

        clsEXP.dCal[iPS][iAdd] = pSat
        clsEXP.dCal[iVS][iAdd] = Vswl

#======================================================================
#  End of Module
#======================================================================

    return
예제 #7
0
def calcCCE(iExp, qDif, clsEOS, dicSAM, clsEXP, clsIO):

    nCom = clsEOS.nComp
    nSam = clsEXP.nSamp
    nPrs = clsEXP.nRow

    clsSAM = dicSAM[nSam]

    sNam = clsSAM.sNam

    #== Independent & Calculated Data =====================================

    typIND = AP.classLIB().INDshrt.get("CCE")
    typCAL = AP.classLIB().CALshrt.get("CCE")

    iPR = typIND.index("PRES")

    iRV = typCAL.index("RELV")
    iSL = typCAL.index("SLIQ")
    iZF = typCAL.index("ZFAC")
    iDO = typCAL.index("DENO")
    iUG = typCAL.index("VISG")
    iUO = typCAL.index("VISO")

    iMO = typCAL.index("MWO")
    iMG = typCAL.index("MWG")
    iDG = typCAL.index("DENG")
    iFT = typCAL.index("IFT")
    iHO = typCAL.index("HO")
    iHG = typCAL.index("HG")
    iCO = typCAL.index("CPO")
    iCG = typCAL.index("CPG")

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

    Z = NP.zeros(nCom)
    for iC in range(nCom):
        Z[iC] = clsSAM.gZI(iC)

    #-- Reservoir Temperature -------------------------------------------

    tRes = clsEXP.Tres

    #-- Saturation Pressure ---------------------------------------------

    if clsEXP.PsatO > 0.0: pObs = clsEXP.PsatO
    else: pObs = -1.0

    qBub, pSat, logK = clsEXP.getPsatInfo(qDif, nCom)

    qBub, pSat, Ksat = CS.calcPsat(pObs, tRes, qBub, pSat, logK, clsEOS,
                                   clsSAM, clsIO)

    if not qDif: clsEXP.setPsatInfo(qBub, pSat, NP.log(Ksat))

    clsEXP.setPsatCal(pSat)

    iNeu = 0
    iLiq = 1
    iVap = -1

    Msat, Vsat, Dsat, Zsat, Usat, dumS, dumS = CE.calcProps(
        iNeu, pSat, tRes, Z, clsEOS)

    #if qBub : vEst = 0.0
    #else :    vEst = 1.0

    vEst = None

    #======================================================================
    #  Loop over user defined pressures
    #======================================================================

    for iPrs in range(nPrs):

        pRes = clsEXP.dInd[iPR][iPrs]

        #== 1-Phase or 2-Phase? ===============================================

        if pRes > pSat:

            Moil, Vliq, Doil, Zoil, Uoil, dumS, dumS = CE.calcProps(
                iNeu, pRes, tRes, Z, clsEOS)
            #print("calcCCE[Z]: iP,pR,Mw,Vm,Ro,ZF,vS {:2d} {:8.2f} {:7.3f} {:8.4f} {:8.3f} {:8.4f} {:8.4f}".format(iPrs,pRes,M1P,V1P,D1P,Z1P,V1P))

            relV = Vliq / Vsat

            if qBub: sLiq = 1.0
            else: sLiq = 0.0

            Mgas = Moil
            Vvap = Vliq
            Dgas = Doil
            Zgas = Zoil
            Ugas = Uoil

            IFT = 0.0  #-- Surface Tension [dyne/cm]

            HO,CPO,uJTO = \
                CE.calcEnthSpecHeat(iNeu,pRes,tRes,Z,clsEOS)  #-- Enthalpy & Spec Heat

            HG = HO
            CPG = CPO
            uJTG = uJTO  #-- Gas = Oil = 1-Phase!

            #print("P,uJTO,uJTG,IFT {:8.2f} {:10.3e} {:10.3e} {:8.4f}".format(pRes,uJTO,uJTG,IFT))

        else:  #-- Two-Phase => Flash the Fluid

            V, K, X, Y = CF.calcFlash(pRes, tRes, Z, vEst, clsEOS, clsIO)
            vEst = V

            Moil, Vliq, Doil, Zoil, Uoil, dumS, dumS = CE.calcProps(
                iLiq, pRes, tRes, X, clsEOS)
            Mgas, Vvap, Dgas, Zgas, Ugas, dumS, dumS = CE.calcProps(
                iVap, pRes, tRes, Y, clsEOS)

            Voil = (1.0 - V) * Vliq
            Vgas = V * Vvap

            Vtot = Voil + Vgas

            relV = Vtot / Vsat

            if clsEXP.sLCCE == "TOT": sLiq = Voil / Vtot
            else: sLiq = Voil / Vsat

            if sLiq < 0.0:
                crash = 1.0 / 0.0

            IFT = CE.calcIFT(Vliq, Vvap, X, Y, clsEOS)

            HO,CPO,uJTO = \
                CE.calcEnthSpecHeat(iLiq,pRes,tRes,X,clsEOS)  #-- Enthalpy & Spec Heat
            HG,CPG,uJTG = \
                CE.calcEnthSpecHeat(iVap,pRes,tRes,Y,clsEOS)  #-- Enthalpy & Spec Heat

            #print("P,uJTO,uJTg {:8.2f} {:10.3e} {:10.3e} {:8.4f}".format(pRes,uJTO,uJTG,IFT))

#== Store the data for this stage =====================================

        clsEXP.dCal[iRV][iPrs] = relV
        clsEXP.dCal[iSL][iPrs] = sLiq
        clsEXP.dCal[iZF][iPrs] = Zgas
        clsEXP.dCal[iDO][iPrs] = Doil
        clsEXP.dCal[iUG][iPrs] = Ugas
        clsEXP.dCal[iUO][iPrs] = Uoil

        clsEXP.dCal[iMO][iPrs] = Moil
        clsEXP.dCal[iMG][iPrs] = Mgas
        clsEXP.dCal[iDG][iPrs] = Dgas
        clsEXP.dCal[iFT][iPrs] = IFT
        clsEXP.dCal[iHO][iPrs] = HO
        clsEXP.dCal[iHG][iPrs] = HG
        clsEXP.dCal[iCO][iPrs] = CPO
        clsEXP.dCal[iCG][iPrs] = CPG

#======================================================================
#  End of Module
#======================================================================

    return
예제 #8
0
def calcSAT(iExp, qDif, clsEOS, dicSAM, clsEXP, clsIO):

    nCom = clsEOS.nComp
    nSam = clsEXP.nSamp
    nTem = clsEXP.nRow

    clsSAM = dicSAM[nSam]

    sNam = clsSAM.sNam

    #print("calcSEP: nCom,nSam,nRow ",nCom,nSam,nPrs)

    typIND = AP.classLIB().INDshrt.get("SAT")
    typOBS = AP.classLIB().OBSshrt.get("SAT")

    iTR = typIND.index("TEMP")

    iPS = typOBS.index("PSAT")
    iZF = typOBS.index("ZFAC")
    iDO = typOBS.index("DENO")

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

    Z = NP.zeros(nCom)
    for iC in range(nCom):
        Z[iC] = dicSAM[nSam].gZI(iC)

    #======================================================================
    #  Loop over user defined 'stages'
    #======================================================================

    for iTem in range(nTem):

        tRes = clsEXP.dInd[iTR][iTem]
        pSatO = clsEXP.dObs[iPS][iTem]

        if pSatO > 0.0: pEst = 0.95 * pSatO
        else: pEst = -1.0

        qBub = None
        pSat = None
        logK = NP.empty(nCom)

        qBub,pSat,Ksat = \
            CS.calcPsat(pEst,tRes,qBub,pSat,logK,clsEOS,clsSAM,clsIO)

        iLiq = 0
        MPs, VPs, DPs, ZPs, UPs, dmS, dmS = CE.calcProps(
            iLiq, pSat, tRes, Z, clsEOS)

        clsEXP.dCal[iPS][iTem] = pSat
        clsEXP.dCal[iZF][iTem] = ZPs
        clsEXP.dCal[iDO][iTem] = DPs

        #print("calcSAT: tRes,qBub,pSat ",tRes,qBub,pSat)

#======================================================================
#  End of Module
#======================================================================

    return
예제 #9
0
def calcDLE(iExp, qDif, clsEOS, dicSAM, clsEXP, clsIO):

    nCom = clsEOS.nComp
    nSam = clsEXP.nSamp
    nPrs = clsEXP.nRow

    clsSAM = dicSAM[nSam]

    sNam = clsSAM.sNam

    #print("calcCVD: nCom,nSam,nRow ",nCom,nSam,nPrs)

    typIND = AP.classLIB().INDshrt.get("DLE")
    typOBS = AP.classLIB().OBSshrt.get("DLE")

    iPR = typIND.index("PRES")

    iBO = typOBS.index("BO")
    iRS = typOBS.index("GOR")
    iDO = typOBS.index("DENO")
    iBT = typOBS.index("BT")
    iBG = typOBS.index("BG")
    iZF = typOBS.index("ZFAC")
    iGG = typOBS.index("GGRV")
    iUO = typOBS.index("VISO")

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

    Z = NP.zeros(nCom)
    for iC in range(nCom):
        Z[iC] = clsSAM.gZI(iC)

    #-- Reservoir Temperature -------------------------------------------

    tRes = clsEXP.Tres

    #-- Saturation Pressure ---------------------------------------------

    if clsEXP.PsatO > 0.0: pObs = clsEXP.PsatO
    else: pObs = -1.0

    qBub, pSat, logK = clsEXP.getPsatInfo(qDif, nCom)

    qBub, pSat, Ksat = CS.calcPsat(pObs, tRes, qBub, pSat, logK, clsEOS,
                                   clsSAM, clsIO)

    if not qDif: clsEXP.setPsatInfo(qBub, pSat, NP.log(Ksat))

    clsEXP.setPsatCal(pSat)

    iLiq = 1
    iVap = -1

    Msat, Vsat, Dsat, Zsat, Usat, dumS, dumS = CE.calcProps(
        iLiq, pSat, tRes, Z, clsEOS)

    #if qBub : vEst = 0.0
    #else :    vEst = 1.0

    vEst = None

    #======================================================================
    #  Loop over user defined pressures
    #======================================================================

    zMol = 1.0
    rTot = 0.0
    psTs = UT.pStand / UT.tStand

    for iPrs in range(nPrs):

        pRes = clsEXP.dInd[iPR][iPrs]

        #== 1-Phase or 2-Phase? ===============================================

        if pRes > pSat:

            M1P, V1P, D1P, Z1P, U1P, dmS, dmS = CE.calcProps(
                iLiq, pRes, tRes, Z, clsEOS)

            if qBub: sLiq = 1.0
            else: sLiq = 0.0

            Voil = V1P
            Vrem = 0.0
            Doil = D1P
            Vtot = V1P
            Bgas = 0.0
            Zgas = 0.0
            gGrv = 0.0
            Uoil = U1P

        else:

            V, K, X, Y = CF.calcFlash(pRes, tRes, Z, vEst, clsEOS, clsIO)
            vEst = V

            Moil, Vliq, Doil, Zoil, Uoil, dumS, dumS = CE.calcProps(
                iLiq, pRes, tRes, X, clsEOS)
            Mgas, Vvap, Dgas, Zgas, Ugas, dumS, dumS = CE.calcProps(
                iVap, pRes, tRes, Y, clsEOS)

            Voil = zMol * (1.0 - V) * Vliq
            Vgas = zMol * V * Vvap

            zRem = pRes * Vgas / (Zgas * UT.gasCon * tRes)
            zMol = zMol - zRem

            Vrem = zRem * UT.volMol

            rTot = rTot + Vrem

            Z = NP.copy(X)

            Vtot = Voil + Vgas
            Bgas = psTs * Zgas * tRes / pRes
            gGrv = Mgas / UT.molAir

#-- Temporary Storage Ahead of Stock Tank Corrections ---------------

        clsEXP.dCal[iBO][iPrs] = Voil
        clsEXP.dCal[iRS][iPrs] = Vrem
        clsEXP.dCal[iDO][iPrs] = Doil
        clsEXP.dCal[iBT][iPrs] = Vtot
        clsEXP.dCal[iBG][iPrs] = Bgas
        clsEXP.dCal[iZF][iPrs] = Zgas
        clsEXP.dCal[iGG][iPrs] = gGrv
        clsEXP.dCal[iUO][iPrs] = Uoil

#== Stock Tank Volume =================================================

    Mst, Vst, Dst, Zst, Ust, dmS, dmS = CE.calcProps(iLiq, UT.pStand,
                                                     UT.tStand, Z, clsEOS)

    Vsto = zMol * Vst

    #== "Normalise" via Stock Tank Volume =================================

    for iPrs in range(nPrs):

        rTot = rTot - clsEXP.dCal[iRS][iPrs]

        clsEXP.dCal[iBO][iPrs] = clsEXP.dCal[iBO][iPrs] / Vsto
        clsEXP.dCal[iRS][iPrs] = rTot / Vsto

        clsEXP.dCal[iBT][iPrs] = clsEXP.dCal[iBO][iPrs] + \
                                 clsEXP.dCal[iBG][iPrs]*(clsEXP.dCal[iRS][0] - clsEXP.dCal[iRS][iPrs])

#======================================================================
#  End of Module
#======================================================================

    return
예제 #10
0
def calcSEP(iExp, qDif, clsEOS, dicSAM, clsEXP, clsIO):

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

    nCom = clsEOS.nComp
    nSam = clsEXP.nSamp
    nPrs = clsEXP.nRow

    clsSAM = dicSAM[nSam]

    sNam = clsSAM.sNam

    #print("calcSEP: nCom,nSam,nRow ",nCom,nSam,nPrs)

    typIND = AP.classLIB().INDshrt.get("SEP")
    typOBS = AP.classLIB().OBSshrt.get("SEP")

    iPR = typIND.index("PRES")
    iTR = typIND.index("TEMP")

    iBO = typOBS.index("BO")
    iRS = typOBS.index("GOR")
    iDO = typOBS.index("DENO")
    iGG = typOBS.index("GGRV")

    Lsep = clsEXP.Lsep
    Vsep = clsEXP.Vsep

    #print("calcSEP: Lsep ",Lsep)
    #print("calcSEP: Vsep ",Vsep)

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

    Z = NP.zeros(nCom)
    for iC in range(nCom):
        Z[iC] = clsSAM.gZI(iC)

    molZ = NP.zeros(nPrs)
    comZ = NP.zeros((nCom, nPrs))

    xSTO = NP.zeros(nCom)
    ySTG = NP.zeros(nCom)
    molO = NP.zeros(nPrs)
    molG = NP.zeros(nPrs)

    mSTO = 0.0
    mSTG = 0.0

    #-- First Stage is (pSat,tRes) and all feed goes to Stage-2 ---------

    molZ[0] = 1.0
    molZ[1] = 1.0
    for iC in range(nCom):
        comZ[iC][0] = Z[iC]
        comZ[iC][1] = Z[iC]

#-- 1st-Stage is Assumed to (Psat,tRes) -----------------------------

    pObs = clsEXP.dInd[iPR][0]
    tRes = clsEXP.dInd[iTR][0]

    #print("calcSEP: pObs,tRes ",pObs,tRes)

    #-- Saturation Pressure ---------------------------------------------

    if clsEXP.PsatO > 0.0: pObs = clsEXP.PsatO
    else: pObs = -1.0

    qBub, pSat, logK = clsEXP.getPsatInfo(qDif, nCom)

    qBub, pSat, Ksat = CS.calcPsat(pObs, tRes, qBub, pSat, logK, clsEOS,
                                   clsSAM, clsIO)

    #print("CalcSEP: Psat {:10.3f}".format(pSat))

    if not qDif: clsEXP.setPsatInfo(qBub, pSat, NP.log(Ksat))

    clsEXP.setPsatCal(pSat)

    iLiq = 1
    iVap = -1

    Msat, Vsat, Dsat, Zsat, Usat, dumS, dumS = CE.calcProps(
        iLiq, pSat, tRes, Z, clsEOS)

    #vEst = 0.5

    vEst = None

    #======================================================================
    #  Loop over user defined pressures
    #======================================================================

    zGas = 0.0
    zOil = 0.0
    zTot = 1.0

    for iPrs in range(1, nPrs):

        pRes = clsEXP.dInd[iPR][iPrs]
        tRes = clsEXP.dInd[iTR][iPrs]

        #print("iPrs,pRes,tRes {:2d} {:10.3f} {:8.3f}".format(iPrs,pRes,tRes))

        #-- 2-Phase Flash ---------------------------------------------------

        for iC in range(nCom):
            Z[iC] = comZ[iC][iPrs]

        #zSum = NP.sum(Z)
        #Z    = NP.divide(Z,zSum)

        Z = UT.Norm(Z)

        #print("iSep,Z ",iPrs,Z)

        V, K, X, Y = CF.calcFlash(pRes, tRes, Z, vEst, clsEOS, clsIO)

        if V < 0.0: V = 0.0  #-- calcFlash sets X=Z & Y=Z if 1-Phase
        elif V > 1.0: V = 1.0

        vEst = V

        zGas = molZ[iPrs] * V
        zOil = molZ[iPrs] * (1.0 - V)

        molG[iPrs] = zGas
        molO[iPrs] = zOil

        #print("iSep,molZ,molG,molO {:2d} {:10.5f} {:10.5f} {:10.5f}".format(iPrs,molZ[iPrs],molG[iPrs],molO[iPrs]))

        #-- Properties of the Liquid and Vapour Output of this stage --------

        Moil, Vliq, Doil, Zoil, Uoil, dumS, dumS = CE.calcProps(
            iLiq, pRes, tRes, X, clsEOS)
        Mgas, Vvap, Dgas, Zgas, Ugas, dumS, dumS = CE.calcProps(
            iVap, pRes, tRes, Y, clsEOS)

        #-- Where is Liquid Output Going Next? ------------------------------

        kSepL = Lsep[iPrs]

        if kSepL == 0:
            if mSTO + zOil > 0.0:
                for iC in range(nCom):
                    xSTO[iC] = (xSTO[iC] * mSTO + zOil * X[iC]) / (mSTO + zOil)
                mSTO = mSTO + zOil
            else:
                xSTO = BP.copy(X)
        else:
            for iC in range(nCom):
                comZ[iC][kSepL] = (comZ[iC][kSepL] * molZ[kSepL] +
                                   X[iC] * zOil) / (molZ[kSepL] + zOil)
            molZ[kSepL] = molZ[kSepL] + zOil

#-- Where is Vapour Output Going Next? ------------------------------

        kSepV = Vsep[iPrs]

        if kSepV == 0:
            if mSTG + zGas > 0.0:
                for iC in range(nCom):
                    ySTG[iC] = (ySTG[iC] * mSTG + zGas * Y[iC]) / (mSTG + zGas)
                mSTG = mSTG + zGas
            else:
                ySTG = NP.copy(Y)
        else:
            for iC in range(nCom):
                comZ[iC][kSepV] = (comZ[iC][kSepV] * molZ[kSepV] +
                                   Y[iC] * zGas) / (molZ[kSepV] + zGas)
            molZ[kSepV] = molZ[kSepV] + zGas

        Voil = zOil * Vliq
        Vgas = zGas * UT.volMol

        #-- Temporary storage for Bo & Rs ahead of divide by Vsto below -----

        clsEXP.dCal[iBO][iPrs] = Voil
        clsEXP.dCal[iRS][iPrs] = Vgas
        clsEXP.dCal[iDO][iPrs] = Doil
        clsEXP.dCal[iGG][iPrs] = Mgas / UT.molAir

#== Stock Tank Oil Volume =============================================

    nTot = 0.0
    rTot = 0.0
    gTot = 0.0
    Vsto = clsEXP.dCal[iBO][nPrs - 1]

    for iPrs in range(1, nPrs):

        clsEXP.dCal[iBO][iPrs] = clsEXP.dCal[iBO][iPrs] / Vsto  #-- Bo
        clsEXP.dCal[iRS][iPrs] = clsEXP.dCal[iRS][iPrs] / Vsto  #-- GOR

        nTot = nTot + molG[iPrs]
        rTot = rTot + molG[iPrs] * clsEXP.dCal[iRS][iPrs]
        gTot = gTot + molG[iPrs] * clsEXP.dCal[iGG][iPrs]

#== Saturation Pressure Stage =========================================

    if nTot > 0.0: gTot = gTot / nTot
    else: gTot = 0.0

    #print("mSTG,mSTO {:10.5f} {:10.5f}".format(mSTG,mSTO))

    clsEXP.dCal[iBO][0] = Vsat / Vsto
    clsEXP.dCal[iRS][0] = mSTG * UT.volMol / Vsto
    clsEXP.dCal[iDO][0] = Dsat
    clsEXP.dCal[iGG][0] = gTot

    #======================================================================
    #  End of Module
    #======================================================================

    return
예제 #11
0
def calcCVD(iExp, qDif, clsEOS, dicSAM, clsEXP, clsIO):

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

    nCom = clsEOS.nComp
    nSam = clsEXP.nSamp
    nPrs = clsEXP.nRow

    clsSAM = dicSAM[nSam]

    sNam = clsSAM.sNam

    if qDeb:
        sOut = "calcCVD: nCom,nSam,nRow {:2d} {:2d} {:2d}\n".format(
            nCom, nSam, nPrs)
        fDeb.write(sOut)

#-- Independent & Calculated Data -----------------------------------

    typIND = AP.classLIB().INDshrt.get("CVD")
    typCAL = AP.classLIB().CALshrt.get("CVD")

    iPR = typIND.index("PRES")

    iMR = typCAL.index("MREM")
    iSL = typCAL.index("SLIQ")
    iZF = typCAL.index("ZFAC")
    iMO = typCAL.index("MWO")
    iMG = typCAL.index("MWG")
    iDO = typCAL.index("DENO")
    iDG = typCAL.index("DENG")
    iUO = typCAL.index("VISO")
    iUG = typCAL.index("VISG")

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

    Z = NP.zeros(nCom)
    for iC in range(nCom):
        Z[iC] = clsSAM.gZI(iC)

    #-- Reservoir Temperature -------------------------------------------

    tRes = clsEXP.Tres

    #-- Saturation Pressure ---------------------------------------------

    if clsEXP.PsatO > 0.0: pObs = clsEXP.PsatO
    else: pObs = -1.0

    qBub, pSat, logK = clsEXP.getPsatInfo(qDif, nCom)

    qBub, pSat, Ksat = CS.calcPsat(pObs, tRes, qBub, pSat, logK, clsEOS,
                                   clsSAM, clsIO)

    if qDeb:
        sOut = "calcCVD: tRes,qBub,pSat {:8.2f} {:} {:10.3f}\n".format(
            tRes, qBub, pSat)
        fDeb.write(sOut)

    if not qDif: clsEXP.setPsatInfo(qBub, pSat, NP.log(Ksat))

    clsEXP.setPsatCal(pSat)

    iNeu = 0
    iLiq = 1
    iVap = -1

    Msat, Vsat, Dsat, Zsat, Usat, dumS, dumS = CE.calcProps(
        iNeu, pSat, tRes, Z, clsEOS)

    #if qBub : vEst = 0.0
    #else :    vEst = 1.0

    vEst = None

    #======================================================================
    #  Loop over user defined pressures
    #======================================================================

    zMol = 1.0
    zTot = 0.0

    for iPrs in range(nPrs):

        pRes = clsEXP.dInd[iPR][iPrs]

        #== 1-Phase or 2-Phase? ===============================================

        if pRes > pSat:

            Moil, Vliq, Doil, Zoil, Uoil, dumS, dumS = CE.calcProps(
                iNeu, pRes, tRes, Z, clsEOS)

            if qBub: sLiq = 1.0
            else: sLiq = 0.0

            zTot = 0.0
            Mgas = Moil
            Dgas = Doil
            Zgas = Zoil
            Ugas = Uoil

        else:

            V, K, X, Y = CF.calcFlash(pRes, tRes, Z, vEst, clsEOS, clsIO)
            vEst = V

            Moil, Vliq, Doil, Zoil, Uoil, dumS, dumS = CE.calcProps(
                iLiq, pRes, tRes, X, clsEOS)
            Mgas, Vvap, Dgas, Zgas, Ugas, dumS, dumS = CE.calcProps(
                iVap, pRes, tRes, Y, clsEOS)

            Voil = zMol * (1.0 - V) * Vliq
            Vgas = zMol * V * Vvap

            sLiq = Voil / Vsat

            Vtot = Voil + Vgas
            Vrem = Vtot - Vsat

            zRem = pRes * Vrem / (Zgas * UT.gasCon * tRes)  #-- Moles Removed

            for iC in range(nCom):
                Z[iC] = (zMol * Z[iC] - zRem * Y[iC]) / (zMol - zRem)

            zMol = zMol - zRem
            zTot = zTot + zRem

            if qDeb:
                sOut = "calcCVD: zRem {:10.3e}\n".format(zRem)
                fDeb.write(sOut)

#-- Load Data -------------------------------------------------------

        clsEXP.dCal[iMR][iPrs] = zTot
        clsEXP.dCal[iSL][iPrs] = sLiq
        clsEXP.dCal[iZF][iPrs] = Zgas
        clsEXP.dCal[iMO][iPrs] = Moil
        clsEXP.dCal[iMG][iPrs] = Mgas
        clsEXP.dCal[iDO][iPrs] = Doil
        clsEXP.dCal[iDG][iPrs] = Dgas
        clsEXP.dCal[iUO][iPrs] = Uoil
        clsEXP.dCal[iUG][iPrs] = Ugas

#======================================================================
#  End of Module
#======================================================================

    return
예제 #12
0
def genPlots(clsIO,dicEXP,dicSAM,clsUNI) :

    #return

    nExp = len(dicEXP)
    iInd = 0

#--------------------------------------------------------------------
#   By default, write graphs to GraphOut sub-directory
#   If it doesn't already exist, create it!
#--------------------------------------------------------------------

    graphOut = "GraphOut"
    rootN    = clsIO.rNam

    outRoot  = graphOut + "/" + rootN + "_"

    if not os.path.exists(graphOut): os.makedirs(graphOut)

    print("Generating Plots in Sub-Directory ",graphOut)

    for iExp in range(nExp) :

        clsEXP = dicEXP[iExp]

        if clsEXP.IsAct :

            nObs = clsEXP.nObs
            nRow = clsEXP.nRow
            nSam = clsEXP.nSamp
            sNam = dicSAM[nSam].sNam

            xTyp = clsEXP.xName

            titLS = AP.classLIB().OBSlong.get(xTyp)

            for iObs in range(nObs) :

                if clsEXP.qObs[iObs] and clsEXP.qPlt[iObs] :

                    xVec = NP.zeros(nRow)
                    yObs = NP.zeros(nRow)
                    yCal = NP.zeros(nRow)

                    for iRow in range(nRow) :

                        xVec[iRow] = clsUNI.I2X(clsEXP.dInd[iInd][iRow],clsEXP.uInd[iInd])
                        yObs[iRow] = clsUNI.I2X(clsEXP.dObs[iObs][iRow],clsEXP.uObs[iObs])
                        yCal[iRow] = clsUNI.I2X(clsEXP.dCal[iObs][iRow],clsEXP.uObs[iObs])

                    yObs = UT.zero_to_nan(yObs)
                    yCal = UT.zero_to_nan(yCal)

                    titL = xTyp + " " + titLS[iObs] + " of Sample " + sNam

                    sLobs = clsEXP.hObs[iObs] + "-Obs"
                    sLcal = clsEXP.hObs[iObs] + "-Cal"

                    xLab = clsEXP.hInd[iInd] + "/[" + clsEXP.uInd[iInd] + "]"
                    yLab = clsEXP.hObs[iObs] + "/[" + clsEXP.uObs[iObs] + "]"

                    figN = outRoot + xTyp + "_" + str(iExp+1) + "_" + clsEXP.hObs[iObs] + ".png"
        
                    PL.plot(xVec,yObs,label=sLobs,marker="s",linestyle='None',color='r')
                    PL.plot(xVec,yCal,label=sLcal,color='r')
                
                    PL.title(titL)
                
                    PL.xlabel(xLab)
                    PL.ylabel(yLab)
                
                    PL.legend()
                
                    PL.savefig(figN)
                
                    PL.close()

    return
예제 #13
0
def regPlots(clsIO,dicEXP0,dicEXP1,dicSAM1,qReg,clsUNI) :

    #return

    nExp = len(dicEXP0)
    iInd = 0
    if qReg :
        sReg = "Reg]"
        sExt = "_REG"
    else    :
        sReg = "Grp]"
        sExt = "_GRP"

#--------------------------------------------------------------------
#   By default, write graphs to GraphOut sub-directory
#   If it doesn't already exist, create it!
#--------------------------------------------------------------------

    graphOut = "GraphOut"
    rootN    = clsIO.rNam

    outRoot  = graphOut + "/" + rootN + "_"

    if not os.path.exists(graphOut): os.makedirs(graphOut)

    print("Generating Plots in Sub-Directory ",graphOut)

    for iExp in range(nExp) :

        clsEXP0 = dicEXP0[iExp]
        clsEXP1 = dicEXP1[iExp]

        if clsEXP1.IsAct :

            nObs = clsEXP0.nObs
            nRow = clsEXP0.nRow
            nSam = clsEXP1.nSamp
            sNam = dicSAM1[nSam].sNam

            xTyp = clsEXP0.xName

            titLS = AP.classLIB().OBSlong.get(xTyp)

            for iObs in range(nObs) :

                if clsEXP0.qObs[iObs] :

                    xVec = NP.zeros(nRow)
                    yObs = NP.zeros(nRow)
                    yBef = NP.zeros(nRow)
                    yAft = NP.zeros(nRow)

                    for iRow in range(nRow) :

                        xVec[iRow] = clsUNI.I2X(clsEXP0.dInd[iInd][iRow],clsEXP0.uInd[iInd])
                        yObs[iRow] = clsUNI.I2X(clsEXP0.dObs[iObs][iRow],clsEXP0.uObs[iObs])
                        yBef[iRow] = clsUNI.I2X(clsEXP0.dCal[iObs][iRow],clsEXP0.uObs[iObs])
                        yAft[iRow] = clsUNI.I2X(clsEXP1.dCal[iObs][iRow],clsEXP0.uObs[iObs])

#-- Switch zeros to nan's to prevent plotting -----------------------

                    yObs = UT.zero_to_nan(yObs)
                    yBef = UT.zero_to_nan(yBef)
                    yAft = UT.zero_to_nan(yAft)

                    sObs = clsEXP0.hObs[iObs]

                    titL = xTyp + " " + titLS[iObs] + " of Sample " + sNam

                    sLobs  = clsEXP0.hObs[iObs] + "-Obs"
                    sLcal0 = clsEXP0.hObs[iObs] + "-Cal[Bef-" + sReg
                    sLcal1 = clsEXP0.hObs[iObs] + "-Cal[Aft-" + sReg

                    xLab = clsEXP0.hInd[iInd] + "/[" + clsEXP0.uInd[iInd] + "]"
                    yLab = clsEXP0.hObs[iObs] + "/[" + clsEXP0.uObs[iObs] + "]"

                    figN = graphFileName(outRoot,xTyp,iExp,sObs,sExt)

                    PL.plot(xVec,yObs,label=sLobs ,marker="s",linestyle='None',color='r')
                    PL.plot(xVec,yBef,label=sLcal0,color='r')
                    PL.plot(xVec,yAft,label=sLcal1,color='g')
                
                    PL.title(titL)
                
                    PL.xlabel(xLab)
                    PL.ylabel(yLab)
                
                    PL.legend()
                
                    PL.savefig(figN)
                
                    PL.close()

    return
예제 #14
0
def readGen(sTyp,clsIO,clsEOS,dicSAM,dicEXP,clsUNI) :

    nCom = clsEOS.nComp

    clsEXP = AD.classEXP(sTyp)  #-- Create a New Exp Class
    nX     = len(dicEXP)        #-- Current Size of Exp Dictionary

    #print("readGen: sTyp,nX ",sTyp,nX)

    dicEXP.update({nX:clsEXP})  #-- Add New Exp to the Dictionary

    iERR  = 0
    iLine = 0

    sName = None    #-- Sample Name for Exp
    sNInj = None    #-- Injection Sample Name (SWL only)
    Tres  = None    #-- Reservoir Temp
    sLCCE = None    #-- SL-definition for CCE
    
    colH  = []      #-- Column Headers
    colU  = []      #-- Column Units
    dTab  = []      #-- Data Table

    qData = False

#-- Independent and Observed Data for this Experiment ---------------

    sIndA = AP.classLIB().INDshrt.get(sTyp)
    sObsA = AP.classLIB().OBSshrt.get(sTyp)
    sCalA = AP.classLIB().CALshrt.get(sTyp)
    
    nIndA = len(sIndA)  #-- Num Allowed Independent Vars for this Exp
    nObsA = len(sObsA)  #-- Num Allowed Observed    Vars for this Exp
    nCalA = len(sCalA)  #-- Num Allowed Calculated  Vars for this Exp

    #print("sTyp,nIndA,nObsA,nCalA ",sTyp,nIndA,nObsA,nCalA)

    dWal = NP.ones(nObsA)      ; dWps = 1.0
    qPlt = NP.full(nObsA,True)

#== Read lines until blank found ======================================

    fInp = clsIO.fInp

    for curL in fInp :

        iLine += 1

        if iLine > 100 :
            print("Too Many Lines of Data for Experiment ",sTyp)
            iERR = -1
            break

        tokS = curL.split()
        nTok = len(tokS)

        if nTok == 0 : break
        else :

#-- Must be reading Column Headers ----------------------------------
            
            if   tokS[0][:2].upper() == "PR" or \
                 tokS[0][:2].upper() == "TE" or \
                 tokS[0][:2].upper() == "MO" or \
                 tokS[0][:2].upper() == "HE" :

                for iTok in range(nTok) : colH.append(tokS[iTok])                

                nHed = nTok
                nexL = next(fInp)               #-- Next line must define units

                tokS = nexL.split()
                nUni = len(tokS)

                if nHed != nUni :
                    print("Must have same number of Headers and Units for experiment ",sTyp," - Error")
                    return -1

                for iTok in range(nUni) : colU.append(tokS[iTok])

                qData = True
                
#-- Comment? --------------------------------------------------------                

            elif tokS[0][:2] == "--" : pass

#-- Weighting Factors -----------------------------------------------

            elif tokS[0][:4].upper() == "WEIG" :

                if sTyp == "CCE" or sTyp == "CVD" or \
                   sTyp == "DLE" or sTyp == "SEP" : qTyp = True
                else                              : qTyp = False

                iTok = 1                #-- Ignore 1st Token [WEIG]
                while iTok < nTok :  
                    sTok = tokS[iTok].upper()
                    if sTok == "PSAT" and qTyp :
                        iTok += 1
                        dTok  = tokS[iTok].upper()
                        dWps  = float(dTok)
                        iTok += 1
                    else :
                        for iObs in range(nObsA) :
                            sObs = sObsA[iObs]
                            if sTok == sObs :
                                iTok += 1
                                dTok  = tokS[iTok].upper()
                                dWal[iObs] = float(dTok)
                        iTok += 1

#-- Plot Oberseved Quantity -----------------------------------------

            elif tokS[0][:4].upper() == "PLOT" :

                iTok = 1                #-- Ignore 1st Token [PLOT]
                while iTok < nTok :  
                    sTok = tokS[iTok].upper()
                    if sTok == "NO" : qPlt[iTok-1] = False
                    else            : qPlt[iTok-1] = True
                    iTok += 1

#-- Must now be read the numeric data -------------------------------

            elif qData :

                dRow = NP.zeros(nHed)              #-- Store data on this row

                if   tokS[0][:1].upper() == "P" :  #-- Found PSAT
                    nLow =  1
                    isPD =  1
                elif tokS[0][:1].upper() == "D" or \
                     tokS[0][:1].upper() == "H"    :  #-- Found DREF (GRD-Only)
                    nLow =  1                         #--    or HREF
                    isPD = -1
                else :
                    nLow =  0
                    isPD =  0

                for iTok in range(nLow,nTok) :
                    dRow[iTok-nLow] = float(tokS[iTok])

                dTab.append(dRow)                  #-- Append Row to Table

                if   isPD ==  1 :
                    nRsat = len(dTab)
                    clsEXP.setPsatRow(nRsat-1)
                elif isPD == -1 :
                    nDref = len(dTab)
                    clsEXP.setDrefRow(nDref-1)

#-- Line following EXP type contains non-Table information ----------                

            else :  

                iTok = 0
                while iTok < nTok :
                    if   tokS[iTok].upper() == "SAMP" :
                        iTok += 1
                        sName = tokS[iTok]
                        #print("sName ",sName)
                    elif tokS[iTok].upper() == "TRES" :
                        iTok += 1
                        Tres = float(tokS[iTok])
                        iTok += 1
                        Tuni =       tokS[iTok]
                        #print("Tres,Tuni ",Tres,Tuni)
                    elif tokS[iTok].upper() == "SINJ" :
                        iTok += 1
                        sNInj = tokS[iTok]
                    elif tokS[iTok].upper() == "SLIQ" :
                        iTok += 1
                        sLCCE = tokS[iTok].upper()
                    iTok += 1
        
#========================================================================
#  Process the read data
#========================================================================

#-- Fluid Sample ----------------------------------------------------

    if sName == None :
        print("No sample defined (using SAMP=) for Experiment ",sTyp," - Error")
        return -1
    else :
        nSamp = len(dicSAM)
        qFoun = False
        for iS in range(nSamp) :
            if sName == dicSAM[iS].sNam :
                qFoun = True
                clsEXP.setSamp(iS,sName)
                break
        if not qFoun :
            print("Sample ",sName," specified for Experiment ",sTyp," not found - Error")
            return -1

#-- Injection Sample (SWL only) -------------------------------------

    if sTyp == 'SWL' :
        if sNInj == None :
            print("No Injection Sample defined (using SINJ) for Experiment SWL - Error")
            return -1
        else:
            nSamp = len(dicSAM)
            qFoun = False
            for iS in range(nSamp) :
                if sNInj == dicSAM[iS].sNam :
                    qFoun = True
                    clsEXP.setSinj(iS)
                    clsEXP.setSNin(sNInj)
                    break
            if not qFoun :
                print("Injection Sample ",sNInj," specified for Experiment SWL not found - Error")
                return -1
    else :
        if sNInj != None :
            print("Experiment ",sTyp," does not support SINJ= parameter [SWL only] - Error")
            return -1

#-- Reservoir Temperature -------------------------------------------

    if sTyp == 'CCE' or sTyp == 'CVD' or sTyp == 'DLE' or \
       sTyp == 'SWL' or sTyp == 'GRD' :
        if Tres == None :
            print("No Reservoir Temperature defined (using TRES=) for Experiment ",sTyp," - Error")
            return -1
        else :
            Tint = clsUNI.X2I(Tres,Tuni)
            if Tint == -999.9 : return -1
            else              : clsEXP.setTres(Tint,Tuni)

#-- CCE Liquid Saturation Definition (SL = VL/VTot or SL = VL/Vdew) -

    if sTyp == 'CCE' :
        if sLCCE == None :
            print("CCE Experiment has not set SLIQ-Type: SLiq = VLiq/Vdew assumed")
            clsEXP.setSLCCE("DEW")
        else:
            if   sLCCE == "DEW" or sLCCE == "TOT" :
                clsEXP.setSLCCE(sLCCE)
            else :
                print("SLIQ= argument of CCE Experiment = ",sLCCE,": Should be DEW or TOT - Error")
                return -1
    else :
        if sLCCE != None :
            print("Experiment ",sTyp," does not support SLIQ= parameter [CCE only] - Error")
            return -1
                
#== Process the Column Headers and Associated Units ===================

    nHead = len(colH)
    nUnit = len(colU)

    #print("colH ",colH)
    #print("colU ",colU)

    if nHead != nUnit :
        print("Number of Column Headers not equal to Column Units for Experiment ",sTyp," - Error")
        return -1

#-- Number of Rows of Data and Initialise Structures in classEXP ----

    nRowS = len(dTab)
    nObsL = nHead - nIndA

    if sTyp == "GRD" : nRowD = nRowS + 1
    else             : nRowD = nRowS

    clsEXP.createExpArrays(nIndA,nObsA,nCalA,nRowD)

    if sTyp == "GRD" : clsEXP.createCompArray(nRowD,nCom,"Z","C")   #-- zCal-Array

#-- SEP experiment; create Lsep & Vsep Arrays -----------------------    

    if sTyp == "SEP" :                  #-- Create Lsep/Vsep arrays
        clsEXP.createSepStages(nRowS)
        qLsep = False ; qVsep = False
        for i in range(nHead) :         #-- Test if they have been read
            if colH[i].upper() == "LSEP" : qLsep = True
            if colH[i].upper() == "VSEP" : qVsep = True
        if       qLsep and     qVsep :
            qSep = True
        elif     qLsep and not qVsep :
            print("Lsep provided but not Vsep - Error")
            return -1
        elif not qLsep and     qVsep :
            print("Vsep provided but not Lsep - Error")
            return -1
        else :
            qSep = False

#-- Calculated Data [Store Full Array Regardless of User Entry] -----

    nTemp = len(clsEXP.hCal)

    for i in range(nCalA) :
        clsEXP.hCal[i] =            sCalA[i]
        clsEXP.uCal[i] = clsUNI.DUN(sCalA[i])

#-- Independent Data ------------------------------------------------

    nFoun = 0
    for i in range(nIndA) :
        sInd = sIndA[i].upper()
        for j in range(nHead) :
            sCol = colH[j].upper()
            sUni = colU[j].upper()
            if sInd == sCol :
                nFoun += 1
                clsEXP.hInd[i] = sCol
                clsEXP.uInd[i] = sUni
                #print("i,sInd,j,sCol,sUni ",i,sInd,j,sCol,sUni)
                for k in range(nRowS) :
                    clsEXP.dInd[i][k] = clsUNI.X2I(dTab[k][j],sUni)
                    #print("k,dTab,cInd ",k,dTab[k][j],clsEXP.dInd[i][k])

    if nIndA != nFoun :
        print("Experiment ",sTyp," expects ",nIndA," columns of Independent data: Only ",nFoun," found - Error")
        return -1

#-- Independent/Observed Psat for selected Experiments --------------

    if sTyp == "CCE" or sTyp == "CVD" or sTyp == "DLE" or sTyp == "SEP" :
        nRsat = clsEXP.nRsat
        if nRsat < 0 :
            print("Experiment ",sTyp," must have one row starting with PSAT - Error")
            return -1
        else :
            PsatO = clsEXP.dInd[0][nRsat]
            PsatU = clsEXP.uInd[0]
            clsEXP.setPsatObs(PsatO)
            clsEXP.setPsatWei(dWps)
            clsEXP.setPsatUni(PsatU)

#-- Reference Depth and Pressure for GRD ----------------------------

    if sTyp == "GRD" :
        nDref = clsEXP.nDref
        if nDref < 0 :
            print("Experiment GRD must have one row starting with DREF - Error")
            return -1
        else :
            Dref = clsEXP.dInd[0][nDref]
            Pref = None
            for i in range(nHead) :
                sObs = colH[i].upper()
                sUni = colU[i].upper()
                if sObs[:2] == "PR" :
                    Pref = clsUNI.X2I(dTab[nDref][i],sUni)
                    break
            if Pref == None :
                print("Experiment GRD must a Pressure define on DREF row - Error")
                return -1

        clsEXP.setDref(Dref)
        clsEXP.setPref(Pref)
        
#-- Observed Data ---------------------------------------------------

    qObsA = [False for i in range(nObsA)]

    nFoun = 0
    iPlt  = 0
    for i in range(nHead) :
        sObs = colH[i].upper()
        sUni = colU[i].upper()
        for j in range(nObsA) :
            sCol = sObsA[j].upper()
            if sObs == sCol :
                clsEXP.hObs[j] = sCol
                clsEXP.uObs[j] = sUni
                clsEXP.uCal[j] = sUni  #-- Over-write default Cal-Unit with Obs-Unit
                clsEXP.qObs[j] = True
                clsEXP.qPlt[j] = qPlt[iPlt]
                iPlt         += 1
                for k  in range(nRowS) :
                    clsEXP.dObs[j][k] = clsUNI.X2I(dTab[k][i],sUni)
                    clsEXP.dWei[j][k] = dWal[j]
                nFoun += 1
        if sTyp == "SEP" and sObs == "LSEP" :
            for k in range(nRowS) : clsEXP.Lsep[k] = int(dTab[k][i])
        if sTyp == "SEP" and sObs == "VSEP" :
            for k in range(nRowS) : clsEXP.Vsep[k] = int(dTab[k][i])

    clsEXP.setUserObs(nFoun)

#-- If SEP experiment, default the Lsep/Vsep arrays if not set ------

    if sTyp == "SEP" and not qSep :
        for k in range(nRowS) :
            if   k == 0 :
                clsEXP.Lsep[k] =   1 ; clsEXP.Vsep[k] = 1
            elif k == nRowS - 1 :
                clsEXP.Lsep[k] =   0 ; clsEXP.Vsep[k] = 0
            else :
                clsEXP.Lsep[k] = k+1 ; clsEXP.Vsep[k] = 0

#== End of Routine ======================================================

    if iERR == 0 : clsEXP.isDef = True      #-- Exp is Defined!!

    return iERR
예제 #15
0
def calcIntSamp(clsEOS, dicSAM, clsUNI, clsIO):

    nSamp = len(dicSAM)
    nComp = clsEOS.nComp

    #== Process Existing Samples ==========================================

    iPlus = 0
    for iC in range(nComp):
        if clsEOS.gPP("MW", iC) > 90.0:
            iPlus = iC
            break

    for iS in range(nSamp - 1):
        clsSAM = dicSAM[iS]
        clsSAM.sCom[iPlus] = UT.moleFracC7P(clsSAM.sCom, clsEOS)
        for iC in range(iPlus + 1, nComp):
            clsSAM.sCom[iC] = 0.0

#== New Sample ========================================================

    clsSAM = dicSAM[nSamp - 1]  #-- Get Working Sample-Class

    #-- Extract eXact (full supplied) string or Part of string ----------

    X = 'X'
    P = 'P'

    #-- Total Number of Components and Plus Fraction Properties ---------

    nCom = clsSAM.nCtot

    nPlus = clsSAM.uPlsCN
    mPlus = clsSAM.uPlsMW
    sPlus = clsSAM.uPlsSG

    #-- Inorganics and Neo-Pentane --------------------------------------

    iH2 = findComp("H2", X, clsSAM)
    iHE = findComp("HE", X, clsSAM)
    iN2 = findComp("N2", X, clsSAM)
    iCO2 = findComp("CO2", X, clsSAM)
    iH2S = findComp("H2S", X, clsSAM)
    iNeo = findComp("Neo", P, clsSAM)

    #-- First Few Hydrocarbons ------------------------------------------

    iC1 = findComp("C1", X, clsSAM)
    iC2 = findComp("C2", X, clsSAM)
    iC3 = findComp("C3", X, clsSAM)

    iIC4 = findComp("iC4", X, clsSAM)
    iNC4 = findComp("nC4", X, clsSAM)
    iIC5 = findComp("iC5", X, clsSAM)
    iNC5 = findComp("nC5", X, clsSAM)

    #-- SCN's C6 to C11 -------------------------------------------------

    iC6 = findComp("C6", X, clsSAM)
    iC7 = findComp("C7", X, clsSAM)
    iC8 = findComp("C8", X, clsSAM)
    iC9 = findComp("C9", X, clsSAM)
    iC10 = findComp("C10", X, clsSAM)
    iC11 = findComp("C11", X, clsSAM)

    #== Process ===========================================================

    #-- N2 [Nitrogen]: Also H2 & HE (will be zero or trace) -------------

    zN2 = 0.0

    if iN2 >= 0: zN2 = zN2 + clsSAM.uCom[iN2]
    if iH2 >= 0: zN2 = zN2 + clsSAM.uCom[iH2]
    if iHE >= 0: zN2 = zN2 + clsSAM.uCom[iHE]

    if zN2 > 0.0: clsSAM.setInternal("N2", zN2)

    #-- CO2 and H2S -----------------------------------------------------

    zCO2 = 0.0
    zH2S = 0.0

    if iCO2 >= 0: zCO2 = zCO2 + clsSAM.uCom[iCO2]
    if iH2S >= 0: zH2S = zH2S + clsSAM.uCom[iH2S]

    if zCO2 > 0.0: clsSAM.setInternal("CO2", zCO2)
    if zH2S > 0.0: clsSAM.setInternal("H2S", zH2S)

    #-- C1 -> nC5 -------------------------------------------------------

    zC1 = 0.0
    zC2 = 0.0
    zC3 = 0.0
    zIC4 = 0.0
    zNC4 = 0.0
    zIC5 = 0.0
    zNC5 = 0.0

    if iC1 >= 0: zC1 = zC1 + clsSAM.uCom[iC1]
    if iC2 >= 0: zC2 = zC2 + clsSAM.uCom[iC2]
    if iC3 >= 0: zC3 = zC3 + clsSAM.uCom[iC3]
    if iIC4 >= 0: zIC4 = zIC4 + clsSAM.uCom[iIC4]
    if iNC4 >= 0: zNC4 = zNC4 + clsSAM.uCom[iNC4]
    if iIC5 >= 0: zIC5 = zIC5 + clsSAM.uCom[iIC5]
    if iNC5 >= 0: zNC5 = zNC5 + clsSAM.uCom[iNC5]

    if iNeo >= 0: zIC5 = zIC5 + clsSAM.uCom[iNeo]

    if zC1 > 0.0: clsSAM.setInternal("C1", zC1)
    if zC2 > 0.0: clsSAM.setInternal("C2", zC2)
    if zC3 > 0.0: clsSAM.setInternal("C3", zC3)
    if zIC4 > 0.0: clsSAM.setInternal("IC4", zIC4)
    if zNC4 > 0.0: clsSAM.setInternal("NC4", zNC4)
    if zIC5 > 0.0: clsSAM.setInternal("IC5", zIC5)
    if zNC5 > 0.0: clsSAM.setInternal("NC5", zNC5)

    #-- SCN's C6 -> C10 -------------------------------------------------

    uC7P = []

    if iC6 >= 0: zC6 = clsSAM.uCom[iC6]
    if zC6 > 0.0: clsSAM.setInternal("C6", zC6)

    if nPlus > 7: uC7P = sumSCN(iC6, iC7, uC7P, clsSAM)
    if nPlus > 8: uC7P = sumSCN(iC7, iC8, uC7P, clsSAM)
    if nPlus > 9: uC7P = sumSCN(iC8, iC9, uC7P, clsSAM)

    if nPlus > 10:  #-- C10

        uC7P = sumSCN(iC9, iC10, uC7P, clsSAM)

        iCN = 11
        for iC in range(iC10 + 1, nCom - 1):
            zNam = 'C' + str(iCN)
            uC7P.append(clsSAM.uCom[iC])
            iCN = iCN + 1

    nC7P = len(uC7P)

    #print("nC7P ",nC7P)

    #-- User Plus Fraction ----------------------------------------------

    zPlus = "C" + str(nPlus) + "+"

    #== Internal [C7+] Plus Fraction Properties ===========================

    clsLIB = AP.classLIB()

    zC7P = 0.0
    mC7P = 0.0
    sC7P = 0.0
    jC7P = 7

    for iC7P in range(nC7P):
        zNam = 'C' + str(jC7P)
        zC7P = zC7P + uC7P[iC7P]
        mC7P = mC7P + uC7P[iC7P] * clsLIB.scnMW[zNam]
        sC7P = sC7P + uC7P[iC7P] * clsLIB.scnMW[zNam] / clsLIB.scnSG[zNam]
        jC7P = jC7P + 1
        #print("zNam,z,Mw,SG ",zNam,uC7P[iC7P],clsLIB.scnMW[zNam],clsLIB.scnSG[zNam])

#-- Add User Plus Fraction ------------------------------------------

    zPls = clsSAM.uCom[nCom - 1]

    #print("zPls,mPls,sPls ",zPls,clsSAM.uPlsMW,clsSAM.uPlsSG)

    zC7P = zC7P + zPls
    mC7P = mC7P + zPls * clsSAM.uPlsMW
    sC7P = sC7P + zPls * clsSAM.uPlsMW / clsSAM.uPlsSG

    #-- Renormalise the MW & SG -----------------------------------------

    zInt = 'C7+'
    sC7P = mC7P / sC7P
    mC7P = mC7P / zC7P

    #print("zNam,zC7P,mC7P,sC7P {:s} {:7.5f} {:7.3f} {:7.5f}".format(zInt,zC7P,mC7P,sC7P))

    #== Calculate Whitson-Alpha Parameter, if Appropriate =================

    if nC7P > 5:

        #-- Minimum & Maximum Values ----------------------------------------

        aMin = 0.5
        fMin = fitAlpha(aMin, zC7P, mC7P, uC7P)
        aMax = 2.5
        fMax = fitAlpha(aMax, zC7P, mC7P, uC7P)

        #== Brent's Method to minimise fSSQ and hence optimal-Alpha ===========

        fMid = 1.0E+6

        #-- Mid-Value less than Min or Max? ---------------------------------

        while fMid > fMin or fMid > fMax:

            aMid = 0.5 * (aMin + aMax)
            fMid = fitAlpha(aMid, zC7P, mC7P, uC7P)

            if fMid > fMax:
                aMin = aMid
                fMin = fMid
            if fMid > fMin:
                aMax = aMid
                fMax = fMid

#== Call Brent ========================================================

        alfa = brentAlpha(aMin, aMid, aMax, zC7P, mC7P, uC7P)

    else:

        alfa = 1.0  #-- Default Value if Fit Not Possible

#== Add Values to the Sample Class ====================================

    clsSAM.setInternal(zInt, zC7P)

    clsSAM.setIntPlusMW(mC7P)
    clsSAM.setIntPlusSG(sC7P)
    clsSAM.setIntPlusAL(alfa)

    nUser = len(clsSAM.iCom)
    nPseu = clsEOS.NumPsu  #-- #Pseudo's to split from C7+

    nCint = nUser + nPseu - 1

    clsSAM.setIntComp(nCint, nUser)

    clsEOS.setNComp(nCint)
    clsEOS.setNUser(nUser)
    clsEOS.setNPseu(nPseu)
    clsEOS.setNSamp(nSamp)

    #-- And define component names in EOS-class -------------------------

    for iC in range(nUser):
        clsEOS.sNM(iC, clsSAM.iNam[iC])

    #-- And copy 'internal' composition to 'working' --------------------

    for iC in range(nUser):
        clsSAM.sZI(iC, clsSAM.iCom[iC])

    #== Calculate Properties ==============================================

    iERR = CP.allProps(clsEOS, dicSAM, clsUNI, clsIO)

    #== Return ============================================================

    return