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 = ST.twoSidedStabCheck(qSat,pRes,tMax,Z,clsEOS,clsIO) iMin,trMn,Kmin = ST.twoSidedStabCheck(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.NC) return tMin,tMax,logK #---------------------------------------------------------------------- # Interval Halving #---------------------------------------------------------------------- tInt = 0.5*(tMin + tMax) while abs(tMax - tMin) > 100.0 : iTyp,triV,K = ST.twoSidedStabCheck(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 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 = ST.twoSidedStabCheck(qSat,pMax,tRes,Z,clsEOS,clsIO) iMin,trMn,Kmin = ST.twoSidedStabCheck(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.NC) return iTyp,pMin,pMax,logK #---------------------------------------------------------------------- # Interval Halving #---------------------------------------------------------------------- pInt = 0.5*(pMin + pMax) while abs(pMax - pMin) > 100.0 : iTyp,triV,K = ST.twoSidedStabCheck(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) else : pMax = pInt pInt = 0.5*(pMin + pMax) #== Return values ===================================================== return iTyp,pMin,pMax,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 = ST.twoSidedStabCheck(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 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 = ST.twoSidedStabCheck(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 = ST.twoSidedStabCheck(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 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.NC) 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 = ST.twoSidedStabCheck(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 calcFlash(pRes, tRes, Z, vEst, clsEOS, clsIO): if clsIO.Deb['FLASH'] > 0: qDeb = True fDeb = clsIO.fDeb else: qDeb = False nCom = clsEOS.NC #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 = ST.twoSidedStabCheck(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 % CO.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