turbo-design 1.3.7__py3-none-any.whl → 1.3.9__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.
Potentially problematic release.
This version of turbo-design might be problematic. Click here for more details.
- {turbo_design-1.3.7.dist-info → turbo_design-1.3.9.dist-info}/METADATA +2 -1
- turbo_design-1.3.9.dist-info/RECORD +46 -0
- {turbo_design-1.3.7.dist-info → turbo_design-1.3.9.dist-info}/WHEEL +1 -1
- turbodesign/__init__.py +57 -4
- turbodesign/agf.py +346 -0
- turbodesign/arrayfuncs.py +31 -1
- turbodesign/bladerow.py +237 -155
- turbodesign/compressor_math.py +374 -0
- turbodesign/compressor_spool.py +837 -0
- turbodesign/coolant.py +18 -6
- turbodesign/deviation/__init__.py +5 -0
- turbodesign/deviation/axial_compressor.py +3 -0
- turbodesign/deviation/carter_deviation.py +79 -0
- turbodesign/deviation/deviation_base.py +20 -0
- turbodesign/deviation/fixed_deviation.py +42 -0
- turbodesign/enums.py +5 -6
- turbodesign/flow_math.py +159 -0
- turbodesign/inlet.py +126 -56
- turbodesign/isentropic.py +59 -15
- turbodesign/loss/__init__.py +3 -1
- turbodesign/loss/compressor/OTAC_README.md +39 -0
- turbodesign/loss/compressor/__init__.py +54 -0
- turbodesign/loss/compressor/diffusion.py +61 -0
- turbodesign/loss/compressor/lieblein.py +1 -0
- turbodesign/loss/compressor/otac.py +799 -0
- turbodesign/loss/compressor/references/schobeiri-2012-shock-loss-model-for-transonic-and-supersonic-axial-compressors-with-curved-blades.pdf +0 -0
- turbodesign/loss/fixedpolytropic.py +27 -0
- turbodesign/loss/fixedpressureloss.py +30 -0
- turbodesign/loss/losstype.py +2 -30
- turbodesign/loss/turbine/TD2.py +25 -29
- turbodesign/loss/turbine/__init__.py +0 -1
- turbodesign/loss/turbine/ainleymathieson.py +6 -5
- turbodesign/loss/turbine/craigcox.py +6 -5
- turbodesign/loss/turbine/fixedefficiency.py +8 -7
- turbodesign/loss/turbine/kackerokapuu.py +7 -5
- turbodesign/loss/turbine/traupel.py +17 -16
- turbodesign/outlet.py +81 -22
- turbodesign/passage.py +98 -63
- turbodesign/radeq.py +3 -2
- turbodesign/row_factory.py +129 -0
- turbodesign/solve_radeq.py +9 -10
- turbodesign/{td_math.py → turbine_math.py} +125 -175
- turbodesign/turbine_spool.py +984 -0
- turbo_design-1.3.7.dist-info/RECORD +0 -33
- turbodesign/compressorspool.py +0 -60
- turbodesign/loss/turbine/fixedpressureloss.py +0 -25
- turbodesign/rotor.py +0 -38
- turbodesign/spool.py +0 -317
- turbodesign/turbinespool.py +0 -543
|
@@ -1,87 +1,17 @@
|
|
|
1
1
|
from typing import List, Optional, Tuple
|
|
2
|
+
import warnings
|
|
2
3
|
import numpy as np
|
|
3
|
-
import math
|
|
4
4
|
import numpy.typing as npt
|
|
5
|
+
from .isentropic import IsenP, IsenT
|
|
6
|
+
from turbodesign.loss import losstype
|
|
5
7
|
from .bladerow import BladeRow, compute_gas_constants
|
|
6
8
|
from .enums import RowType, LossType
|
|
9
|
+
from .outlet import OutletType
|
|
7
10
|
from scipy.integrate import trapezoid
|
|
11
|
+
from scipy.optimize import minimize
|
|
8
12
|
from .passage import Passage
|
|
9
13
|
from .isentropic import IsenP
|
|
10
|
-
|
|
11
|
-
def T0_coolant_weighted_average(row:BladeRow) -> float:
|
|
12
|
-
"""Calculate the new weighted Total Temperature array considering coolant
|
|
13
|
-
|
|
14
|
-
Args:
|
|
15
|
-
coolant (Coolant): Coolant
|
|
16
|
-
massflow (np.ndarray): massflow mainstream
|
|
17
|
-
|
|
18
|
-
Returns:
|
|
19
|
-
float: Total Temperature drop
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
massflow = row.massflow
|
|
23
|
-
total_massflow_no_coolant = row.total_massflow_no_coolant
|
|
24
|
-
Cp = row.Cp
|
|
25
|
-
|
|
26
|
-
Cpc = row.coolant.Cp
|
|
27
|
-
T0c = row.coolant.T0
|
|
28
|
-
massflow_coolant = row.coolant.massflow_percentage*total_massflow_no_coolant*row.massflow[1:]/row.massflow[-1]
|
|
29
|
-
if massflow_coolant.mean()>0:
|
|
30
|
-
if row.row_type == RowType.Stator:
|
|
31
|
-
T0= row.T0
|
|
32
|
-
dT0 = T0.copy() * 0
|
|
33
|
-
T0_new = (massflow[1:]*Cp*T0[1:] + massflow_coolant*Cpc*T0c) \
|
|
34
|
-
/(massflow[1:]*Cp + massflow_coolant*Cpc)
|
|
35
|
-
dT0[1:] = T0_new - row.T0[1:]
|
|
36
|
-
dT0[0] = dT0[1]
|
|
37
|
-
else:
|
|
38
|
-
T0R = row.T0R
|
|
39
|
-
T0R_new = T0R.copy()
|
|
40
|
-
Cp = row.Cp
|
|
41
|
-
T0R_new[1:] = (massflow[1:]*Cp*T0R[1:] + massflow_coolant*Cpc*T0c) \
|
|
42
|
-
/(massflow[1:]*Cp + massflow_coolant*Cpc)
|
|
43
|
-
T0R_new[0] = T0R_new[1]
|
|
44
|
-
|
|
45
|
-
T = T0R_new - row.W**2/(2*Cp) # Dont change the velocity triangle but adjust the static temperature
|
|
46
|
-
T0_new = T+row.V**2/(2*Cp) # Use new static temperature to calculate the total temperature
|
|
47
|
-
dT0 = T0_new - row.T0
|
|
48
|
-
return dT0
|
|
49
|
-
else:
|
|
50
|
-
return row.T0*0
|
|
51
|
-
|
|
52
|
-
def compute_massflow(row:BladeRow) -> None:
|
|
53
|
-
"""Populates row.massflow and row.calculated_massflow
|
|
54
|
-
|
|
55
|
-
Calculated_massflow is massflow[-1]
|
|
56
|
-
|
|
57
|
-
Args:
|
|
58
|
-
row (BladeRow): current blade row. All quantities are at exit
|
|
59
|
-
upstream (BladeRow): upstream blade row. All quantities are at exit
|
|
60
|
-
"""
|
|
61
|
-
massflow_fraction = np.linspace(0,1,len(row.percent_hub_shroud))
|
|
62
|
-
massflow = row.percent_hub_shroud*0
|
|
63
|
-
total_area = 0
|
|
64
|
-
for j in range(1,len(row.percent_hub_shroud)):
|
|
65
|
-
Vm = (row.Vm[j]+row.Vm[j-1])/2
|
|
66
|
-
rho = (row.rho[j]+row.rho[j-1])/2
|
|
67
|
-
if np.abs((row.x[j]-row.x[j-1]))<1E-5: # Axial Machines
|
|
68
|
-
total_area += np.pi*(row.r[j]**2-row.r[j-1]**2)
|
|
69
|
-
massflow[j] = Vm * rho * np.pi* (row.r[j]**2-row.r[j-1]**2) + massflow[j-1]
|
|
70
|
-
else: # Radial Machines
|
|
71
|
-
dx = row.x[j]-row.x[j-1]
|
|
72
|
-
S = (row.r[j]-row.r[j-1])
|
|
73
|
-
C = np.sqrt(1+((row.r[j]-row.r[j-1])/dx)**2)
|
|
74
|
-
area = 2*np.pi*C*(S/2*dx**2+row.r[j-1]*dx)
|
|
75
|
-
total_area += area
|
|
76
|
-
massflow[j] = Vm * rho *area + massflow[j-1]
|
|
77
|
-
|
|
78
|
-
row.total_massflow_no_coolant = massflow[-1]
|
|
79
|
-
if row.coolant != None:
|
|
80
|
-
massflow += massflow_fraction*row.coolant.massflow_percentage*row.total_massflow_no_coolant # Take into account the coolant massflow
|
|
81
|
-
row.massflow = massflow
|
|
82
|
-
row.calculated_massflow = massflow[-1]
|
|
83
|
-
row.total_massflow = massflow[-1]
|
|
84
|
-
row.area = total_area
|
|
14
|
+
from .flow_math import compute_massflow, compute_streamline_areas, compute_power
|
|
85
15
|
|
|
86
16
|
def compute_reynolds(rows:List[BladeRow],passage:Passage):
|
|
87
17
|
"""Calculates the Reynolds Number
|
|
@@ -111,34 +41,6 @@ def compute_reynolds(rows:List[BladeRow],passage:Passage):
|
|
|
111
41
|
row.axial_chord = max(c,1E-12) # Axial chord
|
|
112
42
|
# row.num_blades = int(2*np.pi*row.r.mean() / row.pitch_to_chord * row.axial_chord)
|
|
113
43
|
|
|
114
|
-
def compute_power(row:BladeRow,upstream:BladeRow) -> None:
|
|
115
|
-
"""Calculates the power
|
|
116
|
-
|
|
117
|
-
Args:
|
|
118
|
-
row (BladeRow): _description_
|
|
119
|
-
upstream (BladeRow): _description_
|
|
120
|
-
"""
|
|
121
|
-
if row.row_type == RowType.Stator:
|
|
122
|
-
row.power = 0
|
|
123
|
-
row.eta_static = 0
|
|
124
|
-
row.eta_total = 0
|
|
125
|
-
row.stage_loading = 0
|
|
126
|
-
row.euler_power = 0
|
|
127
|
-
row.T_is = 0 * row.T0
|
|
128
|
-
row.T0_is = 0 * row.T0 # Make it an array
|
|
129
|
-
else:
|
|
130
|
-
P0_P = (upstream.P0/row.P).mean()
|
|
131
|
-
row.T_is = upstream.T0 * (1/P0_P)**((row.gamma-1)/row.gamma)
|
|
132
|
-
a = np.sqrt(row.gamma*row.R*row.T_is)
|
|
133
|
-
row.T0_is = row.T_is * (1+(row.gamma-1)/2*(row.V/a)**2)
|
|
134
|
-
|
|
135
|
-
row.power = row.massflow[-1] * (row.Cp * (upstream.T0 - row.T0)).mean()
|
|
136
|
-
# row.power = sum(v * w for v, w in zip(row.power[1:], np.diff(row.massflow))) # Massflow weighted average
|
|
137
|
-
row.eta_static = row.power/ (row.massflow[-1]*row.Cp*(upstream.T0.mean()-row.T_is.mean()))
|
|
138
|
-
row.eta_total = (upstream.T0.mean() - row.T0.mean()) / (upstream.T0.mean() - row.T0_is.mean())
|
|
139
|
-
row.stage_loading = row.Cp*(upstream.T0.mean() - row.T0.mean())/row.U.mean()**2
|
|
140
|
-
row.euler_power = row.massflow[-1]* (upstream.U*upstream.Vt - row.U*row.Vt).mean()
|
|
141
|
-
|
|
142
44
|
def compute_quantities(row:BladeRow,upstream:BladeRow):
|
|
143
45
|
"""Calculation of all quantites after radial equilibrium has been solved assuming we know the static pressure at the exit.
|
|
144
46
|
|
|
@@ -152,14 +54,14 @@ def compute_quantities(row:BladeRow,upstream:BladeRow):
|
|
|
152
54
|
row (BladeRow): current blade row. All quantities are at exit
|
|
153
55
|
upstream (BladeRow): upstream blade row. All quantities are at exit
|
|
154
56
|
"""
|
|
155
|
-
|
|
156
57
|
if row.row_type == RowType.Rotor:
|
|
157
58
|
Cp_avg = (row.Cp+upstream.Cp)/2
|
|
158
59
|
# Factor any coolant added and changes in streamline radius
|
|
159
60
|
row.T0R = upstream.T0R - T0_coolant_weighted_average(row) # - (upstream.U**2-row.U**2)/(2*Cp_avg)
|
|
160
61
|
row.P = upstream.P0_stator_inlet/row.P0_P
|
|
161
|
-
|
|
162
|
-
|
|
62
|
+
|
|
63
|
+
loss_type = getattr(row.loss_function, "loss_type", None)
|
|
64
|
+
if loss_type == LossType.Pressure:
|
|
163
65
|
# This affects the velocity triangle
|
|
164
66
|
row.P0R = upstream.P0R - row.Yp*(upstream.P0R-row.P)
|
|
165
67
|
row.T = (row.P/row.P0R)**((row.gamma-1)/row.gamma) * row.T0R
|
|
@@ -168,7 +70,7 @@ def compute_quantities(row:BladeRow,upstream:BladeRow):
|
|
|
168
70
|
row.power = np.trapezoid(row.power_distribution,row.r-row.r[0])
|
|
169
71
|
row.power_mean = row.massflow[-1] * row.Cp * (upstream.T0.mean()-row.T0.mean())
|
|
170
72
|
|
|
171
|
-
elif
|
|
73
|
+
elif loss_type == LossType.Enthalpy:
|
|
172
74
|
' For Enthalpy related loss, assume the static quantities do not change '
|
|
173
75
|
row.T = (row.P/row.P0R)**((row.gamma-1)/row.gamma) * row.T0R
|
|
174
76
|
row.T0 = (1+(row.gamma-1)/2 * row.M**2) * row.T
|
|
@@ -196,7 +98,8 @@ def compute_quantities(row:BladeRow,upstream:BladeRow):
|
|
|
196
98
|
|
|
197
99
|
elif row.row_type == RowType.Stator:
|
|
198
100
|
' For the stator we already assume the upstream P0 already applied '
|
|
199
|
-
|
|
101
|
+
loss_type = getattr(row.loss_function, "loss_type", None)
|
|
102
|
+
if loss_type == LossType.Pressure:
|
|
200
103
|
row.P0 = upstream.P0 - row.Yp*(upstream.P0-row.P)
|
|
201
104
|
else:
|
|
202
105
|
row.P0 = upstream.P0
|
|
@@ -206,32 +109,45 @@ def compute_quantities(row:BladeRow,upstream:BladeRow):
|
|
|
206
109
|
row.T0R = row.T + row.W**2 / (2*row.Cp)
|
|
207
110
|
row.P0R = row.P*(row.T0R/row.T)**((row.gamma)/(row.gamma-1))
|
|
208
111
|
|
|
209
|
-
def stator_calc(row:BladeRow,upstream:BladeRow,downstream:Optional[BladeRow]=None,calculate_vm:bool=True):
|
|
112
|
+
def stator_calc(row:BladeRow,upstream:BladeRow,downstream:Optional[BladeRow]=None,calculate_vm:bool=True, outlet_type:OutletType=OutletType.static_pressure):
|
|
210
113
|
"""Given P0, T0, P, alpha2 of stator calculate all other quantities
|
|
211
114
|
|
|
212
115
|
Usage:
|
|
213
116
|
Set row.P0 = upstream.P0 - any pressure loss
|
|
214
117
|
row.T0 = upstream.T0 - any cooling
|
|
215
|
-
row.P = row.rp*(row.P0 - rotor.P) + rotor.P
|
|
216
|
-
Set alpha2
|
|
217
|
-
|
|
118
|
+
row.P = row.rp*(row.P0 - rotor.P) + rotor.P
|
|
119
|
+
Set alpha2
|
|
120
|
+
|
|
218
121
|
Args:
|
|
219
122
|
row (BladeRow): Stator Row
|
|
220
|
-
upstream (BladeRow): Stator or Rotor Row
|
|
123
|
+
upstream (BladeRow): Stator or Rotor Row
|
|
221
124
|
downstream (BladeRow): Stator or Rotor Row. Defaults to None
|
|
222
|
-
|
|
125
|
+
calculate_vm (bool): True to calculate the meridional velocity. False, do not calculate this and let radeq calculate it
|
|
126
|
+
outlet_type (OutletType): OutletType.static_pressure if static conditions defined at outlet, OutletType.total_pressure if total conditions defined
|
|
223
127
|
"""
|
|
224
|
-
|
|
225
|
-
#
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
128
|
+
|
|
129
|
+
# Static Pressure is assumed
|
|
130
|
+
T0_coolant = 0
|
|
131
|
+
if row.coolant is not None:
|
|
132
|
+
T0_coolant = T0_coolant_weighted_average(row)
|
|
133
|
+
row.T0 = upstream.T0 - T0_coolant
|
|
134
|
+
|
|
135
|
+
loss_type = getattr(row.loss_function, "loss_type", None)
|
|
136
|
+
if loss_type == LossType.Pressure:
|
|
137
|
+
row.P0 = upstream.P0 - row.Yp*(upstream.P0-row.P) # When static conditions are defined, use it to calculate P0
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
elif loss_type == LossType.Enthalpy:
|
|
141
|
+
b = row.total_area * row.P0 / np.sqrt(row.T0) * np.sqrt(row.gamma/row.R)
|
|
142
|
+
solve_for_M = upstream.total_massflow / b
|
|
143
|
+
fun = lambda M : np.abs(solve_for_M - M*(1+(row.gamma-1)/2 * M**2) ** (-(row.gamma+1)/(2*(row.gamma-1))))
|
|
144
|
+
M_subsonic = minimize(fun,0.1, method='L-BFGS-B', bounds=[0,1])
|
|
145
|
+
M_supersonic = minimize(fun,1.5, method='L-BFGS-B', bounds=[1,5])
|
|
146
|
+
row.M = M_subsonic
|
|
147
|
+
row.T = row.T0/IsenT(M_subsonic,row.gamma)
|
|
148
|
+
a = np.sqrt(row.T*row.gamma*row.R)
|
|
149
|
+
row.P = row.total_massflow * row.R*row.T / (row.total_area * row.M * a) # Use the massflow to find static pressure
|
|
150
|
+
|
|
235
151
|
if downstream is not None:
|
|
236
152
|
row.P0_P = float((row.P0/downstream.P).mean())
|
|
237
153
|
row.rp = ((row.P-downstream.P)/(upstream.P0-downstream.P)).mean()
|
|
@@ -240,7 +156,6 @@ def stator_calc(row:BladeRow,upstream:BladeRow,downstream:Optional[BladeRow]=Non
|
|
|
240
156
|
row.M = ((row.P0/row.P)**((row.gamma-1)/row.gamma) - 1) * 2/(row.gamma-1)
|
|
241
157
|
row.M = np.sqrt(row.M)
|
|
242
158
|
T0_T = (1+(row.gamma-1)/2 * row.M**2)
|
|
243
|
-
row.T0 = upstream.T0 - T0_coolant_weighted_average(row)
|
|
244
159
|
row.T = row.T0/T0_T
|
|
245
160
|
row.V = row.M*np.sqrt(row.gamma*row.R*row.T)
|
|
246
161
|
row.Vm = row.V*np.cos(row.alpha2)
|
|
@@ -252,7 +167,6 @@ def stator_calc(row:BladeRow,upstream:BladeRow,downstream:Optional[BladeRow]=Non
|
|
|
252
167
|
row.Vr = row.Vm*np.sin(row.phi)
|
|
253
168
|
row.Vt = row.Vm*np.tan(row.alpha2)
|
|
254
169
|
row.V = np.sqrt(row.Vx**2 + row.Vr**2 + row.Vt**2)
|
|
255
|
-
|
|
256
170
|
row.T = row.P/(row.R*row.rho) # We know P, this is a guess
|
|
257
171
|
row.M = row.V/np.sqrt(row.gamma*row.R*row.T)
|
|
258
172
|
|
|
@@ -264,12 +178,14 @@ def stator_calc(row:BladeRow,upstream:BladeRow,downstream:Optional[BladeRow]=Non
|
|
|
264
178
|
row.Wt = row.Vt-row.U
|
|
265
179
|
row.P0_stator_inlet = upstream.P0
|
|
266
180
|
|
|
267
|
-
def rotor_calc(row:BladeRow,upstream:BladeRow,calculate_vm:bool=True):
|
|
268
|
-
"""Calculates quantities given beta2
|
|
181
|
+
def rotor_calc(row:BladeRow,upstream:BladeRow,calculate_vm:bool=True,outlet_type:OutletType=OutletType.static_pressure):
|
|
182
|
+
"""Calculates quantities given beta2
|
|
269
183
|
|
|
270
184
|
Args:
|
|
271
185
|
row (BladeRow): Rotor Row
|
|
272
186
|
upstream (BladeRow): Stator Row or Rotor Row
|
|
187
|
+
calculate_vm (bool): True to calculate the meridional velocity. False, do not calculate this and let radeq calculate it
|
|
188
|
+
outlet_type (OutletType): OutletType.static_pressure if static conditions defined at outlet, OutletType.total_pressure if total conditions defined
|
|
273
189
|
"""
|
|
274
190
|
def _log_rotor_failure(reason:str):
|
|
275
191
|
def _fmt(val):
|
|
@@ -295,10 +211,7 @@ def rotor_calc(row:BladeRow,upstream:BladeRow,calculate_vm:bool=True):
|
|
|
295
211
|
## P0_P is assumed
|
|
296
212
|
# row.P = row.P0_stator_inlet*1/row.P0_P
|
|
297
213
|
|
|
298
|
-
# Static Pressure is assumed
|
|
299
|
-
row.P0_P = (row.P0_stator_inlet/row.P).mean()
|
|
300
214
|
upstream_radius = upstream.r
|
|
301
|
-
row.U = row.omega*row.r
|
|
302
215
|
# Upstream Relative Frame Calculations
|
|
303
216
|
upstream.U = upstream.rpm*np.pi/30 * upstream_radius # rad/s
|
|
304
217
|
upstream.Wt = upstream.Vt - upstream.U
|
|
@@ -307,17 +220,23 @@ def rotor_calc(row:BladeRow,upstream:BladeRow,calculate_vm:bool=True):
|
|
|
307
220
|
upstream.T0R = upstream.T+upstream.W**2/(2*upstream.Cp)
|
|
308
221
|
upstream.P0R = upstream.P * (upstream.T0R/upstream.T)**((upstream.gamma)/(upstream.gamma-1))
|
|
309
222
|
upstream.M_rel = upstream.W/np.sqrt(upstream.gamma*upstream.R*upstream.T)
|
|
310
|
-
|
|
311
223
|
upstream_rothalpy = upstream.T0R*upstream.Cp - 0.5*upstream.U**2 # H01R - 1/2 U1^2
|
|
224
|
+
row.U = row.omega*row.r
|
|
225
|
+
|
|
312
226
|
if np.any(upstream_rothalpy < 0):
|
|
313
227
|
print('U is too high, reduce RPM or radius')
|
|
228
|
+
|
|
314
229
|
# Rotor Exit Calculations
|
|
315
230
|
row.beta1 = upstream.beta2
|
|
316
231
|
#row.Yp # Evaluated earlier
|
|
317
232
|
row.P0R = upstream.P0R - row.Yp*(upstream.P0R-row.P)
|
|
318
|
-
|
|
233
|
+
|
|
234
|
+
|
|
319
235
|
# Total Relative Temperature stays constant through the rotor. Adjust for change in radius from rotor inlet to exit
|
|
320
|
-
|
|
236
|
+
T0_coolant = 0
|
|
237
|
+
if row.coolant is not None:
|
|
238
|
+
T0_coolant = T0_coolant_weighted_average(row)
|
|
239
|
+
row.T0R = upstream.T0R - T0_coolant # (upstream_rothalpy + 0.5*row.U**2)/row.Cp # - T0_coolant_weighted_average(row)
|
|
321
240
|
P0R_P = row.P0R / row.P
|
|
322
241
|
T0R_T = P0R_P**((row.gamma-1)/row.gamma)
|
|
323
242
|
row.T = (row.T0R/T0R_T) # Exit static temperature
|
|
@@ -344,7 +263,6 @@ def rotor_calc(row:BladeRow,upstream:BladeRow,calculate_vm:bool=True):
|
|
|
344
263
|
row.M = row.V/np.sqrt(row.gamma*row.R*row.T)
|
|
345
264
|
row.Vm = np.sqrt(row.Vx**2+row.Vr**2)
|
|
346
265
|
row.T0 = row.T + row.V**2/(2*row.Cp)
|
|
347
|
-
row.P0 = row.P*(row.T0/row.T)**(row.gamma/(row.gamma-1))
|
|
348
266
|
row.alpha2 = np.arctan2(row.Vt,row.Vm)
|
|
349
267
|
else: # We know Vm, P0, T0
|
|
350
268
|
row.Vr = row.Vm*np.sin(row.phi)
|
|
@@ -353,15 +271,16 @@ def rotor_calc(row:BladeRow,upstream:BladeRow,calculate_vm:bool=True):
|
|
|
353
271
|
row.W = np.sqrt(2*row.Cp*(row.T0R-row.T))
|
|
354
272
|
row.Wt = row.W*np.sin(row.beta2)
|
|
355
273
|
row.U = row.omega * row.r
|
|
356
|
-
row.Vt = row.Wt+row.U
|
|
274
|
+
row.Vt = row.Wt + row.U
|
|
357
275
|
|
|
358
276
|
row.alpha2 = np.arctan2(row.Vt,row.Vm)
|
|
359
277
|
row.V = np.sqrt(row.Vm**2*(1+np.tan(row.alpha2)**2))
|
|
360
278
|
|
|
361
279
|
row.M = row.V/np.sqrt(row.gamma*row.R*row.T)
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
280
|
+
T0_T = (1+(row.gamma-1)/2 * row.M**2)
|
|
281
|
+
row.P0 = row.P * T0_T**(row.gamma/(row.gamma-1))
|
|
282
|
+
row.P0_P = (row.P0_stator_inlet/row.P).mean()
|
|
283
|
+
|
|
365
284
|
row.M_rel = row.W/np.sqrt(row.gamma*row.R*row.T)
|
|
366
285
|
row.T0 = row.T+row.V**2/(2*row.Cp)
|
|
367
286
|
|
|
@@ -371,40 +290,71 @@ def inlet_calc(row:BladeRow):
|
|
|
371
290
|
Args:
|
|
372
291
|
row (BladeRow): _description_
|
|
373
292
|
"""
|
|
374
|
-
|
|
375
|
-
area = row.Vm.copy()*0
|
|
376
293
|
# Estimate the density
|
|
377
|
-
row.T = row.T0
|
|
378
|
-
row.P = row.P0
|
|
379
|
-
|
|
380
|
-
total_area = 0
|
|
381
|
-
for iter in range(5): # Lets converge the Mach and Total and Static pressures
|
|
382
|
-
for j in range(1,len(row.percent_hub_shroud)):
|
|
383
|
-
rho = row.rho[j]
|
|
384
|
-
tube_massflow = row.massflow[j]-row.massflow[j-1]
|
|
385
|
-
if np.abs((row.x[j]-row.x[j-1]))<1E-6: # Axial Machines
|
|
386
|
-
total_area += np.pi*(row.r[j]**2-row.r[j-1]**2)
|
|
387
|
-
row.Vm[j] = tube_massflow/(rho*np.pi*(row.r[j]**2-row.r[j-1]**2))
|
|
388
|
-
else: # Radial Machines
|
|
389
|
-
dx = row.x[j]-row.x[j-1]
|
|
390
|
-
S = (row.r[j]-row.r[j-1])
|
|
391
|
-
C = np.sqrt(1+((row.r[j]-row.r[j-1])/dx)**2)
|
|
392
|
-
area[j] = 2*np.pi*C*(S/2*dx**2+row.r[j-1]*dx)
|
|
393
|
-
total_area += area[j]
|
|
394
|
-
row.Vm[j] = tube_massflow/(rho*area[j])
|
|
395
|
-
avg_mach = np.mean(row.M)
|
|
396
|
-
row.Vm[0] = 1/(len(row.Vm)-1)*row.Vm[1:].sum() # Initialize the value at the hub to not upset the mean
|
|
397
|
-
row.Vr = row.Vm*np.sin(row.phi)
|
|
398
|
-
row.Vt = row.Vm*np.tan(row.alpha2)
|
|
399
|
-
row.V = np.sqrt(row.Vt**2+row.Vm**2)
|
|
400
|
-
# Fine tune the Temperature and Pressure and density
|
|
401
|
-
row.M = row.V/np.sqrt(row.gamma*row.R*row.T)
|
|
402
|
-
row.T = row.T0 * 1/(1+(row.gamma-1)/2*row.M**2)
|
|
403
|
-
row.P = row.P0 * (row.T/row.T0)**(row.gamma/(row.gamma-1))
|
|
404
|
-
compute_gas_constants(row)
|
|
294
|
+
row.T = row.T0 * 1/(1+(row.gamma-1)/2*row.M**2)
|
|
295
|
+
row.P = row.P0 * (row.T/row.T0)**(row.gamma/(row.gamma-1))
|
|
296
|
+
compute_gas_constants(row)
|
|
405
297
|
|
|
406
|
-
|
|
407
|
-
|
|
298
|
+
total_area, streamline_area = compute_streamline_areas(row)
|
|
299
|
+
row.total_area = total_area
|
|
300
|
+
row.area = streamline_area
|
|
301
|
+
Vm_tube = np.zeros(len(row.percent_hub_shroud)-1)
|
|
302
|
+
|
|
303
|
+
Vm_mean = row.total_massflow / (row.rho.mean()*row.total_area)
|
|
304
|
+
for j in range(1,len(row.percent_hub_shroud)):
|
|
305
|
+
rho = row.rho[j]
|
|
306
|
+
Vm_tube[j-1] = (row.massflow[j]-row.massflow[j-1])/(rho*row.area[j])
|
|
307
|
+
|
|
308
|
+
# Recover per-streamline Vm from tube-averaged Vm_tube assuming piecewise linear variation
|
|
309
|
+
row.Vm[0] = Vm_tube[0] if len(Vm_tube) else Vm_mean
|
|
310
|
+
for j in range(1, len(row.percent_hub_shroud)):
|
|
311
|
+
rho_bar = 0.5 * (row.rho[j] + row.rho[j-1])
|
|
312
|
+
Vm_tube_j = (row.massflow[j] - row.massflow[j-1]) / (rho_bar * row.area[j] + 1e-12)
|
|
313
|
+
row.Vm[j] = 2 * Vm_tube_j - row.Vm[j-1]
|
|
314
|
+
|
|
315
|
+
row.Vr = row.Vm*np.sin(row.phi)
|
|
316
|
+
row.V = row.M*np.sqrt(row.gamma*row.R*row.T)
|
|
317
|
+
row.Vt = row.V*np.sin(row.alpha2)
|
|
318
|
+
row.Vx = row.Vm*np.cos(row.phi)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def T0_coolant_weighted_average(row:BladeRow) -> npt.NDArray:
|
|
322
|
+
"""Calculate the new weighted Total Temperature array considering coolant
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
row (BladeRow): Coolant
|
|
326
|
+
massflow (np.ndarray): massflow mainstream
|
|
327
|
+
|
|
328
|
+
Returns:
|
|
329
|
+
float: Total Temperature drop
|
|
330
|
+
"""
|
|
331
|
+
|
|
332
|
+
massflow = row.massflow
|
|
333
|
+
total_massflow_no_coolant = row.total_massflow_no_coolant
|
|
334
|
+
Cp = row.Cp
|
|
408
335
|
|
|
409
|
-
|
|
410
|
-
|
|
336
|
+
Cpc = row.coolant.Cp
|
|
337
|
+
T0c = row.coolant.T0
|
|
338
|
+
massflow_coolant = row.coolant.massflow_percentage*total_massflow_no_coolant*row.massflow[1:]/row.massflow[-1]
|
|
339
|
+
if massflow_coolant.mean()>0:
|
|
340
|
+
if row.row_type == RowType.Stator:
|
|
341
|
+
T0= row.T0
|
|
342
|
+
dT0 = T0.copy() * 0
|
|
343
|
+
T0_new = (massflow[1:]*Cp*T0[1:] + massflow_coolant*Cpc*T0c) \
|
|
344
|
+
/(massflow[1:]*Cp + massflow_coolant*Cpc)
|
|
345
|
+
dT0[1:] = T0_new - row.T0[1:]
|
|
346
|
+
dT0[0] = dT0[1]
|
|
347
|
+
else: # Rotor use relative total temperature
|
|
348
|
+
T0R = row.T0R
|
|
349
|
+
T0R_new = T0R.copy()
|
|
350
|
+
Cp = row.Cp
|
|
351
|
+
T0R_new[1:] = (massflow[1:]*Cp*T0R[1:] + massflow_coolant*Cpc*T0c) \
|
|
352
|
+
/(massflow[1:]*Cp + massflow_coolant*Cpc)
|
|
353
|
+
T0R_new[0] = T0R_new[1]
|
|
354
|
+
|
|
355
|
+
T = T0R_new - row.W**2/(2*Cp) # Dont change the velocity triangle but adjust the static temperature
|
|
356
|
+
T0_new = T+row.V**2/(2*Cp) # Use new static temperature to calculate the total temperature
|
|
357
|
+
dT0 = T0_new - row.T0
|
|
358
|
+
return dT0
|
|
359
|
+
else:
|
|
360
|
+
return row.T0*0
|