Академический Документы
Профессиональный Документы
Культура Документы
This report outlines the current methods of using the NIST REFPROP
thermodynamic and transport property database (Version 9) within the Queensland Geothermal Energy Centre of Excellence (QGECE). A solution for using
R
this Windows
based software on a UNIX-like system is presented, along
with a cross-platform Python based interface to the REFPROP database.
This work now enables the REFPROP database to be used on available
Linux based supercomputers and facilitates the integration of this database
with a wider variety of analysis software within the QGECE.
1. Introduction
The Reference Fluid Thermodynamic and Transport Properties database (REFPROP)
developed by The National Institute of Standards and Technology (NIST)1 is a software package that implements the most accurate models and equations available for the
evaluation of pure fluid and mixture properties.
R
The REFPROP software package is provided with a Windows
based graphical user
interface, which provides easy access to all of the softwares functionality. For brusque
and simple use of REFPROP, the database can be accessed freely through the NIST
Chemistry WebBook2 .
Queensland Geothermal Energy Centre of Excellence, The University of Queensland, Brisbane, Australia.
1
http://nist.gov/srd/nist23.cfm
2
http://webbook.nist.gov/chemistry/fluid/
The REFPROP graphical program can also be installed and run on UNIX-like systems
using the Wine3 compatibility layer. Wine is available through the software package
repository of all major Linux distributions.
http://www.winehq.org
http://docs.python.org/library/ctypes.html
5
http://leniwiki.epfl.ch/index.php/REFPROP
6
info@coolit.co.za
7
http://coolprop.sourceforge.net
8
http://swig.org
9
http://ascend4.org/FPROPS
10
http://gcc.gnu.org/wiki/GFortran
4
Listing 1: ../../build/makefile
from p y R e f p r o p M a n i a import *
myFluid = r e f p r o p F l u i d ( R134a )
( or ) = r e f p r o p F l u i d ( R404a , MIX )
ALT :
myFluid = r e f p r o p F l u i d ()
myFluid . s e t F l u i d ( R134a )
myFluid . s e t F l u i d ( R404a , MIX )
EXAMPLE :
p , h , s = myFluid . g e t P r o p s ( PHS , T , 30 , Q , 0)
gives pressure , e n t h a l p y and entropy of set fluid at 30 C , 0 quality
CLASS A T T R I B U T E S :
Pure Fluids :
myFluid . name
myFluid . s h o r t n a m e
myFluid . f u l l n a m e
myFluid . casnum
myFluid . c h e m f o r m
myFluid . synonym
myFluid . mw
myFluid . tc
#
myFluid . pc
Critical pressure
#
myFluid . dc
C r i t i c a l density
#
#
Mixtures :
#
As above but with the f o l l o w i n g d i f f e r e c e s :
#
myFluid . c h e m f o r m
C o m p o n e n t short names of mixture
#
myFluid . c o m p o s i t i o n
Mol f r a c t i o n s of c o m p o n e n t s
#
#
Errors :
#
myFluid . ierr . value
C o n t a i n s integer error (0 if no error )
#
myFluid . herr . value
C o n t a i n s error d e s c r i p t i o n ( blank if none )
#
# CLASS METHODS :
#
#
myFluid . s e t F l u i d ( fluidName , ext , useC )
#
fluidName
Short name of fluid
#
ext
R e q u i r e d if using m i x t u r e s ( specify " MIX ")
#
useC
Whether to use degC or K . ( Boolean )
#
Specify FALSE if you want to use K .
#
NB : If you do this , you must also specify either
#
the FLD or MIX e x t e n s i o n . See Example 2 above .
#
#
myFluid . r e s e t F l u i d ()
Resets the class i n s t a n c e ( more or less )
#
#
myFluid . g e t P r o p s ( prop_req , spec1 , value1 , spec2 , value2 )
#
prop_req
String of p r o p e r t i e s requested , one or more of :
#
P
P r e s s u r e [ kPa ]
#
T
T e m p e r a t u r e [ C ] or [ K ] ( see useC below )
#
D
Density [ kg / m3 ]
#
H
E n t h a l p y [ kJ / kg ]
#
S
Entropy [ kJ /( kg / K ) ]
#
U
I n t e r n a l energy [ kJ / kg ]
#
C
Cp [ kJ /( kg K ) ]
#
O
Cv [ kJ /( kg K ) ]
#
K
Ratio of s p e c i f i c heats ( Cp / Cv ) [ -]
#
A
Speed of sound [ m / s ]
#
Q
Quality ( vapour f r a c t i o n ) ( kg / kg )
#
V
Dynamic v i s c o s i t y [ uPa * s ]
#
L
Thermal c o n d u c t i v i t y [ W /( m K ) ]
#
I
Surface tension [ N / m ] ( if liquid )
#
Z
C o m p r e s s i b i l i t y factor ( d i m e n s i o n l e s s )
#
*
Returns all a v a i l a b l e p r o p e r t i e s ( in order )
#
#
spec1
First p r o p e r t y s p e c i f i e d (T , P , H or D )
#
value1
Value of spec1
#
spec2
Second p r o p e r t y s p e c i f i e d (P , D , H , S , U or Q )
#
value2
Value of spec2
#
useC
S p e c i f i e s to use degC or K , default is degC .
#
#
Calling g e t P r o p s () also makes a v a i l a b l e a dict myfluid . reqProps ,
#
which c o n t a i n s values of all p r o p e r t i e s for the last call to
#
g e t P r o p s () if there was no error . O t h e r w i s e it will be empty .
#
# CREDIT TO OTHERS :
#
# Peter Blyton < peter . b l y t o n @ u q c o n n e c t . edu . au > created a new m a k e f i l e for
# b u i l d i n g refprop . so on linux and added the forUnix flag .
#
# Some of the f u n c t i o n s in this class are based on Bruce Wernick s Python
# Refprop library , 2010 -08 -04.
#
# The f u n c t i o n a l i n s p i r a t i o n for this class comes from the Fortran
"""
import time
import os
import sys
import logging
from ctypes import *
import _ctypes
class refpropFluid ( object ) :
def __init__ ( self , fluidName = None , ext = " FLD " , useC = True , nodeRole = None ,
forUnix = None ) :
""" I n i t i a l i s e s the r e f p r o p F l u i d class with paths , d e f a u l t s etc """
self . forUnix = forUnix
# Load a p p r o p r i a t e Refprop lib ( Windows . DLL or Linux . SO )
self . loa dRefprop Lib ()
# For Hadoop madness you must put r e l a t i v e path in for refprop for slave
nodes !
# ( but change it back for the master ) . i . e .: self . r e f p r o p P a t h = ../../
jars / REFPROP /
# for p p s e r v e r you need a h a r d c o d e d path e . g . c :/
p y T u r b i n e M a n i a 2 0 1 2 _ m u l t i n o d e / REFPROP /
if ( nodeRole ) :
self . refpropPath = ../../ jars / REFPROP /
else :
self . refpropPath = os . getcwd () + / REFPROP /
self . fluidPath = self . refpropPath + fluids /
self . mixPath = self . refpropPath + mixtures /
self . name = None
self . lastProps = {}
self . MaxComps = 20
self . k0 = 273.15
self . hfld = c r e a t e _ s t r i n g _ b u f f e r ( , 10000)
self . hfm = c r e a t e _ s t r i n g _ b u f f e r ( self . refpropPath + fluids / hmx . bnc , 255)
self . hrf = c r e a t e _ s t r i n g _ b u f f e r ( DEF , 3)
self . hfile = c r e a t e _ s t r i n g _ b u f f e r ( , 10000)
self . htype = c r e a t e _ s t r i n g _ b u f f e r ( NBS , 3)
self . hmix = c r e a t e _ s t r i n g _ b u f f e r ( NBS , 3)
self . hcomp = c r e a t e _ s t r i n g _ b u f f e r ( NBS , 3)
self . ierr = c_long (0)
self . herr = c r e a t e _ s t r i n g _ b u f f e r ( , 255)
self . hname = c r e a t e _ s t r i n g _ b u f f e r ( , 12)
self . hn80 = c r e a t e _ s t r i n g _ b u f f e r ( , 80)
self . hcas = c r e a t e _ s t r i n g _ b u f f e r ( , 12)
self . nc = c_long (1)
self . wm = c_double ()
self . tc = 0
self . x = ( c_double * self . MaxComps ) (1)
self . xl = ( c_double * self . MaxComps ) ()
self . xv = ( c_double * self . MaxComps ) ()
self . xlkg = ( c_double * self . MaxComps ) ()
self . xvkg = ( c_double * self . MaxComps ) ()
self . useC = useC
if ( nodeRole is not None ) :
# Hadoop hates the logging for some reason
self . setupLogging ()
if fluidName is not None :
def u n l o a d R e f p ro p L i b ( self ) :
""" Unloads the Refprop lib to free r e s o u r c e s for m u l t i p l e calls """
handle = self . rp . _handle
del self . rp
if self . forUnix :
_ctypes . dlclose ( handle )
else :
_ctypes . FreeLibrary ( handle )
MIX
ALL
fluidList = []
if types == PURE or types == ALL :
for filename in os . listdir ( self . fluidPath ) :
if . FLD in filename :
fluidList . append ({ fluid : filename . replace ( . FLD , ) , ext :
FLD })
if types == MIX or types == ALL :
for filename in os . listdir ( self . mixPath ) :
if . MIX in filename :
fluidList . append ({ fluid : filename . replace ( . MIX , ) , ext :
MIX })
return fluidList
10
11
self . resetFluid ()
self . name = str ( fluidName ) . upper ()
self . ext = ext . upper ()
try :
if " FLD " in self . ext :
self . refpropSetup ( self . name + . FLD )
fluidInfoDict = self . r e f p r o p G e t H e a d e r ( self . name )
self . fullname = fluidInfoDict [ fullname ]
self . chemform = fluidInfoDict [ chemform ]
self . synonym = fluidInfoDict [ synonym ]
self . mw = fluidInfoDict [ mw ]
self . pc = fluidInfoDict [ pc ]
self . tc = fluidInfoDict [ tc ]
self . l o w e r T e m p e r a t u r e L i m i t = fluidInfoDict [ tll ]
self . u p p e r T e m p e r a t u r e L i m i t = fluidInfoDict [ tul ]
self . u p p e r P r e s s u r e L i m i t = fluidInfoDict [ pul ]
self . errorHandler ( " Fluid set : " + self . name )
return True
if " MIX " in self . ext :
self . re fp ro p Se tu pM i x ( self . name + . MIX )
fluidInfoDict = self . r e f p r o p G e t M i x H e a d e r ( self . name )
self . fullname = fluidInfoDict [ fullname ]
self . chemform = fluidInfoDict [ chemform ]
self . composition = fluidInfoDict [ composition ]
self . synonym = fluidInfoDict [ synonym ]
self . mw = fluidInfoDict [ mw ]
self . pc = fluidInfoDict [ pc ]
self . tc = fluidInfoDict [ tc ]
self . errorHandler ( " Fluid set : " + self . name )
return True
except :
self . errorHandler ( " Fluid not found : " + self . name + " " + ext )
return False
def setDLL ( self ) :
""" This is to reset the DLL to this i n s t a n c e of the class . This is
n e c e s s a r y to ensure we get the p r o p e r t i e s for this fluid - if we
load more than one class Windows uses the shared vars from the DLL
so data r e t u r n e d will be wrong . If you add any f u n c t i o n s you MUST
call this before doing a n y t h i n g with the DLL ! """
try :
if " FLD " in self . ext :
self . refpropSetup ( self . name + . FLD )
return True
if " MIX " in self . ext :
self . re fp ro p Se tu pM i x ( self . name + . MIX )
return True
except :
self . errorHandler ( " FATAL ERROR WHEN RESETTING DLL FOR : " + self . name +
" " + self . ext )
return False
12
13
else :
self . errorHandler ( " Spec 1 not P , T , D or H " )
self . ierr = c_long ( -999)
# Spec 2 D e f i n i t i o n Select
if spec2 == " P " :
p = c_double ( value2 )
if spec1 == " P " :
self . errorHandler ( " Spec 1 and 2 are the same : " + spec1 )
self . ierr = c_long ( -999)
elif spec1 == " D " :
self . rp . PDFLSHdll ( byref ( p ) , byref ( D ) ,x , byref ( t ) , byref ( Dl ) , byref ( Dv )
,xl , xv , byref ( q ) , byref ( e ) , byref ( h ) , byref ( s ) , byref ( cv ) , byref ( cp )
, byref ( w ) , byref ( ierr ) , byref ( herr ) , c_long (255) )
if ierr . value != 0:
self . errorHandler ( herr . value )
elif spec1 == " H " :
self . rp . PHFLSHdll ( byref ( p ) , byref ( h ) ,x , byref ( t ) , byref ( D ) , byref ( Dl ) ,
byref ( Dv ) ,xl , xv , byref ( q ) , byref ( e ) , byref ( s ) , byref ( cv ) , byref ( cp )
, byref ( w ) , byref ( ierr ) , byref ( herr ) , c_long (255) )
if ierr . value != 0:
self . errorHandler ( herr . value )
else : # TP
self . rp . TPFLSHdll ( byref ( t ) , byref ( p ) ,x , byref ( D ) , byref ( Dl ) , byref ( Dv )
,xl , xv , byref ( q ) , byref ( e ) , byref ( h ) , byref ( s ) , byref ( cv ) , byref ( cp )
, byref ( w ) , byref ( ierr ) , byref ( herr ) , c_long (255) )
if ierr . value != 0:
self . errorHandler ( herr . value )
elif spec2 == " D " :
D_rp = value2 / wm . value # convert to mol - basis
D = c_double ( D_rp )
if spec1 == " D " :
self . errorHandler ( " Spec 1 and 2 are the same : " + spec1 )
self . ierr = c_long ( -999)
elif spec1 == " P " :
self . rp . PDFLSHdll ( byref ( p ) , byref ( D ) ,x , byref ( t ) , byref ( Dl ) , byref ( Dv )
,xl , xv , byref ( q ) , byref ( e ) , byref ( h ) , byref ( s ) , byref ( cv ) , byref ( cp )
, byref ( w ) , byref ( ierr ) , byref ( herr ) , c_long (255) )
if ierr . value != 0:
self . errorHandler ( herr . value )
elif spec1 == " H " :
self . rp . DHFLSHdll ( byref ( D ) , byref ( h ) ,x , byref ( t ) , byref ( p ) , byref ( Dl ) ,
byref ( Dv ) ,xl , xv , byref ( q ) , byref ( e ) , byref ( s ) , byref ( cv ) , byref ( cp )
, byref ( w ) , byref ( ierr ) , byref ( herr ) , c_long (255) )
if ierr . value != 0:
self . errorHandler ( herr . value )
else : # TD
self . rp . TDFLSHdll ( byref ( t ) , byref ( D ) ,x , byref ( p ) , byref ( Dl ) , byref ( Dv )
,xl , xv , byref ( q ) , byref ( e ) , byref ( h ) , byref ( s ) , byref ( cv ) , byref ( cp )
, byref ( w ) , byref ( ierr ) , byref ( herr ) , c_long (255) )
if ierr . value != 0:
self . errorHandler ( herr . value )
elif spec2 == " H " :
h = value2 * wm . value # convert to mol - basis
h = c_double ( h )
if spec1 == " H " :
self . errorHandler ( " Spec 1 and 2 are the same : " + spec1 )
self . ierr = c_long ( -999)
elif spec1 == " T " :
# TH Seems a bit of a crazy one as m u l t i p l e s o l u t i o n s exist ..
14
15
kr = 1
kr = c_long ( kr )
self . rp . TEFLSHdll ( byref ( t ) , byref ( e ) ,x , byref ( kr ) , byref ( p ) , byref ( D ) ,
byref ( Dl ) , byref ( Dv ) ,xl , xv , byref ( q ) , byref ( h ) , byref ( s ) , byref ( cv )
, byref ( cp ) , byref ( w ) , byref ( ierr ) , byref ( herr ) , c_long (255) )
if ierr . value != 0:
self . errorHandler ( herr . value )
elif spec1 == " P " :
self . rp . PEFLSHdll ( byref ( p ) , byref ( e ) ,x , byref ( t ) , byref ( D ) , byref ( Dl ) ,
byref ( Dv ) ,xl , xv , byref ( q ) , byref ( h ) , byref ( s ) , byref ( cv ) , byref ( cp )
, byref ( w ) , byref ( ierr ) , byref ( herr ) , c_long (255) )
if ierr . value != 0:
self . errorHandler ( herr . value )
elif spec1 == " H " :
self . errorHandler ( " HU function not supported . " )
self . ierr = c_long ( -999)
else : # DU
self . rp . DEFLSHdll ( byref ( D ) , byref ( e ) ,x , byref ( t ) , byref ( p ) , byref ( Dl ) ,
byref ( Dv ) ,xl , xv , byref ( q ) , byref ( h ) , byref ( s ) , byref ( cv ) , byref ( cp )
, byref ( w ) , byref ( ierr ) , byref ( herr ) , c_long (255) )
if ierr . value != 0:
self . errorHandler ( herr . value )
elif spec2 == " Q " :
q = c_double ( value2 )
if spec1 == " T " :
kq = 2
kq = c_long ( kq )
""" kq - Flag s p e c i f y i n g units for input quality
kq = 1 quality on MOLAR basis [ moles vapour / total moles ]
kq = 2 quality on MASS basis [ mass vapour / total mass ] """
self . rp . TQFLSHdll ( byref ( t ) , byref ( q ) ,x , byref ( kq ) , byref ( p ) , byref ( D ) ,
byref ( Dl ) , byref ( Dv ) ,xl , xv , byref ( e ) , byref ( h ) , byref ( s ) , byref ( cv )
, byref ( cp ) , byref ( w ) , byref ( ierr ) , byref ( herr ) , c_long (255) )
if ierr . value != 0:
self . errorHandler ( herr . value )
elif spec1 == " P " :
kq = 2
kq = c_long ( kq )
self . rp . PQFLSHdll ( byref ( p ) , byref ( q ) ,x , byref ( kq ) , byref ( t ) , byref ( D ) ,
byref ( Dl ) , byref ( Dv ) ,xl , xv , byref ( e ) , byref ( h ) , byref ( s ) , byref ( cv )
, byref ( cp ) , byref ( w ) , byref ( ierr ) , byref ( herr ) , c_long (255) )
if ierr . value != 0:
self . errorHandler ( herr . value )
elif spec1 == " H " :
self . errorHandler ( " QH function not supported . " )
self . ierr = c_long ( -999)
else : # DQ
# NB : The Matlab Fortran somehow pulls this combo off by making a
call
# to the m y s t e r i o u s DQFL2 function , which doesn t seem to exist
(?)
# kq = 2
# kq = c_long ( kq )
# self . rp . D Q F L 2 d l l ( byref ( D ) , byref ( q ) , x , byref ( kq ) , byref ( t ) ,
byref ( p ) , byref ( Dl ) , byref ( Dv ) , xl , xv , byref ( ierr ) , byref (
herr ) )
# return t . value , p . value , s . value , h . value
# self . rp . T H E R M d l l (.. put in args ...)
self . errorHandler ( " DQ function not supported . " )
self . ierr = c_long ( -999)
16
else :
self . errorHandler ( " Spec 2 not P , H , S , U , Q or D " )
self . ierr = c_long ( -999)
if self . ierr . value == 0:
# C a l c u l a t e thermal c o n d u c t i v i t y and dynamic v i s c o s i t y for fun .
V , L = self . TRNPRP ( t . value , D . value )
# C a l c u l a t e surface tension , has to be in vapour dome , T < Tc
if (( t . value < ( self . tc + k0 ) ) and ( q . value >= 0) and ( q . value <= 1)
):
I = self . SURFT ( t . value , D . value )
else :
I = None
# Build loop of data to return from r e q u e s t e d p r o p e r t i e s
arrData = []
# Check if we want to use C or K , d e f a u l t s to C
temp = t . value
if ( self . useC ) :
temp = t . value - k0
for prop in prop_req :
""" Loop through and build return array """
if prop == T or prop == " * " :
arrData . append ( temp )
if prop == P or prop == " * " :
arrData . append ( p . value )
if prop == D or prop == " * " :
arrData . append ( D . value * wm . value )
if prop == H or prop == " * " :
arrData . append ( h . value / wm . value )
if prop == S or prop == " * " :
arrData . append ( s . value / wm . value )
if prop == " U " or prop == " * " :
arrData . append ( e . value / wm . value )
if prop == " C " or prop == " * " :
arrData . append ( cp . value / wm . value )
if prop == " O " or prop == " * " :
arrData . append ( cv . value / wm . value )
if prop == " K " or prop == " * " :
arrData . append (( cp . value / wm . value ) / ( cv . value / wm . value ) )
if prop == " A " or prop == " * " :
arrData . append ( w . value )
if prop == " Q " or prop == " * " :
arrData . append ( q . value )
if prop == " V " or prop == " * " :
arrData . append ( V )
if prop == " L " or prop == " * " :
arrData . append ( L )
if prop == " I " or prop == " * " :
arrData . append ( I )
if prop == " Z " or prop == " * " :
arrData . append ( p . value / D . value / t . value /8.3144621)
# We also set a d i c t i o n a r y r e q P r o p s which makes a v a i l a b l e
# all the p r o p e r t i e s from the last c a l c u l a t i o n available , even
# if not e x p l i c i t l y r e q u e s t e d to be r e t u r n e d from the f u n c t i o n .
self . reqProps = {
P : p . value ,
T : temp ,
D : D . value * wm . value ,
17
H
S
U
C
O
K
A
Q
V
L
I
Z
: h . value / wm . value ,
: s . value / wm . value ,
: e . value / wm . value ,
: cp . value / wm . value ,
: cv . value / wm . value ,
: ( cp . value / wm . value ) / ( cv . value / wm .
value ) ,
: w . value ,
: q . value ,
: V,
: L,
: I,
: p . value / D . value / t . value /8.3144621
}
if len ( arrData ) == 1:
return arrData [0]
else :
return arrData
else :
""" Fluid isn t set so chuck an error """
self . errorHandler ( " No fluid set . Usage : setFluid ( fluidName ) " )
return False
def TRNPRP ( self , t , D ) :
""" Returns t r a n s p o r t p r o p e r t i e s of thermal c o n d u c t i v i t y and
v i s c o s i t y as f u n c t i o n s of t e m p e r a t u r e and density
eta - v i s c o s i t y ( uPa . s )
tcx - thermal c o n d u c t i v i t y ( W / m . K ) """
# Set the DLL to this i n s t a n c e
self . setDLL ()
t = c_double ( t )
D = c_double ( D )
eta , tcx = c_double () , c_double ()
self . rp . TRNPRPdll ( byref ( t ) , byref ( D ) , self .x , byref ( eta ) , byref ( tcx ) , byref (
self . ierr ) , byref ( self . herr ) , c_long (255) )
return eta . value , tcx . value
def SURFT ( self , t , D ) :
""" Returns surface tension """
# Set the DLL to this i n s t a n c e
self . setDLL ()
t = c_double ( t )
D = c_double ( D )
sigma = c_double ()
self . rp . SURFTdll ( byref ( t ) , byref ( D ) , self .x , byref ( sigma ) , byref ( self . ierr ) ,
byref ( self . herr ) , c_long (255) )
return sigma . value
def errorHandler ( self , msg , newLine = True , log = False , debug = True ) :
""" Raises the error and prints the message """
sys . stderr . write ( RM : + msg )
if ( debug ) :
if ( newLine ) :
print " refpropMania : " , msg , " For fluid : " , self . name
else :
print ( " refpropMania : " + msg , " For fluid : " , self . name ) ,
if ( log ) :
self . logger . debug ( msg )
return False
18
if __name__ == __main__ :
# Quick setup for testing
f = refpropFluid ( R134a , forUnix = True )
print f . getProps ( TPDHS , T , 150 , P , 1000)
print f . getProps ( Z , T , 150 , P , 1000)
# Memory leak test 1
while 1:
f . setFluid ( R134a )
print f . getProps ( TPDHS , T , 150 , P , 2500)
print f . getProps ( Z , T , 150 , P , 2500)
f . setFluid ( R245fa )
print f . getProps ( TPDHS , T , 150 , P , 2500)
print f . getProps ( Z , T , 150 , P , 2500)
Listing 2: ../../pyRefpropMania.py
19