thermofluids 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- thermofluids/Base/Quantity.py +16 -0
- thermofluids/Base/Statepoint.py +1191 -0
- thermofluids/Base/__init__.py +0 -0
- thermofluids/Base/thermofluids_registry.txt +5 -0
- thermofluids/Fluids/Drag.py +169 -0
- thermofluids/Fluids/Moody.py +57 -0
- thermofluids/Fluids/PressureDrop.py +322 -0
- thermofluids/Fluids/Re.py +88 -0
- thermofluids/Fluids/__init__.py +4 -0
- thermofluids/HeatTransfer/Gr.py +12 -0
- thermofluids/HeatTransfer/NTU.py +45 -0
- thermofluids/HeatTransfer/Nusselt.py +59 -0
- thermofluids/HeatTransfer/Ra.py +22 -0
- thermofluids/HeatTransfer/TwoPhase.py +249 -0
- thermofluids/HeatTransfer/__init__.py +6 -0
- thermofluids/HeatTransfer/lmtd.py +32 -0
- thermofluids/ProcessEquipment/Column.py +1004 -0
- thermofluids/ProcessEquipment/Compressor.py +167 -0
- thermofluids/ProcessEquipment/Ejector.py +145 -0
- thermofluids/ProcessEquipment/HeatExchanger.py +109 -0
- thermofluids/ProcessEquipment/IsoCompressor.py +124 -0
- thermofluids/ProcessEquipment/Pipe.py +21 -0
- thermofluids/ProcessEquipment/Pump.py +109 -0
- thermofluids/ProcessEquipment/Turbine.py +53 -0
- thermofluids/ProcessEquipment/Valve.py +35 -0
- thermofluids/ProcessEquipment/__init__.py +3 -0
- thermofluids/Utilities/FlowDiagram.py +111 -0
- thermofluids/Utilities/__init__.py +1 -0
- thermofluids/__init__.py +3 -0
- thermofluids-2.0.0.dist-info/METADATA +29 -0
- thermofluids-2.0.0.dist-info/RECORD +32 -0
- thermofluids-2.0.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,1191 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Written by Luke Erickson for Rebound Technology Jan 27 2015
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .Quantity import Quantity
|
|
6
|
+
from .ThermoExceptions import StatepointError
|
|
7
|
+
from CoolProp.CoolProp import PropsSI, HAPropsSI
|
|
8
|
+
import warnings
|
|
9
|
+
import numpy as np
|
|
10
|
+
from scipy.optimize import curve_fit
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Statepoint():
|
|
14
|
+
"""
|
|
15
|
+
A statepoint instance represents a thermofluid statepoint. It fully characterizes a fluid at a point.
|
|
16
|
+
Specify and two independent intensive properties and the rest will be automatically calculated.
|
|
17
|
+
Some extensive properties are also logged, such as mass flow rate.
|
|
18
|
+
This class uses CoolProp for the backend property lookups.
|
|
19
|
+
|
|
20
|
+
Do not change the properties of a statepoint once it has been fully defined- create a new instance instead.
|
|
21
|
+
|
|
22
|
+
:param name: Name of the statepoint for your own reference. Any string
|
|
23
|
+
:param fluid: Any CoolProp fluid. Can be a simple option like "water" or "R404A", an incompressible fluid like "INCOMP::MMA", or a Refprop fluid, if you have access to that library, like "REFPROP-MIX:METHANOL&WATER"
|
|
24
|
+
:param t: Temperature in Celcius
|
|
25
|
+
:param p: Pressure in bar
|
|
26
|
+
:param x: Quality in fraction 0-1. All liquid is 0, all vapor is 1.
|
|
27
|
+
:param h: Enthalpy in kJ/kg. Reference points are those from CoolProp/Refprop
|
|
28
|
+
:param s: Entropy kJ/kg-C
|
|
29
|
+
:param c: Concentration (used for INCOMP and REFPROP-MIX mixtures) kg/kg
|
|
30
|
+
:param m: Mass flow rate kg/s
|
|
31
|
+
:param twb: Wet bulb temperature C
|
|
32
|
+
:param tdp: Dew point temperature C
|
|
33
|
+
:param rh: Relative humidity -
|
|
34
|
+
:param omega: Humidity ratio kg water/kg dry air
|
|
35
|
+
:param source: Another statepoint instance to import properties from
|
|
36
|
+
:param source_vars: A tuple of strings of the properties you'd like to import from source
|
|
37
|
+
|
|
38
|
+
All the inputs are also available as attributes. Additional dependent attributes include:
|
|
39
|
+
* cp: heat capacity at constant pressure kJ/kg-C
|
|
40
|
+
* cv: heat capacity at constant volume kJ/kg-C
|
|
41
|
+
* rho: density kg/m^3
|
|
42
|
+
* u: internal energy kJ/kg
|
|
43
|
+
* gamma: heat capacity ratio
|
|
44
|
+
* k: thermal conductivity kW/m-C
|
|
45
|
+
* tlsat: saturation temperature of liquid aka bubble point C (Refprop only)
|
|
46
|
+
* tvsat: saturation temperature of vapor aka dew point C (Refprop only)
|
|
47
|
+
* cvap: equilibrium concentration of vapor for a liquid kg/kg (Refprop only)
|
|
48
|
+
* ss: speed of sound m/s
|
|
49
|
+
* visc: Dynamic viscosity (mu) kg/m-s^2
|
|
50
|
+
* pr: Prandtl number -
|
|
51
|
+
* sigma: surface tension N/m
|
|
52
|
+
* beta: coefficient of thermal expansion C^-1
|
|
53
|
+
* t_freeze: freezing temperature C
|
|
54
|
+
|
|
55
|
+
Statepoints can be added or divided (see methods below).
|
|
56
|
+
|
|
57
|
+
Examples:
|
|
58
|
+
* ``sp = Statepoint(fluid='water', t=25., p=1.) # water at room conditions``
|
|
59
|
+
* ``sp = Statepoint(fluid='INCOMP::MMA', t=-20., p=20., c=0.25, m=0.2) # flow of methanol and water``
|
|
60
|
+
* ``sp = Statepoint(fluid='REFPROP-MIX:METHANOL&WATER', x=0.8, p=0.25, c=0.95, m=1.5)``
|
|
61
|
+
* ``sp = Statepoint(source=sp, source_vars=('fluid', 'm', 't'), x=0) # import everything but quality from another statepoint``
|
|
62
|
+
|
|
63
|
+
Warnings:
|
|
64
|
+
You can set `Statepoint.allow_warnings = False` to suppress warnings
|
|
65
|
+
"""
|
|
66
|
+
out_of_bounds_flag = False
|
|
67
|
+
allow_warnings = True
|
|
68
|
+
|
|
69
|
+
def __init__(self, name=None, fluid=None, t=None, p=None, x=None, h=None, s=None, c=None, m=None,
|
|
70
|
+
twb=None, tdp=None, rh=None, omega=None, source=None, source_vars=()):
|
|
71
|
+
# type: (object, object) -> object
|
|
72
|
+
self.name = name
|
|
73
|
+
self.IVs = {}
|
|
74
|
+
self.IVs_formatted = False
|
|
75
|
+
self.fluid = fluid
|
|
76
|
+
self.coolprop_fluid = None
|
|
77
|
+
|
|
78
|
+
self.sink = []
|
|
79
|
+
self.source = []
|
|
80
|
+
|
|
81
|
+
self.nameisset = False
|
|
82
|
+
|
|
83
|
+
self.prints = ()
|
|
84
|
+
|
|
85
|
+
if t is not None:
|
|
86
|
+
self.set_t(t)
|
|
87
|
+
if p is not None:
|
|
88
|
+
self.set_p(p)
|
|
89
|
+
if x is not None:
|
|
90
|
+
self.set_x(x)
|
|
91
|
+
if h is not None:
|
|
92
|
+
self.set_h(h)
|
|
93
|
+
if s is not None:
|
|
94
|
+
self.set_s(s)
|
|
95
|
+
if c is not None:
|
|
96
|
+
if c < 0.000001:
|
|
97
|
+
self.set_c(0.000001)
|
|
98
|
+
else:
|
|
99
|
+
self.set_c(c)
|
|
100
|
+
if m is not None:
|
|
101
|
+
self.set_m(m)
|
|
102
|
+
if twb is not None:
|
|
103
|
+
self.set_twb(twb)
|
|
104
|
+
if tdp is not None:
|
|
105
|
+
self.set_tdp(tdp)
|
|
106
|
+
if rh is not None:
|
|
107
|
+
self.set_rh(rh)
|
|
108
|
+
if omega is not None:
|
|
109
|
+
self.set_omega(omega)
|
|
110
|
+
if source is not None:
|
|
111
|
+
self.set_source(source, source_vars)
|
|
112
|
+
|
|
113
|
+
def __add__(self, other):
|
|
114
|
+
"""
|
|
115
|
+
Adding two statepoints mixes them isenthalpically, conserving mass and energy. It assumes the higher pressure fluid is expanded to the lower pressure
|
|
116
|
+
The function returns another statepoint instance with fluid, mass, enthalpy, and pressure (and optionally concentration) set
|
|
117
|
+
"""
|
|
118
|
+
if other.__class__ is not Statepoint:
|
|
119
|
+
print((other.__class__))
|
|
120
|
+
raise TypeError('Can\'t add a Statepoint to anything other than a Statepoint')
|
|
121
|
+
|
|
122
|
+
#if other.fluid is not self.fluid: #This statement causes problems because the fluid name changes based on concentration and must be updated to remove that text before comparing
|
|
123
|
+
#raise StatepointError('Can\'t add statepoints of different fluids')
|
|
124
|
+
|
|
125
|
+
new = Statepoint(name=None)
|
|
126
|
+
new.set_fluid(self.fluid)
|
|
127
|
+
new.set_m(self.m + other.m)
|
|
128
|
+
new.set_h((self.m * self.h + other.m * other.h) / (self.m + other.m))
|
|
129
|
+
new.set_p(min(self.p, other.p))
|
|
130
|
+
if hasattr(self, 'c'):
|
|
131
|
+
new.set_c((self.c*self.m + other.c*other.m)/new.m)
|
|
132
|
+
|
|
133
|
+
return new
|
|
134
|
+
|
|
135
|
+
def __div__(self, other):
|
|
136
|
+
"""
|
|
137
|
+
Diving a statepoint by an integer divides the mass flow rate by the integer leaving all other properties equal
|
|
138
|
+
:param other: an integer
|
|
139
|
+
:return: new statepoint
|
|
140
|
+
"""
|
|
141
|
+
try:
|
|
142
|
+
return Statepoint(name=self.name, fluid=self.fluid, p=self.p, h=self.h, c=self.c, m=self.m/other)
|
|
143
|
+
except AttributeError:
|
|
144
|
+
return Statepoint(name=self.name, fluid=self.fluid, p=self.p, h=self.h, m=self.m/other)
|
|
145
|
+
|
|
146
|
+
def __truediv__(self, other):
|
|
147
|
+
"""
|
|
148
|
+
Diving a statepoint by an integer divides the mass flow rate by the integer leaving all other properties equal
|
|
149
|
+
:param other: an integer
|
|
150
|
+
:return: new statepoint
|
|
151
|
+
"""
|
|
152
|
+
try:
|
|
153
|
+
return Statepoint(name=self.name, fluid=self.fluid, p=self.p, h=self.h, c=self.c, m=self.m/other)
|
|
154
|
+
except AttributeError:
|
|
155
|
+
return Statepoint(name=self.name, fluid=self.fluid, p=self.p, h=self.h, m=self.m/other)
|
|
156
|
+
|
|
157
|
+
def _repr_default(self):
|
|
158
|
+
"""Lists several useful properties of the statepoint"""
|
|
159
|
+
repr = ''
|
|
160
|
+
try:
|
|
161
|
+
repr += self.fluid + '\t'
|
|
162
|
+
except AttributeError:
|
|
163
|
+
pass
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
repr += str(self.m) + '\t'
|
|
167
|
+
except AttributeError:
|
|
168
|
+
pass
|
|
169
|
+
|
|
170
|
+
try:
|
|
171
|
+
repr += str(self.t) + '\t'
|
|
172
|
+
except AttributeError:
|
|
173
|
+
pass
|
|
174
|
+
|
|
175
|
+
try:
|
|
176
|
+
repr += f'{self.c*100.: .1f}%' + '\t'
|
|
177
|
+
except AttributeError:
|
|
178
|
+
pass
|
|
179
|
+
|
|
180
|
+
try:
|
|
181
|
+
repr += str(self.p) + '\t'
|
|
182
|
+
except AttributeError:
|
|
183
|
+
pass
|
|
184
|
+
|
|
185
|
+
return repr
|
|
186
|
+
|
|
187
|
+
def print_options(self, tuple_of_prints=()):
|
|
188
|
+
self.prints = tuple_of_prints
|
|
189
|
+
|
|
190
|
+
def __repr__(self):
|
|
191
|
+
"""Statepoint_name\tfluid_name\tmdot\ttemp\tconc\tenthalpy"""
|
|
192
|
+
if len(self.prints) == 0:
|
|
193
|
+
return self._repr_default()
|
|
194
|
+
else:
|
|
195
|
+
repr = ""
|
|
196
|
+
for var in self.prints:
|
|
197
|
+
repr = repr+'\t'+str(getattr(self, var))
|
|
198
|
+
return repr
|
|
199
|
+
|
|
200
|
+
def warn_out_of_bounds(self):
|
|
201
|
+
if Statepoint.allow_warnings:
|
|
202
|
+
if not Statepoint.out_of_bounds_flag:
|
|
203
|
+
Statepoint.out_of_bounds_flag = True
|
|
204
|
+
warnings.warn('Using extrapolated property data. Accuracy may be diminished.')
|
|
205
|
+
|
|
206
|
+
def set_fluid(self, fluid):
|
|
207
|
+
self.fluid = fluid
|
|
208
|
+
|
|
209
|
+
def set_t(self, val, unit='degC'):
|
|
210
|
+
if hasattr(self, '_t'):
|
|
211
|
+
self.update_prop(prop_val=val, prop_name='t')
|
|
212
|
+
else:
|
|
213
|
+
if val.__class__ == Quantity:
|
|
214
|
+
self._t = val
|
|
215
|
+
else:
|
|
216
|
+
self._t = Quantity(val, unit)
|
|
217
|
+
self.IVs['T'] = self._t
|
|
218
|
+
|
|
219
|
+
def set_h(self, val, unit='kJ*kg^-1'):
|
|
220
|
+
if hasattr(self, '_h'):
|
|
221
|
+
self.update_prop(prop_val=val, prop_name='h')
|
|
222
|
+
else:
|
|
223
|
+
if val.__class__ == Quantity:
|
|
224
|
+
self._h = val
|
|
225
|
+
else:
|
|
226
|
+
self._h = Quantity(val, unit)
|
|
227
|
+
self.IVs['H'] = self._h
|
|
228
|
+
|
|
229
|
+
def set_s(self, val, unit='degC^-1*kJ*kg^-1'):
|
|
230
|
+
if hasattr(self, '_s'):
|
|
231
|
+
self.update_prop(prop_val=val, prop_name='s')
|
|
232
|
+
else:
|
|
233
|
+
if val.__class__ == Quantity:
|
|
234
|
+
self._s = val
|
|
235
|
+
else:
|
|
236
|
+
self._s = Quantity(val, unit)
|
|
237
|
+
self.IVs['S'] = self._s
|
|
238
|
+
|
|
239
|
+
def set_p(self, val, unit='bar'):
|
|
240
|
+
if hasattr(self, '_p'):
|
|
241
|
+
self.update_prop(prop_val=val, prop_name='p')
|
|
242
|
+
else:
|
|
243
|
+
if val.__class__ == Quantity:
|
|
244
|
+
self._p = val
|
|
245
|
+
else:
|
|
246
|
+
self._p = Quantity(val, unit)
|
|
247
|
+
self.IVs['P'] = self._p
|
|
248
|
+
|
|
249
|
+
def set_x(self, val, unit=''):
|
|
250
|
+
if hasattr(self, '_x'):
|
|
251
|
+
self.update_prop(prop_val=val, prop_name='x')
|
|
252
|
+
else:
|
|
253
|
+
if val.__class__ == Quantity:
|
|
254
|
+
self._x = val
|
|
255
|
+
else:
|
|
256
|
+
self._x = Quantity(val, unit)
|
|
257
|
+
self.IVs['Q'] = self._x
|
|
258
|
+
|
|
259
|
+
def set_c(self, val, unit=''):
|
|
260
|
+
if val < 0.000001:
|
|
261
|
+
val = 0.000001
|
|
262
|
+
if val.__class__ == Quantity:
|
|
263
|
+
self.c = val.to('').magnitude
|
|
264
|
+
else:
|
|
265
|
+
# self.c = Quantity(val, unit)
|
|
266
|
+
self.c = val
|
|
267
|
+
|
|
268
|
+
def set_m(self, val, unit='kg*s^-1'):
|
|
269
|
+
if val.__class__ == Quantity:
|
|
270
|
+
self.m = val
|
|
271
|
+
else:
|
|
272
|
+
self.m = Quantity(val, unit)
|
|
273
|
+
|
|
274
|
+
def set_twb(self, val, unit='degC'):
|
|
275
|
+
if hasattr(self, '_twb'):
|
|
276
|
+
self.update_prop(prop_val=val, prop_name='twb')
|
|
277
|
+
else:
|
|
278
|
+
if val.__class__ == Quantity:
|
|
279
|
+
self._twb = val
|
|
280
|
+
else:
|
|
281
|
+
self._twb = Quantity(val, unit)
|
|
282
|
+
self.IVs['Twb'] = self._twb
|
|
283
|
+
|
|
284
|
+
def set_tdp(self, val, unit='degC'):
|
|
285
|
+
if hasattr(self, '_tdp'):
|
|
286
|
+
self.update_prop(prop_val=val, prop_name='tdp')
|
|
287
|
+
else:
|
|
288
|
+
if val.__class__ == Quantity:
|
|
289
|
+
self._tdp = val
|
|
290
|
+
else:
|
|
291
|
+
self._tdp = Quantity(val, unit)
|
|
292
|
+
self.IVs['Tdp'] = self._tdp
|
|
293
|
+
|
|
294
|
+
def set_rh(self, val, unit=''):
|
|
295
|
+
if hasattr(self, '_rh'):
|
|
296
|
+
self.update_prop(prop_val=val, prop_name='rh')
|
|
297
|
+
else:
|
|
298
|
+
if val.__class__ == Quantity:
|
|
299
|
+
self._rh = val
|
|
300
|
+
else:
|
|
301
|
+
self._rh = Quantity(val, unit)
|
|
302
|
+
self.IVs['RH'] = self._rh
|
|
303
|
+
|
|
304
|
+
def set_omega(self, val, unit=''):
|
|
305
|
+
if hasattr(self, '_omega'):
|
|
306
|
+
self.update_prop(prop_val=val, prop_name='omega')
|
|
307
|
+
else:
|
|
308
|
+
if val.__class__ == Quantity:
|
|
309
|
+
self._omega = val
|
|
310
|
+
else:
|
|
311
|
+
self._omega = Quantity(val, unit)
|
|
312
|
+
self.IVs['Omega'] = self._omega
|
|
313
|
+
|
|
314
|
+
def _formatIVs(self):
|
|
315
|
+
if self.fluid == None:
|
|
316
|
+
raise StatepointError("Fluid must be set (statepoint.set_fluid(val)) before calling properties")
|
|
317
|
+
self.cpargs = []
|
|
318
|
+
for key in self.IVs:
|
|
319
|
+
self.cpargs.append(key)
|
|
320
|
+
self.cpargs.append(self.IVs[key].to_base_units().magnitude)
|
|
321
|
+
if len(self.cpargs) != 4 and self.fluid != 'humid air':
|
|
322
|
+
raise StatepointError('%s statepoint requires 2 independent properties to be set. Only %s is set'
|
|
323
|
+
% (self.name, list(self.IVs.keys())))
|
|
324
|
+
if len(self.cpargs) != 6 and self.fluid == 'humid air':
|
|
325
|
+
raise StatepointError('%s statepoint requires 3 independent properties to be set. Only %s is set'
|
|
326
|
+
% (self.name, list(self.IVs.keys())))
|
|
327
|
+
|
|
328
|
+
# if hasattr(self, 'c') and self.fluid[-1] != ']':
|
|
329
|
+
if hasattr(self, 'c'):
|
|
330
|
+
if 'REFPROP' in self.fluid:
|
|
331
|
+
mw1 = PropsSI('M', 'T', 273, 'P', 101325., self.fluid[self.fluid.find('&')+1:self.fluid.__len__()])
|
|
332
|
+
mw2 = PropsSI('M', 'T', 273, 'P', 101325, self.fluid[self.fluid.find(':')+1:self.fluid.find('&')])
|
|
333
|
+
if float(self.c) == 0.0:
|
|
334
|
+
c_mol = 0.0
|
|
335
|
+
else:
|
|
336
|
+
c_mol = (self.c / mw2) / (self.c / mw2 + (1.-self.c) / mw1)
|
|
337
|
+
self.coolprop_fluid = self.fluid.replace('&', '[%s]&'%str(c_mol).strip()) + '[%s]'%str(1.0-c_mol).strip()
|
|
338
|
+
self.nameisset = True
|
|
339
|
+
else:
|
|
340
|
+
self.coolprop_fluid = self.fluid + '[%s]' % str(self.c).strip()
|
|
341
|
+
self.nameisset = True
|
|
342
|
+
else:
|
|
343
|
+
self.coolprop_fluid = self.fluid
|
|
344
|
+
self.nameisset = True
|
|
345
|
+
|
|
346
|
+
@property
|
|
347
|
+
def tmax(self): # Maximum t for dataset
|
|
348
|
+
if hasattr(self, '_tmax'):
|
|
349
|
+
return self._tmax
|
|
350
|
+
if not self.IVs_formatted:
|
|
351
|
+
self._formatIVs()
|
|
352
|
+
if '[' in self.fluid:
|
|
353
|
+
local_fluid = self.fluid.split('[')[0]
|
|
354
|
+
else:
|
|
355
|
+
local_fluid = self.fluid
|
|
356
|
+
if self.fluid == 'humid air':
|
|
357
|
+
val = 187. # not documented, just guess and tested
|
|
358
|
+
else:
|
|
359
|
+
val = PropsSI('Tmax', 'T', 298., 'P', 1.e5, local_fluid)-273.15
|
|
360
|
+
self._tmax = Quantity(val, 'degC')
|
|
361
|
+
return self._tmax
|
|
362
|
+
|
|
363
|
+
@property
|
|
364
|
+
def tmin(self): # Minimum t for dataset
|
|
365
|
+
if hasattr(self, '_tmin'):
|
|
366
|
+
return self._tmin
|
|
367
|
+
if not self.IVs_formatted:
|
|
368
|
+
self._formatIVs()
|
|
369
|
+
if '[' in self.fluid:
|
|
370
|
+
local_fluid = self.fluid.split('[')[0]
|
|
371
|
+
else:
|
|
372
|
+
local_fluid = self.fluid
|
|
373
|
+
if self.fluid == 'humid air':
|
|
374
|
+
val = -223. # not documented, just guess and tested
|
|
375
|
+
else:
|
|
376
|
+
val = PropsSI('Tmin', 'T', 298., 'P', 1.e5, local_fluid)-273.15
|
|
377
|
+
self._tmin = Quantity(val, 'degC')
|
|
378
|
+
return self._tmin
|
|
379
|
+
|
|
380
|
+
@property
|
|
381
|
+
def pmax(self): # Maximum p for dataset
|
|
382
|
+
if hasattr(self, '_pmax'):
|
|
383
|
+
return self._pmax
|
|
384
|
+
if not self.IVs_formatted:
|
|
385
|
+
self._formatIVs()
|
|
386
|
+
if self.fluid == 'humid air':
|
|
387
|
+
val = 1000. # not documented, just guess and tested
|
|
388
|
+
else:
|
|
389
|
+
val = PropsSI('Pmax', 'T', 298., 'P', 1.e5, self.coolprop_fluid) / 1.e5
|
|
390
|
+
self._pmax = Quantity(val, 'bar')
|
|
391
|
+
return self._pmax
|
|
392
|
+
|
|
393
|
+
@property
|
|
394
|
+
def pmin(self): # Minimum p for dataset
|
|
395
|
+
if hasattr(self, '_pmin'):
|
|
396
|
+
return self._pmin
|
|
397
|
+
if not self.IVs_formatted:
|
|
398
|
+
self._formatIVs()
|
|
399
|
+
if self.fluid == 'humid air':
|
|
400
|
+
val = 0.0001 # not documented, just guess and tested
|
|
401
|
+
else:
|
|
402
|
+
val = PropsSI('Pmin', 'T', 298., 'P', 1.e5, self.coolprop_fluid) / 1.e5
|
|
403
|
+
self._pmin = Quantity(val, 'bar')
|
|
404
|
+
return self._pmin
|
|
405
|
+
|
|
406
|
+
@property
|
|
407
|
+
def cmax(self): # Maximum c for dataset
|
|
408
|
+
if hasattr(self, '_cmax'):
|
|
409
|
+
return self._cmax
|
|
410
|
+
if not self.IVs_formatted:
|
|
411
|
+
self._formatIVs()
|
|
412
|
+
if self.fluid == 'humid air':
|
|
413
|
+
val = None
|
|
414
|
+
else:
|
|
415
|
+
val = PropsSI('fraction_max', 'T', 298., 'P', 1.e5, self.coolprop_fluid)
|
|
416
|
+
self._cmax = Quantity(val, '')
|
|
417
|
+
return self._cmax
|
|
418
|
+
|
|
419
|
+
@property
|
|
420
|
+
def cmin(self): # Minimum c for dataset
|
|
421
|
+
if hasattr(self, '_cmin'):
|
|
422
|
+
return self._cmin
|
|
423
|
+
if not self.IVs_formatted:
|
|
424
|
+
self._formatIVs()
|
|
425
|
+
if self.fluid == 'humid air':
|
|
426
|
+
val = None
|
|
427
|
+
else:
|
|
428
|
+
val = PropsSI('fraction_min', 'T', 298., 'P', 1.e5, self.coolprop_fluid)
|
|
429
|
+
self._cmin = Quantity(val, '')
|
|
430
|
+
return self._cmin
|
|
431
|
+
|
|
432
|
+
@property
|
|
433
|
+
def t(self): # Temperature
|
|
434
|
+
if hasattr(self, '_t'):
|
|
435
|
+
return self._t
|
|
436
|
+
if not self.IVs_formatted:
|
|
437
|
+
self._formatIVs()
|
|
438
|
+
try:
|
|
439
|
+
if self.fluid == 'humid air':
|
|
440
|
+
val = HAPropsSI('T', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.cpargs[4], self.cpargs[5]) - 273.15
|
|
441
|
+
else:
|
|
442
|
+
val = PropsSI('T', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.coolprop_fluid)-273.15
|
|
443
|
+
self._t = Quantity(val, 'degC')
|
|
444
|
+
return self._t
|
|
445
|
+
except ValueError as e:
|
|
446
|
+
if not hasattr(self, 'c'): # only use extrapolated data for salt brines
|
|
447
|
+
raise e
|
|
448
|
+
elif 'H' in self.cpargs and 'P' in self.cpargs:
|
|
449
|
+
cp_at_20C_below_max = PropsSI('C', 'T', self.tmax.to('degC').magnitude - 20. + 273.15, 'P', 1.e5, self.coolprop_fluid) / 1000.
|
|
450
|
+
cp_at_max = PropsSI('C', 'T', self.tmax.to('degC').magnitude + 273.15, 'P', 1.e5, self.coolprop_fluid) / 1000.
|
|
451
|
+
h_at_tmax = PropsSI('H', 'T', self.tmax.to('degC').magnitude + 273.15, 'P', 1.e5, self.coolprop_fluid) / 1000.
|
|
452
|
+
|
|
453
|
+
# solve the extrapolation equations for enthalpy and cp for t
|
|
454
|
+
val = (40.**0.5 * (10. * cp_at_max**2. + cp_at_max * (self.h.magnitude - h_at_tmax) + cp_at_20C_below_max * (h_at_tmax - self.h.magnitude))**0.5 +
|
|
455
|
+
cp_at_max * (self.tmax.magnitude - 20.) - cp_at_20C_below_max * self.tmax.magnitude) / (cp_at_max - cp_at_20C_below_max)
|
|
456
|
+
self._t = Quantity(val, 'degC')
|
|
457
|
+
return self._t
|
|
458
|
+
else:
|
|
459
|
+
raise ValueError(f'No temperature extrapolation data for incompressible fluids unless using P and H inputs. Got {self.cpargs} instead')
|
|
460
|
+
|
|
461
|
+
@property
|
|
462
|
+
def p(self): # Pressure
|
|
463
|
+
if hasattr(self, '_p'):
|
|
464
|
+
return self._p
|
|
465
|
+
if not self.IVs_formatted:
|
|
466
|
+
self._formatIVs()
|
|
467
|
+
if self.fluid == 'humid air':
|
|
468
|
+
val = HAPropsSI('P', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.cpargs[4], self.cpargs[5]) / 100000.
|
|
469
|
+
else:
|
|
470
|
+
val = PropsSI('P', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.coolprop_fluid) / 100000.
|
|
471
|
+
self._p = Quantity(val, 'bar')
|
|
472
|
+
return self._p
|
|
473
|
+
|
|
474
|
+
@property
|
|
475
|
+
def h(self): # Enthalpy
|
|
476
|
+
if hasattr(self, '_h'):
|
|
477
|
+
return self._h
|
|
478
|
+
if not self.IVs_formatted:
|
|
479
|
+
self._formatIVs()
|
|
480
|
+
if self.tmin <= self.t <= self.tmax:
|
|
481
|
+
if self.fluid == 'humid air':
|
|
482
|
+
# print(self.cpargs)
|
|
483
|
+
val = HAPropsSI('Hha', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.cpargs[4], self.cpargs[5]) / 1000.
|
|
484
|
+
else:
|
|
485
|
+
val = PropsSI('H', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.coolprop_fluid) / 1000.
|
|
486
|
+
self._h = Quantity(val, 'kJ*kg^-1')
|
|
487
|
+
return self._h
|
|
488
|
+
elif hasattr(self, 'c') and self.t > self.tmax:
|
|
489
|
+
"""
|
|
490
|
+
Integrate extrapolated cp over t. See cp function for more info about extrapolation of cp.
|
|
491
|
+
Assumes cp extrapolation is linear.
|
|
492
|
+
"""
|
|
493
|
+
self.warn_out_of_bounds()
|
|
494
|
+
cp_at_t = self.cp.magnitude
|
|
495
|
+
cp_at_tmax = PropsSI('C', 'T', self.tmax.to('degC').magnitude+273.15, 'P', 1.e5, self.coolprop_fluid) / 1000.
|
|
496
|
+
h_at_tmax = PropsSI('H', 'T', self.tmax.to('degC').magnitude+273.15, 'P', 1.e5, self.coolprop_fluid) / 1000.
|
|
497
|
+
val = h_at_tmax + (cp_at_t + cp_at_tmax) * (self.t - self.tmax).magnitude / 2.
|
|
498
|
+
self._h = Quantity(val, 'kJ*kg^-1')
|
|
499
|
+
return self._h
|
|
500
|
+
else:
|
|
501
|
+
raise ValueError(f'Temperature {self.t} is not within data range {self.tmin}-{self.tmax} and no extrapolation has been created')
|
|
502
|
+
|
|
503
|
+
@property
|
|
504
|
+
def s(self): # Entropy
|
|
505
|
+
if hasattr(self, '_s'):
|
|
506
|
+
return self._s
|
|
507
|
+
if not self.IVs_formatted:
|
|
508
|
+
self._formatIVs()
|
|
509
|
+
if self.tmin <= self.t <= self.tmax:
|
|
510
|
+
if self.fluid == 'humid air':
|
|
511
|
+
val = HAPropsSI('Sha', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.cpargs[4], self.cpargs[5]) / 1000.
|
|
512
|
+
else:
|
|
513
|
+
val = PropsSI('S', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.coolprop_fluid) / 1000.
|
|
514
|
+
elif hasattr(self, 'c') and self.t > self.tmax: # extrapolate for high temp salt mixes
|
|
515
|
+
s_at_tmax = PropsSI('S', 'T', self.tmax.to('degC').magnitude+273.15, 'P', 1.e5, self.coolprop_fluid) / 1000.
|
|
516
|
+
s_at_tmax_minus_10 = PropsSI('S', 'T', self.tmax.to('degC').magnitude+263.15, 'P', 1.e5, self.coolprop_fluid) / 1000.
|
|
517
|
+
val = s_at_tmax + (s_at_tmax - s_at_tmax_minus_10) / 10. * (self.t - self.tmax).magnitude
|
|
518
|
+
else:
|
|
519
|
+
raise ValueError('No entropy data available at these conditions, and no extrapolation has been created')
|
|
520
|
+
self._s = Quantity(val, 'delta_degC^-1*kJ*kg^-1')
|
|
521
|
+
return self._s
|
|
522
|
+
|
|
523
|
+
@property
|
|
524
|
+
def cp(self): # Heat capacity at const pressure
|
|
525
|
+
if hasattr(self, '_cp'):
|
|
526
|
+
return self._cp
|
|
527
|
+
if not self.IVs_formatted:
|
|
528
|
+
self._formatIVs()
|
|
529
|
+
if self.tmin <= self.t <= self.tmax:
|
|
530
|
+
if self.fluid == 'humid air':
|
|
531
|
+
val = HAPropsSI('Cha', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.cpargs[4], self.cpargs[5]) / 1000.
|
|
532
|
+
else:
|
|
533
|
+
val = PropsSI('C', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.coolprop_fluid) / 1000.
|
|
534
|
+
self._cp = Quantity(val, 'delta_degC^-1*kJ*kg^-1')
|
|
535
|
+
return self._cp
|
|
536
|
+
elif hasattr(self, 'c') and self.t > self.tmax: # extrapolate for salt mixtures above the data range
|
|
537
|
+
"""
|
|
538
|
+
linearly extrapolate cp as a function of temperature, holding p and c constant
|
|
539
|
+
based on my (Luke's) testing, this seems to be within a few percent up to the boiling pointish
|
|
540
|
+
if you change this extrapolation, you also need to change the enthalpy and temperature function because they assumes linear extrapolation
|
|
541
|
+
"""
|
|
542
|
+
self.warn_out_of_bounds()
|
|
543
|
+
cp_at_20C_below_max = PropsSI('C', 'T', self.tmax.to('degC').magnitude-20.+273.15, 'P', 1.e5, self.coolprop_fluid) / 1000.
|
|
544
|
+
cp_at_max = PropsSI('C', 'T', self.tmax.to('degC').magnitude+273.15, 'P', 1.e5, self.coolprop_fluid) / 1000.
|
|
545
|
+
val = cp_at_max + (cp_at_max - cp_at_20C_below_max) / 20. * (self.t - self.tmax).magnitude
|
|
546
|
+
self._cp = Quantity(val, 'delta_degC^-1*kJ*kg^-1')
|
|
547
|
+
return self._cp
|
|
548
|
+
else:
|
|
549
|
+
raise ValueError('Temperature %0.1f is not within data range %0.1f-%0.1f and no extrapolation has been created' % (self.t, self.tmin, self.tmax))
|
|
550
|
+
|
|
551
|
+
@property
|
|
552
|
+
def rho(self): # density
|
|
553
|
+
if hasattr(self, '_rho'):
|
|
554
|
+
return self._rho
|
|
555
|
+
if not self.IVs_formatted:
|
|
556
|
+
self._formatIVs()
|
|
557
|
+
if self.tmin <= self.t <= self.tmax:
|
|
558
|
+
if self.fluid == 'humid air':
|
|
559
|
+
val = 1. / HAPropsSI('Vha', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.cpargs[4], self.cpargs[5])
|
|
560
|
+
else:
|
|
561
|
+
val = PropsSI('D', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.coolprop_fluid)
|
|
562
|
+
self._rho = Quantity(val, 'kg*m^-3')
|
|
563
|
+
return self._rho
|
|
564
|
+
elif hasattr(self, 'c') and self.t > self.tmax: # extrapolate for salt mixtures above the data range
|
|
565
|
+
"""
|
|
566
|
+
Assume density decreases at the same rate as pure water
|
|
567
|
+
"""
|
|
568
|
+
rho_water_at_tmax = PropsSI('D', 'T', self.tmax.to('degC').magnitude+273.15, 'P', 1.e5, 'water')
|
|
569
|
+
if self.t < Quantity(99.6, 'degC'):
|
|
570
|
+
rho_water_at_t = PropsSI('D', 'T', self.t+273.15, 'P', 1.e5, 'water')
|
|
571
|
+
else:
|
|
572
|
+
rho_water_at_t = PropsSI('D', 'T', self.t+273.15, 'Q', 0., 'water')
|
|
573
|
+
rho_at_tmax = PropsSI('D', 'T', self.tmax.to('degC').magnitude+273.15, 'P', 1.e5, self.coolprop_fluid)
|
|
574
|
+
val = rho_at_tmax + rho_water_at_t - rho_water_at_tmax
|
|
575
|
+
self._rho = Quantity(val, 'kg*m^-3')
|
|
576
|
+
return self._rho
|
|
577
|
+
else:
|
|
578
|
+
raise ValueError('Temperature %0.1f is not within data range %0.1f-%0.1f and no extrapolation has been created' % (self.t, self.tmin, self.tmax))
|
|
579
|
+
|
|
580
|
+
@property
|
|
581
|
+
def u(self): # internal energy
|
|
582
|
+
if hasattr(self, '_u'):
|
|
583
|
+
return self._u
|
|
584
|
+
if not self.IVs_formatted:
|
|
585
|
+
self._formatIVs()
|
|
586
|
+
if self.fluid == 'humid air':
|
|
587
|
+
val = HAPropsSI('U', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.cpargs[4], self.cpargs[5]) / 1000.
|
|
588
|
+
else:
|
|
589
|
+
val = PropsSI('U', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.coolprop_fluid) / 1000.
|
|
590
|
+
self._u = Quantity(val, 'kJ*kg^-1')
|
|
591
|
+
return self._u
|
|
592
|
+
|
|
593
|
+
@property
|
|
594
|
+
def cv(self): # Heat capacity at const volume
|
|
595
|
+
if hasattr(self, '_cv'):
|
|
596
|
+
return self._cv
|
|
597
|
+
if not self.IVs_formatted:
|
|
598
|
+
self._formatIVs()
|
|
599
|
+
if self.fluid == 'humid air':
|
|
600
|
+
val = HAPropsSI('CVMASS', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.cpargs[4], self.cpargs[5]) / 1000.
|
|
601
|
+
else:
|
|
602
|
+
val = PropsSI('CVMASS', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.coolprop_fluid) / 1000.
|
|
603
|
+
self._cv = Quantity(val, 'delta_degC^-1*kJ*kg^-1')
|
|
604
|
+
return self._cv
|
|
605
|
+
|
|
606
|
+
@property
|
|
607
|
+
def gamma(self): # Heat capacity ratio
|
|
608
|
+
if hasattr(self, '_gamma'):
|
|
609
|
+
return self._gamma
|
|
610
|
+
self._gamma = self.cp / self.cv
|
|
611
|
+
return self._gamma
|
|
612
|
+
|
|
613
|
+
@property
|
|
614
|
+
def k(self): # Thermal conductivity
|
|
615
|
+
if hasattr(self, '_k'):
|
|
616
|
+
return self._k
|
|
617
|
+
if not self.IVs_formatted:
|
|
618
|
+
self._formatIVs()
|
|
619
|
+
try:
|
|
620
|
+
if self.fluid == 'humid air':
|
|
621
|
+
val = HAPropsSI('L', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.cpargs[4], self.cpargs[5]) / 1000.
|
|
622
|
+
else:
|
|
623
|
+
val = PropsSI('L', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.coolprop_fluid) / 1000.
|
|
624
|
+
except ValueError as e:
|
|
625
|
+
if 'METHANOL' in self.fluid and self.x < 0:
|
|
626
|
+
local_fluid = 'INCOMP::MMA[%f]' % self.c
|
|
627
|
+
val = PropsSI('L', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], local_fluid) / 1000.
|
|
628
|
+
elif hasattr(self, 'c') and self.fluid[:4] == 'REFP':
|
|
629
|
+
newFluid = self.coolprop_fluid.split(':')[1].split('&')[1].split('[')[0]
|
|
630
|
+
if Statepoint.allow_warnings:
|
|
631
|
+
warnings.warn('Using %s to get thermal conductivity because no properties available for %s' % (newFluid, self.coolprop_fluid))
|
|
632
|
+
if 0. <= self.x <= 1.:
|
|
633
|
+
# if the fluid is saturated, use the same pressure and quality with just the first fluid, not a mixture
|
|
634
|
+
newSP = Statepoint(fluid=newFluid, p=self.p, x=self.x)
|
|
635
|
+
val = newSP.k.magnitude
|
|
636
|
+
else:
|
|
637
|
+
# if the fluid is not saturated, set it to the same pressure and the same delta from the saturation temp
|
|
638
|
+
tSatOld = Statepoint(fluid=self.coolprop_fluid, p=self.p, x=0.).t
|
|
639
|
+
tSatNew = Statepoint(fluid=newFluid, p=self.p, x=0.).t
|
|
640
|
+
newSP = Statepoint(fluid=newFluid, p=self.p, t=tSatNew + self.t - tSatOld)
|
|
641
|
+
val = newSP.k.magnitude
|
|
642
|
+
elif hasattr(self, 'c') and self.t > self.tmax: # extrapolate for salt mixtures above the data range
|
|
643
|
+
"""
|
|
644
|
+
Assume density decreases at the same rate as pure water
|
|
645
|
+
"""
|
|
646
|
+
k_water_at_tmax = PropsSI('L', 'T', self.tmax.to('degC').magnitude+273.15, 'P', 1.e5, 'water') / 1000.
|
|
647
|
+
if self.t < 99.6:
|
|
648
|
+
k_water_at_t = PropsSI('L', 'T', self.t+273.15, 'P', 1.e5, 'water') / 1000.
|
|
649
|
+
else:
|
|
650
|
+
k_water_at_t = PropsSI('L', 'T', self.t+273.15, 'Q', 0., 'water') / 1000.
|
|
651
|
+
k_at_tmax = PropsSI('L', 'T', self.tmax.to('degC').magnitude+273.15, 'P', 1.e5, self.coolprop_fluid) / 1000.
|
|
652
|
+
val = k_at_tmax + k_water_at_t - k_water_at_tmax
|
|
653
|
+
else:
|
|
654
|
+
raise ValueError('Conductivity inputs are out of range and there are no extrapolations available')
|
|
655
|
+
self._k = Quantity(val, 'delta_degC^-1*kJ*s^-1*m^-1')
|
|
656
|
+
return self._k
|
|
657
|
+
|
|
658
|
+
@property
|
|
659
|
+
def x(self): # Quality (vapor fraction by mass)
|
|
660
|
+
if hasattr(self, '_x'):
|
|
661
|
+
return self._x
|
|
662
|
+
if not self.IVs_formatted:
|
|
663
|
+
self._formatIVs()
|
|
664
|
+
if self.fluid == 'humid air':
|
|
665
|
+
raise Exception('Quality not defined for humid air')
|
|
666
|
+
val = PropsSI('Q', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.coolprop_fluid)
|
|
667
|
+
self._x = Quantity(val, '')
|
|
668
|
+
return self._x
|
|
669
|
+
|
|
670
|
+
@property
|
|
671
|
+
def tlsat(self): #
|
|
672
|
+
if hasattr(self, '_tlsat'):
|
|
673
|
+
return self._tlsat
|
|
674
|
+
if not self.IVs_formatted:
|
|
675
|
+
self._formatIVs()
|
|
676
|
+
if 'REFPROP' not in self.fluid:
|
|
677
|
+
raise Exception('saturation properties only availible for REFPROP fluids')
|
|
678
|
+
val = PropsSI('T', 'Q', 0.0, 'P', self.p.to_base_units(), self.coolprop_fluid)-273.15
|
|
679
|
+
self._tlsat = Quantity(val, 'degC')
|
|
680
|
+
return self._tlsat
|
|
681
|
+
|
|
682
|
+
@property
|
|
683
|
+
def tvsat(self): #
|
|
684
|
+
if hasattr(self, '_tvsat'):
|
|
685
|
+
return self._tvsat
|
|
686
|
+
if not self.IVs_formatted:
|
|
687
|
+
self._formatIVs()
|
|
688
|
+
if 'REFPROP' not in self.fluid:
|
|
689
|
+
raise Exception('saturation properties only availible for REFPROP fluids')
|
|
690
|
+
val = PropsSI('T', 'Q', 1.0, 'P', self.p.to_base_units(), self.coolprop_fluid)-273.15
|
|
691
|
+
self._tvsat = Quantity(val, 'degC')
|
|
692
|
+
return self._tvsat
|
|
693
|
+
|
|
694
|
+
@property
|
|
695
|
+
def cvap(self): #
|
|
696
|
+
if hasattr(self, '_cvap'):
|
|
697
|
+
return self._cvap
|
|
698
|
+
if not self.IVs_formatted:
|
|
699
|
+
self._formatIVs()
|
|
700
|
+
if 'REFPROP' not in self.fluid:
|
|
701
|
+
raise Exception('saturation properties only availible for REFPROP fluids')
|
|
702
|
+
|
|
703
|
+
tlsat = PropsSI('T', 'Q', 0.0, 'P', self.p.to_base_units(), self.coolprop_fluid)-273.15
|
|
704
|
+
res = 1.
|
|
705
|
+
c_int = self.c
|
|
706
|
+
count = 0
|
|
707
|
+
fluid = self.coolprop_fluid
|
|
708
|
+
while res>0.001:
|
|
709
|
+
count = count + 1
|
|
710
|
+
fluid = fluid[0:fluid.find('[')] + fluid[fluid.find('&'):fluid.rfind('[')]
|
|
711
|
+
|
|
712
|
+
mw1 = PropsSI('M', 'T', 273, 'P', 101325., self.coolprop_fluid[self.coolprop_fluid.find('&')+1:self.coolprop_fluid.__len__()])
|
|
713
|
+
mw2 = PropsSI('M', 'T', 273, 'P', 101325, self.coolprop_fluid[self.coolprop_fluid.find(':')+1:self.coolprop_fluid.find('&')])
|
|
714
|
+
c_mol = (c_int / mw2) / (c_int / mw2 + (1.-c_int) / mw1)
|
|
715
|
+
|
|
716
|
+
fluid = fluid.replace('&', '[%s]&'%str(c_mol).strip()) + '[%s]'%str(1.-c_mol).strip()
|
|
717
|
+
tvsat = PropsSI('T', 'Q', 1.0, 'P', self.p.to_base_units(), fluid)-273.15
|
|
718
|
+
c_last = c_int
|
|
719
|
+
c_int = c_last+(tvsat-tlsat)/500.
|
|
720
|
+
res = abs((c_int-c_last)/c_int)
|
|
721
|
+
if count > 500:
|
|
722
|
+
raise Exception('vapor composition did not converge after 500 iterations')
|
|
723
|
+
|
|
724
|
+
try:
|
|
725
|
+
self._cvap = Quantity(c_int, '')
|
|
726
|
+
except:
|
|
727
|
+
self._cvap = c_int
|
|
728
|
+
return self._cvap
|
|
729
|
+
|
|
730
|
+
@property
|
|
731
|
+
def ss(self): # Speed of sound
|
|
732
|
+
if hasattr(self, '_ss'):
|
|
733
|
+
return self._ss
|
|
734
|
+
if not self.IVs_formatted:
|
|
735
|
+
self._formatIVs()
|
|
736
|
+
if self.fluid == 'humid air':
|
|
737
|
+
raise Exception('CoolProp doesn\'t provide data for humid air speed of sound')
|
|
738
|
+
val = PropsSI('speed_of_sound', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.coolprop_fluid)
|
|
739
|
+
self._ss = Quantity(val, 'm*s^-1')
|
|
740
|
+
return self._ss
|
|
741
|
+
|
|
742
|
+
@property
|
|
743
|
+
def visc(self): # Dyanmic viscosity
|
|
744
|
+
def exp_func(t, mu0, E):
|
|
745
|
+
return mu0 * np.exp(E / (8.314 * (t + 273.15)))
|
|
746
|
+
|
|
747
|
+
if (hasattr(self, '_visc')):
|
|
748
|
+
return self._visc
|
|
749
|
+
if not self.IVs_formatted:
|
|
750
|
+
self._formatIVs()
|
|
751
|
+
if self.tmin <= self.t <= self.tmax:
|
|
752
|
+
if self.fluid == 'humid air':
|
|
753
|
+
val = HAPropsSI('Visc', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.cpargs[4], self.cpargs[5])
|
|
754
|
+
else:
|
|
755
|
+
val = PropsSI('viscosity', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.coolprop_fluid)
|
|
756
|
+
self._visc = Quantity(val, 'kg*m^-1*s^-1')
|
|
757
|
+
return self._visc
|
|
758
|
+
elif hasattr(self, 'c') and self.t > self.tmax:
|
|
759
|
+
"""Exponential curve fit to data from t=0 to tmax extrapolated out to t.
|
|
760
|
+
https://en.wikipedia.org/wiki/Temperature_dependence_of_liquid_viscosity#Arrhenius_model"""
|
|
761
|
+
ts = np.linspace(1., self.tmax.magnitude)
|
|
762
|
+
mu_act = np.array([Statepoint(fluid=self.fluid, t=t, p=1., c=self.c).visc.magnitude for t in ts])
|
|
763
|
+
m, garbage = curve_fit(exp_func, ts, mu_act)
|
|
764
|
+
val = exp_func(self.t.magnitude, m[0], m[1])
|
|
765
|
+
self._visc = Quantity(val, 'kg*m^-1*s^-1')
|
|
766
|
+
return self._visc
|
|
767
|
+
else:
|
|
768
|
+
raise ValueError('Temperature %0.1f is not within data range %0.1f-%0.1f and no extrapolation has been created' % (self.t, self.tmin, self.tmax))
|
|
769
|
+
|
|
770
|
+
@property
|
|
771
|
+
def pr(self): # Prandtl number
|
|
772
|
+
if (hasattr(self, '_pr')):
|
|
773
|
+
return self._pr
|
|
774
|
+
if not self.IVs_formatted:
|
|
775
|
+
self._formatIVs()
|
|
776
|
+
try: # handle viscosity being undefined for refprop mixtures with alcohols
|
|
777
|
+
mu = self.visc
|
|
778
|
+
except ValueError as e:
|
|
779
|
+
newFluid = self.fluid.split(':')[1].split('&')[0].split('[')[0]
|
|
780
|
+
if Statepoint.allow_warnings:
|
|
781
|
+
warnings.warn('Using %s instead because ' % newFluid + e.message)
|
|
782
|
+
if 0. <= self.x <= 1.:
|
|
783
|
+
# if the fluid is saturated, use the same pressure and quality with just the first fluid, not a mixture
|
|
784
|
+
newSP = Statepoint(fluid=newFluid, p=self.p, x=self.x)
|
|
785
|
+
mu = newSP.visc
|
|
786
|
+
else:
|
|
787
|
+
# if the fluid is not saturated, set it to the same pressure and the same delta from the saturation temp
|
|
788
|
+
tSatOld = Statepoint(fluid=self.fluid, p=self.p, x=0.).t
|
|
789
|
+
tSatNew = Statepoint(fluid=newFluid, p=self.p, x=0.).t
|
|
790
|
+
newSP = Statepoint(fluid=newFluid, p=self.p, t=tSatNew + self.t - tSatOld)
|
|
791
|
+
mu = newSP.visc
|
|
792
|
+
self._pr = self.cp * mu / self.k
|
|
793
|
+
return self._pr
|
|
794
|
+
|
|
795
|
+
@property
|
|
796
|
+
def sigma(self): # surface tension
|
|
797
|
+
if (hasattr(self, '_sigma')):
|
|
798
|
+
return self._sigma
|
|
799
|
+
if not self.IVs_formatted:
|
|
800
|
+
self._formatIVs()
|
|
801
|
+
val = PropsSI('I', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.coolprop_fluid)
|
|
802
|
+
self._sigma = Quantity(val, 'kg*s^-2')
|
|
803
|
+
return self._sigma
|
|
804
|
+
|
|
805
|
+
@property
|
|
806
|
+
def beta(self): # coefficient of thermal expansion
|
|
807
|
+
if hasattr(self, '_beta'):
|
|
808
|
+
return self._beta
|
|
809
|
+
if not self.IVs_formatted:
|
|
810
|
+
self._formatIVs()
|
|
811
|
+
try:
|
|
812
|
+
val = PropsSI('ISOBARIC_EXPANSION_COEFFICIENT', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.coolprop_fluid)
|
|
813
|
+
except ValueError:
|
|
814
|
+
rho1 = PropsSI('D', 'T', self.t+273.15, 'P', self.p*1.e5, self.coolprop_fluid)
|
|
815
|
+
rho2 = PropsSI('D', 'T', self.t+0.1+273.15, 'P', self.p*1.e5, self.coolprop_fluid)
|
|
816
|
+
rho3 = PropsSI('D', 'T', self.t-0.1+273.15, 'P', self.p*1.e5, self.coolprop_fluid)
|
|
817
|
+
val1 = (rho1 - rho2) / rho1
|
|
818
|
+
val2 = (rho3 - rho1) / rho1
|
|
819
|
+
if abs((val1 - val2) / val1) < 0.01: # check both higher and lower temps to make sure we're not at a discontinuity
|
|
820
|
+
val = (val1 + val2) / 2.
|
|
821
|
+
else:
|
|
822
|
+
raise ValueError('Thermal expansion coefficient calc failed- discontinuity detected. Vals: %f %f' % (val1, val2))
|
|
823
|
+
self._beta = Quantity(val, 'delta_degC^-1')
|
|
824
|
+
return self._beta
|
|
825
|
+
|
|
826
|
+
@property
|
|
827
|
+
def t_freeze(self): # freezing point
|
|
828
|
+
if hasattr(self, '_t_freeze'):
|
|
829
|
+
return self._t_freeze
|
|
830
|
+
if not self.IVs_formatted:
|
|
831
|
+
self._formatIVs()
|
|
832
|
+
val = PropsSI('T_FREEZE', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.coolprop_fluid) - 273.15
|
|
833
|
+
self._t_freeze = Quantity(val, 'degC')
|
|
834
|
+
return self._t_freeze
|
|
835
|
+
|
|
836
|
+
@property
|
|
837
|
+
def Z(self): # compressibility
|
|
838
|
+
if hasattr(self, '_Z'):
|
|
839
|
+
return self._Z
|
|
840
|
+
if not self.IVs_formatted:
|
|
841
|
+
self._formatIVs()
|
|
842
|
+
if self.fluid == 'humid air':
|
|
843
|
+
val = HAPropsSI('Z', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.cpargs[4], self.cpargs[5])
|
|
844
|
+
else:
|
|
845
|
+
val = PropsSI('Z', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.coolprop_fluid)
|
|
846
|
+
self._Z = Quantity(val, '')
|
|
847
|
+
return self._Z
|
|
848
|
+
|
|
849
|
+
@property
|
|
850
|
+
def MW(self): # molecular weight
|
|
851
|
+
if hasattr(self, '_MW'):
|
|
852
|
+
return self._MW
|
|
853
|
+
if not self.IVs_formatted:
|
|
854
|
+
self._formatIVs()
|
|
855
|
+
val = PropsSI('M', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.coolprop_fluid)
|
|
856
|
+
self._MW = Quantity(val, 'kg*mol^-1')
|
|
857
|
+
return self._MW
|
|
858
|
+
|
|
859
|
+
@property
|
|
860
|
+
def vdot(self): # volumetric flow rate
|
|
861
|
+
if hasattr(self, '_vdot'):
|
|
862
|
+
return self._vdot
|
|
863
|
+
if not self.IVs_formatted:
|
|
864
|
+
self._formatIVs()
|
|
865
|
+
self._vdot = self.m / self.rho
|
|
866
|
+
return self._vdot
|
|
867
|
+
|
|
868
|
+
@property
|
|
869
|
+
def twb(self):
|
|
870
|
+
""" Wet bulb temperature """
|
|
871
|
+
if self.fluid != 'humid air':
|
|
872
|
+
raise Exception(f'Wet bulb temperature not defined for {self.fluid}')
|
|
873
|
+
if hasattr(self, '_twb'):
|
|
874
|
+
return self._twb
|
|
875
|
+
if not self.IVs_formatted:
|
|
876
|
+
self._formatIVs()
|
|
877
|
+
val = HAPropsSI('Twb', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.cpargs[4], self.cpargs[5]) - 273.15
|
|
878
|
+
self._twb = Quantity(val, 'degC')
|
|
879
|
+
return self._twb
|
|
880
|
+
|
|
881
|
+
@property
|
|
882
|
+
def tdp(self):
|
|
883
|
+
""" Dew point temperature """
|
|
884
|
+
if self.fluid != 'humid air':
|
|
885
|
+
raise Exception(f'Dew point temperature not defined for {self.fluid}')
|
|
886
|
+
if hasattr(self, '_tdp'):
|
|
887
|
+
return self._tdp
|
|
888
|
+
if not self.IVs_formatted:
|
|
889
|
+
self._formatIVs()
|
|
890
|
+
val = HAPropsSI('Tdp', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.cpargs[4], self.cpargs[5]) - 273.15
|
|
891
|
+
self._tdp = Quantity(val, 'degC')
|
|
892
|
+
return self._tdp
|
|
893
|
+
|
|
894
|
+
@property
|
|
895
|
+
def rh(self):
|
|
896
|
+
""" Relative humidity """
|
|
897
|
+
if self.fluid != 'humid air':
|
|
898
|
+
raise Exception(f'Relative humidity not defined for {self.fluid}')
|
|
899
|
+
if hasattr(self, '_rh'):
|
|
900
|
+
return self._rh
|
|
901
|
+
if not self.IVs_formatted:
|
|
902
|
+
self._formatIVs()
|
|
903
|
+
val = HAPropsSI('RH', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.cpargs[4], self.cpargs[5])
|
|
904
|
+
self._rh = Quantity(val, '')
|
|
905
|
+
return self._rh
|
|
906
|
+
|
|
907
|
+
@property
|
|
908
|
+
def omega(self):
|
|
909
|
+
""" Humidity ratio, kg water / kg dry air """
|
|
910
|
+
if self.fluid != 'humid air':
|
|
911
|
+
raise Exception(f'Humidity ratio not defined for {self.fluid}')
|
|
912
|
+
if hasattr(self, '_omega'):
|
|
913
|
+
return self._omega
|
|
914
|
+
if not self.IVs_formatted:
|
|
915
|
+
self._formatIVs()
|
|
916
|
+
val = HAPropsSI('Omega', self.cpargs[0], self.cpargs[1], self.cpargs[2], self.cpargs[3], self.cpargs[4], self.cpargs[5])
|
|
917
|
+
self._omega = Quantity(val, '')
|
|
918
|
+
return self._omega
|
|
919
|
+
|
|
920
|
+
def set_source(self, source, setprops=()):
|
|
921
|
+
"""
|
|
922
|
+
This method allows the user to create a map of statepoints and update the sink from the source properties
|
|
923
|
+
:param source: [Statepoint]
|
|
924
|
+
:param setprops: [Tuple of strings] A list of the properties that should be constant from source to sink
|
|
925
|
+
:return: None
|
|
926
|
+
"""
|
|
927
|
+
self.source.append(source)
|
|
928
|
+
source.sink.append(self)
|
|
929
|
+
propToMethod = {'fluid': self.set_fluid, 'h': self.set_h, 't': self.set_t, 'p': self.set_p, 'x': self.set_x,
|
|
930
|
+
'm': self.set_m, 'c': self.set_c, 's': self.set_s}
|
|
931
|
+
for prop in setprops:
|
|
932
|
+
if getattr(source, prop) == None:
|
|
933
|
+
raise StatepointError('Source does not have \'%s\' set' % prop)
|
|
934
|
+
else:
|
|
935
|
+
propToMethod[prop](getattr(source, prop)) # sets the props
|
|
936
|
+
return True
|
|
937
|
+
|
|
938
|
+
def set_sink(self, sink):
|
|
939
|
+
self.sink.append(sink)
|
|
940
|
+
sink.source.append(self)
|
|
941
|
+
return True
|
|
942
|
+
|
|
943
|
+
def update_prop(self, prop_val, prop_name):
|
|
944
|
+
"""
|
|
945
|
+
This method allows the user to update a property value and have the statepoint clear its dependent variables
|
|
946
|
+
:param prop_val: [Float or Quantity] The updated value of the property
|
|
947
|
+
:param prop_name: [string] The name of the property to be updated
|
|
948
|
+
:return: None
|
|
949
|
+
"""
|
|
950
|
+
if prop_name in ('t','T','temp','Temp','temperature','Temperature'):
|
|
951
|
+
if 'T' in list(self.IVs.keys()):
|
|
952
|
+
del self._t
|
|
953
|
+
if hasattr(self, '_p') and 'P' not in list(self.IVs.keys()):
|
|
954
|
+
del self._p
|
|
955
|
+
if hasattr(self, '_h') and 'H' not in list(self.IVs.keys()):
|
|
956
|
+
del self._h
|
|
957
|
+
if hasattr(self, '_k'):
|
|
958
|
+
del self._k
|
|
959
|
+
if hasattr(self, '_s') and 'S' not in list(self.IVs.keys()):
|
|
960
|
+
del self._s
|
|
961
|
+
if hasattr(self, '_x') and 'Q' not in list(self.IVs.keys()):
|
|
962
|
+
del self._x
|
|
963
|
+
if hasattr(self, '_twb') and 'Twb' not in list(self.IVs.keys()):
|
|
964
|
+
del self._twb
|
|
965
|
+
if hasattr(self, '_tdp') and 'Tdp' not in list(self.IVs.keys()):
|
|
966
|
+
del self._tdp
|
|
967
|
+
if hasattr(self, '_rh') and 'RH' not in list(self.IVs.keys()):
|
|
968
|
+
del self._rh
|
|
969
|
+
if hasattr(self, '_omega') and 'Omega' not in list(self.IVs.keys()):
|
|
970
|
+
del self._omega
|
|
971
|
+
if isinstance(prop_val, Quantity):
|
|
972
|
+
self._t = prop_val
|
|
973
|
+
else:
|
|
974
|
+
self._t = Quantity(prop_val, 'degC')
|
|
975
|
+
self.IVs['T'] = self._t
|
|
976
|
+
self._formatIVs()
|
|
977
|
+
else:
|
|
978
|
+
raise StatepointError('T was not an initial property input for [%s]' %self.name)
|
|
979
|
+
|
|
980
|
+
if prop_name in ('p','P','pressure','Pressure'):
|
|
981
|
+
if 'P' in list(self.IVs.keys()):
|
|
982
|
+
del self._p
|
|
983
|
+
if hasattr(self, '_t') and 'T' not in list(self.IVs.keys()):
|
|
984
|
+
del self._t
|
|
985
|
+
if hasattr(self, '_h') and 'H' not in list(self.IVs.keys()):
|
|
986
|
+
del self._h
|
|
987
|
+
if hasattr(self, '_k'):
|
|
988
|
+
del self._k
|
|
989
|
+
if hasattr(self, '_s') and 'S' not in list(self.IVs.keys()):
|
|
990
|
+
del self._s
|
|
991
|
+
if hasattr(self, '_x') and 'Q' not in list(self.IVs.keys()):
|
|
992
|
+
del self._x
|
|
993
|
+
if hasattr(self, '_twb') and 'Twb' not in list(self.IVs.keys()):
|
|
994
|
+
del self._twb
|
|
995
|
+
if hasattr(self, '_tdp') and 'Tdp' not in list(self.IVs.keys()):
|
|
996
|
+
del self._tdp
|
|
997
|
+
if hasattr(self, '_rh') and 'RH' not in list(self.IVs.keys()):
|
|
998
|
+
del self._rh
|
|
999
|
+
if hasattr(self, '_omega') and 'Omega' not in list(self.IVs.keys()):
|
|
1000
|
+
del self._omega
|
|
1001
|
+
if isinstance(prop_val, Quantity):
|
|
1002
|
+
self._p = prop_val
|
|
1003
|
+
else:
|
|
1004
|
+
self._p = Quantity(prop_val, 'bar')
|
|
1005
|
+
self.IVs['P'] = self._p
|
|
1006
|
+
self._formatIVs()
|
|
1007
|
+
else:
|
|
1008
|
+
raise StatepointError('P was not an initial property input for [%s]' %self.name)
|
|
1009
|
+
|
|
1010
|
+
if prop_name in ('h','H','enthalpy','Enthalpy'):
|
|
1011
|
+
if 'H' in list(self.IVs.keys()):
|
|
1012
|
+
del self._h
|
|
1013
|
+
if hasattr(self, '_t') and 'T' not in list(self.IVs.keys()):
|
|
1014
|
+
del self._t
|
|
1015
|
+
if hasattr(self, '_p') and 'P' not in list(self.IVs.keys()):
|
|
1016
|
+
del self._p
|
|
1017
|
+
if hasattr(self, '_k'):
|
|
1018
|
+
del self._k
|
|
1019
|
+
if hasattr(self, '_s') and 'S' not in list(self.IVs.keys()):
|
|
1020
|
+
del self._s
|
|
1021
|
+
if hasattr(self, '_x') and 'Q' not in list(self.IVs.keys()):
|
|
1022
|
+
del self._x
|
|
1023
|
+
if hasattr(self, '_twb') and 'Twb' not in list(self.IVs.keys()):
|
|
1024
|
+
del self._twb
|
|
1025
|
+
if hasattr(self, '_tdp') and 'Tdp' not in list(self.IVs.keys()):
|
|
1026
|
+
del self._tdp
|
|
1027
|
+
if hasattr(self, '_rh') and 'RH' not in list(self.IVs.keys()):
|
|
1028
|
+
del self._rh
|
|
1029
|
+
if hasattr(self, '_omega') and 'Omega' not in list(self.IVs.keys()):
|
|
1030
|
+
del self._omega
|
|
1031
|
+
if isinstance(prop_val, Quantity):
|
|
1032
|
+
self._h = prop_val
|
|
1033
|
+
else:
|
|
1034
|
+
self._h = Quantity(prop_val, 'kJ*kg^-1')
|
|
1035
|
+
self.IVs['H'] = self._h
|
|
1036
|
+
self._formatIVs()
|
|
1037
|
+
else:
|
|
1038
|
+
raise StatepointError('H was not an initial property input for [%s]' %self.name)
|
|
1039
|
+
|
|
1040
|
+
if prop_name in ('s','S','entropy','Entropy'):
|
|
1041
|
+
if 'S' in list(self.IVs.keys()):
|
|
1042
|
+
del self._s
|
|
1043
|
+
if hasattr(self, '_t') and 'T' not in list(self.IVs.keys()):
|
|
1044
|
+
del self._t
|
|
1045
|
+
if hasattr(self, '_p') and 'P' not in list(self.IVs.keys()):
|
|
1046
|
+
del self._p
|
|
1047
|
+
if hasattr(self, '_k'):
|
|
1048
|
+
del self._k
|
|
1049
|
+
if hasattr(self, '_h') and 'H' not in list(self.IVs.keys()):
|
|
1050
|
+
del self._h
|
|
1051
|
+
if hasattr(self, '_x') and 'Q' not in list(self.IVs.keys()):
|
|
1052
|
+
del self._x
|
|
1053
|
+
if hasattr(self, '_twb') and 'Twb' not in list(self.IVs.keys()):
|
|
1054
|
+
del self._twb
|
|
1055
|
+
if hasattr(self, '_tdp') and 'Tdp' not in list(self.IVs.keys()):
|
|
1056
|
+
del self._tdp
|
|
1057
|
+
if hasattr(self, '_rh') and 'RH' not in list(self.IVs.keys()):
|
|
1058
|
+
del self._rh
|
|
1059
|
+
if hasattr(self, '_omega') and 'Omega' not in list(self.IVs.keys()):
|
|
1060
|
+
del self._omega
|
|
1061
|
+
if isinstance(prop_val, Quantity):
|
|
1062
|
+
self._s = prop_val
|
|
1063
|
+
else:
|
|
1064
|
+
self._s = Quantity(prop_val, 'degC^-1*kJ*kg^-1')
|
|
1065
|
+
self.IVs['S'] = self._s
|
|
1066
|
+
self._formatIVs()
|
|
1067
|
+
else:
|
|
1068
|
+
raise StatepointError('S was not an initial property input for [%s]' %self.name)
|
|
1069
|
+
|
|
1070
|
+
if prop_name in ('X','x','quality','Quality'):
|
|
1071
|
+
if 'Q' in list(self.IVs.keys()):
|
|
1072
|
+
del self._x
|
|
1073
|
+
if hasattr(self, '_t') and 'T' not in list(self.IVs.keys()):
|
|
1074
|
+
del self._t
|
|
1075
|
+
if hasattr(self, '_p') and 'P' not in list(self.IVs.keys()):
|
|
1076
|
+
del self._p
|
|
1077
|
+
if hasattr(self, '_k'):
|
|
1078
|
+
del self._k
|
|
1079
|
+
if hasattr(self, '_h') and 'H' not in list(self.IVs.keys()):
|
|
1080
|
+
del self._h
|
|
1081
|
+
if hasattr(self, '_s') and 'S' not in list(self.IVs.keys()):
|
|
1082
|
+
del self._x
|
|
1083
|
+
if hasattr(self, '_twb') and 'Twb' not in list(self.IVs.keys()):
|
|
1084
|
+
del self._twb
|
|
1085
|
+
if hasattr(self, '_tdp') and 'Tdp' not in list(self.IVs.keys()):
|
|
1086
|
+
del self._tdp
|
|
1087
|
+
if hasattr(self, '_rh') and 'RH' not in list(self.IVs.keys()):
|
|
1088
|
+
del self._rh
|
|
1089
|
+
if hasattr(self, '_omega') and 'Omega' not in list(self.IVs.keys()):
|
|
1090
|
+
del self._omega
|
|
1091
|
+
if isinstance(prop_val, Quantity):
|
|
1092
|
+
self._x = prop_val
|
|
1093
|
+
else:
|
|
1094
|
+
self._x = Quantity(prop_val, '')
|
|
1095
|
+
self.IVs['Q'] = self._x
|
|
1096
|
+
self._formatIVs()
|
|
1097
|
+
else:
|
|
1098
|
+
raise StatepointError('X was not an initial property input for [%s]' % self.name)
|
|
1099
|
+
|
|
1100
|
+
|
|
1101
|
+
|
|
1102
|
+
|
|
1103
|
+
|
|
1104
|
+
if __name__=='__main__':
|
|
1105
|
+
s = Statepoint(fluid='REFPROP-MIX:METHANOL&WATER', p=1., t=10., c=0.5)
|
|
1106
|
+
print((s.rho))
|
|
1107
|
+
|
|
1108
|
+
s = Statepoint(fluid='REFPROP-MIX:METHANOL&WATER', p=0.11, t=10., c=0.3)
|
|
1109
|
+
print((s.cvap))
|
|
1110
|
+
|
|
1111
|
+
|
|
1112
|
+
""" Luke wrote this script to validate the salt water property extrapolations"""
|
|
1113
|
+
# from thermofluids import Statepoint
|
|
1114
|
+
# import matplotlib.pyplot as plt
|
|
1115
|
+
# import numpy as np
|
|
1116
|
+
#
|
|
1117
|
+
#
|
|
1118
|
+
# fluid = 'INCOMP::MCA'
|
|
1119
|
+
# t = np.arange(0., 40., step=1.)
|
|
1120
|
+
# c = np.arange(0., 0.3, 0.03)
|
|
1121
|
+
# rhos = np.zeros_like(t)
|
|
1122
|
+
# cps = np.zeros_like(t)
|
|
1123
|
+
# viscs = np.zeros_like(t)
|
|
1124
|
+
# hs = np.zeros_like(t)
|
|
1125
|
+
# ks = np.zeros_like(t)
|
|
1126
|
+
#
|
|
1127
|
+
# plt.style.use('seaborn')
|
|
1128
|
+
# fig, ax = plt.subplots(nrows=1, sharex=True)
|
|
1129
|
+
# # ax[0].set_ylabel('rho')
|
|
1130
|
+
# # ax[1].set_ylabel('cp')
|
|
1131
|
+
# # ax[2].set_ylabel('visc')
|
|
1132
|
+
# # ax[3].set_ylabel('h')
|
|
1133
|
+
# ax.set_ylabel('k')
|
|
1134
|
+
# ax.set_xlabel('t')
|
|
1135
|
+
#
|
|
1136
|
+
# for cx in c:
|
|
1137
|
+
# for i, tx in enumerate(t):
|
|
1138
|
+
# sp = Statepoint(fluid=fluid, t=tx, p=1., c=cx)
|
|
1139
|
+
# rhos[i] = sp.rho
|
|
1140
|
+
# cps[i] = sp.cp
|
|
1141
|
+
# viscs[i] = sp.visc
|
|
1142
|
+
# hs[i] = sp.h
|
|
1143
|
+
# ks[i] = sp.k
|
|
1144
|
+
#
|
|
1145
|
+
# # ax[0].plot(t, rhos, label=cx)
|
|
1146
|
+
# # ax[1].plot(t, cps, label=cx)
|
|
1147
|
+
# # ax[2].plot(t, viscs, label=cx)
|
|
1148
|
+
# # ax[3].plot(t, hs, label=cx)
|
|
1149
|
+
# ax.plot(ks, label=cx)
|
|
1150
|
+
#
|
|
1151
|
+
# t = np.arange(1., 100., 1.)
|
|
1152
|
+
# rhos = np.zeros_like(t)
|
|
1153
|
+
# cps = np.zeros_like(t)
|
|
1154
|
+
# viscs = np.zeros_like(t)
|
|
1155
|
+
# hs = np.zeros_like(t)
|
|
1156
|
+
# ks = np.zeros_like(t)
|
|
1157
|
+
# for i, tx in enumerate(t):
|
|
1158
|
+
# sp = Statepoint(fluid='water', t=tx, p=1.)
|
|
1159
|
+
# rhos[i] = sp.rho
|
|
1160
|
+
# cps[i] = sp.cp
|
|
1161
|
+
# viscs[i] = sp.visc
|
|
1162
|
+
# hs[i] = sp.h
|
|
1163
|
+
# ks[i] = sp.k
|
|
1164
|
+
# # ax[0].plot(t, rhos, label='Water', c='black')
|
|
1165
|
+
# # ax[1].plot(t, cps, label='Water', c='black')
|
|
1166
|
+
# # ax[2].plot(t, viscs, label='Water', c='black')
|
|
1167
|
+
# # ax[3].plot(t, hs, label='Water', c='black')
|
|
1168
|
+
# ax.plot(t, ks, label='Water', c='black')
|
|
1169
|
+
#
|
|
1170
|
+
# t = np.arange(41., 100., 1.)
|
|
1171
|
+
# cps = np.zeros_like(t)
|
|
1172
|
+
# hs = np.zeros_like(t)
|
|
1173
|
+
# rhos = np.zeros_like(t)
|
|
1174
|
+
# viscs = np.zeros_like(t)
|
|
1175
|
+
# ks = np.zeros_like(t)
|
|
1176
|
+
# for cx in c:
|
|
1177
|
+
# for i, tx in enumerate(t):
|
|
1178
|
+
# sp = Statepoint(fluid='INCOMP::MCA', t=tx, p=1., c=cx)
|
|
1179
|
+
# cps[i] = sp.cp
|
|
1180
|
+
# hs[i] = sp.h
|
|
1181
|
+
# rhos[i] = sp.rho
|
|
1182
|
+
# viscs[i] = sp.visc
|
|
1183
|
+
# ks[i] = sp.k
|
|
1184
|
+
# # ax[0].plot(t, rhos, linestyle='dashed')
|
|
1185
|
+
# # ax[1].plot(t, cps, linestyle='dashed')
|
|
1186
|
+
# # ax[2].plot(t, viscs, linestyle='dashed')
|
|
1187
|
+
# # ax[3].plot(t, hs, linestyle='dashed')
|
|
1188
|
+
# ax.plot(t, ks, linestyle='dashed')
|
|
1189
|
+
#
|
|
1190
|
+
# # plt.legend()
|
|
1191
|
+
# plt.show()
|