mirror of
https://github.com/CoolProp/CoolProp.git
synced 2026-02-18 09:41:31 -05:00
1029 lines
45 KiB
Python
1029 lines
45 KiB
Python
from __future__ import division, print_function
|
|
import numpy as np
|
|
|
|
import hashlib, os, json, sys
|
|
import matplotlib.pyplot as plt
|
|
import matplotlib.gridspec as gridspec
|
|
from CPIncomp.DataObjects import SolutionData
|
|
from CPIncomp.BaseObjects import IncompressibleData, IncompressibleFitter
|
|
from matplotlib.patches import Rectangle
|
|
from matplotlib.ticker import MaxNLocator
|
|
from matplotlib.backends.backend_pdf import PdfPages
|
|
import itertools
|
|
|
|
class SolutionDataWriter(object):
|
|
"""
|
|
A base class that defines all the variables needed
|
|
in order to make a proper fit. You can copy this code
|
|
put in your data and add some documentation for where the
|
|
information came from.
|
|
"""
|
|
def __init__(self):
|
|
pass
|
|
|
|
def fitAll(self, fluidObject=SolutionData()):
|
|
|
|
if fluidObject.Tbase==None:
|
|
fluidObject.Tbase = (fluidObject.Tmin + fluidObject.Tmax) / 2.0
|
|
|
|
if fluidObject.xbase==None:
|
|
fluidObject.xbase = (fluidObject.xmin + fluidObject.xmax) / 2.0
|
|
|
|
tData = fluidObject.temperature.data
|
|
xData = fluidObject.concentration.data
|
|
tBase = fluidObject.Tbase
|
|
xBase = fluidObject.xbase
|
|
|
|
# Set the standard order for polynomials
|
|
std_xorder = 3+1
|
|
std_yorder = 5+1
|
|
std_coeffs = np.zeros((std_xorder,std_yorder))
|
|
|
|
errList = (ValueError, AttributeError, TypeError, RuntimeError)
|
|
|
|
if fluidObject.density.coeffs == None:
|
|
try:
|
|
fluidObject.density.setxyData(tData,xData)
|
|
fluidObject.density.coeffs = np.copy(std_coeffs)
|
|
fluidObject.density.type = IncompressibleData.INCOMPRESSIBLE_POLYNOMIAL
|
|
fluidObject.density.fitCoeffs(tBase,xBase)
|
|
except errList as ve:
|
|
if fluidObject.density.DEBUG: print("{0}: Could not fit polynomial {1} coefficients: {2}".format(fluidObject.name,'density',ve))
|
|
pass
|
|
|
|
if fluidObject.specific_heat.coeffs == None:
|
|
try:
|
|
fluidObject.specific_heat.setxyData(tData,xData)
|
|
fluidObject.specific_heat.coeffs = np.copy(std_coeffs)
|
|
fluidObject.specific_heat.type = IncompressibleData.INCOMPRESSIBLE_POLYNOMIAL
|
|
fluidObject.specific_heat.fitCoeffs(tBase,xBase)
|
|
except errList as ve:
|
|
if fluidObject.specific_heat.DEBUG: print("{0}: Could not fit polynomial {1} coefficients: {2}".format(fluidObject.name,'specific heat',ve))
|
|
pass
|
|
|
|
if fluidObject.conductivity.coeffs == None:
|
|
try:
|
|
fluidObject.conductivity.setxyData(tData,xData)
|
|
fluidObject.conductivity.coeffs = np.copy(std_coeffs)
|
|
fluidObject.conductivity.type = IncompressibleData.INCOMPRESSIBLE_POLYNOMIAL
|
|
fluidObject.conductivity.fitCoeffs(tBase,xBase)
|
|
except errList as ve:
|
|
if fluidObject.conductivity.DEBUG: print("{0}: Could not fit polynomial {1} coefficients: {2}".format(fluidObject.name,'conductivity',ve))
|
|
pass
|
|
|
|
if fluidObject.viscosity.coeffs == None:
|
|
try:
|
|
fluidObject.viscosity.setxyData(tData,xData)
|
|
tried = False
|
|
if len(fluidObject.viscosity.yData)==1:# and np.isfinite(fluidObject.viscosity.data).sum()<10:
|
|
fluidObject.viscosity.coeffs = np.array([+5e+2, -6e+1, +1e+1])
|
|
fluidObject.viscosity.type = IncompressibleData.INCOMPRESSIBLE_EXPONENTIAL
|
|
fluidObject.viscosity.fitCoeffs(tBase,xBase)
|
|
if fluidObject.viscosity.coeffs==None or IncompressibleFitter.allClose(fluidObject.viscosity.coeffs, np.array([+5e+2, -6e+1, +1e+1])): # Fit failed
|
|
tried = True
|
|
if len(fluidObject.viscosity.yData)>1 or tried:
|
|
#fluidObject.viscosity.coeffs = np.zeros(np.round(np.array(std_coeffs.shape) * 1.5))
|
|
fluidObject.viscosity.coeffs = np.copy(std_coeffs)
|
|
fluidObject.viscosity.type = IncompressibleData.INCOMPRESSIBLE_EXPPOLYNOMIAL
|
|
fluidObject.viscosity.fitCoeffs(tBase,xBase)
|
|
except errList as ve:
|
|
if fluidObject.viscosity.DEBUG: print("{0}: Could not fit polynomial {1} coefficients: {2}".format(fluidObject.name,'viscosity',ve))
|
|
pass
|
|
|
|
if fluidObject.saturation_pressure.coeffs == None:
|
|
try:
|
|
fluidObject.saturation_pressure.setxyData(tData,xData)
|
|
tried = False
|
|
if len(fluidObject.saturation_pressure.yData)==1:# and np.isfinite(fluidObject.saturation_pressure.data).sum()<10:
|
|
fluidObject.saturation_pressure.coeffs = np.array([-5e+3, +6e+1, -1e+1])
|
|
fluidObject.saturation_pressure.type = IncompressibleData.INCOMPRESSIBLE_EXPONENTIAL
|
|
fluidObject.saturation_pressure.fitCoeffs(tBase,xBase)
|
|
if fluidObject.saturation_pressure.coeffs==None or IncompressibleFitter.allClose(fluidObject.saturation_pressure.coeffs, np.array([-5e+3, +6e+1, -1e+1])): # Fit failed
|
|
tried = True
|
|
if len(fluidObject.saturation_pressure.yData)>1 or tried:
|
|
#fluidObject.saturation_pressure.coeffs = np.zeros(np.round(np.array(std_coeffs.shape) * 1.5))
|
|
fluidObject.saturation_pressure.coeffs = np.copy(std_coeffs)
|
|
fluidObject.saturation_pressure.type = IncompressibleData.INCOMPRESSIBLE_EXPPOLYNOMIAL
|
|
fluidObject.saturation_pressure.fitCoeffs(tBase,xBase)
|
|
except errList as ve:
|
|
if fluidObject.saturation_pressure.DEBUG: print("{0}: Could not fit polynomial {1} coefficients: {2}".format(fluidObject.name,'saturation pressure',ve))
|
|
pass
|
|
|
|
# reset data for getArray and read special files
|
|
if fluidObject.xid!=fluidObject.ifrac_pure and fluidObject.xid!=fluidObject.ifrac_undefined:
|
|
if fluidObject.T_freeze.coeffs == None:
|
|
fluidObject.T_freeze.setxyData([0.0],xData)
|
|
try:
|
|
if len(fluidObject.T_freeze.xData)==1:# and np.isfinite(fluidObject.T_freeze.data).sum()<10:
|
|
fluidObject.T_freeze.coeffs = np.array([+7e+2, -6e+1, +1e+1])
|
|
fluidObject.T_freeze.type = IncompressibleData.INCOMPRESSIBLE_EXPONENTIAL
|
|
else:
|
|
fluidObject.specific_heat.coeffs = np.copy(std_coeffs)
|
|
fluidObject.T_freeze.type = IncompressibleData.INCOMPRESSIBLE_EXPPOLYNOMIAL
|
|
fluidObject.T_freeze.fitCoeffs(tBase,xBase)
|
|
except errList as ve:
|
|
if fluidObject.T_freeze.DEBUG: print("{0}: Could not fit {1} coefficients: {2}".format(fluidObject.name,"T_freeze",ve))
|
|
pass
|
|
#
|
|
# # reset data for getArray again
|
|
# if fluidObject.xid==fluidObject.ifrac_volume:
|
|
# try:
|
|
# fluidObject.mass2input.coeffs = np.copy(std_coeffs)
|
|
# fluidObject.mass2input.type = fluidObject.mass2input.INCOMPRESSIBLE_POLYNOMIAL
|
|
# fluidObject.mass2input.fitCoeffs([fluidObject.Tbase],massData,fluidObject.Tbase,fluidObject.xbase)
|
|
# except errList as ve:
|
|
# if fluidObject.mass2input.DEBUG: print("{0}: Could not fit {1} coefficients: {2}".format(fluidObject.name,"mass2input",ve))
|
|
# pass
|
|
# elif fluidObject.xid==fluidObject.ifrac_mass:
|
|
# _,_,fluidObject.volume2input.data = IncompressibleData.shfluidObject.ray(massData,axs=1)
|
|
# #_,_,volData = IncompressibleData.shapeArray(volData,axs=1)
|
|
# try:
|
|
# fluidObject.volume2input.coeffs = np.copy(std_coeffs)
|
|
# fluidObject.volume2input.type = fluidObject.volume2input.INCOMPRESSIBLE_POLYNOMIAL
|
|
# fluidObject.volume2input.fitCoeffs([fluidObject.Tbase],volData,fluidObject.Tbase,fluidObject.xbase)
|
|
# except errList as ve:
|
|
# if fluidObject.volume2input.DEBUG: print("{0}: Could not fit {1} coefficients: {2}".format(fluidObject.name,"volume2input",ve))
|
|
# pass
|
|
# else:
|
|
# raise ValueError("Unknown xid specified.")
|
|
|
|
|
|
def get_hash(self,data):
|
|
return hashlib.sha224(data).hexdigest()
|
|
|
|
def get_hash_file(self):
|
|
return os.path.join(os.path.dirname(__file__), 'data', "hashes.json")
|
|
|
|
def load_hashes(self):
|
|
hashes_fname = self.get_hash_file()
|
|
if os.path.exists(hashes_fname):
|
|
hashes = json.load(open(hashes_fname,'r'))
|
|
else:
|
|
hashes = dict()
|
|
return hashes
|
|
|
|
def write_hashes(self, hashes):
|
|
hashes_fname = self.get_hash_file()
|
|
fp = open(hashes_fname,'w')
|
|
fp.write(json.dumps(hashes))
|
|
fp.close()
|
|
return True
|
|
|
|
|
|
def toJSON(self,data,quiet=False):
|
|
jobj = {}
|
|
|
|
jobj['name'] = data.name # Name of the current fluid
|
|
jobj['description'] = data.description # Description of the current fluid
|
|
jobj['reference'] = data.reference # Reference data for the current fluid
|
|
|
|
jobj['Tmax'] = data.Tmax # Maximum temperature in K
|
|
jobj['Tmin'] = data.Tmin # Minimum temperature in K
|
|
jobj['xmax'] = data.xmax # Maximum concentration
|
|
jobj['xmin'] = data.xmin # Minimum concentration
|
|
jobj['xid'] = data.xid # Concentration is mole, mass or volume-based
|
|
jobj['TminPsat'] = data.TminPsat # Minimum saturation temperature in K
|
|
jobj['Tbase'] = data.Tbase # Base value for temperature fits
|
|
jobj['xbase'] = data.xbase # Base value for concentration fits
|
|
|
|
#data.temperature # Temperature for data points in K
|
|
#data.concentration # Concentration data points in weight fraction
|
|
jobj['density'] = data.density.toJSON() # Density in kg/m3
|
|
jobj['specific_heat'] = data.specific_heat.toJSON() # Heat capacity in J/(kg.K)
|
|
jobj['viscosity'] = data.viscosity.toJSON() # Dynamic viscosity in Pa.s
|
|
jobj['conductivity'] = data.conductivity.toJSON() # Thermal conductivity in W/(m.K)
|
|
jobj['saturation_pressure'] = data.saturation_pressure.toJSON() # Saturation pressure in Pa
|
|
jobj['T_freeze'] = data.T_freeze.toJSON() # Freezing temperature in K
|
|
jobj['mass2input'] = data.mass2input.toJSON() # dd
|
|
jobj['volume2input'] = data.volume2input.toJSON() # dd
|
|
jobj['mole2input'] = data.mole2input.toJSON() # dd
|
|
|
|
original_float_repr = json.encoder.FLOAT_REPR
|
|
#print json.dumps(1.0001)
|
|
stdFmt = "1.{0}e".format(int(data.significantDigits-1))
|
|
#pr = np.finfo(float64).eps * 10.0
|
|
#pr = np.finfo(float64).precision - 2 # stay away from numerical precision
|
|
#json.encoder.FLOAT_REPR = lambda o: format(np.around(o,decimals=pr), stdFmt)
|
|
json.encoder.FLOAT_REPR = lambda o: format(o, stdFmt)
|
|
dump = json.dumps(jobj, indent = 2, sort_keys = True)
|
|
json.encoder.FLOAT_REPR = original_float_repr
|
|
|
|
#print dump
|
|
hashes = self.load_hashes()
|
|
hash = self.get_hash(dump)
|
|
|
|
name = jobj['name']
|
|
|
|
if name not in hashes or \
|
|
hashes[name] != hash: # update hashes and write file
|
|
|
|
hashes[name] = hash
|
|
self.write_hashes(hashes)
|
|
path = os.path.join("json",name+'.json')
|
|
fp = open(path, 'w')
|
|
fp.write(dump)
|
|
fp.close()
|
|
if not quiet: print(" ({0})".format("w"), end="")
|
|
else:
|
|
if not quiet: print(" ({0})".format("i"), end="")
|
|
|
|
|
|
# Update the object:
|
|
self.fromJSON(data=data)
|
|
|
|
|
|
def fromJSON(self,data=SolutionData()):
|
|
|
|
path = os.path.join("json",data.name+'.json')
|
|
|
|
with open(path) as json_file:
|
|
jobj = json.load(json_file)
|
|
|
|
data.name = jobj['name'] # Name of the current fluid
|
|
data.description = jobj['description'] # Description of the current fluid
|
|
data.reference = jobj['reference'] # Reference data for the current fluid
|
|
|
|
data.Tmax = jobj['Tmax'] # Maximum temperature in K
|
|
data.Tmin = jobj['Tmin'] # Minimum temperature in K
|
|
data.xmax = jobj['xmax'] # Maximum concentration
|
|
data.xmin = jobj['xmin'] # Minimum concentration
|
|
data.xid = jobj['xid'] # Concentration is mole, mass or volume-based
|
|
data.TminPsat = jobj['TminPsat'] # Minimum saturation temperature in K
|
|
data.Tbase = jobj['Tbase'] # Base value for temperature fits
|
|
data.xbase = jobj['xbase'] # Base value for concentration fits
|
|
|
|
#data.temperature # Temperature for data points in K
|
|
#data.concentration # Concentration data points in weight fraction
|
|
data.density.fromJSON(jobj['density']) # Density in kg/m3
|
|
data.specific_heat.fromJSON(jobj['specific_heat']) # Heat capacity in J/(kg.K)
|
|
data.viscosity.fromJSON(jobj['viscosity']) # Dynamic viscosity in Pa.s
|
|
data.conductivity.fromJSON(jobj['conductivity']) # Thermal conductivity in W/(m.K)
|
|
data.saturation_pressure.fromJSON(jobj['saturation_pressure']) # Saturation pressure in Pa
|
|
data.T_freeze.fromJSON(jobj['T_freeze']) # Freezing temperature in K
|
|
data.mass2input.fromJSON(jobj['mass2input']) # dd
|
|
data.volume2input.fromJSON(jobj['volume2input']) # dd
|
|
data.mole2input.fromJSON(jobj['mole2input']) # dd
|
|
|
|
return data
|
|
|
|
|
|
def printStatusID(self, fluidObjs, obj):
|
|
#obj = fluidObjs[num]
|
|
if obj==fluidObjs[0]:
|
|
print(" {0}".format(obj.name), end="")
|
|
elif obj==fluidObjs[-1]:
|
|
print(", {0}".format(obj.name), end="")
|
|
else:
|
|
print(", {0}".format(obj.name), end="")
|
|
|
|
sys.stdout.flush()
|
|
return
|
|
|
|
|
|
def fitFluidList(self, fluidObjs):
|
|
print("Fitting normal fluids:", end="")
|
|
for obj in fluidObjs:
|
|
self.printStatusID(fluidObjs, obj)
|
|
try:
|
|
self.fitAll(obj)
|
|
except (TypeError, ValueError) as e:
|
|
print("An error occurred for fluid: {0}".format(obj.name))
|
|
print(obj)
|
|
print(e)
|
|
pass
|
|
print(" ... done")
|
|
return
|
|
|
|
|
|
def readFluidList(self, fluidObjs):
|
|
print("Reading fluids:", end="")
|
|
for obj in fluidObjs:
|
|
self.printStatusID(fluidObjs, obj)
|
|
try:
|
|
self.fromJSON(obj)
|
|
except (TypeError, ValueError) as e:
|
|
print("An error occurred for fluid: {0}".format(obj.name))
|
|
print(obj)
|
|
print(e)
|
|
pass
|
|
print(" ... done")
|
|
return
|
|
|
|
|
|
def fitSecCoolList(self, fluidObjs):
|
|
print("Fitting SecCool fluids:", end="")
|
|
for obj in fluidObjs:
|
|
self.printStatusID(fluidObjs, obj)
|
|
try:
|
|
obj.fitFluid()
|
|
except (TypeError, ValueError) as e:
|
|
print("An error occurred for fluid: {0}".format(obj.name))
|
|
print(obj)
|
|
print(e)
|
|
pass
|
|
print(" ... done")
|
|
return
|
|
|
|
|
|
def writeFluidList(self, fluidObjs):
|
|
print("Legend: FluidName (w) | (i) -> (w)=written, (i)=ignored, unchanged coefficients")
|
|
print("Writing fluids to JSON:", end="")
|
|
for obj in fluidObjs:
|
|
self.printStatusID(fluidObjs, obj)
|
|
try:
|
|
self.toJSON(obj)
|
|
except (TypeError, ValueError) as e:
|
|
print("An error occurred for fluid: {0}".format(obj.name))
|
|
print(obj)
|
|
print(e)
|
|
pass
|
|
print(" ... done")
|
|
return
|
|
|
|
def writeReportList(self, fluidObjs, pdfFile=None):
|
|
print("Writing fitting reports:", end="")
|
|
pdfObj = None
|
|
if pdfFile!=None: pdfObj = PdfPages(pdfFile)
|
|
for obj in fluidObjs:
|
|
self.printStatusID(fluidObjs, obj)
|
|
self.makeFitReportPage(obj,pdfObj=pdfObj)
|
|
try:
|
|
self.makeFitReportPage(obj)
|
|
except (TypeError, ValueError) as e:
|
|
print("An error occurred for fluid: {0}".format(obj.name))
|
|
print(obj)
|
|
print(e)
|
|
pass
|
|
if pdfFile!=None: pdfObj.close()
|
|
print(" ... done")
|
|
return
|
|
|
|
|
|
#####################################
|
|
# Plotting routines
|
|
#####################################
|
|
def relError(self, A=[], B=[], PCT=False):
|
|
"""
|
|
Returns the absolute relative Error from either
|
|
(B-A)/B or (A-B)/A for abs(B)>abs(A) and abs(A)>abs(B),
|
|
respectively. If PCT is True, it returns it in percent.
|
|
"""
|
|
A_a = np.array(A)
|
|
B_a = np.array(B)
|
|
|
|
abl = np.absolute(B_a)
|
|
eps = np.ones_like(abl) * np.finfo(float).eps
|
|
#div = np.amax(np.hstack((abl,eps)), axis=1)*np.sign(B_a)
|
|
|
|
pos = np.isfinite(B_a)
|
|
pos2 = (B_a>eps)
|
|
result = np.ones_like(A_a)*np.NAN
|
|
|
|
result[pos & pos2] = (A_a[pos & pos2]-B_a[pos & pos2])/B_a[pos & pos2]
|
|
|
|
if PCT:
|
|
return result * 100.
|
|
else:
|
|
return result
|
|
|
|
############################################################
|
|
# Define the general purpose routines for plotting
|
|
############################################################
|
|
def wireFrame2D(self,xz,yz,linesX=5,linesY=None,color='black',ax=None,plot=False):
|
|
"""
|
|
xz is a 2D array that holds x-values for constant z1 and z2.
|
|
yz is a 2D array that holds y-values for the same z1 and z2.
|
|
xz and yz have to have the same size.
|
|
The first dimension of xz should be greater than
|
|
or equal to the lines input.
|
|
"""
|
|
if xz.ndim!=2:
|
|
raise ValueError("xz has to be a 2D array.")
|
|
if yz.ndim!=2:
|
|
raise ValueError("yz has to be a 2D array.")
|
|
if xz.shape!=yz.shape:
|
|
raise ValueError("xz and yz have to have the same shape: {0} != {1}".format(xz.shape,yz.shape))
|
|
if linesY==None and linesX!=None:
|
|
linesY = linesX
|
|
if linesX==None and linesY!=None:
|
|
linesX = linesY
|
|
if linesY==None and linesX==None:
|
|
raise ValueError("You have to provide linesX or linesY")
|
|
|
|
xl,yl = xz.shape
|
|
x_index = np.round(np.linspace(0, xl-1, linesX))
|
|
y_index = np.round(np.linspace(0, yl-1, linesY))
|
|
x_toPlot = []
|
|
y_toPlot = []
|
|
for i in x_index:
|
|
x_toPlot += [xz.T[i]]
|
|
y_toPlot += [yz.T[i]]
|
|
for i in y_index:
|
|
x_toPlot += [xz[i]]
|
|
y_toPlot += [yz[i]]
|
|
if plot==False:
|
|
return x_toPlot,y_toPlot
|
|
if ax==None:
|
|
raise ValueError("You have to give an axis to plot.")
|
|
for i in range(len(x_toPlot)):
|
|
ax.plot(x_toPlot[i],y_toPlot[i],color=color)
|
|
return x_toPlot,y_toPlot
|
|
|
|
|
|
def plotValues(self,axVal,axErr,solObj=SolutionData(),dataObj=IncompressibleData(),func=None,old=None):
|
|
"""
|
|
Plots two data series using the same axis. You can
|
|
choose if you prefer points or a line for the reference
|
|
data. This can be used to show that we have experimental
|
|
data or a reference equation.
|
|
You can use the old input to call CoolProp with this ID.
|
|
You can use this feature to visualise changes for new
|
|
data fits. Primarily intended to highlight changes from
|
|
v4 to v5 of CoolProp.
|
|
"""
|
|
|
|
if dataObj.type==dataObj.INCOMPRESSIBLE_NOT_SET \
|
|
or dataObj.source==dataObj.SOURCE_NOT_SET:
|
|
return
|
|
|
|
# TODO: Improve this work-around
|
|
xFunction = False
|
|
try:
|
|
if solObj.T_freeze.coeffs.shape==dataObj.coeffs.shape:
|
|
if np.all(solObj.T_freeze.coeffs==dataObj.coeffs):
|
|
xFunction = True
|
|
except AttributeError as ae:
|
|
if False: print(ae)
|
|
pass
|
|
|
|
points = 30
|
|
|
|
dataFormatter = {}
|
|
tData = None
|
|
xData = None
|
|
pData = None
|
|
zData = None
|
|
zError= None
|
|
|
|
if dataObj.source==dataObj.SOURCE_DATA or dataObj.source==dataObj.SOURCE_EQUATION:
|
|
dataFormatter['color'] = 'blue'
|
|
dataFormatter['marker'] = 'o'
|
|
dataFormatter['ls'] = 'none'
|
|
|
|
|
|
dataObj.setxyData(solObj.temperature.data,solObj.concentration.data)
|
|
|
|
tData = dataObj.xData
|
|
xData = dataObj.yData
|
|
pData = 1e7 # 100 bar
|
|
zData = dataObj.data
|
|
|
|
if func!=None and zData!=None:
|
|
r,c = zData.shape
|
|
zError= np.zeros((r,c))
|
|
for i in range(r):
|
|
for j in range(c):
|
|
zError[i,j]= func(tData[i],pData,xData[j])
|
|
|
|
zError = self.relError(zData, zError) * 1e2
|
|
|
|
|
|
## Find the column with the largest single error
|
|
#maxVal = np.amax(zError, axis=0) # largest error per column
|
|
#col2plot = np.argmax(maxVal) # largest error in row
|
|
## Find the column with the largest total error
|
|
#totVal = np.sum(zError, axis=0) # summed error per column
|
|
#col2plot = np.argmax(totVal) # largest error in row
|
|
# Find the column with the largest average error
|
|
if xFunction:
|
|
#avgVal = np.average(zError, axis=1) # summed error per column
|
|
#set2plot = np.argmax(avgVal) # largest error in row
|
|
set2plot = int(np.round(r/2.0))
|
|
tData = np.array([tData[set2plot]])
|
|
zData = zData[set2plot]
|
|
zError= zError[set2plot]
|
|
else:
|
|
#avgVal = np.average(zError, axis=0) # summed error per column
|
|
#set2plot = np.argmax(avgVal) # largest error in row
|
|
set2plot = int(np.round(c/2.0))
|
|
xData = np.array([xData[set2plot]])
|
|
zData = zData.T[set2plot]
|
|
zError= zError.T[set2plot]
|
|
else:
|
|
raise ValueError("You have to provide data and a fitted function.")
|
|
|
|
elif dataObj.source==dataObj.SOURCE_COEFFS:
|
|
dataFormatter['color'] = 'blue'
|
|
#dataFormatter['marker'] = 'o'
|
|
dataFormatter['ls'] = 'solid'
|
|
|
|
if xFunction:
|
|
xData = np.linspace(solObj.xmin, solObj.xmax, num=points)
|
|
if solObj.xid==solObj.ifrac_pure: tData = np.array([0.0])
|
|
else: tData = np.array([solObj.Tmin+solObj.Tmax])/2.0
|
|
else:
|
|
tData = np.linspace(solObj.Tmin, solObj.Tmax, num=points)
|
|
if solObj.xid==solObj.ifrac_pure: xData = np.array([0.0])
|
|
else: xData = np.array([solObj.xmin+solObj.xmax])/2.0
|
|
|
|
pData = 1e7 # 100 bar
|
|
|
|
#zData= np.zeros((len(tData),len(xData)))
|
|
#for i in range(len(tData)):
|
|
# for j in range(len(xData)):
|
|
# zData[i,j] = func(tData[i],pData,xData[j])
|
|
#r,c = zData.shape
|
|
#if r==1 or c==1:
|
|
# zData = np.array(zData.flat)
|
|
#else:
|
|
# raise ValueError("Cannot plot non-flat arrays!")
|
|
|
|
|
|
# Copy the arrays
|
|
tFunc = tData
|
|
xFunc = xData
|
|
pFunc = pData
|
|
zFunc = None
|
|
zMiMa = None
|
|
xFree = xData
|
|
tFree = tData
|
|
zFree = None
|
|
|
|
if func!=None:
|
|
if len(tFunc)<points and len(tFunc)>1:
|
|
tFunc = np.linspace(solObj.Tmin, solObj.Tmax, num=points)
|
|
if len(xFunc)<points and len(xFunc)>1:
|
|
xFunc = np.linspace(solObj.xmin, solObj.xmax, num=points)
|
|
|
|
zFunc = np.zeros((len(tFunc),len(xFunc)))
|
|
for i in range(len(tFunc)):
|
|
for j in range(len(xFunc)):
|
|
zFunc[i,j] = func(tFunc[i],pFunc,xFunc[j])
|
|
r,c = zFunc.shape
|
|
if r==1 or c==1:
|
|
zFunc = np.array(zFunc.flat)
|
|
else:
|
|
raise ValueError("Cannot plot non-flat arrays!")
|
|
|
|
if xFunction:
|
|
tMiMa = np.array([solObj.Tmin, solObj.Tmax])
|
|
xMiMa = xFunc
|
|
else:
|
|
tMiMa = tFunc
|
|
xMiMa = np.array([solObj.xmin, solObj.xmax])
|
|
|
|
zMiMa = np.zeros((len(tMiMa),len(xMiMa)))
|
|
for i in range(len(tMiMa)):
|
|
for j in range(len(xMiMa)):
|
|
zMiMa[i,j] = func(tMiMa[i],pFunc,xMiMa[j])
|
|
|
|
if not xFunction: # add the freezing front
|
|
if solObj.T_freeze.type!=IncompressibleData.INCOMPRESSIBLE_NOT_SET:
|
|
cols = len(tMiMa)
|
|
conc = np.linspace(solObj.xmin, solObj.xmax, num=cols)
|
|
tFree = np.zeros_like(conc)
|
|
zFree = np.zeros_like(conc)
|
|
for i in range(cols):
|
|
tFree[i] = solObj.Tfreeze(10.0, p=pFunc, x=conc[i])
|
|
zFree[i] = func(tFree[i],pFunc,conc[i])
|
|
#zMiMa = np.hstack((zMiMa,temp.reshape((len(conc),1))))
|
|
|
|
fitFormatter = {}
|
|
fitFormatter['color'] = 'red'
|
|
fitFormatter['ls'] = 'solid'
|
|
|
|
errorFormatter = {}
|
|
errorFormatter['color'] = dataFormatter['color']
|
|
errorFormatter['marker'] = 'o'
|
|
errorFormatter['ls'] = 'none'
|
|
errorFormatter['alpha'] = 0.25
|
|
|
|
pData = None
|
|
pFree = None
|
|
if xFunction:
|
|
pData = xData
|
|
pFunc = xFunc
|
|
pMiMa = xMiMa
|
|
zMiMa = zMiMa.T
|
|
#pFree = xFree
|
|
#zFree = zFree.T
|
|
else:
|
|
pData = tData - 273.15
|
|
pFunc = tFunc - 273.15
|
|
pMiMa = tMiMa - 273.15
|
|
#zMiMa = zMiMa
|
|
pFree = tFree - 273.15
|
|
|
|
if zData!=None and axVal!=None:
|
|
axVal.plot(pData, zData, label='data', **dataFormatter)
|
|
|
|
if zFunc!=None and axVal!=None:
|
|
axVal.plot(pFunc, zFunc, label='function' , **fitFormatter)
|
|
if solObj.xid!=solObj.ifrac_pure and not xFunction:
|
|
axVal.set_title("showing x={0:3.2f}".format(xFunc[0]))
|
|
else:
|
|
axVal.set_title(" ")
|
|
|
|
if zMiMa!=None and axVal!=None:
|
|
axVal.plot(pMiMa, zMiMa, alpha=0.25, ls=':', color=fitFormatter["color"])
|
|
|
|
if zFree!=None and axVal!=None:
|
|
axVal.plot(pFree, zFree, alpha=0.25, ls=':', color=fitFormatter["color"])
|
|
|
|
if zError!=None and axErr!=None:
|
|
axErr.plot(pData, zError, label='error' , **errorFormatter)
|
|
|
|
elif axErr!=None:
|
|
errorFormatter['alpha'] = 0.00
|
|
axErr.plot([pData[0],pData[-1]], [0,0], **errorFormatter)
|
|
#axErr.xaxis.set_visible(False)
|
|
#axErr.yaxis.set_visible(False)
|
|
#axErr.plot(pData, zFunc, label='function' , **fitFormatter)
|
|
|
|
|
|
|
|
|
|
|
|
#else:
|
|
# plt.setp(axErr.get_yticklabels(), visible=False)
|
|
# plt.setp(axErr.yaxis.get_label(), visible=False)
|
|
|
|
|
|
def printFluidInfo(self,ax,solObj=SolutionData()):
|
|
"""
|
|
Prints some fluid information on top of the fitting report.
|
|
"""
|
|
#ax = subplot(111, frame_on=False)
|
|
ax.xaxis.set_visible(False)
|
|
ax.yaxis.set_visible(False)
|
|
|
|
#cellText = [["1","2"],["3","4"]]
|
|
#rowLabels = ["Name","Source"]
|
|
## Add a table at the bottom of the axes
|
|
#the_table = ax.table(cellText=cellText)
|
|
|
|
annotateSettingsTitle = {}
|
|
#annotateSettingsLabel['xycoords']=('figure fraction', 'figure fraction')
|
|
annotateSettingsTitle['ha'] = 'center'
|
|
annotateSettingsTitle['va'] = 'baseline'
|
|
annotateSettingsTitle['fontsize'] = 'xx-large'
|
|
annotateSettingsTitle['fontweight'] = 'bold'
|
|
|
|
annotateSettingsLabel = {}
|
|
#annotateSettingsLabel['xycoords']=('figure fraction', 'figure fraction')
|
|
annotateSettingsLabel['ha'] = 'right'
|
|
annotateSettingsLabel['va'] = 'baseline'
|
|
#annotateSettingsLabel['fontsize'] = 'large'
|
|
annotateSettingsLabel['fontweight'] = 'semibold'
|
|
|
|
annotateSettingsText = {}
|
|
#annotateSettingsText['xycoords']=('figure fraction', 'figure fraction')
|
|
annotateSettingsText['ha'] = 'left'
|
|
annotateSettingsText['va'] = 'baseline'
|
|
#annotateSettingsText['fontsize'] = 'large'
|
|
annotateSettingsText['fontweight'] = 'medium'
|
|
|
|
|
|
#ax.set_title('Fitting Report for {0}'.format(solObj.name))
|
|
ax.text(0.5, 0.8, 'Fitting Report for {0}'.format(solObj.name), **annotateSettingsTitle)
|
|
|
|
def myAnnotate(label,text,x=0.0,y=0.0):
|
|
dx = 0.005
|
|
ax.text(x-dx,y, label, **annotateSettingsLabel)
|
|
ax.text(x+dx,y, text, **annotateSettingsText)
|
|
|
|
#ax.annotate(r'Enthalpy [$\mathdefault{10^5\!J/kg}$]', xy=(0.25, 0.03), **annotateSettings)
|
|
#ax.annotate(r'Enthalpy [$\mathdefault{10^5\!J/kg}$]', xy=(0.25, 0.03), **annotateSettings)
|
|
|
|
dx = 0.50
|
|
dy = 0.10
|
|
|
|
xStart = 0.175 ; x = xStart
|
|
yStart = 0.575; y = yStart
|
|
|
|
#myAnnotate('Name: ',solObj.name,x=x,y=y); x += .0; y -= dy
|
|
myAnnotate('Description: ',solObj.description,x=x,y=y); x += .0; y -= dy
|
|
myAnnotate('Source: ',solObj.reference,x=x,y=y); x += .0; y -= dy
|
|
myAnnotate('Temperature: ',u'{0} \u00B0C to {1} \u00B0C'.format(solObj.Tmin-273.15, solObj.Tmax-273.15),x=x,y=y); x += .0; y -= dy
|
|
conc = False
|
|
if solObj.xid==solObj.ifrac_mass: conc=True
|
|
if solObj.xid==solObj.ifrac_volume: conc=True
|
|
if solObj.xid==solObj.ifrac_mole: conc=True
|
|
if conc==True:
|
|
myAnnotate('Composition: ',u'{0} % to {1} %, {2}'.format(solObj.xmin*100., solObj.xmax*100., solObj.xid),x=x,y=y)
|
|
else:
|
|
myAnnotate('Composition: ','pure fluid',x=x,y=y)
|
|
x += .0; y -= dy
|
|
|
|
if solObj.density.source!=solObj.density.SOURCE_NOT_SET:
|
|
myAnnotate('Density: ',u'{0} to {1} {2}'.format(solObj.density.source, solObj.density.type, solObj.density.coeffs.shape),x=x,y=y)
|
|
else:
|
|
myAnnotate('Density: ','no information',x=x,y=y)
|
|
x += .0; y -= dy
|
|
if solObj.specific_heat.source!=solObj.specific_heat.SOURCE_NOT_SET:
|
|
myAnnotate('Spec. Heat: ',u'{0} to {1} {2}'.format(solObj.specific_heat.source, solObj.specific_heat.type, solObj.specific_heat.coeffs.shape),x=x,y=y)
|
|
else:
|
|
myAnnotate('Spec. Heat: ','no information',x=x,y=y)
|
|
x += .0; y -= dy
|
|
|
|
x = xStart + dx; y = yStart-dy-dy
|
|
if solObj.conductivity.source!=solObj.conductivity.SOURCE_NOT_SET:
|
|
myAnnotate('Th. Cond.: ',u'{0} to {1} {2}'.format(solObj.conductivity.source, solObj.conductivity.type, solObj.conductivity.coeffs.shape),x=x,y=y)
|
|
else:
|
|
myAnnotate('Th. Cond.: ','no information',x=x,y=y)
|
|
x += .0; y -= dy
|
|
if solObj.viscosity.source!=solObj.viscosity.SOURCE_NOT_SET:
|
|
myAnnotate('Viscosity: ',u'{0} to {1} {2}'.format(solObj.viscosity.source, solObj.viscosity.type, solObj.viscosity.coeffs.shape),x=x,y=y)
|
|
else:
|
|
myAnnotate('Viscosity: ','no information',x=x,y=y)
|
|
x += .0; y -= dy
|
|
if solObj.saturation_pressure.source!=solObj.saturation_pressure.SOURCE_NOT_SET:
|
|
myAnnotate('Psat: ',u'{0} to {1} {2}'.format(solObj.saturation_pressure.source, solObj.saturation_pressure.type, solObj.saturation_pressure.coeffs.shape),x=x,y=y)
|
|
else:
|
|
myAnnotate('Psat: ','no information',x=x,y=y)
|
|
x += .0; y -= dy
|
|
if solObj.T_freeze.source!=solObj.T_freeze.SOURCE_NOT_SET:
|
|
myAnnotate('Tfreeze: ',u'{0} to {1} {2}'.format(solObj.T_freeze.source, solObj.T_freeze.type, solObj.T_freeze.coeffs.shape),x=x,y=y)
|
|
else:
|
|
myAnnotate('Tfreeze: ','no information',x=x,y=y)
|
|
x += .0; y -= dy
|
|
|
|
|
|
#ax5.set_xlabel(ur'$\mathregular{Temperature\/(\u00B0C)}$')
|
|
|
|
#x += dx; y = yStart
|
|
#myAnnotate('Name: ',solObj.name,x=x,y=y); x += .0; y -= dy
|
|
|
|
ax.set_xlim((0,1))
|
|
ax.set_ylim((0,1))
|
|
|
|
|
|
def printFitDetails(self):
|
|
pass
|
|
|
|
|
|
|
|
def makeFitReportPage(self, solObj=SolutionData(), pdfObj=None):
|
|
"""
|
|
Creates a whole page with some plots and basic information
|
|
for both fit quality, reference data, data sources and
|
|
more.
|
|
"""
|
|
|
|
# First we determine some basic settings
|
|
|
|
gs = gridspec.GridSpec(4, 2, wspace=None, hspace=None, height_ratios=[2.5,3,3,3])
|
|
#gs.update(top=0.75, hspace=0.05)
|
|
div = 22
|
|
fig = plt.figure(figsize=(210/div,297/div))
|
|
table_axis = plt.subplot(gs[0,:], frame_on=False)
|
|
|
|
|
|
|
|
|
|
# Info text settings
|
|
infoText = {}
|
|
infoText['ha'] = 'center'
|
|
infoText['va'] = 'baseline'
|
|
infoText['fontsize'] = 'smaller'
|
|
infoText['xycoords'] =('axes fraction', 'axes fraction')
|
|
|
|
# Setting the labels
|
|
#errLabel = ur'$\mathdefault{rel.\/Error\/[\u2030]}$'
|
|
errLabel = r'$\mathdefault{rel.\/Error\/[\%]}$'
|
|
tempLabel = ur'$\mathdefault{Temperature\/(\u00B0C)}$'
|
|
|
|
density_axis = plt.subplot(gs[1,0])
|
|
density_error = density_axis.twinx()
|
|
density_axis.set_ylabel(r'Density [$\mathdefault{kg/m^3\!}$]')
|
|
density_axis.set_xlabel(tempLabel)
|
|
density_error.set_ylabel(errLabel)
|
|
if solObj.density.source!=solObj.density.SOURCE_NOT_SET:
|
|
self.plotValues(density_axis,density_error,solObj=solObj,dataObj=solObj.density,func=solObj.rho)
|
|
else:
|
|
raise ValueError("Density data has to be provided!")
|
|
|
|
capacity_axis = plt.subplot(gs[1,1])
|
|
capacity_error = capacity_axis.twinx()
|
|
capacity_axis.set_ylabel(r'Heat Capacity [$\mathdefault{J/kg/K}$]')
|
|
capacity_axis.set_xlabel(tempLabel)
|
|
capacity_error.set_ylabel(errLabel)
|
|
if solObj.specific_heat.source!=solObj.specific_heat.SOURCE_NOT_SET:
|
|
self.plotValues(capacity_axis,capacity_error,solObj=solObj,dataObj=solObj.specific_heat,func=solObj.c)
|
|
else:
|
|
raise ValueError("Specific heat data has to be provided!")
|
|
|
|
# Optional plots, might not all be shown
|
|
conductivity_axis = plt.subplot(gs[2,0])#, sharex=density_axis)
|
|
conductivity_error = conductivity_axis.twinx()
|
|
conductivity_axis.set_ylabel(r'Thermal Conductivity [$\mathdefault{W/m/K}$]')
|
|
conductivity_axis.set_xlabel(tempLabel)
|
|
conductivity_error.set_ylabel(errLabel)
|
|
if solObj.conductivity.source!=solObj.conductivity.SOURCE_NOT_SET:
|
|
self.plotValues(conductivity_axis,conductivity_error,solObj=solObj,dataObj=solObj.conductivity,func=solObj.cond)
|
|
else:
|
|
#conductivity_axis.xaxis.set_visible(False)
|
|
#conductivity_axis.yaxis.set_visible(False)
|
|
#conductivity_error.xaxis.set_visible(False)
|
|
#conductivity_error.yaxis.set_visible(False)
|
|
conductivity_axis.annotate("No conductivity information",xy=(0.5,0.5),**infoText)
|
|
|
|
viscosity_axis = plt.subplot(gs[2,1])#, sharex=capacity_axis)
|
|
viscosity_error = viscosity_axis.twinx()
|
|
viscosity_axis.set_yscale('log')
|
|
viscosity_axis.set_ylabel(r'Dynamic Viscosity [$\mathdefault{Pa\/s}$]')
|
|
viscosity_axis.set_xlabel(tempLabel)
|
|
viscosity_error.set_ylabel(errLabel)
|
|
if solObj.viscosity.source!=solObj.viscosity.SOURCE_NOT_SET:
|
|
self.plotValues(viscosity_axis,viscosity_error,solObj=solObj,dataObj=solObj.viscosity,func=solObj.visc)
|
|
else:
|
|
#viscosity_axis.xaxis.set_visible(False)
|
|
#viscosity_axis.yaxis.set_visible(False)
|
|
#viscosity_error.xaxis.set_visible(False)
|
|
#viscosity_error.yaxis.set_visible(False)
|
|
viscosity_axis.annotate("No viscosity information",xy=(0.5,0.5),**infoText)
|
|
|
|
saturation_axis = plt.subplot(gs[3,0])#, sharex=density_axis)
|
|
saturation_error = saturation_axis.twinx()
|
|
saturation_axis.set_yscale('log')
|
|
saturation_axis.set_ylabel(r'Saturation Pressure [$\mathdefault{Pa}$]')
|
|
saturation_axis.set_xlabel(tempLabel)
|
|
saturation_error.set_ylabel(errLabel)
|
|
if solObj.saturation_pressure.source != solObj.saturation_pressure.SOURCE_NOT_SET: # exists
|
|
self.plotValues(saturation_axis,saturation_error,solObj=solObj,dataObj=solObj.saturation_pressure,func=solObj.psat)
|
|
else:
|
|
#saturation_axis.xaxis.set_visible(False)
|
|
#saturation_axis.yaxis.set_visible(False)
|
|
#saturation_error.xaxis.set_visible(False)
|
|
#saturation_error.yaxis.set_visible(False)
|
|
saturation_axis.annotate("No saturation state information",xy=(0.5,0.5),**infoText)
|
|
|
|
Tfreeze_axis = plt.subplot(gs[3,1])#, sharex=capacity_axis)
|
|
Tfreeze_error = Tfreeze_axis.twinx()
|
|
Tfreeze_axis.set_ylabel(r'Freezing Temperature [$\mathdefault{K}$]')
|
|
Tfreeze_axis.set_xlabel("{0} fraction".format(solObj.xid.title()))
|
|
Tfreeze_error.set_ylabel(errLabel)
|
|
if solObj.T_freeze.source != solObj.T_freeze.SOURCE_NOT_SET: # exists
|
|
self.plotValues(Tfreeze_axis,Tfreeze_error,solObj=solObj,dataObj=solObj.T_freeze,func=solObj.Tfreeze)
|
|
else:
|
|
#Tfreeze_axis.xaxis.set_visible(False)
|
|
#Tfreeze_axis.yaxis.set_visible(False)
|
|
#Tfreeze_error.xaxis.set_visible(False)
|
|
#Tfreeze_error.yaxis.set_visible(False)
|
|
Tfreeze_axis.annotate("No freezing point information",xy=(0.5,0.5),**infoText)
|
|
Tfreeze_axis.set_xlabel("Fraction")
|
|
|
|
#saturation_axis = plt.subplot2grid((3,2), (2,0))
|
|
#Tfreeze_axis = plt.subplot2grid((3,2), (2,0))
|
|
#mass2input_axis = plt.subplot2grid((3,2), (2,0))
|
|
#volume2input_axis = plt.subplot2grid((3,2), (2,0))
|
|
|
|
# Set a minimum error level and do some more formatting
|
|
minAbsErrorScale = 0.05 # in per cent
|
|
for a in fig.axes:
|
|
if a.get_ylabel()==errLabel:
|
|
mi,ma = a.get_ylim()
|
|
if mi>-minAbsErrorScale: a.set_ylim(bottom=-minAbsErrorScale)
|
|
if ma< minAbsErrorScale: a.set_ylim( top= minAbsErrorScale)
|
|
a.xaxis.set_major_locator(MaxNLocator(5))
|
|
#a.yaxis.set_major_locator(MaxNLocator(7))
|
|
|
|
|
|
|
|
# print headlines etc.
|
|
self.printFluidInfo(table_axis, solObj)
|
|
# Prepare the legend
|
|
legenddict = {}
|
|
for a in fig.axes:
|
|
handles, labels = a.get_legend_handles_labels()
|
|
for i in range(len(labels)):
|
|
legenddict[labels[i]] = handles[i]
|
|
|
|
legKey = ["Legend: "]
|
|
legVal = [Rectangle((0, 0), 1, 1, alpha=0.0)]
|
|
legKey += legenddict.keys()
|
|
legVal += legenddict.values()
|
|
legKey += [" "]
|
|
legVal += [Rectangle((0, 0), 1, 1, alpha=0.0)]
|
|
|
|
table_axis.legend(
|
|
legVal, legKey,
|
|
bbox_to_anchor=(0.0, -0.025, 1., -0.025),
|
|
ncol=len(legKey), mode="expand", borderaxespad=0.,
|
|
numpoints=1)
|
|
#table_axis.legend(handles, labels, bbox_to_anchor=(0.0, -0.1), loc=2, ncol=3)
|
|
|
|
gs.tight_layout(fig)#, rect=[0, 0, 1, 0.75])
|
|
# Fine-tune figure; make subplots close to each other
|
|
# and hide x ticks for all but bottom plot.
|
|
#fig.subplots_adjust(wspace=0)
|
|
#plt.setp([a.get_xticklabels() for a in fig.axes[:-1]], visible=False)
|
|
|
|
plt.savefig(os.path.join("report","{0}_fitreport.pdf".format(solObj.name)))
|
|
if pdfObj!=None: pdfObj.savefig(fig)
|
|
plt.close()
|
|
pass
|
|
|
|
|
|
def makeSolutionPlots(self, solObjs=[SolutionData()], pdfObj=None):
|
|
"""
|
|
Creates a whole page with some plots and basic information
|
|
for both fit quality, reference data, data sources and
|
|
more.
|
|
"""
|
|
# First we determine some basic settings
|
|
water=None
|
|
solutions=[]
|
|
|
|
for i in range(len(solObjs)-1):
|
|
if solObjs[i].xid==SolutionData.ifrac_mass or \
|
|
solObjs[i].xid==SolutionData.ifrac_mole or \
|
|
solObjs[i].xid==SolutionData.ifrac_volume:
|
|
solutions += [solObjs[i]]
|
|
#elif solObjs[i].xid==SolutionData.ifrac_pure:
|
|
# purefluids += [doneObjs[i]]
|
|
elif solObjs[i].name=="NBS":
|
|
water = solObjs[i]
|
|
solutions += [solObjs[i]]
|
|
|
|
if water==None: raise ValueError("No water found, reference values missing.")
|
|
|
|
# Set temperature data for all fluids
|
|
dataDict = {}
|
|
dataList = []
|
|
obj = SolutionData()
|
|
for i in range(len(solutions)-1):
|
|
obj = solutions[i]
|
|
T = np.arange(np.max([275,np.round(obj.Tmin)]), np.min([300,np.round(obj.Tmax)]), 1)
|
|
P = 100e5
|
|
x = obj.xmin
|
|
dataDict["name"] = obj.name
|
|
dataDict["desc"] = obj.description
|
|
dataDict["T"] = T
|
|
dataDict["P"] = P
|
|
dataDict["x"] = x
|
|
if obj.density.type!=IncompressibleData.INCOMPRESSIBLE_NOT_SET:
|
|
dataDict["D"] = np.array([obj.rho(Ti, P, x) for Ti in T])
|
|
else: dataDict["D"] = None
|
|
if obj.specific_heat.type!=IncompressibleData.INCOMPRESSIBLE_NOT_SET:
|
|
dataDict["C"] = np.array([obj.c(Ti, P, x) for Ti in T])
|
|
else: dataDict["C"] = None
|
|
if obj.conductivity.type!=IncompressibleData.INCOMPRESSIBLE_NOT_SET:
|
|
dataDict["L"] = np.array([obj.cond(Ti, P, x) for Ti in T])
|
|
else: dataDict["L"] = None
|
|
if obj.viscosity.type!=IncompressibleData.INCOMPRESSIBLE_NOT_SET:
|
|
dataDict["V"] = np.array([obj.visc(Ti, P, x) for Ti in T])
|
|
else: dataDict["V"] = None
|
|
dataList.append(dataDict.copy())
|
|
|
|
rat = np.array([5.5,3.05])
|
|
mul = 2.25
|
|
#fig = plt.figure(figsize=(297/div,210/div))
|
|
fig = plt.figure(figsize=rat*mul)
|
|
|
|
ax = fig.add_subplot(121)
|
|
ax.set_xlabel(r'Temperature [$\mathdefault{K}$]')
|
|
ax.set_ylabel(r'Density [$\mathdefault{kg/m^3\!}$]')
|
|
fig.suptitle(r'Aqueous solutions with a concentration of 0.0',fontsize='x-large',fontweight='bold')
|
|
|
|
#obj = water
|
|
#T = np.linspace(obj.Tmin, obj.Tmax, num=int(obj.Tmax-obj.Tmin))
|
|
#D =
|
|
|
|
#import matplotlib.pyplot as plt
|
|
#from itertools import cycle
|
|
lines = ["-","--","-.", ":"]
|
|
colours = ['r', 'g', 'b', 'c', 'm']
|
|
|
|
linecycler = itertools.cycle(lines)
|
|
colourcycler = itertools.cycle(colours)
|
|
|
|
for i in range(len(dataList)-1):
|
|
obj = dataList[i]
|
|
if obj["T"]!=None and obj["D"]!=None:
|
|
if obj["x"]==0.0 and np.any(np.isfinite(obj["D"])) and obj["name"]!="NBS":
|
|
lc = next(colourcycler)
|
|
if lc==colours[0]: ls = next(linecycler)
|
|
ax.plot(obj["T"],obj["D"],label="{0}: {1}".format(obj["name"],obj["desc"]),ls=ls,color=lc)
|
|
#if not np.any(np.isfinite(obj["D"])):
|
|
# print("Name: {0}, Dmin: {1}, Dmax: {1}".format(obj["name"],np.min(obj["D"]),np.max(obj["D"])))
|
|
|
|
obj = (item for item in dataList if item["name"] == "NBS").next()
|
|
ax.plot(obj["T"],obj["D"],label="{0}: {1}".format(obj["name"],obj["desc"]),ls='-',color='black')
|
|
|
|
ax.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0., ncol=1)#, prop={'size':'smaller'})
|
|
plt.tight_layout(rect=(0, 0, 1, 0.95))
|
|
plt.savefig("all_solutions_00.pdf")
|
|
|
|
|
|
|
|
|
|
def generateRstTable(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|