Вы находитесь на странице: 1из 19

School of Mechanical and Mining Engineering

The University of Queensland

Cross-platform Use of the NIST REFPROP


Database via Pythons ctypes Library
Peter J. Blytonand Andrew S. Rowlands
12 June 2012

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.

2. Access to REFPROP from Alternative Environments


REFPROP 9 is provided with a dynamic-link library (DLL) and a suite of examples
R
R
and
, Excel
which utilise this DLL to allow REFPROP to be used from MATLAB
R

C++ applications on the Windows operating system.
Within the QGECE, the REFPROP database is also used from the Python programming environment. The Python interface class in Appendix B utilises the Python ctypes
library4 to access functions from the REFPROP DLL. This Python interface class was
adapted from the REFPROP 8 Python interface of Bruce Wernick5 6 . This approach is
R
limited to use on the Windows
operating system due to the DLL dependency.
7
The CoolProp program also provides a Python interface to the REFPROP database
R
on the Windows
operating system. CoolProp uses the REFPROP DLL in a C++
program, which is then made accessible to Python with a SWIG8 generated interface.
CoolProp may also be used as an alternative to REFPROP, as it provides an open source
implementation of a subset of the thermodynamic and transport property models used in
REFPROP. Similarly, the open source FPROPS9 library may be used as an alternative
to REFPROP.

3. Access to REFPROP on UNIX-like Systems


The Python interface class in Appendix B has been adapted for use on UNIX-like systems. The Python ctypes library used in the interface class is capable of calling functions
in dynamically linked shared object libraries on UNIX-like systems. The required shared
object library has been built with the GNU Fortran compiler10 , using the Fortran source
code for the subroutines and associated fluid data files provided with REFPROP.
A small modification to the REFPROP Fortran source code was required to build
the shared object library. The PASS_FTN.FOR file was modified by commenting out the
export_dll statements as these statements are only required when building the DLL
with the Lahey fortran compiler, as used by NIST. The exporting of function names
when building the shared object library with gfortran is not required as this compiler
automatically makes all public functions available. In addition, the UTILITY.FOR file
3

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

was modified by commenting out a pause statement, as this statement is a removed


feature in Fortran 95 and causes a compiler warning.
Using this shared object library, REFPROP has also been used from C++ programs
on UNIX-like systems. In C++, the library is loaded using the dlopen() function, and
REFPROP functions are made accessible using the dlsym() function. A REFPROP gas
model for the Eilmer3 CFD program has been built using this approach, which is also
accessible in Python through a SWIG generated interface.

4. Instructions for Use


The Python interface class and the makefile in Appendix A for compiling the required
shared object library are available through the following Mercurial repository. To establish authentication to access this repository, and for developer access, contact the authors
or the QGECE. The makefile and Python interface have been written for REFPROP
Version 9, and are currently only applicable for this version.
$ hg clone https://geolocal@triton.pselab.uq.edu.au/geothermal-hg/refprop-hg/ refprop
To build the shared object library, the gfortran compiler must first be installed. This
compiler is available through the software package repository of all major Linux distributions. Once a copy of the repository is retrieved, the shared object library can be
built using the following commands:
$ cd refprop/build
$ make
The REFPROP library is then available as a Python module as illustrated in the
following example. Refer to the source code and documentation in Appendix B for
further usage. The forUnix parameter may be used when creating a refpropFluid
object in Python, it is this parameter that is used to select the REFPROP DLL when
R
on a Windows
machine, or the shared object library when on a UNIX-like system.
Using the Python interface to the REFPROP database, the pressure, enthalpy and
entropy of R134a at 30 C and a quality of zero are:
>>> from pyRefpropMania import *
>>> myFluid = refpropFluid(R134a, forUnix=True)
>>> myFluid.getProps(PHS, T, 30, Q, 0)
[770.1963030769567, 241.72240453606855, 1.1435003296043484]

A. Makefile for Compiling REFPROP with GCC


# M a k e f i l e for b u i l d i n g a REFPROP shared library with gcc .
COMPILE = gfortran
LINK = gfortran
CFLAG = -c - fPIC -fno - underscoring
LFLAG = - fPIC
SOURCE_NAMES = CMNS . FOR CORE_ANC . FOR CORE_BWR . FOR CORE_CPP . FOR CORE_DE . FOR \
CORE_ECS . FOR CORE_FEQ . FOR CORE_MLT . FOR CORE_PH0 . FOR CORE_PR . FOR \
CORE_STN . FOR CORE_QUI . FOR FLASH2 . FOR FLSH_SUB . FOR IDEALGAS . FOR \
MIX_AGA8 . FOR MIX_HMX . FOR PROP_SUB . FOR REALGAS . FOR SAT_SUB . FOR SETUP . FOR \
SETUP2 . FOR TRNS_ECS . FOR TRNS_TCX . FOR TRNS_VIS . FOR TRNSP . FOR
SOURCES = $ ( addprefix ../ REFPROP / fortran / , $ ( SOURCE_NAMES ) ) \
../ source / PASS_FTN . FOR ../ source / UTILITY . FOR
R EF PR OP _ OB JE CT S = $ ( SOURCE_NAMES :%. FOR =%. o ) PASS_FTN . o UTILITY . o
all : refprop . so
install : refprop . so
cp $ + ../ REFPROP / $ +
refprop . so : $ ( RE F PR OP _O B JE CT S )
$ ( LINK ) $ ( LFLAG ) - shared -o $@ $ +
$ ( RE F PR OP _O B JE CT S ) : $ ( SOURCES )
$ ( COMPILE ) $ ( CFLAG ) $ +
clean :
- rm - rf *. o
all - clean :
make clean
- rm - rf *. so
- rm - rf ../ REFPROP /*. so

Listing 1: ../../build/makefile

B. Python REFPROP Interface Class


"""
################################################################################
#
_____
#
#
_______
_____ / ____ \ _ _ _ _ _ _ _ _ _ _ _ _ ____ ______
#
#
\ _ __ \ _ / __ \
__ \\ ____ \ _ __ \/ _ \\ ____ \
#
#
| | \/\ ___ /| | | |_ > > | \( <_ > ) |_ > >
#
#
| __ |
\ ___ > __ | |
__ /| __ |
\ ____ /|
__ /
#
#
\/
| __ |
. __
| __ |
#
#
_____ _____
____ | __ | ____
#
#
/
\\ __ \ /
\| \ __ \
#
#
| Y Y \/ __ \|
| \ |/ __ \ _
#
#
| __ | _ | ( ____ / ___ | / __ ( ____ /
#
#
\/
\/
\/
\/
#
#
#
#
Python Refprop I n t e r f a c e Class
#
#
#
#
Andy S . R o w l a n d s
#
#
a . r o w l a n d s @ u q . edu . au
#
#
#
#
THE U N I V E R S I T Y OF Q U E E N S L A N D
#
#
#
################################################################################
"""
from __future__ import division
# VERSION
_ _ P Y R E F P R O P M A N I A V E R S I O N _ _ = 2012.05.29
"""
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#

C a l c u l a t e s t h e r m o p h y s i c a l p r o p e r t i e s of pure and mixed fluids using Refprop


USAGE :

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

EXAMPLE 2: Using Kelvin instead of Celcius :


myFluid = r e f p r o p F l u i d ( R134a , FLD , False )
Note : You must supply the fluid file e x t e n s i o n when using Kelvin .

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

Short name of fluid


Short name of fluid
Full name of fluid
CAS Number
C h e m i c a l formula
Fluid common synonym
M o l e c u l a r weight
Critical temperature

#
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

Matlab - Refprop i n t e r f a c e by Paul M . Brown and J o h a n n e s Lux , 2007 -04 -05.

"""
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 :

self . setFluid ( fluidName , ext )


self . errorHandler ( " Class Initialised " )

def loadR efpropLi b ( self ) :


""" Loads the a p p r o p r i a t e version of refprop for Win / Linux """
if self . forUnix :
self . rp = cdll . LoadLibrary ( " ./ REFPROP / refprop . so " )
# g f o r t r a n p r o d u c e s a shared library that has symbols in lower case ,
a p p e n d e d with an u n d e r s c o r e .
# our m a k e f i l e removes the underscores , but we must m a n u a l l y map
between upper and lower case symbols .
# Setup f u n c t i o n s :
self . rp . SETUPdll = self . rp . setupdll
self . rp . WMOLdll = self . rp . wmoldll
self . rp . SETREFdll = self . rp . setrefdll
self . rp . SETMIXdll = self . rp . setmixdll
# With density :
self . rp . PDFLSHdll = self . rp . pdflshdll
self . rp . TDFLSHdll = self . rp . tdflshdll
# With p r e s s u r e :
self . rp . TPFLSHdll = self . rp . tpflshdll
# With e n t h a l p y :
self . rp . PHFLSHdll = self . rp . phflshdll
self . rp . DHFLSHdll = self . rp . dhflshdll
self . rp . THFLSHdll = self . rp . thflshdll
# With entropy :
self . rp . PSFLSHdll = self . rp . psflshdll
self . rp . DSFLSHdll = self . rp . dsflshdll
self . rp . TSFLSHdll = self . rp . tsflshdll
self . rp . HSFLSHdll = self . rp . hsflshdll
# With i n t e r n a l energy :
self . rp . PEFLSHdll = self . rp . peflshdll
self . rp . DEFLSHdll = self . rp . deflshdll
self . rp . TEFLSHdll = self . rp . teflshdll
# With quality :
self . rp . TQFLSHdll = self . rp . tqflshdll
self . rp . PQFLSHdll = self . rp . pqflshdll
# Transport properties :
self . rp . TRNPRPdll = self . rp . trnprpdll
self . rp . SURFTdll = self . rp . surftdll
else :
self . rp = windll . LoadLibrary ( r " REFPROP / refprop . dll " )

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 )

def g e t R e f p r o p F l u i d L i s t ( self , types = PURE ) :


""" Returns a list of PURE | MIX | ALL the fluids s u p p o r t e d by Refprop
NB : p y R e f p r o p M a n i a c u r r e n t l y doesn t support pseudo - pure fluids !
Specify types to return :
PURE
All pure fluids

MIX
ALL

All defined mix fluids


All pure and defined fluids """

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

def setupLogging ( self ) :


""" Sets up the logging system for p y R e f p r o p M a n i a """
LOG_FILENAME = " pyRef propMani a . log "
self . logger = logging . getLogger ( " pyRefpro pMania " )
self . logger . setLevel ( logging . DEBUG )
fh = logging . FileHandler ( LOG_FILENAME )
fh . setLevel ( logging . DEBUG )
formatter = logging . Formatter ( " %( asctime ) s - %( name ) s - %( levelname ) s - %(
message ) s " )
fh . setFormatter ( formatter )
self . logger . addHandler ( fh )

def refpropSetup ( self , FluidName = R134A . FLD , FluidRef = DEF ) :


""" Define models and i n i t i a l i s e c arrays """
self . nc . value = 1
self . hfld . value = self . fluidPath + FluidName
self . hrf . value = FluidRef
self . u n l o a d R e f p r o pL i b ()
self . loa dRefprop Lib ()
self . rp . SETUPdll ( byref ( self . nc ) , byref ( self . hfld ) , byref ( self . hfm ) , byref (
self . hrf ) , byref ( self . ierr ) , byref ( self . herr ) , c_long (10000) , c_long (255) ,
c_long (3) , c_long (255) )
if self . ierr . value == 0:
ixflag = c_long (1)
h0 , s0 , t0 , p0 = c_double (0) , c_double (0) , c_double (0) , c_double (0)
self . rp . SETREFdll ( byref ( self . hrf ) , byref ( ixflag ) , self .x , byref ( h0 ) , byref (
s0 ) , byref ( t0 ) , byref ( p0 ) , byref ( self . ierr ) , byref ( self . herr ) , c_long (3) ,
c_long (255) )
if self . ierr . value == 0:
self . rp . WMOLdll ( self .x , byref ( self . wm ) )
return

def r ef pr op S et up Mi x ( self , FluidName = R404A . MIX , FluidRef = DEF ) :


""" Open a mixture file and read c o n s t i t u e n t s and mole f r a c t i o n s """
self . hfld . value = self . mixPath + FluidName
self . hrf . value = FluidRef
self . u n l o a d R e f p r o pL i b ()
self . loa dRefprop Lib ()
self . rp . SETMIXdll ( byref ( self . hfld ) , byref ( self . hfm ) , byref ( self . hrf ) , byref (
self . nc ) , byref ( self . hfile ) , self .x , byref ( self . ierr ) , byref ( self . herr ) ,
c_long (255) , c_long (255) , c_long (3) , c_long (10000) , c_long (255) )

if self . ierr . value == 0:


ixflag = c_long (0)
h0 , s0 , t0 , p0 = c_double (0) , c_double (0) , c_double (0) , c_double (0)
self . rp . SETREFdll ( byref ( self . hrf ) , byref ( ixflag ) , self .x , byref ( h0 ) , byref (
s0 ) , byref ( t0 ) , byref ( p0 ) , byref ( self . ierr ) , byref ( self . herr ) , c_long (3) ,
c_long (255) )
if self . ierr . value == 0:
self . rp . WMOLdll ( self .x , byref ( self . wm ) )
return
def r e f p r o p G e t H e a de r ( self , fluid ) :
""" Read and i n t e r p r e t text at head of fluid d e f i n i t i o n file
NB : This r e q u i r e s that the fluid files don t change in layout ,
be aware of that with any version changes etc ! """
def gets () :
s = f . readline ()
if ! in s :
lhs , rhs = s . split ( ! )
lhs = lhs . strip ()
rhs = rhs . strip ()
else :
lhs = s . strip ()
rhs =
return lhs , rhs
H = {}
f = open ( self . fluidPath + fluid + . FLD , r )
H [ shortname ] , rhs = gets ()
H [ casnum ] , rhs = gets ()
H [ fullname ] , rhs = gets ()
H [ chemform ] , rhs = gets ()
H [ synonym ] , rhs = gets () # R - Number
H [ mw ] , rhs = gets ()
H [ ttp ] , rhs = gets ()
H [ tnbp ] , rhs = gets ()
H [ tc ] , rhs = gets ()
H [ tc ] = float ( H [ tc ])
if ( self . useC ) :
H [ tc ] = H [ tc ] - self . k0
H [ pc ] , rhs = gets ()
H [ pc ] = float ( H [ pc ])
H [ dc ] , rhs = gets ()
H [ dc ] = float ( H [ dc ])
H [ accen ] , rhs = gets ()
H [ dip ] , rhs = gets ()
lhs , rhs = gets ()
H [ ref ] = lhs
if lhs [0:2]. lower () == ot :
H [ ref ] = OTH # # not sure why some fluids have OT0
lhs , rhs = gets ()
a = lhs . split ()
H [ tphs ] = a [0]+ , + a [1]+ , + a [2]+ , + a [3]
H [ ver ] , rhs = gets ()
lhs , rhs = gets ()
if rhs [0:2]. lower () == un :
H [ unnum ] = lhs
lhs , rhs = gets ()
else :
H [ unnum ] =
H [ family ] = lhs
H [ comps ] = 1

10

# Get maximum and minimum ranges for EOS :


while end of info section not in rhs :
lhs , rhs = gets ()
H [ tll ] , rhs = gets ()
H [ tll ] = float ( H [ tll ])
if ( self . useC ) :
H [ tll ] = H [ tll ] - self . k0
H [ tul ] , rhs = gets ()
H [ tul ] = float ( H [ tul ])
if ( self . useC ) :
H [ tul ] = H [ tul ] - self . k0
H [ pul ] , rhs = gets ()
H [ pul ] = float ( H [ pul ])
if ( self . useC ) :
H [ pul ] = H [ pul ] - self . k0
f . close ()
return H
def r e f p r o p G e t M i x H e a d e r ( self , mix ) :
""" Read and i n t e r p r e t text at head of mixed fluid d e f i n i t i o n file """
H = {}
f = open ( self . mixPath + mix + . MIX , r )
# prev : f = open ( mixpath + mix , r )
s = f . readline () . strip ()
H [ shortname ] = s
H [ casnum ] =
H [ fullname ] = s
H [ synonym ] = s
H [ ref ] =
H [ family ] =
s = f . readline ()
a = s . split ()
H [ mw ] = float ( a [0])
H [ tc ] = float ( a [1])
if ( self . useC ) :
H [ tc ] = H [ tc ] - self . k0
H [ pc ] = float ( a [2])
H [ dc ] = float ( a [3])
nc = int ( f . readline () . strip () )
H [ comps ] = nc
# Read c o m p o n e n t names
chemform = []
for i in range ( nc ) :
lhs , rhs = f . readline () . strip () . split ( . )
chemform . append ( lhs )
H [ chemform ] = chemform
# Read p r o p o r t i o n s
# Updated to include c o m p o s i t i o n in header return array
composition = []
for i in range ( nc ) :
s = f . readline () . strip ()
composition . append ( s )
H [ composition ] = composition
f . close ()
return H
def setFluid ( self , fluidName , ext = " FLD " ) :
""" Sets the fluid for the current i n s t a n c e of the class """

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

def resetFluid ( self ) :


""" Resets / removes all the fluid p r o p e r t i e s """
self . name = None
self . fullname = None
self . chemform = None

12

self . composition = None


self . synonym = None
self . mw = None
self . pc = None
self . tc = None
def getProps ( self , prop_req = None , spec1 = None , value1 = None , spec2 = None , value2 =
None ) :
""" C a l c u l a t e s p r o p e r t i e s based on two input p r o p e r t i e s that must be
s p e c i f i e d """
# Set the DLL to this i n s t a n c e
self . setDLL ()
# If we have a name lets go !
if self . name is not None :
# Use the class vars for the local calcs
wm = self . wm
k0 = self . k0
ierr = self . ierr
herr = self . herr
x = self . x
xl = self . xl
xv = self . xv
xlkg = self . xlkg
xvkg = self . xvkg
# Reset the r e q u e s t e d p r o p e r t i e s d i c t i o n a r y in case of errors
self . reqProps = {}
# Setup c - types for DLL calls
p = c_double ()
D = c_double ()
t = c_double ()
q = c_double ()
Dl , Dv = c_double () , c_double ()
q , e , h , s = c_double () , c_double () , c_double () , c_double ()
cv , cp = c_double () , c_double ()
w = c_double ()
# Debug outputs
# self . e r r o r H a n d l e r (" Spec 1: " + str ( spec1 ) )
# self . e r r o r H a n d l e r (" Spec 2: " + str ( spec2 ) )
# self . e r r o r H a n d l e r (" Value 1: " + str ( value1 ) )
# self . e r r o r H a n d l e r (" Value 2: " + str ( value2 ) )
# Turn the r e q u e s t e d p r o p e r t y string into an array
prop_req = list ( prop_req . upper () )
# Spec 1 D e f i n i t i o n Select
if spec1 == " P " :
p = c_double ( value1 )
elif spec1 == " T " :
if ( self . useC ) :
value1 = value1 + k0
t = c_double ( value1 )
elif spec1 == " D " :
D_rp = value1 / wm . value # convert to mol - basis
D = c_double ( D_rp )
elif spec1 == " H " :
h = value1 * wm . value # convert to mol - basis
h = c_double ( h )

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

kr = 1 # Choose lower density root ( this seems to be correct )


kr = c_long ( kr )
self . rp . THFLSHdll ( byref ( t ) , byref ( h ) ,x , byref ( kr ) , byref ( p ) , 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 )
elif spec1 == " P " :
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 : # DH
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 )
elif spec2 == " S " :
s = value2 * wm . value # convert to mol - basis
s = c_double ( s )
if spec1 == " T " :
kr = 1
kr = c_long ( kr )
""" kr - Phase flag :
1 = Liquid ,
2 = Vapour in e q u i l i b r i u m with liq ,
3 = Liquid in e q u i l i b r i u m with solid ,
4 = Vapour in e q u i l i b r i u m with solid """
self . rp . TSFLSHdll ( byref ( t ) , byref ( s ) ,x , byref ( kr ) , byref ( p ) , byref ( D ) ,
byref ( Dl ) , byref ( Dv ) ,xl , xv , byref ( q ) , byref ( e ) , byref ( h ) , 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 . PSFLSHdll ( byref ( p ) , byref ( s ) ,x , byref ( t ) , byref ( D ) , byref ( Dl ) ,
byref ( Dv ) ,xl , xv , byref ( q ) , byref ( e ) , byref ( h ) , 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 . HSFLSHdll ( byref ( h ) , byref ( s ) ,x , byref ( t ) , byref ( p ) , byref ( D ) ,
byref ( Dl ) , byref ( Dv ) ,xl , xv , byref ( q ) , byref ( e ) , byref ( cv ) , byref ( cp
) , byref ( w ) , byref ( ierr ) , byref ( herr ) , c_long (255) )
if ierr . value != 0:
self . errorHandler ( herr . value )
else : # DS
self . rp . DSFLSHdll ( byref ( D ) , byref ( s ) ,x , byref ( t ) , byref ( p ) , byref ( Dl ) ,
byref ( Dv ) ,xl , xv , byref ( q ) , byref ( e ) , byref ( h ) , byref ( cv ) , byref ( cp )
, byref ( w ) , byref ( ierr ) , byref ( herr ) , c_long (255) )
if ierr . value != 0:
self . errorHandler ( herr . value )
elif spec2 == " U " :
e = value2 * wm . value # convert to mol - basis
e = c_double ( e )
if spec1 == " U " :
self . errorHandler ( " Spec 1 and 2 are the same : " + spec1 )
self . ierr = c_long ( -999)
elif spec1 == " T " :

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)

# f = r e f p r o p F l u i d ( R134a , forUnix = True )


# print f . g e t P r o p s ( TPDHS , T , 150 , P , 1000)
# print f . g e t P r o p s ( Z , T , 150 , P , 1000)

Listing 2: ../../pyRefpropMania.py

19

Вам также может понравиться