def get_state(self, volume, temperature=None): ''' Using SAFT gamma mie and automatic differentiation, return all the properties that could be derived from the EoS: (A, P, S, G, H) ''' Var.set_order(2) self.volume = Var(mt.m3mol_to_nm(volume, molecules=self.__moltol())) # nm3 if isinstance(temperature, float): self.temp = Var(temperature) else: self.temp = Var(self.temp) A = self.helmholtz() # J total for current system, Var molcs = self.__moltol() d1 = derivative(A, self.volume, self.temp, order=1, getvar=False) P = -d1[0] / pow(cst.nmtom, 3) # Pa, float S = -d1[1] / molcs # J/K per molecule, float G = (A + P * self.volume * pow(cst.nmtom, 3)) / molcs # (J + Pa*m3) for each molecule, Var H = G + S * self.temp # J + J/K * K (it is already in per molecule here), Var A = A.value / molcs # Reset system back to floats self.volume = self.volume.value self.temp = self.temp.value return (A, P, S, G.value, H.value)
def critical_point(self, initial_t=300, initial_v=3e-4, v_nd=None, get_volume=False, get_density=False, print_results=True, solver=least_squares, solver_kwargs={'bounds': (0.1, 10)}, xtol=1e-8, print_progress=False): tscale = initial_t x0 = np.array([1.]) if not isinstance(solver_kwargs, dict): solver_kwargs = {} if not isinstance(v_nd, np.ndarray): v_nd = np.logspace(-4, -2, 50) Var.set_order(2) crit_pt = solver(self.__crit_t, x0, xtol=xtol, args=(v_nd, tscale, print_progress), **solver_kwargs) if print_progress: print() if print_results: print(crit_pt) T = crit_pt.x[0] * tscale crit_v = solver(self.__crit_v, np.array([initial_v]), xtol=xtol, args=(T, ), bounds=(min(v_nd), max(v_nd))) v = crit_v.x[0] Var.set_order(1) self.volume = Var(mt.m3mol_to_nm(v, molecules=self.__moltol())) self.temp = T A = self.helmholtz() P = -derivative(A, self.volume, order=1) / pow(cst.nmtom, 3) self.volume = mt.m3mol_to_nm(v, molecules=self.__moltol()) results = (P, T) if get_volume: results += (v, ) if get_density: results += (1 / v, ) return results
def __crit_v(self, v, T): self.temp = T v = v[0] self.volume = Var(mt.m3mol_to_nm(v, molecules=self.__moltol())) A = self.helmholtz() _, dpdv = derivative(A, self.volume, order=2) dpdv = -dpdv / (pow(cst.nmtom, 6) * cst.Na) / (cst.R * T) return dpdv
def __getp(self, x, targetP): ''' Takes in single value to get P ''' x = x[0] self.volume = Var(mt.m3mol_to_nm(x, molecules=self.__moltol())) A = self.helmholtz() P = -derivative(A, self.volume, order=1) / pow(cst.nmtom, 3) return P - targetP
def get_critical_point(self, initial_guess=(3e-4, 300), get_volume=False, get_density=False, print_results=True, solver=least_squares, solver_kwargs={'bounds': ((1e-1, 1e-1), (10, 10))}, xtol=1e-8, print_progress=False): scaler = initial_guess x0 = np.array([1., 1.]) if not isinstance(solver_kwargs, dict): solver_kwargs = {} Var.set_order(3) crit_pt = solver(self.__critpt, x0, xtol=xtol, args=(print_progress, scaler), **solver_kwargs) if print_progress: print() if print_results: print(crit_pt) vT = crit_pt.x v = vT[0] * scaler[0] T = vT[1] * scaler[1] Var.set_order(1) self.volume = Var(mt.m3mol_to_nm(v, molecules=self.__moltol())) self.temp = T A = self.helmholtz() P = -derivative(A, self.volume, order=1) / pow(cst.nmtom, 3) self.volume = mt.m3mol_to_nm(v, molecules=self.__moltol()) results = (P, T) if get_volume: results += (v, ) if get_density: results += (1 / v, ) return results
def __crit_t(self, x, v_nd, scale, print_): T = x[0] * scale dp = np.zeros(np.size(v_nd)) for i in range(len(v_nd)): v = v_nd[i] self.volume = Var(mt.m3mol_to_nm(v, molecules=self.__moltol())) self.temp = T A = self.helmholtz() _, dpdv = derivative(A, self.volume, order=2) dp[i] = -dpdv / (pow(cst.nmtom, 6) * cst.Na) / (cst.R * T) if print_: print(f'Current: T = {T:7.3f}: max dP/dV = {max(dp):7.3e}', end='\r') return max(dp)
def vapour_pressure(self, temperature=None, initial_guess=(1e-4, .1), get_volume=False, get_gibbs=False, print_results=True, solver=least_squares, solver_kwargs={'bounds': ((0.1, 1e-2), (1e2, 1e2))}, print_progress=False): if isinstance(temperature, float) or isinstance(temperature, int): self.temp = temperature scaler = initial_guess x0 = np.array([1., 1.]) if not isinstance(solver_kwargs, dict): solver_kwargs = {} vle = solver(self.__eqpg, x0, args=(print_progress, scaler), **solver_kwargs) if print_progress: print() if print_results: print( f'Scaled wrt initial guess of ({scaler[0]:7.3e},{scaler[1]:7.3e})' ) print(vle) vlv = (vle.x[0] * scaler[0], vle.x[1] * scaler[1]) v = vlv[1] self.volume = Var(mt.m3mol_to_nm(v, molecules=self.__moltol())) A = self.helmholtz() P = -derivative(A, self.volume, order=1) / pow(cst.nmtom, 3) G = (A.value + P * self.volume.value * pow(cst.nmtom, 3)) / self.__moltol() self.volume = mt.m3mol_to_nm(v, molecules=self.__moltol()) result = (P, ) if get_volume: result += (vlv, ) if get_gibbs: result += (G, ) return result
def __eqpg(self, x, print_, scaler): ''' Takes in ndarray to find Pressure1 - Pressure2 ''' P = [] G = [] v_ = [x[0] * scaler[0], x[1] * scaler[1]] for i in v_: self.volume = Var(mt.m3mol_to_nm(i, molecules=self.__moltol())) A = self.helmholtz() Pi = -derivative(A, self.volume, order=1) / pow(cst.nmtom, 3) P.append(Pi) G.append((A.value + Pi * self.volume.value * pow(cst.nmtom, 3)) * cst.Na) if print_: print( f'Current: v\'s = {v_[0]:7.3e}, {v_[1]:7.3e}; dP = {(P[0]-P[1]):7.3e}, dG = {(G[0]-G[1]):7.3e}' ) return np.array([(P[0] - P[1]), (G[0] - G[1])])
def __critpt(self, x, print_, scale): ''' Takes in (v, T) to solve for dP/dV = 0 and d2P/dV2 = 0 ''' v_ = scale[0] T_ = scale[1] v = x[0] * v_ T = x[1] * T_ self.volume = Var(mt.m3mol_to_nm(v, molecules=self.__moltol())) self.temp = T A = self.helmholtz() dP = -np.array(derivative(A, self.volume, order=3)) / pow(cst.nmtom, 3) dP[1] = dP[1] / (pow(cst.nmtom, 3) * cst.Na) / (cst.R * T) dP[2] = dP[2] / (pow(cst.nmtom, 6) * pow(cst.Na, 2)) / (cst.R * T) dP[0] = dP[0] / (cst.R * T) if print_: print( f'Current: v = {v:7.3e}, T = {T:7.3f}: P, dP/dV, d2P/dV2 = {dP[0]:7.3e},{dP[1]:7.3e},{dP[2]:7.3e}', end='\r') dP[0] = min(dP[0], 0) return dP