from CoolProp import CoolProp as CP from PDSim.misc.datatypes import Collector import numpy as np import matplotlib.pyplot as plt from scipy.odr import * import textwrap # #fluid = 'Propane' #Rfluid = 'REFPROP-propane' #e_k = 263.88 #sigma = 0.49748 # fluid = 'DimethylEther' Rfluid = 'REFPROP-DME' e_k = 329.72 sigma = 0.5529 molemass = CP.Props(fluid, 'molemass') Ttriple = CP.Props(fluid, 'Ttriple') Tcrit = CP.Props(fluid, 'Tcrit') rhocrit = CP.Props(fluid, 'rhocrit') n = 6 m = 3 NP = 1 Nb = 0 N = (n - 1) * (m + 1) + 3 + Nb mu, mu_dilute, RHO, TTT = Collector(), Collector(), Collector(), Collector() rhomax = CP.Props('D', 'T', Ttriple, 'Q', 0, fluid) # Build a database of "experimental" data for T in np.linspace(Ttriple, Tcrit + 30, 400): for rho in np.linspace(1e-10, rhomax, 400): muval = CP.Props('V', 'T', T, 'D', rho, Rfluid) mudilute = CP.viscosity_dilute(fluid, T, rho, e_k, sigma) # Want positive value, and single-phase if (muval > 0 and T > Tcrit or rho > CP.rhosatL_anc(fluid, T) or rho < CP.rhosatV_anc(fluid, T)): mu << muval mu_dilute << mudilute TTT << T RHO << rho from CoolProp.Plots.Plots import Trho Trho(fluid) plt.plot(RHO.vec, TTT.vec, '.') plt.show() #tau = np.array(TTT.vec)/Tcrit tau = np.array(TTT.vec) / Tcrit delta = np.array(RHO.vec) / rhocrit Tstar = np.array(TTT.vec) / e_k # Define the objective function def OBJECTIVE_fit(c, x): tau = x[0, :] delta = x[1, :] # Unpack the inputs into e matrix and f vector e = np.zeros((n + 1, m + 1)) sum = 0 k = 0 for i in range(2, n + 1): for j in range(0, m + 1): e[i][j] = c[k] sum += e[i][j] * delta**i / tau**j k += 1 for o in range(0, NP): f1 = c[k + o * 3] g1 = c[k + 1 + o * 3] g2 = c[k + 2 + o * 3] delta_0 = g1 * (1 + g2 * tau**0.5) sum += f1 * (delta / (delta_0 - delta) - delta / delta_0) return sum + np.array(mu_dilute.vec) print('starting fit') XXX = np.r_[np.array(tau, ndmin=2), np.array(delta, ndmin=2)] mod = Model(OBJECTIVE_fit) mydata = Data(XXX.copy(), np.array(mu.vec)) beta0 = [1 for _ in range(N)] myodr = ODR(mydata, mod, beta0=beta0) myoutput = myodr.run() myoutput.pprint() print(myoutput.sum_square) YFIT = OBJECTIVE_fit(myoutput.beta, XXX) plt.plot(np.array(mu.vec), YFIT / np.array(mu.vec), 'o') plt.show() rel_error = (YFIT) / np.array(mu.vec) - 1 MAE = np.mean(np.abs(rel_error)) * 100 SSE = np.sum(np.power(YFIT - np.array(mu.vec), 2)) print(SSE) def write_output(c): e = np.zeros((n + 1, m + 1)) k = 0 edata = '' for i in range(2, n + 1): erow = '' for j in range(0, m + 1): e[i][j] = c[k] erow += 'e[{i:d}][{j:d}] = {val:0.16g}; '.format(val=e[i][j], i=i, j=j) k += 1 edata += erow + '\n' f1 = c[k] g1 = c[k + 1] g2 = c[k + 2] template = textwrap.dedent( """ double {name:s}Class::viscosity_Trho(double T, double rho) {{ // This function was generated by fitting REFPROP ECS data // to the functional form of Vogel, 1998 (propane viscosity) // The script entitled dev/fit_avoid_ECS.py was used to make this // function. The mean absolute error of the fit is equal to // {MAE:g} % double delta_0, sum, DELTA_H_eta, e_k, sigma, tau, delta; double e[{n:d}+1][{m:d}+1]; tau = T/reduce.T; //[Opposite to normal definition] delta = rho/reduce.rho; // Load the coefficients double f1 = {f1:0.16g}, g1 = {g1:0.16g}, g2 = {g2:0.16g}; for (int i=0;i<={n:d};i++){{ for(int j=0;j<={m:d};j++){{ e[i][j]=0.0; }} }} {edata:s} delta_0=g1*(1+g2*sqrt(tau)); //[no units] sum=0; for (int i=2;i<={n:d};i++){{ for (int j=0;j<={m:d};j++){{ sum += e[i][j]*pow(delta,i)/pow(tau,j); }} }} DELTA_H_eta = sum + f1*(delta/(delta_0-delta)-delta/delta_0); //[Pa-s] try{{ // Get the ECS params for the fluid if it has them ECSParams(&e_k,&sigma); }} catch(NotImplementedError) {{ throw ValueError(format("Your fluid does not implement ECSParams")); }} return viscosity_dilute(T,e_k,sigma) + DELTA_H_eta; }} """ ) values = dict(f1=f1, g1=g1, g2=g2, n=n, m=m, name=fluid, edata=edata, MAE=MAE) print(template.format(**values)) write_output(myoutput.beta)