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.
File without changes
@@ -0,0 +1,5 @@
1
+ tons_of_refrigeration = 3.51685 kW
2
+ TR = tons_of_refrigeration
3
+ GPM = 1 gal/min = gpm
4
+ LPM = 1 L/min = lpm
5
+ CFM = 1 ft^3/min = cfm
@@ -0,0 +1,169 @@
1
+ from warnings import warn
2
+ from ..Base.Quantity import Quantity
3
+
4
+
5
+ def c_d(shape):
6
+ """
7
+ https://en.wikipedia.org/wiki/Drag_coefficient
8
+ :param shape:
9
+ :return:
10
+ """
11
+ if shape == 'sphere':
12
+ cd = 0.47
13
+ elif shape == 'half sphere':
14
+ cd = 0.42
15
+ elif shape == 'cone':
16
+ cd = 0.5
17
+ elif shape == 'cube':
18
+ cd = 1.05
19
+ elif shape == 'angled cube':
20
+ cd = 0.8
21
+ elif shape == 'long cylinder':
22
+ cd = 0.82
23
+ elif shape == 'short cylinder':
24
+ cd = 1.15
25
+ elif shape == 'streamlined':
26
+ cd = 0.04
27
+ elif shape == 'half streamlined':
28
+ cd = 0.09
29
+ else:
30
+ raise ValueError(f'No drag coefficient available for {shape}. Please select from sphere, half sphere, cone, '
31
+ f'cube, angled cube, long cylinder, short cylinder, streamlined, half streamlined.')
32
+ return cd
33
+
34
+
35
+ def f_drag(shape, density, velocity, area=None):
36
+ """
37
+
38
+ :param shape: Shape of the object <str>
39
+ :param density: Density of the fluid <Quantity, kg/m^3>
40
+ :param velocity: Velocity of the fluid relative to the thing getting dragged <Quantity, m/s>
41
+ :param area: Optional, frontal area of the object <Quantity, m^2>
42
+ :return: Pressure on the object (without area specified) or force on the object (with area specified)
43
+ """
44
+ cd = c_d(shape.lower())
45
+
46
+ if area == None:
47
+ return 0.5 * cd * density * velocity**2. # return as pressure
48
+ else:
49
+ return 0.5 * cd * density * velocity**2. * area # return as force
50
+
51
+
52
+ def _settling_vel_stokes(rho_solid, rho_liquid, visc_liquid, d_solid):
53
+ g = Quantity(9.81, 'm*s^-2')
54
+ if rho_solid > rho_liquid:
55
+ return 2. / 9. * (rho_solid - rho_liquid) / visc_liquid * g * (d_solid / 2.) ** 2.
56
+ else:
57
+ return 2. / 9. * (rho_liquid - rho_solid) / visc_liquid * g * (d_solid / 2.) ** 2.
58
+
59
+
60
+ def _settling_vel_laminar(rho_solid, rho_liquid, d_solid, re):
61
+ from math import exp, log
62
+ g = Quantity(9.81, 'm*s^-2')
63
+ cd = exp(0.0453 * log(re)**2. - 0.8379 * log(re) + 2.8568) # fit to 25 < Re < 4000 from https://en.wikipedia.org/wiki/Drag_coefficient#/media/File:Drag_coefficient_on_a_sphere_vs._Reynolds_number_-_main_trends.svg
64
+ if rho_solid > rho_liquid:
65
+ return (4. / (3. * cd) * d_solid * g * (rho_solid - rho_liquid) / rho_liquid) ** 0.5
66
+ else:
67
+ return (4. / (3. * cd) * d_solid * g * (rho_liquid - rho_solid) / rho_liquid) ** 0.5
68
+
69
+
70
+ def _settling_vel_turbulent(rho_solid, rho_liquid, d_solid, re):
71
+ g = Quantity(9.81, 'm*s^-2')
72
+ cd = 0.47
73
+ if rho_solid > rho_liquid:
74
+ return (4. / (3. * cd) * d_solid * g * (rho_solid - rho_liquid) / rho_liquid) ** 0.5
75
+ else:
76
+ return (4. / (3. * cd) * d_solid * g * (rho_liquid - rho_solid) / rho_liquid) ** 0.5
77
+
78
+
79
+ def settling_vel(statepoint, d_solid, rho_solid, d_h_ext, re='auto', detailed=False):
80
+ """
81
+ This function calculates the settling velocity for a solid particle in a flowing liquid. If the fluid is moving
82
+ slower than the settling velocity, the particle will tend to settle out. If its moving faster, it will tend to
83
+ remain entrained.
84
+ There are three regimes:
85
+
86
+ 1. Stokes flow (Re<10: force balance is Stokes drag vs gravity
87
+ 2. Laminar flow (10<Re<3000): force balance is hydrodynamic drag vs gravity
88
+ 3. Turbulent flow (Re>3000): force balance is hydrodynamic drag vs gravity
89
+
90
+ :param statepoint: statepoint instance of the fluid containing the solids
91
+ :param d_solid: diameter of the solid particle
92
+ :param rho_solid: density of the solid particle
93
+ :param d_h_ext: hydraulic diameter of the flow area
94
+ :param re: Reynolds number, if known. If left default='auto', it will be calculated from the settling velocity
95
+ :return: settling velocity [m/s]
96
+ """
97
+ # assert rho_solid > statepoint.rho, "Not currently set up to handle solids less dense than fluid"
98
+
99
+ if re != 'auto':
100
+ if re < 10.: # Stokes flow
101
+ v = _settling_vel_stokes(rho_solid=rho_solid, rho_liquid=statepoint.rho, visc_liquid=statepoint.visc, d_solid=d_solid)
102
+ elif re < 3000.: # Laminar flow
103
+ v = _settling_vel_laminar(rho_solid=rho_solid, rho_liquid=statepoint.rho, d_solid=d_solid, re=re)
104
+ else: # Turbulent flow
105
+ v = _settling_vel_turbulent(rho_solid=rho_solid, rho_liquid=statepoint.rho, d_solid=d_solid, re=re)
106
+ else:
107
+ v = Quantity(0.01, 'm*s^-1')
108
+ res = 1.
109
+ n_iter = 0.
110
+ while res > 0.01:
111
+ v_last = v
112
+ re = statepoint.rho * v * d_h_ext / statepoint.visc
113
+ # print(statepoint.rho, v, d_h_ext, statepoint.visc, re)
114
+ if re < 10.: # Stokes flow
115
+ v = _settling_vel_stokes(rho_solid=rho_solid, rho_liquid=statepoint.rho, visc_liquid=statepoint.visc, d_solid=d_solid)
116
+ elif re < 3000.: # Laminar flow
117
+ v = _settling_vel_laminar(rho_solid=rho_solid, rho_liquid=statepoint.rho, d_solid=d_solid, re=re)
118
+ else: # Turbulent flow
119
+ v = _settling_vel_turbulent(rho_solid=rho_solid, rho_liquid=statepoint.rho, d_solid=d_solid, re=re)
120
+ res = abs((v - v_last) / v)
121
+ n_iter += 1
122
+ if n_iter > 1000:
123
+ warn(f'Settling velocity calculation did not converge. Last two iterations gave v={v} and v={v_last}')
124
+ break
125
+ # print 'Residual: ', res, v, re
126
+
127
+ if detailed:
128
+ if re < 10:
129
+ print('\tSettling velocity in Stokes flow regime')
130
+ elif re < 3000:
131
+ print('\tSettling velocity in laminar flow regime')
132
+ else:
133
+ print('\tSettling velocity in turbulent flow regime. Warning- this is not well characterized in this model')
134
+
135
+ return v
136
+
137
+
138
+
139
+
140
+ if __name__ == '__main__':
141
+ import matplotlib.pyplot as plt
142
+ from ..Base.Statepoint import Statepoint
143
+
144
+ rho = Quantity(1000., 'kg*m^-3')
145
+ u = Quantity(5., 'm*s^-1')
146
+ A = Quantity(3.14 / 4. * 0.0254**2., 'm^2')
147
+ # print f_drag(shape='sphere', density=rho, velocity=u, area=A)
148
+
149
+ sp = Statepoint(fluid='INCOMP::TD12', t=0., p=1.)
150
+ fig1 = plt.figure()
151
+ ax1 = fig1.add_subplot(111)
152
+ ds = [0.01, 0.003, 0.001, 0.00033, 0.0001]
153
+ for d in ds:
154
+ vs = []
155
+ re_array = list(range(4000))
156
+ for re in re_array:
157
+ v = settling_vel(statepoint=sp,
158
+ d_solid=Quantity(d, 'm'),
159
+ rho_solid=Quantity(1000., 'kg*m^-3'),
160
+ d_h_ext=Quantity(0.1, 'm'),
161
+ re=re)
162
+ vs.append(v)
163
+
164
+ plt.plot(re_array, vs)
165
+ plt.legend(ds, title='Ice size', )
166
+ plt.xlabel('Re')
167
+ plt.ylabel('Settling velocity [m/s]')
168
+ plt.ylim(0, 0.5)
169
+ plt.show()
@@ -0,0 +1,57 @@
1
+ """
2
+ From http://nullege.com/codes/show/src@l@i@libtsl-HEAD@mr_darcy.py
3
+ Edited by Luke Erickson to include transition region
4
+ """
5
+
6
+ from warnings import warn
7
+ from math import log10
8
+ from ..Base.Quantity import Quantity
9
+
10
+
11
+ def frictionfactor(Re,relrough):
12
+ """
13
+ Returns the Darcy friction factor based on reynolds # and relative roughness.
14
+ """
15
+ if type(Re) is Quantity:
16
+ assert Re.units == '', f'Re must be unitless but has units {Re.units}'
17
+ if type(relrough) is Quantity:
18
+ assert relrough.units == '', f'Relative roughness must be unitless but has units {relrough.units}'
19
+ if relrough > 0.05:
20
+ warn('Moody diagram only valid for relative roughness < 0.05. Received value %f' % relrough)
21
+
22
+ regime = _flowregime(Re,relrough)
23
+
24
+ if regime=='laminar':
25
+ return _laminar(Re)
26
+ elif regime=='turbulent':
27
+ return _turbulent(Re,relrough)
28
+ elif regime=='transition':
29
+ return _transition(Re, relrough)
30
+
31
+ def _flowregime(Re,relrough):
32
+ if Re < 2300.:
33
+ return "laminar"
34
+ elif Re > 4000.:
35
+ return "turbulent"
36
+ else:
37
+ return "transition"
38
+
39
+ def _laminar(Re):
40
+ return 64.0 / Re
41
+
42
+ def _turbulent(Re,relrough):
43
+ # Uses Serghides's Solution to approximate the Colebrook eqn
44
+ a=-2*log10(relrough/3.7 + 12.0/Re)
45
+ b=-2*log10(relrough/3.7 + 2.51*a/Re)
46
+ c=-2*log10(relrough/3.7 + 2.51*b/Re)
47
+ return (a-(b-a)**2/(c-2*b+a))**-2.0 #returns f
48
+
49
+ def _transition(Re, relrough):
50
+ """
51
+ Assume linear interpolation between laminar and turbulent regions
52
+ """
53
+ warn("Using interpolated friction factor in high uncertainly transition Re region")
54
+
55
+ turb = _turbulent(Re, relrough)
56
+ lam = _laminar(Re)
57
+ return lam + (Re.magnitude-2300.) / (4000.-2300.) * (turb - lam)
@@ -0,0 +1,322 @@
1
+ from math import sqrt, log, sin, cos, tan
2
+
3
+ from thermofluids import Quantity
4
+ from thermofluids.Fluids.Moody import frictionfactor
5
+ from thermofluids.Fluids.Re import Re
6
+
7
+
8
+ def pressure_drop(statepoint, roughness, L, d1, d2=None, v=None, shape='round', props='REFPROP', units='bar', detailed=False):
9
+ """
10
+
11
+ :param statepoint:
12
+ :param roughness:
13
+ :param L:
14
+ :param d1:
15
+ :param d2:
16
+ :param shape:
17
+ :param props:
18
+ :return:
19
+ """
20
+ # if not isinstance(L, Quantity):
21
+ # L = Quantity(L, 'm')
22
+ # if not isinstance(d1, Quantity):
23
+ # d1 = Quantity(d1, 'm')
24
+ # if not isinstance(d2, Quantity):
25
+ # d2 = Quantity(d2, 'm')
26
+ # if not isinstance(roughness, Quantity):
27
+ # roughness = Quantity(roughness, 'm')
28
+ # assert type(shape) in (str, None), 'shape needs to be a string, got %r' % shape
29
+
30
+ if props=='ideal':
31
+ if statepoint.fluid.lower()=='air':
32
+ rho = statepoint.p.to('bar').magnitude * 1.e5 / (287.058 * (statepoint.t.magnitude+273.15))
33
+ else:
34
+ raise Exception('No ideal density calcs available for this fluid')
35
+ else:
36
+ rho = statepoint.rho
37
+
38
+ m = statepoint.m
39
+
40
+ if type(shape) is str:
41
+ if shape.lower() in ('round', 'circle'):
42
+ d_h = d1
43
+ v = m / rho / (3.14/4.*d_h**2.)
44
+ elif shape.lower() == 'square':
45
+ d_h = d1
46
+ v = m / rho / d_h**2.
47
+ elif shape.lower() == 'rectangle':
48
+ if d2 == None:
49
+ raise Exception("d2 must be set for rectangular pressure drop calcs")
50
+ d_h = 4.*d1*d2 / (2. * d1 + 2. * d2)
51
+ v = m / rho / (d1 * d2)
52
+ elif shape.lower() == 'pillow':
53
+ #use this for a mueller plate, assumes d1 is pillow height and d2 is pillow width but they can acutally be put in any which way
54
+ if d2 == None:
55
+ raise Exception("d2 must be set for pillow pressure drop calcs")
56
+ A = d1*d2*2.
57
+ P = ((d1/2.)**2 + (d2/2.)**2)**(0.5)*4.
58
+ d_h = 4. * A / P
59
+ v = m / rho / A
60
+ elif shape.lower() == 'annulus':
61
+ if d2 == None:
62
+ raise Exception("d2 must be set for annular pressure drop calcs")
63
+ d_h = d1 - d2
64
+ v = m / rho / (3.14 / 4. * (d1**2. - d2**2.))
65
+ elif shape.lower() == 'shell-and-tube':
66
+ d_h = d1
67
+ v = v
68
+ else:
69
+ raise ValueError(f"No calculations available for shape type {shape}")
70
+ elif shape is None:
71
+ d_h = d1
72
+ assert v is not None, 'Must assign either shape and dimensions or velocity'
73
+ else:
74
+ raise TypeError("Shape parameter must be string or None")
75
+
76
+ if detailed:
77
+ print('\t\tHydraulic diameter: ', d_h)
78
+ print('\t\tVelocity: ', v)
79
+
80
+ re = Re(statepoint, d_h, shape='rectangle', v=v)
81
+ if detailed:
82
+ print('\t\tRe: ', re)
83
+
84
+ ff = frictionfactor(re, roughness/d_h)
85
+ if detailed:
86
+ print('\t\tff: ', ff)
87
+
88
+ dP = (ff * rho / 2. * v**2 / d_h * L)
89
+ if detailed:
90
+ print('\t\tdP: ', dP)
91
+
92
+ if units == 'bar':
93
+ return dP * Quantity(1.e-5, 'bar^1*m^1*s^2*kg^-1')
94
+ if units in ('Pa', 'kg/m*s^2', 'kg*m^-1*s^-2'):
95
+ return dP
96
+ if units == 'kPa':
97
+ return dP * Quantity(1.e-3, 'kPa*kg^-1*m*s^2')
98
+ if units == 'psi':
99
+ return dP * Quantity(0.000145, 'psi*kg^-1*m*s^2')
100
+ if units == 'm':
101
+ return dP / (Quantity(9.81, 'm*s^-2') * statepoint.rho)
102
+ if units == 'in':
103
+ return (dP / (Quantity(9.81, 'm*s^-2') * statepoint.rho)).to('in')
104
+ else:
105
+ raise ValueError('No conversion for units ' + str(units))
106
+
107
+ def pressure_drop_sudden_expansion(statepoint, d1, d2,roughness, units='bar'):
108
+ """
109
+ Calculates the pressure drop through a sudden expansion
110
+ Based on https://neutrium.net/fluid_flow/pressure-loss-from-fittings-expansion-and-reduction-in-pipe-size/
111
+ :param Re: Reynolds number of the inlet flow [-]
112
+ :param d1: diameter of inlet flow [m]
113
+ :param d2: diameter of the outlet flow [m]
114
+ :param ff: Darcy friction factor [-]
115
+ :param units: return units
116
+ :return: pressure drop [return units]
117
+ """
118
+ v = statepoint.m / statepoint.rho / (3.14 / 4. * d1 ** 2.)
119
+ re = Re(statepoint, d1, shape='round', v=v)
120
+ ff = frictionfactor(re, roughness / d1)
121
+
122
+ # raise Exception('This model seems real dubious- value shouldn\'t get so big at high diameter ratios')
123
+ if re < 4000:
124
+ K = 2. * (1. - (d1 / d2)**4.)
125
+ else:
126
+ K = (1. + 0.8 * ff) * (1. - (d1 / d2)**2.)**2.
127
+
128
+ vel = statepoint.m / statepoint.rho / (3.14 / 4. * d1**2.)
129
+ dP = 0.5 * K * statepoint.rho * vel**2.
130
+ dP.to(units)
131
+ return dP
132
+
133
+ def pressure_drop_sudden_contraction(statepoint, roughness, d1, d2, units='bar'):
134
+ """
135
+ Calculates the pressure drop through a sudden contraction
136
+ Based on https://neutrium.net/fluid_flow/pressure-loss-from-fittings-expansion-and-reduction-in-pipe-size/
137
+ :param Re: Reynolds number of the inlet flow [-]
138
+ :param d1: diameter of inlet flow [m]
139
+ :param d2: diameter of the outlet flow [m]
140
+ :param ff: Darcy friction factor [-]
141
+ :param units: return units
142
+ :return: pressure drop [return units]
143
+ """
144
+ v = statepoint.m / statepoint.rho / (3.14 / 4. * d1 ** 2.)
145
+ re = Re(statepoint, d1, shape='round', v=v)
146
+ ff = frictionfactor(re, roughness / d1)
147
+ #raise Exception('This model seems real dubious- value shouldn\'t get so big at high diameter ratios')
148
+ if re < 2500:
149
+ K = (1.2 + 160. / re) * ((d1 / d2)**4. - 1.)
150
+ else:
151
+ K = (0.6 + 0.48 * ff) * (d1 / d2)**2. * ((d1 / d2)**2. - 1.)
152
+
153
+ dP = 0.5 * K * statepoint.rho * v**2.
154
+ dP.to(units)
155
+ print('Kc: ', K, 'Re: ', Re, 'ff: ', ff)
156
+ return dP
157
+
158
+ def pressure_drop_tapered_contraction(statepoint, Re, d1, d2, ff, angle, units='bar'):
159
+ """
160
+ Calculates the pressure drop through a sudden contraction
161
+ Based on https://neutrium.net/fluid_flow/pressure-loss-from-fittings-expansion-and-reduction-in-pipe-size/
162
+ :param Re: Reynolds number of the inlet flow [-]
163
+ :param d1: diameter of inlet flow [m]
164
+ :param d2: diameter of the outlet flow [m]
165
+ :param ff: Darcy friction factor [-]
166
+ :param units: return units
167
+ :param angle: angle between the axis of the pipe and the wall of the taper [degrees]
168
+ ----\
169
+ ( \
170
+ angle ( \\_____
171
+ flow----> ------ _____
172
+ /
173
+ /
174
+ ____/
175
+ :return: pressure drop [return units]
176
+ """
177
+ raise Exception('This model seems real dubious- value shouldn\'t get so big at high diameter ratios')
178
+ dP_base = pressure_drop_sudden_contraction(statepoint=statepoint, Re=Re, d1=d1, d2=d2, ff=ff, units=units)
179
+ if angle < 22.5:
180
+ dP = dP_base * 1.6 * sin(angle * 3.14 / 180.)
181
+ else:
182
+ dP = dP_base * sqrt(sin(angle * 3.14 / 180.))
183
+ return dP
184
+
185
+ def pressure_drop_tapered_expansion(statepoint, Re, d1, d2, ff, angle, units='bar'):
186
+ """
187
+ Calculates the pressure drop through a sudden contraction
188
+ Based on https://neutrium.net/fluid_flow/pressure-loss-from-fittings-expansion-and-reduction-in-pipe-size/
189
+ :param Re: Reynolds number of the inlet flow [-]
190
+ :param d1: diameter of inlet flow [m]
191
+ :param d2: diameter of the outlet flow [m]
192
+ :param ff: Darcy friction factor [-]
193
+ :param units: return units
194
+ :param angle: angle between the axis of the pipe and the wall of the taper [degrees]
195
+ ----\
196
+ ( \
197
+ angle ( \\_____
198
+ ------ _____ <--- flow
199
+ /
200
+ /
201
+ ____/
202
+ :return: pressure drop [return units]
203
+ """
204
+ raise Exception('This model seems real dubious- value shouldn\'t get so big at high diameter ratios')
205
+ dP_base = pressure_drop_sudden_expansion(statepoint=statepoint, Re=Re, d1=d1, d2=d2, ff=ff, units=units)
206
+ if angle < 22.5:
207
+ dP = dP_base * 2.6 * sin(angle * 3.14 / 180.)
208
+ else:
209
+ dP = dP_base
210
+ return dP
211
+
212
+ def pressure_drop_fitting(statepoint, fitting_type, d1, roughness, units='bar'):
213
+ """
214
+ Calculates the pressure drop through an elbow
215
+ Based on https://neutrium.net/fluid_flow/pressure-loss-from-fittings-equivalent-length-method/
216
+ Secondary source for L/d values: http://www.metropumps.com/ResourcesFrictionLossData.pdf
217
+ :param statepoint: statepoint instance of fluid flowing through pipe
218
+ :param fitting_type: 'elbow', 'long elbow', '45 elbow'
219
+ :param d1: Hydraulic diameter [m]
220
+ :param roughness: pipe roughness [m]
221
+ :param units: return units [str]
222
+ :return: pressure drop [return units]
223
+ """
224
+ ks = {'elbow-threaded': 30.,
225
+ 'elbow-welded': 20., # r/d = 1
226
+ 'long elbow-threaded': 16.,
227
+ 'long elbow-welded': 12., # r/d = 2
228
+ '45 elbow': 16.,
229
+ 'tee-straight': 20.,
230
+ 'tee-branch': 60.,
231
+ 'ball valve': 3.,
232
+ 'gate valve': 8.,
233
+ 'butterfly valve': 45., # Source 2, derived from k ratio of butterfly valve to gate valve
234
+ 'pipe entrance flush': 0.5, # Source 2
235
+ 'pipe exit': 1. # Source 2
236
+ }
237
+ try:
238
+ Ldeq = ks[fitting_type]
239
+ except:
240
+ raise ValueError('No minor loss coefficient for %s. Please select from %s' % (fitting_type, list(ks.keys())))
241
+ dP = pressure_drop(statepoint=statepoint, roughness=roughness, L=d1 * Ldeq, d1=d1, units=units)
242
+
243
+ return dP.to(units)
244
+
245
+ def pressure_drop_packed_bed(statepoint, L, d,A_cross,epsilon, units='bar'):
246
+ velocity = statepoint.m/(A_cross*statepoint.rho)
247
+ dP = L*(150.*statepoint.visc*velocity*(1-epsilon)**2/(d**2*epsilon**3) + 1.75*statepoint.rho*velocity**2*(1-epsilon)/(d*epsilon**3))
248
+
249
+ return dP.to(units)
250
+
251
+ def pressure_drop_corrugated_plates(statepoint, length, width, spacing, chevron_angle, detailed=False, units='bar'):
252
+ """
253
+ Calcualtes the pressure drop through a channel of corrugated plates, such as in a brazed plate heat exchanger
254
+ Based on http://achp.sourceforge.net/ACHPComponents/PlateHeatExchanger.html#single-phase-flow
255
+ Seems to match Alfa Lavals pressure drop calculations pretty well
256
+ :param statepoint: a statepoint instance of the fluid flowing through the hx
257
+ :param length: plate length (in direction of flow)
258
+ :param width: plate width (perpendicular to direction of flow)
259
+ :param spacing: spacing between the plates [m]
260
+ :param chevron_angle: Angle between flow direction and chevron lines in radians. pi/2 is perpendicular to flow, 0 is parallel to flow
261
+ :return: pressure drop in specified units
262
+ """
263
+ assert chevron_angle < 3.14/2., 'Chevron angle must be in radians, not degrees, and between 0 and pi/2'
264
+
265
+ vel = statepoint.m / (statepoint.rho * spacing * width)
266
+ if detailed:
267
+ print('\tVelocity: ', vel)
268
+ d_h = 2. * width * spacing / (width + spacing)
269
+ re = statepoint.rho * vel * d_h / statepoint.visc
270
+ if detailed:
271
+ print('\tReynolds number: ', re)
272
+
273
+ zeta0 = 1. / (1.8 * log(re) - 1.5) ** 2.
274
+ zeta1 = 3.8 * 39. / re ** 0.289
275
+ ff = 1. / (cos(chevron_angle) / sqrt(0.18 * tan(chevron_angle) + 0.36 * sin(chevron_angle) + zeta0 / cos(chevron_angle)) +
276
+ (1. - cos(chevron_angle)) / sqrt(zeta1)) ** 2.
277
+ if detailed:
278
+ print('\tFriction factor: ', ff)
279
+ hg = ff * re ** 2. / 2.
280
+ if detailed:
281
+ print('\tHagen number: ', hg)
282
+ dP_hg = hg * statepoint.visc ** 2. * length / (statepoint.rho * d_h ** 3.)
283
+ if detailed:
284
+ print('\tPressure drop: ', dP_hg)
285
+ return dP_hg.to(units)
286
+
287
+
288
+ def flow_at_dp(statepoint, dP, roughness, L, d1, d2=None, v=None, shape='round', props='REFPROP', detailed=False):
289
+ from thermofluids.Base import Statepoint
290
+ sp = Statepoint(fluid=statepoint.fluid, h=statepoint.h, p=statepoint.p, m=0.1)
291
+ res = 1.
292
+ while res > 0.001:
293
+ dP_check = pressure_drop(sp, roughness, L, d1, d2, v, shape, props, units=dP.units, detailed=detailed)
294
+ sp.set_m(sp.m * (dP / dP_check)**0.5)
295
+ res = abs(dP_check - dP) / dP.magnitude
296
+ if detailed:
297
+ print(sp.m, dP, dP_check, res)
298
+
299
+ return sp.m
300
+
301
+
302
+ if __name__ == '__main__':
303
+ from thermofluids.Base import Statepoint
304
+ from thermofluids.Base import Quantity
305
+
306
+ s = Statepoint(fluid='air')
307
+ s.set_t(0.)
308
+ s.set_p(1.)
309
+ s.set_m(3.)
310
+
311
+ # print PressureDrop(statepoint=s, roughness=1.e-6, L=100., d1=0.1, d2=1., shape='rectangle')
312
+ d1 = Quantity(0.1, 'm')
313
+ d2 = Quantity(0.2, 'm')
314
+ # print pressure_drop_sudden_expansion(statepoint=s, Re=6000., d1=d1, d2=d2, ff=1.e-5)
315
+
316
+ s = Statepoint(fluid='water', t=10., p=1., m=0.116)
317
+ dP = Quantity(0.5, 'bar')
318
+ roughness = Quantity(1.e-4, 'm')
319
+ L = Quantity(1., 'm')
320
+ d = Quantity(0.25, 'in').to('m')
321
+ s.set_m(flow_at_dp(statepoint=s, dP=dP, roughness=roughness, L=L, d1=d, detailed=True))
322
+ print('Pressure drop check: ', pressure_drop(statepoint=s, roughness=roughness, L=L, d1=d))
@@ -0,0 +1,88 @@
1
+ from warnings import warn
2
+
3
+ from thermofluids import Quantity, Statepoint
4
+
5
+
6
+ def Re(statepoint, d_h, d_2=None, shape='round', v=None):
7
+ assert type(statepoint) is Statepoint, 'Statepoint must be a statepoint instance'
8
+ assert type(d_h) is Quantity, 'Hydraulic diameter must a Quantity instance'
9
+ assert d_h.check('[length]'), f'Hydraulic diameter must have units of length but has units {d_h.units}'
10
+ if v == None:
11
+ if shape=='round' or shape=='circle':
12
+ v = statepoint.m / statepoint.rho / (3.14/4.*d_h**2.)
13
+ d_h_x = d_h
14
+ elif shape=='square':
15
+ v = statepoint.m / statepoint.rho / d_h**2.
16
+ d_h_x = d_h
17
+ elif shape=='rectangle':
18
+ v = statepoint.m / statepoint.rho / (d_h * d_2)
19
+ d_h_x = 2. * d_h * d_2 / (d_h + d_2)
20
+ elif shape=='annulus':
21
+ assert d_2 is not None, 'd_2 must be set for annulus'
22
+ assert d_h > d_2, 'd_h must be greater than d_2 for an annulus'
23
+ v = statepoint.m / statepoint.rho / (3.14 / 4. * (d_h**2. - d_2**2.))
24
+ d_h_x = d_h - d_2
25
+ else:
26
+ raise Exception("No velocity calc available for shape '%s'. Please provide a velocity as an input" % shape)
27
+ else:
28
+ d_h_x = d_h
29
+
30
+ rho = statepoint.rho
31
+ try:
32
+ mu = statepoint.visc
33
+ except ValueError as e:
34
+ newFluid = statepoint.fluid.split(':')[1].split('&')[0].split('[')[0]
35
+ warn('Using %s instead because ' % newFluid + e.message)
36
+ rho = statepoint.rho
37
+ if 0. <= statepoint.x <= 1.:
38
+ # if the fluid is saturated, use the same pressure and quality with just the first fluid, not a mixture
39
+ newSP = Statepoint(fluid=newFluid, p=statepoint.p, x=statepoint.x)
40
+ mu = newSP.visc
41
+ else:
42
+ # if the fluid is not saturated, set it to the same pressure and the same delta from the saturation temp
43
+ tSatOld = Statepoint(fluid=statepoint.fluid, p=statepoint.p, x=0.).t
44
+ tSatNew = Statepoint(fluid=newFluid, p=statepoint.p, x=0.).t
45
+ newSP = Statepoint(fluid=newFluid, p=statepoint.p, t=tSatNew + statepoint.t - tSatOld)
46
+ mu = newSP.visc
47
+
48
+ return rho * v * d_h_x / mu
49
+
50
+ def Re_ext(statepoint, vel, d1, d2=None, shape=None):
51
+ """
52
+ Reynolds number for external flow
53
+ :param statepoint: statepoint of fluid flowing over object
54
+ :param vel: velocty m/s
55
+ :param d1: dimension 1 [m]
56
+ :param d2: dimension 2 [m]
57
+ :param shape: not implemented
58
+ :return:
59
+ """
60
+ # TODO: expand to calculate d_h for different geometries rho = statepoint.rho
61
+ try:
62
+ mu = statepoint.visc
63
+ rho = statepoint.rho
64
+ except ValueError as e:
65
+ newFluid = statepoint.fluid.split(':')[1].split('&')[0].split('[')[0]
66
+ warn('Using %s instead because ' % newFluid + e.message)
67
+ rho = statepoint.rho
68
+ if 0. <= statepoint.x <= 1.:
69
+ # if the fluid is saturated, use the same pressure and quality with just the first fluid, not a mixture
70
+ newSP = Statepoint(fluid=newFluid, p=statepoint.p, x=statepoint.x)
71
+ mu = newSP.visc
72
+ else:
73
+ # if the fluid is not saturated, set it to the same pressure and the same delta from the saturation temp
74
+ tSatOld = Statepoint(fluid=statepoint.fluid, p=statepoint.p, x=0.).t
75
+ tSatNew = Statepoint(fluid=newFluid, p=statepoint.p, x=0.).t
76
+ newSP = Statepoint(fluid=newFluid, p=statepoint.p, t=tSatNew + statepoint.t - tSatOld)
77
+ mu = newSP.visc
78
+
79
+ return rho * vel * d1 / mu
80
+
81
+
82
+ if __name__ == "__main__":
83
+
84
+ s = Statepoint(fluid='water')
85
+ s.set_t(25.)
86
+ s.set_p(1.)
87
+ s.set_m(0.01)
88
+ print(Re(statepoint=s, d_h=Quantity(0.01, 'm')))
@@ -0,0 +1,4 @@
1
+ from thermofluids.Fluids.Drag import f_drag, settling_vel
2
+ from thermofluids.Fluids.Moody import frictionfactor
3
+ from thermofluids.Fluids.PressureDrop import pressure_drop, pressure_drop_fitting, pressure_drop_corrugated_plates, pressure_drop_packed_bed,pressure_drop_sudden_expansion,pressure_drop_sudden_contraction
4
+ from thermofluids.Fluids.Re import Re, Re_ext
@@ -0,0 +1,12 @@
1
+ from thermofluids.Base import Quantity, Statepoint
2
+
3
+
4
+ def Gr(statepoint, L, t_wall):
5
+ assert isinstance(statepoint, Statepoint)
6
+ assert isinstance(L, Quantity)
7
+ assert isinstance(t_wall, Quantity)
8
+
9
+ g = Quantity(9.81, 'm*s^-2')
10
+ gr = statepoint.rho ** 2. * g * statepoint.beta * L ** 3. * (t_wall - statepoint.t) / statepoint.visc ** 2.
11
+
12
+ return gr