turbo-design 1.1.3__py3-none-any.whl → 1.2.1__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.1.3.dist-info → turbo_design-1.2.1.dist-info}/METADATA +2 -3
- {turbo_design-1.1.3.dist-info → turbo_design-1.2.1.dist-info}/RECORD +12 -12
- {turbo_design-1.1.3.dist-info → turbo_design-1.2.1.dist-info}/WHEEL +1 -1
- turbodesign/bladerow.py +26 -20
- turbodesign/coolant.py +2 -2
- turbodesign/inlet.py +47 -19
- turbodesign/passage.py +41 -12
- turbodesign/radeq.py +6 -1
- turbodesign/solve_radeq.py +2 -1
- turbodesign/spool.py +5 -5
- turbodesign/td_math.py +26 -23
- turbodesign/turbinespool.py +59 -49
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: turbo-design
|
|
3
|
-
Version: 1.1
|
|
3
|
+
Version: 1.2.1
|
|
4
4
|
Summary: TurboDesign is a library used to design turbines and compressors using radial equilibrium.
|
|
5
5
|
Author: Paht Juangphanich
|
|
6
6
|
Author-email: paht.juangphanich@nasa.gov
|
|
@@ -10,7 +10,6 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
10
10
|
Classifier: Programming Language :: Python :: 3.10
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.11
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
14
13
|
Requires-Dist: cantera
|
|
15
14
|
Requires-Dist: findiff
|
|
16
15
|
Requires-Dist: matplotlib
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
turbodesign/__init__.py,sha256=N8Nu0I1vrlEHYJZZ7yhhg-FtbNbLyrgjy7hoicygUqg,325
|
|
2
2
|
turbodesign/arrayfuncs.py,sha256=GHIlTyLfeNsNCQQoh5m1aXK3iyvU6RjdYQipkqpU_ps,519
|
|
3
|
-
turbodesign/bladerow.py,sha256=
|
|
3
|
+
turbodesign/bladerow.py,sha256=M28spmHMwPc_3jVxzjzPwY-mbn4aeX5GrBEf4UomqYA,24857
|
|
4
4
|
turbodesign/cantera_gas/co2.yaml,sha256=M2o_RzxV9B9rDkgkXJC-l3voKraFZguTZuKKt4F7S_c,887
|
|
5
5
|
turbodesign/compressorspool.py,sha256=z8ZVczJ-EdZvIqqZArC6UdwC5MbU2SZh_MT2CGq5avY,2600
|
|
6
|
-
turbodesign/coolant.py,sha256=
|
|
6
|
+
turbodesign/coolant.py,sha256=evDtUFOYhfZKTVAsDWzxRzUX20gTvfjj0uybaWg4CsI,427
|
|
7
7
|
turbodesign/enums.py,sha256=T4aFrGMnx9fgZkrExMBIY2IbCueA0utqr_afk-TUe9Q,1188
|
|
8
|
-
turbodesign/inlet.py,sha256=
|
|
8
|
+
turbodesign/inlet.py,sha256=9vAI0rf8O03SV5iI2Kf154cktlPFzyuW-LR2Xy2hWz0,7365
|
|
9
9
|
turbodesign/isentropic.py,sha256=YLTmNx69e_M5fTuLOmk_KvaQ6ABv0aZsityfBihJOmI,2003
|
|
10
10
|
turbodesign/loss/__init__.py,sha256=ZJomzXa6ElduFruURukCrFwJQXMWS2aW8JSaVQ-M2r8,46
|
|
11
11
|
turbodesign/loss/compressor/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
@@ -20,14 +20,14 @@ turbodesign/loss/turbine/kackerokapuu.py,sha256=hUmZdyA1hAhN3_xbwBhka2dyk0Aq9rqq
|
|
|
20
20
|
turbodesign/loss/turbine/traupel.py,sha256=aZxFE9JDcCfi1gy-fqS1SxjjlhuDG-H-g3LPurty1M0,4164
|
|
21
21
|
turbodesign/lossinterp.py,sha256=B2KEobp-nD9jwD6UINgBmTlH9kKyWg3UNvXxqfUsr-k,6198
|
|
22
22
|
turbodesign/outlet.py,sha256=SwTwoL6XnWlsrE5A6wLxu3qXkydDDUsdKKeBbJm4mrQ,2069
|
|
23
|
-
turbodesign/passage.py,sha256=
|
|
24
|
-
turbodesign/radeq.py,sha256=
|
|
23
|
+
turbodesign/passage.py,sha256=63ScNtLXd6T8flIre6dLsdSzjeS17PvH1atZhHdarEU,10788
|
|
24
|
+
turbodesign/radeq.py,sha256=gD-UYRuS1372GuxuOlhV13nEDqvFAVSf05fnZiF31Mo,10300
|
|
25
25
|
turbodesign/rotor.py,sha256=tHl9o5H4aQ6Etd4gqa8Ime1UK7k0de4GLt5Yb1sJdGs,1376
|
|
26
|
-
turbodesign/solve_radeq.py,sha256=
|
|
27
|
-
turbodesign/spool.py,sha256=
|
|
26
|
+
turbodesign/solve_radeq.py,sha256=CK8uuvhs5jv0v0G90aUjKz0f_SOU16whnJWEiFCeUUA,1971
|
|
27
|
+
turbodesign/spool.py,sha256=kopByiu36urGuAfvDx9EI0DtMTt5leW3c2jUL3j4QhA,14216
|
|
28
28
|
turbodesign/stage.py,sha256=UP45sDKDLsAkO_WfDWJ6kqXU7cYKh_4QO01QZnSN1oQ,166
|
|
29
|
-
turbodesign/td_math.py,sha256=
|
|
30
|
-
turbodesign/turbinespool.py,sha256=
|
|
31
|
-
turbo_design-1.1.
|
|
32
|
-
turbo_design-1.1.
|
|
33
|
-
turbo_design-1.1.
|
|
29
|
+
turbodesign/td_math.py,sha256=ZZmyCCAqha548bb5pkzqlhiGtvhtw8JO9qBAePNaleU,16098
|
|
30
|
+
turbodesign/turbinespool.py,sha256=xRqUmwyzNP5Hm5V9iLj_hcq8gWXpS_6-V90ev9VFZ5g,26619
|
|
31
|
+
turbo_design-1.2.1.dist-info/METADATA,sha256=ez_QBe7YfLBUE67nJZKrqVFpDnL-fDkB3dQ3Nxb_v_M,683
|
|
32
|
+
turbo_design-1.2.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
33
|
+
turbo_design-1.2.1.dist-info/RECORD,,
|
turbodesign/bladerow.py
CHANGED
|
@@ -26,7 +26,6 @@ class BladeRow:
|
|
|
26
26
|
Cp: float = 1019 # Cp J/(Kg*K)
|
|
27
27
|
Cv: float = 1019/1.14 # Cv J/(Kg*K)
|
|
28
28
|
_coolant:Coolant = None # type: ignore # Coolant Fluid
|
|
29
|
-
fluid: composite.Solution = Solution("air.yaml")
|
|
30
29
|
mu:float = 0
|
|
31
30
|
|
|
32
31
|
total_massflow:float = 0 # Massflow spool + all upstream cooling flow [kg/s]
|
|
@@ -437,7 +436,7 @@ class BladeRow:
|
|
|
437
436
|
self._te_s = val
|
|
438
437
|
|
|
439
438
|
def __repr__(self):
|
|
440
|
-
return f"{self.row_type.name
|
|
439
|
+
return f"{self.row_type.name} P0:{np.mean(self.P0):0.2f} T0:{np.mean(self.T0):0.2f} P:{np.mean(self.P):0.2f} massflow:{np.mean(self.total_massflow_no_coolant):0.3f}"
|
|
441
440
|
|
|
442
441
|
def to_dict(self):
|
|
443
442
|
|
|
@@ -463,10 +462,10 @@ class BladeRow:
|
|
|
463
462
|
"Vx":self.Vx.tolist(),
|
|
464
463
|
"Vr":self.Vr.tolist(),
|
|
465
464
|
"Vt":self.Vt.tolist(),
|
|
465
|
+
"U":self.U.tolist(),
|
|
466
466
|
"V":self.V.tolist(),
|
|
467
467
|
"M":self.M.tolist(),
|
|
468
468
|
"M_rel":self.M_rel.tolist(),
|
|
469
|
-
"U":self.U.tolist(),
|
|
470
469
|
"W":self.W.tolist(),
|
|
471
470
|
"Wt":self.Wt.tolist(),
|
|
472
471
|
"omega":self.omega,
|
|
@@ -488,6 +487,10 @@ class BladeRow:
|
|
|
488
487
|
"aspect_ratio":self.aspect_ratio,
|
|
489
488
|
"num_blades":self.num_blades,
|
|
490
489
|
"area": self.area,
|
|
490
|
+
"radius":self.r.tolist(),
|
|
491
|
+
"x":self.x.tolist(),
|
|
492
|
+
"dx":self.x[-1]-self.x[0],
|
|
493
|
+
"dr":self.r[-1]-self.r[0],
|
|
491
494
|
"mprime":self.mprime[-1],
|
|
492
495
|
"Reynolds":self.Reynolds,
|
|
493
496
|
"axial_chord":self.axial_chord
|
|
@@ -605,21 +608,24 @@ def interpolate_quantities(q:npt.NDArray,r:npt.NDArray,r2:npt.NDArray):
|
|
|
605
608
|
else:
|
|
606
609
|
return interp1d(r,q,kind='linear')(r2)
|
|
607
610
|
|
|
608
|
-
def compute_gas_constants(row:BladeRow):
|
|
609
|
-
"""
|
|
610
|
-
|
|
611
|
+
def compute_gas_constants(row:BladeRow,fluid:Solution=None) -> None:
|
|
612
|
+
"""Updates the Cp, Gamma, and density for a blade row. If fluid is not specified then only density and viscosity is updated.
|
|
613
|
+
|
|
614
|
+
Args:
|
|
615
|
+
row (BladeRow): _description_
|
|
616
|
+
fluid (Solution, optional): _description_. Defaults to None.
|
|
617
|
+
|
|
618
|
+
Returns:
|
|
619
|
+
(BladeRow): updated row
|
|
611
620
|
"""
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
# row.rho[i] = P/(T*row.R)
|
|
624
|
-
# i+=1
|
|
625
|
-
return row
|
|
621
|
+
if fluid:
|
|
622
|
+
Tm = row.T.mean()
|
|
623
|
+
Pm = row.P.mean()
|
|
624
|
+
fluid.TP = Tm,Pm
|
|
625
|
+
row.Cp = row.fluid.cp
|
|
626
|
+
row.Cv = row.fluid.cv
|
|
627
|
+
row.R = row.Cp-row.Cv
|
|
628
|
+
row.gamma = row.Cp/row.Cv
|
|
629
|
+
# Use Ideal Gas
|
|
630
|
+
row.rho = row.P/(row.T*row.R)
|
|
631
|
+
row.mu = sutherland(row.T) # type: ignore
|
turbodesign/coolant.py
CHANGED
|
@@ -3,8 +3,8 @@ from cantera import Solution
|
|
|
3
3
|
|
|
4
4
|
@dataclass
|
|
5
5
|
class Coolant:
|
|
6
|
-
fluid:Solution = field(default = Solution('air.yaml')) # cantera solution
|
|
7
6
|
T0:float = field(default=900) # Kelvin
|
|
8
7
|
P0:float = field(default=50*101325) # Pascal
|
|
9
|
-
massflow_percentage:float = field(default=0.03) # Fraction of total massflow going through compressor
|
|
8
|
+
massflow_percentage:float = field(default=0.03) # Fraction of total massflow going through compressor
|
|
9
|
+
Cp:float = field(default=1000) # J/K
|
|
10
10
|
|
turbodesign/inlet.py
CHANGED
|
@@ -16,50 +16,78 @@ class Inlet(BladeRow):
|
|
|
16
16
|
(BladeRow): Defines the properties of the blade row
|
|
17
17
|
"""
|
|
18
18
|
fun: interp1d
|
|
19
|
-
|
|
19
|
+
|
|
20
|
+
def __init__(self,M:float,T0:Union[float,List[float]],
|
|
21
|
+
P0:Union[float,List[float]],
|
|
22
|
+
axial_location:float=0,
|
|
23
|
+
beta:Union[float,List[float]]=[0],
|
|
24
|
+
percent_radii:Union[float,List[float]]=[0.5]):
|
|
20
25
|
"""Initializes the inlet station.
|
|
21
26
|
Uses the beta and exit mach number to predict a value for Vm
|
|
22
27
|
|
|
23
28
|
Args:
|
|
24
29
|
M (float): Mach number at the inlet plane
|
|
25
|
-
beta (Union[float,List[float]]): exit relative flow angle
|
|
26
30
|
T0 (Union[float,List[float]]): Total Temperature Array
|
|
27
31
|
P0 (Union[float,List[float]]): Total Pressure Array
|
|
28
32
|
percent_radii (Union[float,List[float]]): Radius where total pressure and temperature are defined
|
|
29
|
-
fluid (ct.Solution): Cantera mixture
|
|
30
33
|
axial_location (float): Axial Location as a percentage of hub length
|
|
31
34
|
beta (Union[float,List[float]], optional): Inlet flow angle in relative direction. Defaults to [].
|
|
35
|
+
|
|
32
36
|
"""
|
|
33
37
|
super().__init__(row_type=RowType.Inlet,axial_location=axial_location,stage_id=-1)
|
|
34
|
-
self.loss_function = None
|
|
35
38
|
self.beta1 = convert_to_ndarray(beta)
|
|
36
39
|
self.M = convert_to_ndarray(M)
|
|
37
40
|
self.T0 = convert_to_ndarray(T0)
|
|
38
41
|
self.P0 = convert_to_ndarray(P0)
|
|
39
42
|
self.percent_hub_shroud = convert_to_ndarray(percent_radii)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def initialize_fluid(self,fluid:Solution=None,R:float=287.15,gamma:float=1.4,Cp:float=1024):
|
|
46
|
+
"""Initialize the inlet using the fluid. This function should be called by a class that inherits from spool
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
fluid (Solution, optional): Cantera fluid object. Defaults to None.
|
|
50
|
+
R (float, optional): Ideal Gas Constant. Defaults to 287.15 J/(Kg K) for air
|
|
51
|
+
gamma (float, optional): _description_. Defaults to 1.4.
|
|
52
|
+
Cp (float, optional): _description_. Defaults to 1024 J/(Kg K).
|
|
53
|
+
|
|
54
|
+
"""
|
|
55
|
+
self.loss_function = None
|
|
56
|
+
|
|
40
57
|
# if it's inlet alpha and beta are the same, relative flow angle = absolute.
|
|
41
|
-
self.beta2 = np.radians(convert_to_ndarray(
|
|
42
|
-
self.alpha1 = np.radians(convert_to_ndarray(
|
|
43
|
-
fluid.TP = self.T0.mean(),self.P0.mean()
|
|
44
|
-
self.gamma = fluid.cp/fluid.cv
|
|
58
|
+
self.beta2 = np.radians(convert_to_ndarray(self.beta1))
|
|
59
|
+
self.alpha1 = np.radians(convert_to_ndarray(self.beta1))
|
|
45
60
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
61
|
+
if fluid:
|
|
62
|
+
fluid.TP = self.T0.mean(),self.P0.mean()
|
|
63
|
+
self.gamma = fluid.cp/fluid.cv
|
|
64
|
+
self.T = self.T0 * 1/(1 + (self.gamma-1) * self.M**2)
|
|
65
|
+
self.P = self.P0 * 1/(1 + (self.gamma-1) * self.M**2)**(self.gamma/(self.gamma-1))
|
|
66
|
+
fluid.TP = self.T.mean(),self.P.mean()
|
|
67
|
+
self.rho = convert_to_ndarray([fluid.density])
|
|
68
|
+
else:
|
|
69
|
+
self.Cp = Cp
|
|
70
|
+
self.gamma = gamma
|
|
71
|
+
self.R = R
|
|
72
|
+
self.T = self.T0 * 1/(1 + (self.gamma-1) * self.M**2)
|
|
73
|
+
self.P = self.P0 * 1/(1 + (self.gamma-1) * self.M**2)**(self.gamma/(self.gamma-1))
|
|
74
|
+
self.rho = self.P/(self.R*self.T)
|
|
75
|
+
|
|
51
76
|
self.rpm = 0
|
|
52
|
-
|
|
53
77
|
self.beta1_metal = [0]
|
|
54
78
|
self.beta2_metal = [0]
|
|
55
|
-
self.P0_fun = interp1d(self.percent_hub_shroud,P0)
|
|
56
|
-
self.T0_fun = interp1d(self.percent_hub_shroud,T0)
|
|
79
|
+
self.P0_fun = interp1d(self.percent_hub_shroud,self.P0)
|
|
80
|
+
self.T0_fun = interp1d(self.percent_hub_shroud,self.T0)
|
|
57
81
|
self.mprime = [0]
|
|
58
|
-
|
|
59
82
|
|
|
60
83
|
def initialize_velocity(self,passage:Passage,num_streamlines:int):
|
|
61
84
|
"""Initialize velocity calculations. Assumes streamlines and inclination angles have been calculated
|
|
62
|
-
|
|
85
|
+
Call this before performing calculations
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
passage (Passage): Passage object
|
|
89
|
+
num_streamlines (int): number of streamlines
|
|
90
|
+
|
|
63
91
|
"""
|
|
64
92
|
# Perform Calculations on Velocity
|
|
65
93
|
Vm_prev = 0; Vm_err = 0
|
|
@@ -84,7 +112,7 @@ class Inlet(BladeRow):
|
|
|
84
112
|
self.V = np.sqrt(self.Vm**2 + self.Vt**2)
|
|
85
113
|
self.Vr = self.Vm * np.sin(self.phi)
|
|
86
114
|
|
|
87
|
-
|
|
115
|
+
compute_gas_constants(self)
|
|
88
116
|
rho_mean = self.rho.mean()
|
|
89
117
|
for i in range(len(self.massflow)-1):
|
|
90
118
|
tube_massflow = self.massflow[i+1]-self.massflow[i]
|
turbodesign/passage.py
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
from typing import List, Tuple
|
|
2
2
|
import numpy as np
|
|
3
3
|
import numpy.typing as npt
|
|
4
|
-
from scipy.interpolate import
|
|
4
|
+
from scipy.interpolate import PchipInterpolator
|
|
5
5
|
from pyturbo.helper import line2D
|
|
6
6
|
from .enums import PassageType
|
|
7
7
|
from scipy.optimize import minimize_scalar
|
|
8
8
|
from findiff import FinDiff
|
|
9
|
-
from pyturbo.helper import convert_to_ndarray
|
|
9
|
+
from pyturbo.helper import convert_to_ndarray,xr_to_mprime
|
|
10
10
|
import matplotlib.pyplot as plt
|
|
11
11
|
|
|
12
12
|
class Passage:
|
|
13
|
-
xhub:
|
|
14
|
-
rhub:
|
|
13
|
+
xhub:PchipInterpolator
|
|
14
|
+
rhub:PchipInterpolator
|
|
15
15
|
xhub_pts:npt.NDArray
|
|
16
16
|
rhub_pts:npt.NDArray
|
|
17
17
|
|
|
18
|
-
xshroud:
|
|
19
|
-
rshroud:
|
|
18
|
+
xshroud:PchipInterpolator
|
|
19
|
+
rshroud:PchipInterpolator
|
|
20
20
|
xshroud_pts:npt.NDArray
|
|
21
21
|
rshroud_pts:npt.NDArray
|
|
22
22
|
|
|
@@ -25,6 +25,7 @@ class Passage:
|
|
|
25
25
|
|
|
26
26
|
x_streamlines:npt.NDArray
|
|
27
27
|
r_streamlines:npt.NDArray
|
|
28
|
+
hub_arc_len:float
|
|
28
29
|
|
|
29
30
|
def __init__(self,xhub:List[float],rhub:List[float],
|
|
30
31
|
xshroud:List[float],rshroud:List[float],
|
|
@@ -41,12 +42,15 @@ class Passage:
|
|
|
41
42
|
assert len(xhub) == len(xshroud), "xHub and xShroud should be the same length"
|
|
42
43
|
assert len(rhub) == len(rshroud), "rHub and rShroud should be the same length"
|
|
43
44
|
|
|
45
|
+
hub_arc_len = xr_to_mprime(np.vstack([xhub,rhub]).transpose())[1]
|
|
46
|
+
self.hub_arc_len = hub_arc_len[-1]
|
|
47
|
+
|
|
48
|
+
self.xhub = PchipInterpolator(hub_arc_len/hub_arc_len[-1],xhub) # Get the xhub,rhub in terms of the hub arc len
|
|
49
|
+
self.rhub = PchipInterpolator(hub_arc_len/hub_arc_len[-1],rhub)
|
|
50
|
+
self.xshroud = PchipInterpolator(hub_arc_len/hub_arc_len[-1],xshroud)
|
|
51
|
+
self.rshroud = PchipInterpolator(hub_arc_len/hub_arc_len[-1],rshroud)
|
|
52
|
+
|
|
44
53
|
self.n = len(xhub)
|
|
45
|
-
t_streamline = np.linspace(0,1,len(xhub))
|
|
46
|
-
self.xhub = interp1d(t_streamline,xhub)
|
|
47
|
-
self.rhub = interp1d(t_streamline,rhub)
|
|
48
|
-
self.xshroud = interp1d(t_streamline,xshroud)
|
|
49
|
-
self.rshroud = interp1d(t_streamline,rshroud)
|
|
50
54
|
|
|
51
55
|
self.xhub_pts = convert_to_ndarray(xhub)
|
|
52
56
|
self.rhub_pts = convert_to_ndarray(rhub)
|
|
@@ -137,6 +141,30 @@ class Passage:
|
|
|
137
141
|
r = r_streamline
|
|
138
142
|
|
|
139
143
|
return phi, rm, r
|
|
144
|
+
|
|
145
|
+
def get_area(self,t_hub:float) -> float:
|
|
146
|
+
"""Get Area
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
t_hub (float): Percent arc length along the hub
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
float: Area
|
|
153
|
+
"""
|
|
154
|
+
n = 100
|
|
155
|
+
line = self.get_cutting_line(t_hub)[0]
|
|
156
|
+
x,r = line.get_point(np.linspace(0,1,n))
|
|
157
|
+
total_area = 0
|
|
158
|
+
for j in range(1,n):
|
|
159
|
+
if np.abs((x[-1]-x[0]))<1E-12: # Axial Machines
|
|
160
|
+
total_area += np.pi*(r[j]**2-r[j-1]**2)
|
|
161
|
+
else: # Radial Machines
|
|
162
|
+
dx = x[j]-x[j-1]
|
|
163
|
+
S = (r[j]-r[j-1])
|
|
164
|
+
C = np.sqrt(1+((r[j]-r[j-1])/dx)**2)
|
|
165
|
+
area = 2*np.pi*C*(S/2*dx**2+r[j-1]*dx)
|
|
166
|
+
total_area += area
|
|
167
|
+
return total_area
|
|
140
168
|
|
|
141
169
|
def get_cutting_line(self, t_hub:float) -> line2D:
|
|
142
170
|
"""Gets the cutting line perpendicular to hub and shroud
|
|
@@ -148,7 +176,7 @@ class Passage:
|
|
|
148
176
|
(Tuple) containing:
|
|
149
177
|
|
|
150
178
|
cut (line2D): line from hub to shroud
|
|
151
|
-
t_hub (float):
|
|
179
|
+
t_hub (float): Percentage along hub arc length
|
|
152
180
|
t_shroud (float): t corresponding to intersection of bisector of hub
|
|
153
181
|
|
|
154
182
|
"""
|
|
@@ -195,6 +223,7 @@ class Passage:
|
|
|
195
223
|
np.NDArray: _description_
|
|
196
224
|
"""
|
|
197
225
|
t_hub = np.linspace(axial_location[0],axial_location[1],100)
|
|
226
|
+
t_hub = convert_to_ndarray(t_hub)*self.hub_length
|
|
198
227
|
|
|
199
228
|
shroud_pts_cyl = np.vstack([self.xshroud(t_hub),self.rshroud(t_hub)]).transpose()
|
|
200
229
|
hub_pts_cyl = np.vstack([self.xhub(t_hub),self.rhub(t_hub)]).transpose()
|
turbodesign/radeq.py
CHANGED
|
@@ -79,7 +79,12 @@ def radeq(row:BladeRow,upstream:BladeRow) -> BladeRow:
|
|
|
79
79
|
raise Exception("Invalid value of C {C}, change reduce alpha or Vm")
|
|
80
80
|
B = (1-C)**(gamma/(gamma-1))
|
|
81
81
|
A = P0 * gamma/(gamma-1) * (1-C)**(1/(gamma-1))
|
|
82
|
-
|
|
82
|
+
|
|
83
|
+
epsilon = 1e-10 # or another small threshold
|
|
84
|
+
if abs(rm) > epsilon:
|
|
85
|
+
dVm_dr = 1/(2*Vm*A) * (rho*(Vt/r - Vm**2/rm * np.cos(phi) - Vr*dVr_dr) - dP0_dr*B) + 1/(2*T0) *dT0_dr # Eqn 6
|
|
86
|
+
else:
|
|
87
|
+
dVm_dr = 1/(2*Vm*A) * (rho*(Vt/r - Vr*dVr_dr) - dP0_dr*B) + 1/(2*T0) *dT0_dr # Eqn 6
|
|
83
88
|
|
|
84
89
|
ydot = np.array([dP0_dr,dT0_dr,dVm_dr])
|
|
85
90
|
|
turbodesign/solve_radeq.py
CHANGED
|
@@ -18,7 +18,8 @@ def adjust_streamlines(blade_rows:List[BladeRow],passage:Passage):
|
|
|
18
18
|
passage (Passage): passage object describing the hub and shroud
|
|
19
19
|
|
|
20
20
|
"""
|
|
21
|
-
for
|
|
21
|
+
for row_index,row in enumerate(blade_rows):
|
|
22
|
+
print(f"Adjusting Streamlines to balance massflow Row: {row_index}")
|
|
22
23
|
massflow_fraction = np.linspace(0,1,len(row.percent_hub_shroud))
|
|
23
24
|
row.total_massflow = row.massflow[-1]
|
|
24
25
|
ideal_massflow_fraction = row.massflow[-1] * massflow_fraction
|
turbodesign/spool.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# type: ignore[arg-type, reportUnknownArgumentType]
|
|
2
2
|
from dataclasses import field
|
|
3
3
|
import json
|
|
4
|
-
from typing import Dict, List, Union
|
|
4
|
+
from typing import Dict, List, Union, Optional
|
|
5
5
|
import matplotlib.pyplot as plt
|
|
6
6
|
from .bladerow import BladeRow
|
|
7
7
|
import numpy as np
|
|
@@ -70,13 +70,12 @@ class Spool:
|
|
|
70
70
|
2. Counter Rotation: We either use the RPM already persecribed for each blade row.
|
|
71
71
|
'''
|
|
72
72
|
if (type(self.blade_rows[i]) != Inlet) and (type(self.blade_rows[i]) != Outlet):
|
|
73
|
-
self.blade_rows[i].fluid = self.fluid
|
|
74
73
|
self.blade_rows[i].rpm = rpm
|
|
75
74
|
self.blade_rows[i].axial_chord = self.blade_rows[i].axial_location * self.passage.hub_length
|
|
76
75
|
|
|
77
76
|
|
|
78
77
|
@property
|
|
79
|
-
def fluid(self):
|
|
78
|
+
def fluid(self) -> Optional[Solution]:
|
|
80
79
|
return self._fluid
|
|
81
80
|
|
|
82
81
|
@fluid.setter
|
|
@@ -164,8 +163,9 @@ class Spool:
|
|
|
164
163
|
self.calculate_streamline_curvature(row,t_radial)
|
|
165
164
|
|
|
166
165
|
# Set the loss function if it's not set
|
|
167
|
-
if (row
|
|
168
|
-
row.loss_function
|
|
166
|
+
if (type(row)!= Inlet and type(row) != Outlet):
|
|
167
|
+
if row.loss_function == None:
|
|
168
|
+
row.loss_function = TD2()
|
|
169
169
|
|
|
170
170
|
def calculate_streamline_curvature(self,row:BladeRow,t_radial:Union[List[float],npt.NDArray]):
|
|
171
171
|
"""Called to calculate new streamline curvature
|
turbodesign/td_math.py
CHANGED
|
@@ -6,6 +6,7 @@ from .bladerow import BladeRow, compute_gas_constants
|
|
|
6
6
|
from .enums import RowType, LossType
|
|
7
7
|
from scipy.integrate import trapezoid
|
|
8
8
|
from .passage import Passage
|
|
9
|
+
from .isentropic import IsenP
|
|
9
10
|
|
|
10
11
|
def T0_coolant_weighted_average(row:BladeRow) -> float:
|
|
11
12
|
"""Calculate the new weighted Total Temperature array considering coolant
|
|
@@ -17,11 +18,12 @@ def T0_coolant_weighted_average(row:BladeRow) -> float:
|
|
|
17
18
|
Returns:
|
|
18
19
|
float: Total Temperature drop
|
|
19
20
|
"""
|
|
20
|
-
|
|
21
|
+
|
|
21
22
|
massflow = row.massflow
|
|
22
23
|
total_massflow_no_coolant = row.total_massflow_no_coolant
|
|
23
24
|
Cp = row.Cp
|
|
24
|
-
|
|
25
|
+
|
|
26
|
+
Cpc = row.coolant.Cp
|
|
25
27
|
T0c = row.coolant.T0
|
|
26
28
|
massflow_coolant = row.coolant.massflow_percentage*total_massflow_no_coolant*row.massflow[1:]/row.massflow[-1]
|
|
27
29
|
if massflow_coolant.mean()>0:
|
|
@@ -35,8 +37,9 @@ def T0_coolant_weighted_average(row:BladeRow) -> float:
|
|
|
35
37
|
else:
|
|
36
38
|
T0R = row.T0R
|
|
37
39
|
T0R_new = T0R.copy()
|
|
40
|
+
Cp = row.Cp
|
|
38
41
|
T0R_new[1:] = (massflow[1:]*Cp*T0R[1:] + massflow_coolant*Cpc*T0c) \
|
|
39
|
-
/(massflow[1:]*
|
|
42
|
+
/(massflow[1:]*Cp + massflow_coolant*Cpc)
|
|
40
43
|
T0R_new[0] = T0R_new[1]
|
|
41
44
|
|
|
42
45
|
T = T0R_new - row.W**2/(2*Cp) # Dont change the velocity triangle but adjust the static temperature
|
|
@@ -61,7 +64,7 @@ def compute_massflow(row:BladeRow) -> None:
|
|
|
61
64
|
for j in range(1,len(row.percent_hub_shroud)):
|
|
62
65
|
Vm = (row.Vm[j]+row.Vm[j-1])/2
|
|
63
66
|
rho = (row.rho[j]+row.rho[j-1])/2
|
|
64
|
-
if np.abs((row.x[j]-row.x[j-1]))<1E-
|
|
67
|
+
if np.abs((row.x[j]-row.x[j-1]))<1E-5: # Axial Machines
|
|
65
68
|
total_area += np.pi*(row.r[j]**2-row.r[j-1]**2)
|
|
66
69
|
massflow[j] = Vm * rho * np.pi* (row.r[j]**2-row.r[j-1]**2) + massflow[j-1]
|
|
67
70
|
else: # Radial Machines
|
|
@@ -77,6 +80,7 @@ def compute_massflow(row:BladeRow) -> None:
|
|
|
77
80
|
massflow += massflow_fraction*row.coolant.massflow_percentage*row.total_massflow_no_coolant # Take into account the coolant massflow
|
|
78
81
|
row.massflow = massflow
|
|
79
82
|
row.calculated_massflow = massflow[-1]
|
|
83
|
+
row.total_massflow = massflow[-1]
|
|
80
84
|
row.area = total_area
|
|
81
85
|
|
|
82
86
|
def compute_reynolds(rows:List[BladeRow],passage:Passage):
|
|
@@ -125,11 +129,14 @@ def compute_power(row:BladeRow,upstream:BladeRow) -> None:
|
|
|
125
129
|
row.T_is = 0
|
|
126
130
|
row.T0_is = 0
|
|
127
131
|
else:
|
|
128
|
-
|
|
129
|
-
row.
|
|
132
|
+
P0_P = (upstream.P0/row.P).mean()
|
|
133
|
+
row.T_is = upstream.T0 * (1/P0_P)**((row.gamma-1)/row.gamma)
|
|
134
|
+
a = np.sqrt(row.gamma*row.R*row.T_is)
|
|
135
|
+
row.T0_is = row.T_is * (1+(row.gamma-1)/2*(row.V/a)**2)
|
|
136
|
+
|
|
130
137
|
row.power = row.massflow[-1] * row.Cp * (upstream.T0.mean() - row.T0.mean())
|
|
131
|
-
row.eta_static = row.power/ (row.massflow[-1]*row.Cp*(upstream.T0.mean()-row.
|
|
132
|
-
row.eta_total =
|
|
138
|
+
row.eta_static = row.power/ (row.massflow[-1]*row.Cp*(upstream.T0.mean()-row.T_is.mean()))
|
|
139
|
+
row.eta_total = (upstream.T0.mean() - row.T0.mean()) / (upstream.T0.mean() - row.T0_is.mean())
|
|
133
140
|
row.stage_loading = row.Cp*(upstream.T0.mean() - row.T0.mean())/row.U.mean()**2
|
|
134
141
|
row.euler_power = row.massflow[-1]* (upstream.U*upstream.Vt - row.U*row.Vt).mean()
|
|
135
142
|
|
|
@@ -150,7 +157,7 @@ def compute_quantities(row:BladeRow,upstream:BladeRow):
|
|
|
150
157
|
if row.row_type == RowType.Rotor:
|
|
151
158
|
Cp_avg = (row.Cp+upstream.Cp)/2
|
|
152
159
|
# Factor any coolant added and changes in streamline radius
|
|
153
|
-
row.T0R = upstream.T0R - T0_coolant_weighted_average(row) - (upstream.U**2-row.U**2)/(2*Cp_avg)
|
|
160
|
+
row.T0R = upstream.T0R - T0_coolant_weighted_average(row) # - (upstream.U**2-row.U**2)/(2*Cp_avg)
|
|
154
161
|
row.P = upstream.P0_stator_inlet/row.P0_P
|
|
155
162
|
|
|
156
163
|
if row.loss_function.loss_type == LossType.Pressure:
|
|
@@ -232,13 +239,13 @@ def stator_calc(row:BladeRow,upstream:BladeRow,downstream:BladeRow=None,calculat
|
|
|
232
239
|
if calculate_vm:
|
|
233
240
|
row.M = ((row.P0/row.P)**((row.gamma-1)/row.gamma) - 1) * 2/(row.gamma-1)
|
|
234
241
|
row.M = np.sqrt(row.M)
|
|
235
|
-
T0_T = (1+(row.gamma-1)/2 * row.M
|
|
242
|
+
T0_T = (1+(row.gamma-1)/2 * row.M**2)
|
|
236
243
|
row.T0 = upstream.T0 - T0_coolant_weighted_average(row)
|
|
237
244
|
row.T = row.T0/T0_T
|
|
238
245
|
row.V = row.M*np.sqrt(row.gamma*row.R*row.T)
|
|
246
|
+
row.Vm = row.V*np.cos(row.alpha2)
|
|
239
247
|
row.Vx = row.Vm*np.cos(row.phi)
|
|
240
|
-
row.Vr = row.
|
|
241
|
-
row.Vm = np.sqrt(row.Vx**2+row.Vr**2)
|
|
248
|
+
row.Vr = row.Vm*np.sin(row.phi)
|
|
242
249
|
row.Vt = row.Vm*np.tan(row.alpha2)
|
|
243
250
|
else: # We know Vm, P0, T0, P
|
|
244
251
|
row.Vx = row.Vm*np.cos(row.phi)
|
|
@@ -289,7 +296,7 @@ def rotor_calc(row:BladeRow,upstream:BladeRow,calculate_vm:bool=True):
|
|
|
289
296
|
row.P0R = upstream.P0R - row.Yp*(upstream.P0R-row.P)
|
|
290
297
|
|
|
291
298
|
# Total Relative Temperature stays constant through the rotor. Adjust for change in radius from rotor inlet to exit
|
|
292
|
-
row.T0R = (upstream_rothalpy + 0.5*row.U**2)/row.Cp - T0_coolant_weighted_average(row)
|
|
299
|
+
row.T0R =upstream.T0R - T0_coolant_weighted_average(row) # (upstream_rothalpy + 0.5*row.U**2)/row.Cp - T0_coolant_weighted_average(row)
|
|
293
300
|
P0R_P = row.P0R / row.P
|
|
294
301
|
T0R_T = P0R_P**((row.gamma-1)/row.gamma)
|
|
295
302
|
row.T = (row.T0R/T0R_T) # Exit static temperature
|
|
@@ -297,7 +304,7 @@ def rotor_calc(row:BladeRow,upstream:BladeRow,calculate_vm:bool=True):
|
|
|
297
304
|
row.W = np.sqrt(2*row.Cp*(row.T0R-row.T)) #! nan popups here a lot for radial machines
|
|
298
305
|
if np.isnan(np.sum(row.W)):
|
|
299
306
|
# Need to adjust T
|
|
300
|
-
|
|
307
|
+
raise ValueError(f'nan detected: check flow path. Turbine inlet cut should be horizontal')
|
|
301
308
|
row.Vr = row.W*np.sin(row.phi)
|
|
302
309
|
row.Vm = row.W*np.cos(row.beta2)
|
|
303
310
|
row.Wt = row.W*np.sin(row.beta2)
|
|
@@ -327,11 +334,6 @@ def rotor_calc(row:BladeRow,upstream:BladeRow,calculate_vm:bool=True):
|
|
|
327
334
|
|
|
328
335
|
row.M_rel = row.W/np.sqrt(row.gamma*row.R*row.T)
|
|
329
336
|
row.T0 = row.T+row.V**2/(2*row.Cp)
|
|
330
|
-
|
|
331
|
-
T3_is = upstream.T0 * (1/row.P0_P)**((row.gamma-1)/row.gamma)
|
|
332
|
-
a = np.sqrt(row.gamma*row.R*T3_is)
|
|
333
|
-
T03_is = T3_is * (1+(row.gamma-1)/2*(row.V/a)**2)
|
|
334
|
-
row.eta_total = (upstream.T0.mean() - row.T0.mean())/(upstream.T0.mean()-T03_is.mean())
|
|
335
337
|
|
|
336
338
|
def inlet_calc(row:BladeRow):
|
|
337
339
|
"""Calculates the conditions for the Inlet
|
|
@@ -339,12 +341,13 @@ def inlet_calc(row:BladeRow):
|
|
|
339
341
|
Args:
|
|
340
342
|
row (BladeRow): _description_
|
|
341
343
|
"""
|
|
344
|
+
|
|
342
345
|
area = row.Vm.copy()*0
|
|
343
346
|
# Estimate the density
|
|
344
347
|
row.T = row.T0
|
|
345
|
-
row.P = row.P0
|
|
348
|
+
row.P = row.P0
|
|
346
349
|
row.rho = row.P/(row.T*row.R)
|
|
347
|
-
total_area = 0
|
|
350
|
+
total_area = 0
|
|
348
351
|
for iter in range(5): # Lets converge the Mach and Total and Static pressures
|
|
349
352
|
for j in range(1,len(row.percent_hub_shroud)):
|
|
350
353
|
rho = row.rho[j]
|
|
@@ -361,9 +364,9 @@ def inlet_calc(row:BladeRow):
|
|
|
361
364
|
row.Vm[j] = tube_massflow/(rho*area[j])
|
|
362
365
|
avg_mach = np.mean(row.M)
|
|
363
366
|
if np.mean(row.M)>0.5:
|
|
364
|
-
|
|
367
|
+
raise ValueError(f"High inlet mach can lead to errors iter:{iter} Mach:{avg_mach}")
|
|
365
368
|
if np.mean(row.M)<0.01:
|
|
366
|
-
|
|
369
|
+
raise ValueError(f"Unusually slow flow:{iter} Mach:{avg_mach}")
|
|
367
370
|
row.Vm[0] = 1/(len(row.Vm)-1)*row.Vm[1:].sum() # Initialize the value at the hub to not upset the mean
|
|
368
371
|
row.Vr = row.Vm*np.sin(row.phi)
|
|
369
372
|
row.Vt = row.Vm*np.cos(row.phi)*np.tan(row.alpha2)
|
turbodesign/turbinespool.py
CHANGED
|
@@ -10,17 +10,18 @@ import numpy as np
|
|
|
10
10
|
import numpy.typing as npt
|
|
11
11
|
from .td_math import inlet_calc,rotor_calc, stator_calc, compute_massflow, compute_power, compute_gas_constants, compute_reynolds
|
|
12
12
|
from .solve_radeq import adjust_streamlines, radeq
|
|
13
|
-
from scipy.optimize import minimize_scalar,
|
|
13
|
+
from scipy.optimize import minimize_scalar, differential_evolution, fmin_slsqp
|
|
14
14
|
from .inlet import Inlet
|
|
15
15
|
from .outlet import Outlet
|
|
16
16
|
|
|
17
17
|
class TurbineSpool(Spool):
|
|
18
|
+
|
|
18
19
|
def __init__(self,passage:Passage,
|
|
19
20
|
massflow:float,rows:List[BladeRow],
|
|
20
21
|
num_streamlines:int=3,
|
|
21
22
|
fluid:Solution=Solution('air.yaml'),
|
|
22
23
|
rpm:float=-1,
|
|
23
|
-
|
|
24
|
+
massflow_constraint:MassflowConstraint=MassflowConstraint.MatchMassFlow):
|
|
24
25
|
"""Initializes a Turbine Spool
|
|
25
26
|
|
|
26
27
|
Args:
|
|
@@ -45,21 +46,22 @@ class TurbineSpool(Spool):
|
|
|
45
46
|
# Inlet
|
|
46
47
|
W0 = self.massflow
|
|
47
48
|
inlet = self.blade_rows[0]
|
|
48
|
-
if self.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
self.blade_rows[
|
|
49
|
+
if self.fluid:
|
|
50
|
+
inlet.initialize_fluid(self.fluid)
|
|
51
|
+
else:
|
|
52
|
+
inlet.initialize_fluid(R=self.blade_rows[1].R,
|
|
53
|
+
gamma=self.blade_rows[1].gamma,
|
|
54
|
+
Cp=self.blade_rows[1].Cp)
|
|
55
|
+
|
|
56
|
+
inlet.total_massflow = W0
|
|
57
|
+
inlet.total_massflow_no_coolant = W0
|
|
58
|
+
inlet.massflow = np.linspace(0,1,self.num_streamlines)*W0
|
|
52
59
|
|
|
53
|
-
|
|
60
|
+
inlet.initialize_velocity(self.passage,self.num_streamlines)
|
|
61
|
+
interpolate_streamline_radii(inlet,self.passage,self.num_streamlines)
|
|
54
62
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
self.blade_rows[0].Cp = self.blade_rows[0].fluid.cp
|
|
58
|
-
self.blade_rows[0].Cv = self.blade_rows[0].fluid.cv
|
|
59
|
-
self.blade_rows[0].R = self.blade_rows[0].Cp-self.blade_rows[0].Cv
|
|
60
|
-
self.blade_rows[0].gamma = self.blade_rows[0].Cp/self.blade_rows[0].Cv
|
|
61
|
-
self.blade_rows[0].rho[:] = self.blade_rows[0].fluid.density
|
|
62
|
-
inlet_calc(self.blade_rows[0])
|
|
63
|
+
compute_gas_constants(inlet,self.fluid)
|
|
64
|
+
inlet_calc(inlet)
|
|
63
65
|
|
|
64
66
|
for row in self.blade_rows:
|
|
65
67
|
interpolate_streamline_radii(row,self.passage,self.num_streamlines)
|
|
@@ -83,10 +85,10 @@ class TurbineSpool(Spool):
|
|
|
83
85
|
|
|
84
86
|
row = self.blade_rows[i]
|
|
85
87
|
if (row.coolant is not None):
|
|
86
|
-
T0c = self.blade_rows[i].coolant.
|
|
87
|
-
P0c = self.blade_rows[i].coolant.
|
|
88
|
+
T0c = self.blade_rows[i].coolant.T0
|
|
89
|
+
P0c = self.blade_rows[i].coolant.P0
|
|
88
90
|
W0c = self.blade_rows[i].coolant.massflow_percentage * self.massflow
|
|
89
|
-
Cpc = self.blade_rows[i].coolant.
|
|
91
|
+
Cpc = self.blade_rows[i].coolant.Cp
|
|
90
92
|
else:
|
|
91
93
|
T0c = 100
|
|
92
94
|
P0c = 0
|
|
@@ -133,9 +135,9 @@ class TurbineSpool(Spool):
|
|
|
133
135
|
self.initialize_quantities()
|
|
134
136
|
|
|
135
137
|
if self.massflow_constraint ==MassflowConstraint.MatchMassFlow:
|
|
136
|
-
self.__match_massflow()
|
|
138
|
+
self.__match_massflow() # Matches massflow by changing turning angle
|
|
137
139
|
elif self.massflow_constraint == MassflowConstraint.BalanceMassFlow:
|
|
138
|
-
self.__balance_massflow()
|
|
140
|
+
self.__balance_massflow() # Balances massflow by changing row exit static pressure
|
|
139
141
|
|
|
140
142
|
|
|
141
143
|
def __match_massflow(self):
|
|
@@ -169,8 +171,8 @@ class TurbineSpool(Spool):
|
|
|
169
171
|
elif row.row_type == RowType.Stator:
|
|
170
172
|
row.alpha2[j] = np.radians(res.x)
|
|
171
173
|
row.alpha2[0] = 1/(len(row.alpha2)-1)*row.alpha2[1:].sum()
|
|
172
|
-
|
|
173
|
-
|
|
174
|
+
compute_gas_constants(upstream,self.fluid)
|
|
175
|
+
compute_gas_constants(row,self.fluid)
|
|
174
176
|
|
|
175
177
|
|
|
176
178
|
# Step 3: Adjust streamlines to evenly divide massflow
|
|
@@ -198,7 +200,7 @@ class TurbineSpool(Spool):
|
|
|
198
200
|
stage_ids = list(set([row.stage_id for row in self.blade_rows if row.stage_id>=0]))
|
|
199
201
|
for row in blade_rows[1:]:
|
|
200
202
|
total_massflow.append(row.total_massflow_no_coolant)
|
|
201
|
-
|
|
203
|
+
|
|
202
204
|
sign = 1
|
|
203
205
|
for s in stage_ids:
|
|
204
206
|
for row in blade_rows:
|
|
@@ -232,9 +234,10 @@ class TurbineSpool(Spool):
|
|
|
232
234
|
Returns:
|
|
233
235
|
_type_: _description_
|
|
234
236
|
"""
|
|
237
|
+
blade_rows_backup = copy.deepcopy(blade_rows)
|
|
235
238
|
# try:
|
|
236
239
|
if balance_mean_pressure:
|
|
237
|
-
for j in range(self.num_streamlines):
|
|
240
|
+
for j in range(self.num_streamlines):
|
|
238
241
|
Ps_range = outlet_pressure(x0,P0[j],P[j])
|
|
239
242
|
for i in range(1,len(blade_rows)-1):
|
|
240
243
|
blade_rows[i].P[j] = Ps_range[i-1]
|
|
@@ -243,10 +246,14 @@ class TurbineSpool(Spool):
|
|
|
243
246
|
for i in range(1,len(blade_rows)-1):
|
|
244
247
|
for j in range(self.num_streamlines):
|
|
245
248
|
blade_rows[i].P[j] = P[j]*x0[(i-1)*self.num_streamlines+j] # x0 size = num_streamlines -1
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
249
|
+
try:
|
|
250
|
+
calculate_massflows(blade_rows,True)
|
|
251
|
+
print(x0)
|
|
252
|
+
return calculate_error(blade_rows)
|
|
253
|
+
except:
|
|
254
|
+
blade_rows = blade_rows_backup
|
|
255
|
+
return np.inf # Return a high error
|
|
256
|
+
|
|
250
257
|
# except:
|
|
251
258
|
# for i in range(1,len(blade_rows)-1):
|
|
252
259
|
# for j in range(self.num_streamlines):
|
|
@@ -262,9 +269,10 @@ class TurbineSpool(Spool):
|
|
|
262
269
|
|
|
263
270
|
print('Find average P in between stages')
|
|
264
271
|
if len(outlet_P) == 1:
|
|
265
|
-
|
|
266
|
-
|
|
272
|
+
# x = balance_massflows(0.658,self.blade_rows[:-1],self.blade_rows[0].P0,self.blade_rows[-1].P)
|
|
273
|
+
res = minimize_scalar(fun=balance_massflows,args=(self.blade_rows[:-1],self.blade_rows[0].P0,self.blade_rows[-1].P),bounds=outlet_P[0],tol=0.0001,options={'disp': True},method='bounded')
|
|
267
274
|
x = res.x
|
|
275
|
+
print(x)
|
|
268
276
|
else:
|
|
269
277
|
x = fmin_slsqp(func=balance_massflows,args=(self.blade_rows[:-1],self.blade_rows[0].P0,self.blade_rows[-1].P),
|
|
270
278
|
bounds=outlet_P, x0=outlet_P_guess,epsilon=0.001,iter=100) # ,tol=0.001,options={'disp': True})
|
|
@@ -272,6 +280,8 @@ class TurbineSpool(Spool):
|
|
|
272
280
|
|
|
273
281
|
# Adjust the inlet: Set the massflow
|
|
274
282
|
self.blade_rows[0].massflow = np.linspace(0,1,self.num_streamlines)*self.blade_rows[1].total_massflow_no_coolant
|
|
283
|
+
self.blade_rows[0].total_massflow_no_coolant = self.blade_rows[1].total_massflow_no_coolant
|
|
284
|
+
self.blade_rows[0].total_massflow = np.linspace(0,1,self.num_streamlines)*self.blade_rows[1].total_massflow_no_coolant
|
|
275
285
|
inlet_calc(self.blade_rows[0]) # adjust the inlet to match massflow
|
|
276
286
|
|
|
277
287
|
if self.adjust_streamlines:
|
|
@@ -389,7 +399,7 @@ class TurbineSpool(Spool):
|
|
|
389
399
|
json.dump(data, f, indent=4,cls=NumpyEncoder)
|
|
390
400
|
|
|
391
401
|
|
|
392
|
-
def calculate_massflows(blade_rows:List[BladeRow],calculate_vm:bool=False):
|
|
402
|
+
def calculate_massflows(blade_rows:List[BladeRow],calculate_vm:bool=False,fluid:Solution=None):
|
|
393
403
|
"""Calculates the massflow
|
|
394
404
|
|
|
395
405
|
Args:
|
|
@@ -421,15 +431,15 @@ def calculate_massflows(blade_rows:List[BladeRow],calculate_vm:bool=False):
|
|
|
421
431
|
rotor_calc(row,upstream,calculate_vm=True)
|
|
422
432
|
# Finds Equilibrium between Vm, P0, T0
|
|
423
433
|
row = radeq(row,upstream)
|
|
424
|
-
|
|
434
|
+
compute_gas_constants(row,fluid)
|
|
425
435
|
rotor_calc(row,upstream,calculate_vm=False)
|
|
426
436
|
elif row.row_type == RowType.Stator:
|
|
427
437
|
stator_calc(row,upstream,downstream,calculate_vm=True)
|
|
428
438
|
# Finds Equilibrium between Vm, P0, T0
|
|
429
439
|
row = radeq(row,upstream)
|
|
430
|
-
|
|
440
|
+
compute_gas_constants(row,fluid)
|
|
431
441
|
stator_calc(row,upstream,downstream,calculate_vm=False)
|
|
432
|
-
|
|
442
|
+
compute_gas_constants(row,fluid)
|
|
433
443
|
compute_massflow(row)
|
|
434
444
|
compute_power(row,upstream)
|
|
435
445
|
|
|
@@ -442,7 +452,7 @@ def calculate_massflows(blade_rows:List[BladeRow],calculate_vm:bool=False):
|
|
|
442
452
|
row.Yp = Yp
|
|
443
453
|
rotor_calc(row,upstream,calculate_vm=True)
|
|
444
454
|
row = radeq(row,upstream)
|
|
445
|
-
|
|
455
|
+
compute_gas_constants(row,fluid)
|
|
446
456
|
rotor_calc(row,upstream,calculate_vm=False)
|
|
447
457
|
return abs(row.eta_total - eta_total)
|
|
448
458
|
|
|
@@ -452,13 +462,13 @@ def calculate_massflows(blade_rows:List[BladeRow],calculate_vm:bool=False):
|
|
|
452
462
|
row.Yp = 0
|
|
453
463
|
stator_calc(row,upstream,downstream,calculate_vm=True)
|
|
454
464
|
row = radeq(row,upstream)
|
|
455
|
-
row = compute_gas_constants(row)
|
|
465
|
+
row = compute_gas_constants(row,fluid)
|
|
456
466
|
stator_calc(row,upstream,downstream,calculate_vm=False)
|
|
457
|
-
row = compute_gas_constants(row)
|
|
467
|
+
row = compute_gas_constants(row,fluid)
|
|
458
468
|
compute_massflow(row)
|
|
459
469
|
compute_power(row,upstream)
|
|
460
470
|
|
|
461
|
-
def massflow_loss_function(exit_angle:float,index:int,row:BladeRow,upstream:BladeRow,downstream:BladeRow=None):
|
|
471
|
+
def massflow_loss_function(exit_angle:float,index:int,row:BladeRow,upstream:BladeRow,downstream:BladeRow=None,fluid:Solution=None):
|
|
462
472
|
"""Finds the blade exit angles that balance the massflow throughout the stage
|
|
463
473
|
|
|
464
474
|
Args:
|
|
@@ -483,8 +493,8 @@ def massflow_loss_function(exit_angle:float,index:int,row:BladeRow,upstream:Blad
|
|
|
483
493
|
elif row.row_type == RowType.Stator:
|
|
484
494
|
row.alpha2[index] = np.radians(exit_angle)
|
|
485
495
|
stator_calc(row,upstream,downstream)
|
|
486
|
-
upstream = compute_gas_constants(upstream)
|
|
487
|
-
row = compute_gas_constants(row)
|
|
496
|
+
upstream = compute_gas_constants(upstream,fluid)
|
|
497
|
+
row = compute_gas_constants(row,fluid)
|
|
488
498
|
elif row.loss_function.loss_type == LossType.Enthalpy:
|
|
489
499
|
# Search for pressure loss that results in the correct total temperature drop
|
|
490
500
|
if row.row_type == RowType.Rotor:
|
|
@@ -496,8 +506,8 @@ def massflow_loss_function(exit_angle:float,index:int,row:BladeRow,upstream:Blad
|
|
|
496
506
|
def find_yp(Yp):
|
|
497
507
|
row.Yp = Yp
|
|
498
508
|
rotor_calc(row,upstream)
|
|
499
|
-
upstream = compute_gas_constants(upstream)
|
|
500
|
-
row = compute_gas_constants(row)
|
|
509
|
+
upstream = compute_gas_constants(upstream,fluid)
|
|
510
|
+
row = compute_gas_constants(row,fluid)
|
|
501
511
|
return abs(row.T0.mean() - T0_target)
|
|
502
512
|
res = minimize_scalar(find_yp,bounds=[0,0.6])
|
|
503
513
|
row.Yp = res.x
|
|
@@ -505,8 +515,8 @@ def massflow_loss_function(exit_angle:float,index:int,row:BladeRow,upstream:Blad
|
|
|
505
515
|
row.Yp = 0
|
|
506
516
|
row.alpha2[index] = np.radians(exit_angle)
|
|
507
517
|
stator_calc(row,upstream,downstream)
|
|
508
|
-
upstream = compute_gas_constants(upstream)
|
|
509
|
-
row = compute_gas_constants(row)
|
|
518
|
+
upstream = compute_gas_constants(upstream,fluid)
|
|
519
|
+
row = compute_gas_constants(row,fluid)
|
|
510
520
|
|
|
511
521
|
|
|
512
522
|
# if use_radeq:
|
|
@@ -516,12 +526,12 @@ def massflow_loss_function(exit_angle:float,index:int,row:BladeRow,upstream:Blad
|
|
|
516
526
|
compute_power(row,upstream)
|
|
517
527
|
|
|
518
528
|
if row.row_type!=RowType.Inlet:
|
|
519
|
-
if row.row_type == RowType.Rotor:
|
|
520
|
-
|
|
521
|
-
else:
|
|
522
|
-
|
|
529
|
+
# if row.row_type == RowType.Rotor:
|
|
530
|
+
T3_is = upstream.T0 * (1/row.P0_P)**((row.gamma-1)/row.gamma)
|
|
531
|
+
# else:
|
|
532
|
+
# T3_is = upstream.T0 * (row.P0/row.P)**((row.gamma-1)/row.gamma)
|
|
523
533
|
a = np.sqrt(row.gamma*row.R*T3_is)
|
|
524
|
-
T03_is = T3_is * (1+(row.gamma-1)/2*(row.
|
|
534
|
+
T03_is = T3_is * (1+(row.gamma-1)/2*(row.V/a)**2)
|
|
525
535
|
row.eta_total = (upstream.T0.mean() - row.T0.mean())/(upstream.T0.mean()-T03_is.mean())
|
|
526
536
|
|
|
527
537
|
return np.abs(row.total_massflow*index/(len(row.massflow)-1) - row.massflow[index])
|