def boundTsat(pRes,Z,clsEOS,clsIO) : if clsIO.Deb["TSAT"] > 0 : qDeb = True fDeb = clsIO.fDeb else : qDeb = False #== Limiting Values =================================================== qSat = True tMax = 2500.0 tMin = 200.0 iMax,trMx,Kmax = CS.twoSidedStabTest(qSat,pRes,tMax,Z,clsEOS,clsIO) iMin,trMn,Kmin = CS.twoSidedStabTest(qSat,pRes,tMin,Z,clsEOS,clsIO) n2SC = 2 if qDeb : sOut = "boundTsat: iMax,iMin,trMn {:2d} {:2d} {:10.3e}\n".format(iMax,iMin,trMn) fDeb.write(sOut) #-- Test limiting values -------------------------------------------- if iMax > 0 : print("Fluid at (Pres,Tres) = ({:10.3f},{:8.3f}) is 2-Phase: No-Psat".format(pRes,tMax)) iTyp = -1 logK = NP.zeros(clsEOS.nComp) return tMin,tMax,logK #---------------------------------------------------------------------- # Interval Halving #---------------------------------------------------------------------- tInt = 0.5*(tMin + tMax) while abs(tMax - tMin) > 100.0 : iTyp,triV,K = CS.twoSidedStabTest(qSat,pRes,tInt,Z,clsEOS,clsIO) n2SC += 1 if qDeb : sOut = "iTyp,pRes,tMin,tInt,triV,tMax {:2d} {:10.3f} {:10.3f} {:10.3f} {:10.3e}{:10.3f}\n".format(iTyp,pRes,tMin,tInt,triV,tMax) fDeb.write(sOut) if iTyp > 0 : tMin = tInt logK = NP.log(K) else : tMax = tInt tInt = 0.5*(tMin + tMax) #== Return values ===================================================== return tMin,tMax,logK
def rescuePsat(qBub,p2PH,p1PH,tRes,Z,clsEOS,clsIO) : if clsIO.Deb["PSAT"] > 0 : qDeb = True fDeb = clsIO.fDeb else : qDeb = False #== Using interval halfing ============================================ pSat = 0.5*(p2PH+p1PH) qSat = True while abs(p1PH-p2PH) > 0.001 : iTyp,triV,K = CS.twoSidedStabTest(qSat,pSat,tRes,Z,clsEOS,clsIO) if iTyp == 0 : p1PH = pSat else : p2PH = pSat logK = NP.log(K) pSat = 0.5*(p2PH+p1PH) #== Return arguments ================================================== return p2PH,logK
def calcTopBottom(zTyp, dDep, pDep, tRes, zDep, fRef, clsEOS, clsIO): nCom = clsEOS.nComp qSat = True qBub = None pSat = None #-- Calculate a Pressure & Composition at Bottom Depth -------------- pDep, zDep = calcStepGRD(dDep, pDep, tRes, zDep, fRef, clsEOS, clsIO) #-- Is the new Composition Stable? ---------------------------------- iDep, depT, kDep = CT.twoSidedStabTest(qSat, pDep, tRes, zDep, clsEOS, clsIO) #-- Unstable? Re-Initialise and Calculate New Bottom Composition & Pressure if iDep > 0: if iDep == 1: #-- Liquid-Like Fluid Unstable zDep = kDep / zDep elif iDep == 2: #-- Vapour-Like Fluid Unstable zDep = kDep * zDep else: print("Search at " & zTyp & " Depth Returned Unstable Fluid with iStab = 3") crash = 1.0 / 0.0 zDep = UT.Norm(zDep) pDep, zDep = calcStepGRD(dDep, pDep, tRes, zDep, fRef, clsEOS, clsIO) logK = NP.log(kDep) else: logK = NP.zeros(nCom) #== Now Calculate the Saturation Pressure at this Depth =============== clsWRK = AD.classSample("GRDwrk") clsWRK.setIntComp(nCom, nCom) for iC in range(nCom): clsWRK.sZI(iC, zDep[iC]) qSat, pSat, Ksat = CS.calcPsat(pDep, tRes, qBub, pSat, logK, clsEOS, clsWRK, clsIO) #print("calcTopBottom: dDep,pDep,iDep,qSat,pSat ",dDep,pDep,iDep,qSat,pSat) #== Return Values ===================================================== return pDep, zDep, qSat, pSat
def searchOnePhase(qBub,pInc,pRes,tRes,Z,clsEOS,clsIO) : q1PH = False qSat = True #---------------------------------------------------------------------- # Increment upward until we find 1-Phase state #---------------------------------------------------------------------- while not q1PH : iTyp,triV,K = CS.twoSidedStabTest(qSat,pRes,tRes,Z,clsEOS,clsIO) if iTyp == 0 : break else : pRes = pRes + pInc #== Return value ====================================================== return pRes
def searchTwoPhase(qBub,pInc,pRes,tRes,Z,clsEOS,clsIO) : iTyp = 0 qSat = True #---------------------------------------------------------------------- # Increment downward (in pressure) until we find 2-Phase state #---------------------------------------------------------------------- while iTyp == 0 : iTyp,triV,K = CS.twoSidedStabTest(qSat,pRes,tRes,Z,clsEOS,clsIO) if iTyp > 0 : break else : pRes = pRes - pInc #== Return Information ================================================ logK = NP.log(K) return iTyp,pRes,logK
def calcFlash(pRes,tRes,Z,vEst,clsEOS,clsIO) : if clsIO.Deb['FLASH'] > 0 : qDeb = True fDeb = clsIO.fDeb else : qDeb = False nCom = clsEOS.nComp #mFLS = 101 mFLS = 13 #-- SS/GDEM for max-13 steps, then BFGS qSat = False iLiq = 1 ; iVap = -1 #-- Work arrays to hold residuals/GDEM ------------------------------ res0 = NP.zeros(nCom) res1 = NP.zeros(nCom) res2 = NP.zeros(nCom) #-- Check if we have an unstable solution at (P,T): get K-Values ---- iTyp,triV,K = CS.twoSidedStabTest(qSat,pRes,tRes,Z,clsEOS,clsIO) if qDeb : sOut = "calcFlash: tRes,pRes,iTyp {:10.3f} {:10.3f} {:2d}\n".format(tRes,pRes,iTyp) fDeb.write(sOut) WO.writeArrayDebug(fDeb,K,"Post-2SidedStab: K") if iTyp == 0 : #print("Fluid at (P,T) = ({:8.1f},{:8.2f}) is Single-Phase".format(pRes,tRes)) V = -1.0 ; K = NP.ones(nCom) ; X = Z ; Y = Z return V,K,X,Y #-- Will work with log(K) ------------------------------------------- logK = NP.log(K) #====================================================================== # Main Iterative Loop #====================================================================== iFLS = 0 ; iCut = 0 ; icSS = 0 qPro = False ; qCon = False ; qTrv = False V = vEst while iFLS < mFLS : iFLS += 1 ; icSS += 1 #== Call the RR-Solver ================================================ V,X,Y = solveRR(Z,K,V) #== Calculate the 2-Phase Gibbs Free Energy (GFE) and dG/d(Liq Moles) = gfe2,dGdL = calcGFE2(pRes,tRes,V,X,Y,clsEOS) #== If last step was GDEM, ensure GFE has been reduced and V bounded == qUPD = True if qPro : #-- Last step was promoted, check required! if V >= 0.0 and V <= 1.0 : #-- 0 < V < 1: Flash Physical if gfe2 > lstG : qCut = True #-- but GFE has increased else : qCut = False #-- OK else : qCut = True #-- Negative Flash Teritory qPro = False #---------------------------------------------------------------------- # Cut Step [-ve Flash or GFE increased) or Just Take SS # In Newton (or Newton-Like) Scheme, Would Do Line Seach Here # but would need dG/dlnKi and we only have dG/dnLi # As SS+GDEM, Just Half the Proposed Step, But Only 3 Times (1/8th step) # Why 4? Seems to Work!! #---------------------------------------------------------------------- if qCut : iCut += 1 if iCut < 4 : #print("Promotion Step Halved: iCut ",iCut) iFLS -= 1 ; icSS -= 1 dlnK = 0.5*dlnK logK = logK - dlnK K = NP.exp(logK) else : logK = logK - dlnK #-- Remove the last of the Update logK = logK + res0 #-- And make conventional SS K = NP.exp(logK) qUPD = False #== Updates, Tolerance, Triviality Test, if allowed =================== if qUPD : res2 = res1 #-- Store previous two steps for GDEM res1 = res0 res0 = dGdL #-- dG/dnLi = dlnKi tolR = NP.dot(res0,res0) #-- W&B Eqn.(4.30) triV = NP.dot(logK,logK) #-- W&B Eqn.(4.51) if tolR < 1.0E-11 : #-- 1E-13 hard to achieve! qCon = True break if triV < 1.0E-04 : qTrv = True break #-- GDEM or Regular-SS step? ---------------------------------------- lstG = gfe2 #-- Store 'last' GFE in case GDEM makes increase if icSS % UT.mGDEM2 > 0 : qPro = False logK = logK + res0 #-- W&B Eqn.(4.48) K = NP.exp(logK) else : qPro,logK,K,dlnK = GDEM2(tolR,triV,res0,res1,res2,logK,clsIO) icSS = 0 iCut = 0 #== End of Main Loop ================================================== if qDeb : sOut = "calcFlash: I,gfe2,tolR,triV,V {:2d},{:10.3e},{:10.3e},{:10.3e},{:10.3e}\n".format(iFLS,gfe2,tolR,triV,V) fDeb.write(sOut) #== K-Values, Vapour Fraction and Liquid/Vapour Mole Fractions ======== K = NP.exp(logK) #-- K-Values V,X,Y = solveRR(Z,K,V) #-- Solve RR for V,X & Y #====================================================================== # Not Converged and not trivial, try to finish off with BFGS #====================================================================== if not qCon and not qTrv : V,K,X,Y = calcFlashBFGS(pRes,tRes,Z,V,X,Y,clsEOS) #====================================================================== # End of Routine: Return Values #====================================================================== return V,K,X,Y
def sweepPsatNoData(qBub,tRes,Z,clsEOS,clsIO) : iTyp,p2PH,p1PH,logK = boundPsat(tRes,Z,clsEOS,clsIO) if clsIO.Deb["PSAT"] > 0 : qDeb = True fDeb = clsIO.fDeb else : qDeb = False logK = NP.zeros(clsEOS.nComp) if qBub : iFed = 1 #-- Feed is Likely a Liquid else : iFed = -1 # Else a Vapour #== Pressure Limits and # Increments ================================== pMIN = 10.0 pMAX = 15010.0 nINC = 15 #== set pSat = pMIN and calculate Increment =========================== pSat = pMIN pINC = (pMAX - pSat)/float(nINC) p1PH = -1.0 #====================================================================== # Increment in pressure until we find 1-Phase State #====================================================================== qSat = True for iStep in range(nINC+1) : #== Can we split of another composition at this pressure? ============= iThs,tThs,Kths = CS.twoSidedStabTest(qSat,pSat,tRes,Z,clsEOS,clsIO) if iThs > 0 : i2PH = 2 else : i2PH = 1 if qDeb : sOut = "pSat,tRes,i2PH {:10.3f} {:8.3f} {:1d}\n".format(pSat,tRes,i2PH) fDeb.write(sOut) if iThs > 0 : iTyp = iThs p2PH = pSat logK = NP.log(Kths) else : p1PH = pSat break #== Increment pSat estimator and repeat =============================== pSat = pSat + pINC #== Return Information ================================================ return iTyp,p2PH,p1PH,logK
def boundPsat(tRes,Z,clsEOS,clsIO) : if clsIO.Deb["PSAT"] > 0 : qDeb = True fDeb = clsIO.fDeb else : qDeb = False #== Limiting Values =================================================== qSat = True pMax = 15010.0 pMin = 10.0 iMax,trMx,Kmax = CS.twoSidedStabTest(qSat,pMax,tRes,Z,clsEOS,clsIO) iMin,trMn,Kmin = CS.twoSidedStabTest(qSat,pMin,tRes,Z,clsEOS,clsIO) n2SC = 2 #print("boundPsat: iMax,iMin,trMn {:2d} {:2d} {:10.3e}".format(iMax,iMin,trMn)) #-- Test limiting values -------------------------------------------- if iMax > 0 : print("Fluid at (Pres,Tres) = ({:10.3f},{:8.3f}) is 2-Phase: No-Psat".format(pMax,tRes)) iTyp = -1 logK = NP.zeros(clsEOS.nComp) return iTyp,pMin,pMax,logK #---------------------------------------------------------------------- # Interval Halving #---------------------------------------------------------------------- pInt = 0.5*(pMin + pMax) qLog = False while abs(pMax - pMin) > 100.0 : iTyp,triV,K = CS.twoSidedStabTest(qSat,pInt,tRes,Z,clsEOS,clsIO) n2SC += 1 #print("iTyp,pMin,pInt,triV,pMax {:2d} {:10.3f} {:10.3f} {:10.3e} {:10.3f}".format(iTyp,pMin,pInt,triV,pMax)) if iTyp > 0 : pMin = pInt logK = NP.log(K) qLog = True else : pMax = pInt pInt = 0.5*(pMin + pMax) #-- Ensure logK array is defined ------------------------------------ if not qLog : logK = NP.zeros(clsEOS.nComp) #== Return values ===================================================== return iTyp,pMin,pMax,logK