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.
@@ -0,0 +1,45 @@
1
+ from math import log
2
+
3
+ from thermofluids.Base import Quantity
4
+
5
+
6
+ def NTU(m_1, cp_1, m_2, cp_2,T_1_in,T__1_out,T_2_in,flow='counter', type='tube'):
7
+ C_1=m_1*cp_1
8
+ C_2=m_2*cp_2
9
+ C_max=max(C_1,C_2)
10
+ C_min=min(C_1,C_2)
11
+ c=C_min/C_max
12
+ Q_max=C_min*abs(T_1_in-T_2_in)
13
+ Q_1=C_1*abs(T_1_in-T__1_out)
14
+
15
+ epsilon=Q_1/Q_max
16
+
17
+ if type=='tube' and flow=='counter':
18
+ NTU=(1/(c-1))*(log((epsilon-1)/(epsilon*c-1)))
19
+ elif type=='tube' and flow =='parallel':
20
+ NTU=-(log(1-epsilon*(1+c)))/(1+c)
21
+ elif type=='tube' and flow=='counter'and c==1:
22
+ NTU=epsilon/(1-epsilon)
23
+ else:
24
+ raise Exception("No NTU correlations available for type '%s'. Please provide a HX type as an input" % type)
25
+
26
+ return NTU,C_min.magnitude
27
+
28
+
29
+ #######test#####
30
+ if __name__ == "__main__":
31
+ mdot_h=Quantity(2,'kg/s')
32
+ mdot_c=Quantity(1.2,'kg/s')
33
+ cp_h=Quantity(4.31,'kJ/kg*C')
34
+ cp_c=Quantity(4.18,'kJ/kg*C')
35
+ T_in_h=Quantity(160,'C')
36
+ T_in_c=Quantity(20,'C')
37
+ T_out_c=Quantity(80,'C')
38
+
39
+ print(NTU(mdot_c,cp_c,mdot_h,cp_h,T_in_c,T_out_c,T_in_h))
40
+
41
+
42
+
43
+
44
+
45
+
@@ -0,0 +1,59 @@
1
+ from warnings import warn
2
+
3
+
4
+ def Nu(Re, Pr, f=None, mode=None):
5
+ """
6
+ Nusselt number for forced convection
7
+ :param Re: Reynolds number
8
+ :param Pr: Prandtl number
9
+ :param f: Darcy friction factor
10
+ :param mode: 'heating' or 'cooling'
11
+ :return: Nusselt number
12
+ """
13
+ if f != None and Re >= 3000. and Re <= 5.e5 and Pr >= 0.5 and Pr <= 2000.:
14
+ return _Gnielinski(Re, Pr, f)
15
+ elif Re >= 10000. and Pr > 0.6 and Pr < 160:
16
+ return _Dittus_Boelter(Re, Pr, mode)
17
+ elif Re <= 2300.:
18
+ return _laminar()
19
+ else:
20
+ warn("No Nusselt number correlation available for Re=%s, Pr=%s. Using Gnielinski correlation as best guess" % (Re, Pr))
21
+ return _Gnielinski(Re, Pr, f)
22
+
23
+ def _Gnielinski(Re, Pr, f):
24
+ "https://en.wikipedia.org/wiki/Nusselt_number#Gnielinski_correlation"
25
+ return (f/8.) * (Re - 1000.) * Pr / (1. + 12.7*(f/8.)**0.5 * (Pr**0.6667-1.))
26
+
27
+ def _Dittus_Boelter(Re, Pr, mode):
28
+ "https://en.wikipedia.org/wiki/Nusselt_number#Dittus-Boelter_equation"
29
+ if mode.lower() == 'heating':
30
+ n = 0.4
31
+ elif mode.lower() == 'cooling':
32
+ n = 0.3
33
+ else:
34
+ raise Exception('Unknown mode %s. Should be either "heating" or "cooling"' % mode)
35
+
36
+ return 0.023 * Re**0.8 * Pr**n
37
+
38
+ def _laminar():
39
+ "https://en.wikipedia.org/wiki/Nusselt_number#Forced_convection_in_fully_developed_laminar_pipe_flow"
40
+ return 4. # average between const. heat flux and const. temp solutions
41
+
42
+ def Nu_natural(Ra, Pr, shape):
43
+ """
44
+ Nusselt number for natural convection
45
+ References:
46
+ [1] Cengel Heat and Mass Transfer 3rd Ed p511
47
+ :param Ra: Rayleigh number
48
+ :param Pr: Prandtl number
49
+ :param shape: can be 'vertical plate', 'inclined plate', 'horizontal plate', 'vertical cylinder', 'horizontal cylinder', 'sphere'
50
+ :return: Nusselt number <Quantity, ->
51
+ """
52
+ shapes = ('vertical plate', 'inclined plate', 'horizontal plate', 'vertical cylinder', 'horizontal cylinder', 'sphere')
53
+ if shape not in shapes:
54
+ raise ValueError('Natural convection Nusselt correlation not found for %s. Please use one of: \n%s' % (shape, shapes))
55
+ if shape == 'vertical plate':
56
+ return (0.825 + (0.387 * Ra ** (1. / 6.)) / (1. + (0.492 / Pr) ** (9. / 16.)) ** (8. / 27.)) ** 2. # ref [1]
57
+ else:
58
+ raise NotImplementedError("Natural convection Nusselt correlation for %s not yet implemented. \
59
+ Please see Cengel Heat and Mass Transfer p511 to add it.")
@@ -0,0 +1,22 @@
1
+ from thermofluids.Base import Quantity
2
+ from thermofluids.Base import Statepoint
3
+ from .Gr import Gr
4
+
5
+
6
+ def Ra(statepoint, gr=None, L=None, t_wall=None):
7
+ """
8
+ Rayleigh number for natural convection
9
+ Please specify either the Grashof number or the characteristic length and wall temperature
10
+ :param statepoint: A statepoint instance of the fluid being heated/cooled
11
+ :param gr: Grashof number <Quantity [-]>
12
+ :param L: Characteristic length <Quantity [m]>
13
+ :param t_wall: Wall temperature <Quantity [C]>
14
+ :return:
15
+ """
16
+ assert ((Gr is not None) or (L is not None and t_wall is not None))
17
+
18
+ if gr is None:
19
+ g = Quantity(9.81, 'm*s^-2')
20
+ gr = statepoint.rho ** 2. * g * statepoint.beta * L ** 3. * (t_wall - statepoint.t) / statepoint.visc ** 2.
21
+
22
+ return gr * statepoint.pr
@@ -0,0 +1,249 @@
1
+ """
2
+ This file contains functions to calculate the heat transfer for convective boiling flow in a tube. It is based on the
3
+ Shah correlation as described in Carey 'Liquid-Vapor Phase-Change Phenomena' p616.
4
+ """
5
+
6
+ import warnings
7
+ from math import exp, log10,pi
8
+
9
+ from thermofluids.Fluids.Moody import frictionfactor
10
+ from thermofluids.HeatTransfer.Nusselt import Nu
11
+ from thermofluids import Statepoint, Quantity
12
+
13
+
14
+ def warning_on_one_line(message, category, filename, lineno, file=None, line=None):
15
+ return ' %s:%s %s\n' % (filename, lineno, message)
16
+ warnings.formatwarning = warning_on_one_line
17
+
18
+
19
+ def Co(x, rho_v, rho_l):
20
+ """
21
+ Convection number - Some representation of volumetric liquid/gas ratio (higher is more liquid)
22
+ :param x: quality [kg/kg]
23
+ :param rho_v: vapor density [kg/m^3]
24
+ :param rho_l: liquid density [kg/m^3]
25
+ :return: Convenction number [-]
26
+ """
27
+
28
+ return pow((1. - x)/x, 0.8) * pow(rho_v / rho_l, 0.5)
29
+
30
+
31
+ def Bo(q_flux, G, h_v):
32
+ """
33
+ Boiling number - the ratio of flow rate due to boiling vs flow rate through pipe
34
+ :param q_flux: heat flux [kW/m^2]
35
+ :param G: mass flux [kg/m^2-s]
36
+ :param h_v: enthalpy of vaporization [kJ/kg]
37
+ :return: boiling number [-]
38
+ """
39
+
40
+ return q_flux / (G * h_v)
41
+
42
+
43
+ def Fr_le(G, rho_l, d):
44
+ """
45
+ Froude number - the ratio of flow inertia to gravity field
46
+ :param G: mass flux [kg/m^2-s]
47
+ :param rho_l: liquid density [kg/m^3]
48
+ :param d: hydraulic diameter [m]
49
+ :return: Froude number [-]
50
+ """
51
+
52
+ g = Quantity(9.807, 'm*s^-2')
53
+ return G * G / (rho_l * rho_l * g * d)
54
+
55
+ def crit_heat_flux(h_v, rho_l, rho_v, sigma):
56
+ """
57
+ Critical heat flux for boiling heat transfer according to:
58
+ https://en.wikipedia.org/wiki/Critical_heat_flux#Correlations_for_critical_heat_flux
59
+ :param h_v: enthalpy of vaporization [kJ/kg]
60
+ :param rho_l: liquid density [kg/m^3]
61
+ :param rho_v: vapor density [kg/m^3]
62
+ :param sigma: interfacial tension [N/m]
63
+ :return: critical heat transfer [kW/m^2]
64
+ """
65
+ C = 0.149 # supposed to be for 'large horizontal plates'
66
+ g = Quantity(9.806, 'm*s^-2')
67
+
68
+ return C * h_v * rho_v * (sigma * g * (rho_l - rho_v) / rho_v**2.)**0.25
69
+
70
+ def heat_flux_nucleate_boiling(mu_l, h_v, rho_l, rho_v, sigma, cp_l, T_s, T_sat, Csf, n, Pr_l):
71
+ """
72
+ heat flux for nucleate boiling based on Rohsenow correlation
73
+ https://en.wikipedia.org/wiki/Nucleate_boiling#Boiling_Heat_transfer_correlations
74
+ :param mu_l: Liquid viscosity [kg/m-s]
75
+ :param h_v: enthalpy of vaporization [kJ/kg]
76
+ :param rho_l: liquid density [kg/m^3]
77
+ :param rho_v: vapor density [kg/m^3]
78
+ :param sigma: interfacial tension [m^2/s]
79
+ :param cp_l: liquid specific heat capacity [kJ/kg-C]
80
+ :param T_s: surface temperature [C]
81
+ :param T_sat: saturation temperature [C]
82
+ :param Csf: surface fluid combination
83
+ :param Pr_l: liquid prandtl number
84
+ :param n: parameter depending on surface fluid combo, typically 1.0 or 1.7
85
+ :return: heat flux [kW/m^2]
86
+ """
87
+ g = Quantity(9.807, 'm*s^-2')
88
+ q = mu_l * h_v * pow(g * (rho_l - rho_v) / sigma, 0.5) * pow(cp_l * (T_s - T_sat) / (Csf * h_v * pow(Pr_l, n)), 3.)
89
+ q_max = crit_heat_flux(h_v, rho_l, rho_v, sigma)
90
+ if q > q_max:
91
+ raise Exception('Departure from nucleate boiling exceeded')
92
+ return q
93
+
94
+ def htc_conv_boil(x, rho_l, rho_v, G, h_v, d, q_flux, mu_l, k_l, pr_l):
95
+ """
96
+ Heat transfer coefficient of boiling flow through a tube based on Shah correlation as described in
97
+ Carey 'Liquid-Vapor Phase-Change Phenomena' p616.
98
+ :param x: quality [-]
99
+ :param rho_l: liquid density [kg/m^3]
100
+ :param rho_v: vapor density [kg/m^3]
101
+ :param G: mass flux [kg/m^2-s]
102
+ :param h_v: enthalpy of vaporization [kJ/kg]
103
+ :param d: hydraulic diameter [m]
104
+ :param q_flux: Boiling heat flux [kW/m^2]
105
+ :param mu_l: liquid kinematic viscosity [kg/m-s]
106
+ :param k_l: liquid thermal conductivity [kW/m-C]
107
+ :param pr_l: liquid Prandtl number [-]
108
+ :return: Heat transfer coefficient [kW/m^2-C]
109
+ """
110
+
111
+ co = Co(x, rho_v, rho_l)
112
+ bo = Bo(q_flux, G, h_v)
113
+ fr = Fr_le(G, rho_l, d)
114
+
115
+ if fr >= 0.04:
116
+ Ns = co
117
+ else:
118
+ Ns = 0.38*pow(fr, -0.3) * co
119
+ if bo >= 11.e-4:
120
+ Fs = 14.7
121
+ else:
122
+ Fs = 15.4
123
+ psi_cb = 1.8 * pow(Ns, -0.8)
124
+
125
+ if Ns > 1.:
126
+ if bo > 0.3e-4:
127
+ psi_nb = 230 * pow(bo, 0.5)
128
+ else:
129
+ psi_nb = 1 + 46 * pow(bo, 0.5)
130
+ psi_s = max(psi_nb, psi_cb)
131
+ else:
132
+ if Ns > 0.1:
133
+ psi_bs = Fs * pow(bo, 0.5) * exp(2.74 * pow(Ns, -0.1))
134
+ else:
135
+ psi_bs = Fs * pow(bo, 0.5) * exp(2.74 * pow(Ns, -0.15))
136
+ psi_s = max(psi_bs, psi_cb)
137
+ if psi_s < 1.:
138
+ warnings.warn('Shah correlation predicts lower heat transfer than liquid convection. Seems dubious, eh?')
139
+
140
+ # find liquid phase heat transfer coefficient
141
+ re_l = G * (1. - x) * d / mu_l
142
+ ff_l = frictionfactor(Re=re_l, relrough=1.5e-5/d) #TODO: update this for other materials
143
+ htc_l = k_l / d * Nu(Re=re_l, Pr=pr_l, f=ff_l, mode='cooling')
144
+ htc = htc_l * psi_s
145
+
146
+ return htc
147
+
148
+
149
+ def superficial_flow_regime(state, d, orientation, detailed=False):
150
+ liquid_only = Statepoint(fluid=state.fluid,m=(1.-state.x)*state.m,p=state.p, x=0.0)
151
+ gas_only = Statepoint(fluid=state.fluid, m=(state.x) * state.m, p=state.p, x=1.0)
152
+ A = d**2/4.*pi
153
+ G = state.m/A
154
+ x = state.x
155
+ mu_l = liquid_only.visc #/liquid_only.rho
156
+ mu_v = gas_only.visc #/gas_only.rho
157
+ rho_l = liquid_only.rho
158
+ rho_v = gas_only.rho
159
+ # based on Carey p484-486
160
+ Re_l = G * (1. - x) * d / mu_l
161
+ Re_v = G * x * d / mu_v
162
+ # print 'Re #s: ', Re_l, Re_v
163
+ laminar_warning = False
164
+ if float(Re_l) > 2000:
165
+ f_l = 0.079 * Re_l**0.25
166
+ else:
167
+ laminar_warning = True
168
+ f_l = 16 * Re_l
169
+ if float(Re_v) > 2000:
170
+ f_v = 0.079 * Re_v**0.25
171
+ else:
172
+ laminar_warning = True
173
+ f_v = 16 * Re_v
174
+ if laminar_warning:
175
+ warnings.warn('Non-boiling flow is laminar, results may be inaccurate')
176
+ dPdz_l = -2. * f_l * G**2. * (1.-x)**2. / (rho_l * d)
177
+ dPdz_v = - 2 * f_v * G**2. * x**2. / (rho_v * d)
178
+ X = (dPdz_l / dPdz_v) ** 0.5
179
+ if X < 10e-3 or X > 10e4:
180
+ raise ValueError('Martinelli parameter is outside of the range of the correlation')
181
+
182
+ if orientation.lower() == 'horizontal':
183
+ j_v = G * x / rho_v # superficial vapor flux
184
+ j_l = G * (1. - x) / rho_l # superficial liquid flux
185
+ g = Quantity(9.807, 'm*s^-2')
186
+ nu_l = mu_l / rho_l
187
+ K_td = (rho_v * j_v**2. * j_l / (nu_l * (rho_l - rho_v) * g))**0.5
188
+ if (K_td < 0.8):
189
+ warnings.warn('Flow regime K_td parameter is outside of the range of the correlation. Value is %f, min is 1' % K_td)
190
+ F_td = (rho_v * j_v**2. / ((rho_l - rho_v) * d * g))**0.5
191
+ if (F_td < 0.001 or F_td > 10.):
192
+ warnings.warn('Flow regime F_td parameter is outside of the range of the correlation')
193
+ T_td = (-dPdz_l / ((rho_l - rho_v) * g))**0.5
194
+ if (T_td < 0.001 or T_td > 10.):
195
+ warnings.warn('Flow regime parameter is outside of the range of the correlation')
196
+ # print()
197
+
198
+ if detailed:
199
+ print(X, T_td,F_td, 1.3027 - 0.3826*log10(X) + 0.0161 * log10(X)**2.)
200
+ if K_td < 10.**(0.7757 - 0.112*log10(X) - 0.2097 * log10(X)**2.):
201
+ return 'Stratified smooth'
202
+ elif F_td < 10.**(-0.6644 - 0.8985*log10(X) - 0.2362 * log10(X)**2.):
203
+ return 'Stratified wavy'
204
+ elif X < 1.6:
205
+ return 'Annular dispersed'
206
+ elif T_td < 1.3027 - 0.3826*log10(X) + 0.0161 * log10(X)**2.:
207
+ return 'Intermittent'
208
+ else:
209
+ return 'Dispersed bubble'
210
+ elif orientation.lower() == 'vertical':
211
+ j_v = G * x / rho_v # superficial vapor flux
212
+ j_l = G * (1. - x) / rho_l # superficial liquid flux
213
+ return_str = 'Vertical orientation map not currently implemented. \nRefer to page 482 of Liquid-Vapor Phase-Change Phenomena \npvjv2 = '
214
+ return_str = return_str + str(j_v**2*rho_v) + '\npljl2 = ' + str(j_l**2*rho_l)
215
+ return return_str
216
+
217
+ else:
218
+ raise ValueError('Only horizontal or vertical orientation supported at this time')
219
+
220
+
221
+ if __name__ == '__main__':
222
+ from thermofluids.Base import Statepoint
223
+ from thermofluids.Base import Quantity
224
+
225
+ t = Quantity(-14., 'C')
226
+ t_wall = Quantity(-13., 'C')
227
+ Q = Quantity(20., 'kJ*s^-1')
228
+ h = Quantity(0.208 * 0.0254, 'm')
229
+ w = Quantity((39.375 - 1.5) * 0.0254, 'm')
230
+ Csf = 0.0133 # used value for water/chemically etched stainless (https://en.wikipedia.org/wiki/Nucleate_boiling#Boiling_Heat_transfer_correlations)
231
+ n = 1.
232
+ x = 0.5
233
+
234
+ refrigerant = 'ammonia'
235
+ v = Statepoint(fluid=refrigerant, t=t, x=1)
236
+ l = Statepoint(fluid=refrigerant, t=t, x=0)
237
+ mdot = Q / (v.h - l.h)
238
+ G = mdot / (h * w / 2.)
239
+
240
+ for t_wall in range(-14, 1, 1):
241
+ t_wall = Quantity(t_wall, 'degC')
242
+ q_flux = heat_flux_nucleate_boiling(l.visc, v.h - l.h, l.rho, v.rho, l.sigma, l.cp, t_wall, t, Csf, n, l.pr)
243
+ print(t_wall, q_flux)
244
+
245
+ q_flux = heat_flux_nucleate_boiling(l.visc, v.h-l.h, l.rho, v.rho, l.sigma, l.cp, t_wall, t, Csf, n, l.pr)
246
+ print('Flow regime: ', superficial_flow_regime(G, x, h, l.visc, v.visc, l.rho, v.rho, 'horizontal'))
247
+ print('q_flux: ', q_flux)
248
+
249
+ htc_conv_boil(x, v.rho, l.rho, G, v.h - l.h, h*2., q_flux, l.mu, l.k, l.pr)
@@ -0,0 +1,6 @@
1
+ from thermofluids.HeatTransfer.Gr import Gr
2
+ from thermofluids.HeatTransfer.Nusselt import Nu, Nu_natural
3
+ from thermofluids.HeatTransfer.Ra import Ra
4
+ from thermofluids.HeatTransfer.lmtd import lmtd
5
+ from thermofluids.HeatTransfer.lmtd import lmtd
6
+ from thermofluids.HeatTransfer.TwoPhase import superficial_flow_regime
@@ -0,0 +1,32 @@
1
+ from math import log
2
+
3
+ def lmtd(t_hot_in, t_hot_out, t_cold_in, t_cold_out):
4
+ """
5
+ Log Mean Temperature Difference
6
+ :param t_hot_in: C
7
+ :param t_hot_out: C
8
+ :param t_cold_in: C
9
+ :param t_cold_out: C
10
+ :return: log mean temp difference C
11
+ """
12
+ assert t_hot_in > t_cold_out, '%f !> %f' % (t_hot_in, t_cold_out)
13
+ assert t_hot_in >= t_hot_out, '%f !> %f' % (t_hot_in, t_hot_out)
14
+ assert t_hot_out > t_cold_in, '%f !> %f' % (t_hot_out, t_cold_in)
15
+ # assert t_cold_out > t_cold_in, '%f !> %f' % (t_cold_out, t_cold_in)
16
+
17
+ dt_hot = t_hot_in - t_cold_out
18
+ dt_cold = t_hot_out - t_cold_in
19
+ if dt_cold == dt_hot:
20
+ return dt_cold
21
+ else:
22
+ return (dt_hot - dt_cold) / log(dt_hot / dt_cold)
23
+
24
+
25
+
26
+ if __name__ == '__main__':
27
+ print(lmtd(10., 5., 4., 9.))
28
+ print(lmtd(10., 5., 0., 9.))
29
+ try:
30
+ print(lmtd(5., 5., 5., 5.))
31
+ except AssertionError:
32
+ print('that one produced an error as expected')