def findNearest(locarr, loc, notFoundVal=None): # returns nearest index from locarr (minimize abs(loc-locarr[?])) # return values: idxleft, idxright, idxclosest (idxclosesti is either 0 or 1) # # About NaNs: Currently can handle a situation where there are NaNs at # either end of the array. Intermittent NaNs cause unknonwn behaviour. if loc < locarr[0] or loc > locarr[-1]: if notFoundVal is None: raise pyle.PyLerr_OutsideRange (loc) else: return notFoundVal gtearr = [loc >= val for val in locarr] ltearr = [loc <= val for val in locarr] andarr = [gtearr[i] and ltearr[i] for i in range(len(gtearr))] xorarr = [gtearr[i] ^ ltearr[i] for i in range(len(gtearr))] if np.nansum(andarr) == 1: # found exact location idx = andarr.index(True) return (idx, idx, 0) # 0 could as well be 1 elif np.nansum(andarr) == 0 and np.nansum(xorarr) == len(gtearr)-np.isnan(locarr).sum(): ilt = ltearr.index(True)-1 igt = [True if locarr[i]!=locarr[i] else gtearr[i] for i in range(len(gtearr))].index(False) # igt = gtearr.index(False) # <-- this is the idea, but this can't handle Falses in between, caused by nans if ilt != igt-1: raise pyle.PyLerr_Undefined ("ilt != igt-1") if abs(locarr[ilt]-loc) <= abs(locarr[igt]-loc): return (ilt, igt, 0) else: return (ilt, igt, 1) else: raise pyle.PyLerr_Undefined ("Strange locarr, unordered?")
def updatePerplex(self, perplex=None): if perplex is None: if self.perplex is None: raise pyle.PyLerr_Undefined("No valid perplex module") else: perplex = self.perplex else: self.perplex = perplex if set(self.components) != set(perplex.callerComponents) or len( self.components) != len(perplex.callerComponents): raise pyle.PyLerr_Undefined("component set mismatch") if self._P is None or self._T is None: raise pyle.PyLerr_Undefined("P or T not set") idxs = [self.components.index(a) for a in perplex.callerComponents] masses = np.array(self.masses, dtype=float) masses = masses / np.sum(masses) masses = masses[idxs] self.perplexResult = None self.perplexResult = perplex.phaseq(self._P, self._T, masses.tolist(), debug=False)
def interpolate(locarr, valarr, locarrnew, notFoundVal=float('NaN')): # find values from valarr at locations locarrnew valarrnew = [] for loc in locarrnew: if loc < locarr[0] or loc > locarr[-1]: valarrnew.append(notFoundVal) continue try: (ilt, igt, which) = findNearest(locarr, loc) except pyle.PyLerr_OutsideRange as e: valarrnew.append(notFoundVal) continue except Exception as e: raise e if ilt == igt: newval = valarr[ilt] elif which >= 0: newval = valarr[ilt] + (valarr[igt]-valarr[ilt])*(loc-locarr[ilt])/(locarr[igt]-locarr[ilt]) else: raise pyle.PyLerr_Undefined ("interpolate(): I don't understand findNearest()") valarrnew.append(newval) return valarrnew
def __init__(self, copyfrom=None, compos=None, masses=None, perplex=None): if copyfrom is None: if compos is None: self.components = [] self.masses = [] self.ncomponents = 0 self._T = None self._P = None self._H = None else: self.components = compos[:] self.ncomponents = len(self.components) if masses is None: self.masses = [0] * self.ncomponents else: if self.ncomponents != len(masses): raise pyle.PyLerr_Undefined( "len(components) != len(masses)") self.masses = masses[:] self._T = None self._P = None self._H = None else: if not isinstance(copyfrom, Container): raise pyle.PyLerr_TypeError( "Argument is not instance of Container") self.components = copy.components[:] self.masses = copyfrom.masses[:] self.ncomponents = copyfrom.ncomponents self._T = copyfrom._T self._P = copyfrom._P self._H = copyfrom._H self.perplex = perplex self.perplexResult = None
def move_isentropic(self, dP, perplex=None): if self.perplexResult is None: self.updatePerplex(perplex=perplex) if self._P is None or self._T is None: raise pyle.PyLerr_Undefined("T/P not defined") maxerr = 0.01 curerr = 1.1 * maxerr T0 = self.T P0 = self.P V0 = self.perplexResult['SYSPROP'][self.perplex.syspropnum['V']] Cp0 = self.perplexResult['SYSPROP'][self.perplex.syspropnum['Cp']] S0 = self.perplexResult['SYSPROP'][self.perplex.syspropnum['S']] H0 = self.perplexResult['SYSPROP'][self.perplex.syspropnum['H']] dH = V0 * dP # q=0, only expansion work dT = dH / Cp0 self.T = T0 + dT self.P = P0 + dP self.updatePerplex(perplex=perplex) S1 = self.perplexResult['SYSPROP'][self.perplex.syspropnum['S']] Cp1 = self.perplexResult['SYSPROP'][self.perplex.syspropnum['Cp']] dSph = S1 - S0 # entropy mismatch (entropy change of phase changes) dHadj = (-dSph) * self.T # to gain it back, modify enthalpy dTadj = dHadj / Cp1 # calculate corresponding temp change self.T = self.T + dTadj self.updatePerplex(perplex=perplex) S1 = self.perplexResult['SYSPROP'][self.perplex.syspropnum['S']] Cp1 = self.perplexResult['SYSPROP'][self.perplex.syspropnum['Cp']]
def move_adiab(self, dPtot, dP=3e6 * 1e-5, perplex=None): # Assume adiabatic AND isentropic process # # dS = 0 # dH = V dp # # 1. Read current H (H_1), S (S_1) and V (V_1) at T_1, P_1 # 2. Calc dH = V dP # 3. Calc H_2 = H_1 + dH # 4. Find T_2, P_2==P_1 where H==H_2 # 5. Check that S_2 == S_1 # # 1. Estimate dH: dH = V dP # 2. Estimate dT: dT = dH / Cp # 3. method = 2 if self.perplexResult is None: self.updatePerplex(perplex=perplex) if self._P is None or self._T is None: raise pyle.PyLerr_Undefined("T/P not defined") maxdT = 5. if dPtot < 0: dPdir = -1. if dP > 0: dP = -dP else: dPdir = 1. dPsum = 0.0 dTsum = 0.0 T0 = self._T rho0 = self.perplexResult['SYSPROP'][ self.perplex.syspropnum['rho']] # kg/m3 Cp0 = 1000. * self.perplexResult['SYSPROP'][ self.perplex.syspropnum['Cp']] / self.perplexResult['SYSPROP'][ self.perplex.syspropnum['N']] # J K^-1 kg^-1 alpha0 = self.perplexResult['SYSPROP'][ self.perplex.syspropnum['alpha']] #V0 = sum(self.masses) / rho0 V0 = 1000. * self.perplexResult['SYSPROP'][ self.perplex.syspropnum['V']] / self.perplexResult['SYSPROP'][ self.perplex.syspropnum['N']] # J/bar/kg H0 = 1000. * self.perplexResult['SYSPROP'][ self.perplex.syspropnum['H']] / self.perplexResult['SYSPROP'][ self.perplex.syspropnum['N']] # J/kg origP = self.P origT = T0 origV = V0 origH = H0 origCp = Cp0 while abs(dPtot - dPsum) > dPdir * dPtot / 1e3: dP0 = dPdir * min(dPdir * dP, dPdir * dPtot - dPdir * dPsum) if method == 1: dT0 = T0 * alpha0 * dP0 * 1e5 / (Cp0 * rho0) elif method == 2: dH0 = dP0 * V0 dT0 = dH0 / Cp0 self.T = self.T + dT0 self.P = self.P + dP0 dPsum = dPsum + dP0 print dP0, dPsum, dT0, self.T, self.P self.updatePerplex(perplex=perplex) T0 = self.T Cp0 = 1000. * self.perplexResult['SYSPROP'][ self.perplex.syspropnum['Cp']] / self.perplexResult['SYSPROP'][ self.perplex.syspropnum['N']] alpha0 = self.perplexResult['SYSPROP'][ self.perplex.syspropnum['alpha']] rho0 = self.perplexResult['SYSPROP'][ self.perplex.syspropnum['rho']] V0 = 1000. * self.perplexResult['SYSPROP'][ self.perplex.syspropnum['V']] / self.perplexResult['SYSPROP'][ self.perplex.syspropnum['N']] if method == 2: H1 = 1000. * self.perplexResult['SYSPROP'][ self.perplex.syspropnum['H']] / self.perplexResult[ 'SYSPROP'][self.perplex.syspropnum['N']] print "H mismatch: ", (H1 - H0 - dH0), (H1 - H0), dH0 H0 = H1 print self.perplexResult['NAMEPHASES'] if "melt(HP)" in self.perplexResult['NAMEPHASES']: print "Melt!" finalV = 1000. * self.perplexResult['SYSPROP'][self.perplex.syspropnum[ 'V']] / self.perplexResult['SYSPROP'][self.perplex.syspropnum['N']] finalH = 1000. * self.perplexResult['SYSPROP'][self.perplex.syspropnum[ 'H']] / self.perplexResult['SYSPROP'][self.perplex.syspropnum['N']] finalCp = 1000. * self.perplexResult['SYSPROP'][ self.perplex.syspropnum['Cp']] / self.perplexResult['SYSPROP'][ self.perplex.syspropnum['N']] print "dPtot:", dPtot print "P, T, V, H, Cp:" print "orig: ", origP, origT, origV, origH, origCp print "final:", self.P, self.T, finalV, finalH, finalCp