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
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
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
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
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