turbo-design 1.1.4__py3-none-any.whl → 1.3.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.

Potentially problematic release.


This version of turbo-design might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: turbo-design
3
- Version: 1.1.4
3
+ Version: 1.3.0
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,6 +10,7 @@ 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
13
14
  Requires-Dist: cantera
14
15
  Requires-Dist: findiff
15
16
  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=WqAB_BZFXu-y-m-leSbDNxUlt578A4clJhaNkkpxBbM,24731
3
+ turbodesign/bladerow.py,sha256=v4tX27aOL7iuN0ILWYbtSbANWZ_7_LIxksu4ux1aQ2o,24959
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=nuj7ryUXuBhuOPt2jHjHwtEM_LVno7A8Wm14P0lJn-8,436
6
+ turbodesign/coolant.py,sha256=evDtUFOYhfZKTVAsDWzxRzUX20gTvfjj0uybaWg4CsI,427
7
7
  turbodesign/enums.py,sha256=T4aFrGMnx9fgZkrExMBIY2IbCueA0utqr_afk-TUe9Q,1188
8
- turbodesign/inlet.py,sha256=QeSvFi35JeOPevjQrz1TmAhoWkScXT9BRA_5oRTnDEE,6322
8
+ turbodesign/inlet.py,sha256=L_IHE8zzm3uFMSow0iO-VxI71SnyQZwRhJMlJDcwZ4o,7329
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
@@ -19,15 +19,15 @@ turbodesign/loss/turbine/fixedpressureloss.py,sha256=jbm8dt8wtyN1RaOgpgYZsvwM0-0
19
19
  turbodesign/loss/turbine/kackerokapuu.py,sha256=hUmZdyA1hAhN3_xbwBhka2dyk0Aq9rqq62S2ghuKSOk,5071
20
20
  turbodesign/loss/turbine/traupel.py,sha256=aZxFE9JDcCfi1gy-fqS1SxjjlhuDG-H-g3LPurty1M0,4164
21
21
  turbodesign/lossinterp.py,sha256=B2KEobp-nD9jwD6UINgBmTlH9kKyWg3UNvXxqfUsr-k,6198
22
- turbodesign/outlet.py,sha256=SwTwoL6XnWlsrE5A6wLxu3qXkydDDUsdKKeBbJm4mrQ,2069
23
- turbodesign/passage.py,sha256=vKcEzQmQIlc-88DD1zr2f0F5s1r4x6OFQLtuTgkYMBA,10033
24
- turbodesign/radeq.py,sha256=RCsiQzcHvR5dozK6XG0eysAhXYewF0BY_qX0f1knURo,10091
22
+ turbodesign/outlet.py,sha256=-0XpeEmTQpFjUQNYQxOp5WuHkF7cXfx59hxy7BmaxgY,2119
23
+ turbodesign/passage.py,sha256=Ur6zZCzI9Y7HW0o5LrDq9yeatRain1mBLZBcTOzgjEU,11996
24
+ turbodesign/radeq.py,sha256=3XuSf_KtOqddJclcxh9v1V2YWMvbWfd0YxcHGkic7hg,11361
25
25
  turbodesign/rotor.py,sha256=tHl9o5H4aQ6Etd4gqa8Ime1UK7k0de4GLt5Yb1sJdGs,1376
26
- turbodesign/solve_radeq.py,sha256=2VGzFSVkyN0rTPFHaCQiD3v166cdEs39x7x7RuzLgmw,1886
27
- turbodesign/spool.py,sha256=h4m--HR5g8o01Kkhl4Mbvx7WORQez3YpncDE7XxbNaw,14172
26
+ turbodesign/solve_radeq.py,sha256=mGVBHmc20pAXEDKGzyiU3BVUsmY9gJl7zhbtHZqxARg,1956
27
+ turbodesign/spool.py,sha256=XKvYABvfigLulGLHH23X7k6aL6wvfuqgfLkKCMK9X8c,14338
28
28
  turbodesign/stage.py,sha256=UP45sDKDLsAkO_WfDWJ6kqXU7cYKh_4QO01QZnSN1oQ,166
29
- turbodesign/td_math.py,sha256=GjJdH9Mym1_vMSDT7lxilzSLVHBM5-Z5UE0wfsH2hr4,16153
30
- turbodesign/turbinespool.py,sha256=U_TMv5XNTlRWP9NJWTaaFWfNeTEGEuSVWt3HDi8QyFI,26124
31
- turbo_design-1.1.4.dist-info/METADATA,sha256=4pe7fwIxSnpYVF86iou7pFaKh4usQfKMe2Co--6U__w,683
32
- turbo_design-1.1.4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
33
- turbo_design-1.1.4.dist-info/RECORD,,
29
+ turbodesign/td_math.py,sha256=NMKgHkc36LCrr4bZxjxx7TcA4ztaRps1cIsm1tucMrk,16069
30
+ turbodesign/turbinespool.py,sha256=I5e1l8SsvwsQZZkOv7ric83-uNvT9MExwCimJEAhaI8,25194
31
+ turbo_design-1.3.0.dist-info/METADATA,sha256=qSAB19ivwujv2mpnh8XwkwdSuVNIbiYNMYozn6ccPW0,734
32
+ turbo_design-1.3.0.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
33
+ turbo_design-1.3.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.0
2
+ Generator: poetry-core 2.0.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
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]
@@ -35,10 +34,11 @@ class BladeRow:
35
34
  # ----------------------------------
36
35
 
37
36
  # Streamline Properties
38
- axial_location:float = 0 # Where blade row is defined along the hub.
37
+ percent_hub:float = 0 # Where blade row is defined along the hub.
39
38
  percent_hub_shroud: npt.NDArray = field(default_factory=lambda: np.array([0])) # Percent streamline length from hub to shroud.
40
39
  x: npt.NDArray = field(default_factory=lambda: np.array([0])) # x - coordinates (useful for computing axial chord)
41
40
  r: npt.NDArray = field(default_factory=lambda: np.array([0])) # Radius - coordinates
41
+ m: npt.NDArray = field(default_factory=lambda: np.array([0])) # meridional
42
42
  area:float = 0
43
43
  # Calculated massflow is the massflow computed after radial eq solver
44
44
  calculated_massflow: float = 0
@@ -121,6 +121,7 @@ class BladeRow:
121
121
  _tip_clearance:float = 0 # Clearance as a percentage of span or blade height
122
122
 
123
123
  _inlet_to_outlet_pratio = [0.06,0.95]
124
+ location:float = 0 # Percent along hub where bladerow is defined
124
125
 
125
126
  @property
126
127
  def inlet_to_outlet_pratio(self) -> Tuple[float,float]:
@@ -328,18 +329,18 @@ class BladeRow:
328
329
  """
329
330
  self._tip_clearance = val
330
331
 
331
- def __init__(self,axial_location:float,row_type:RowType=RowType.Stator,stage_id:int = 0):
332
+ def __init__(self,location:float,row_type:RowType=RowType.Stator,stage_id:int = 0):
332
333
  """Initializes the blade row to be a particular type
333
334
 
334
335
  Args:
335
- axial_location (float): Location of the blade row as a percentage of the total axial length
336
+ location (float): Location of the blade row as a percentage of hub length
336
337
  row_type (RowType): Specifies the Type. Defaults to RowType.Stator
337
338
  power (float, optional): power . Defaults to 0.
338
339
  P0_P (float, optional): Total to Static Pressure Ratio
339
340
  stage_id (int, optional): ID of the stage so if you have 9 stages, the id could be 9. It's used to separate the stages. Each stage will have it's own unique degree of reaction
340
341
  """
341
342
  self.row_type = row_type
342
- self.axial_location = axial_location
343
+ self.location = location
343
344
  self.Yp = 0 # Loss
344
345
  self.stage_id = stage_id
345
346
 
@@ -437,7 +438,7 @@ class BladeRow:
437
438
  self._te_s = val
438
439
 
439
440
  def __repr__(self):
440
- return f"{self.row_type.name:0.2f}' P0:{np.mean(self.P0):0.2f} T0:{np.mean(self.T0):0.2f} P:{np.mean(self.P):0.2f} massflow:{self.total_massflow_no_coolant}:0.3f"
441
+ 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
442
 
442
443
  def to_dict(self):
443
444
 
@@ -512,7 +513,7 @@ def interpolate_streamline_radii(row:BladeRow,passage:Passage,num_streamlines:in
512
513
  Returns:
513
514
  (BladeRow): new row object with quantities interpolated
514
515
  """
515
- row.cutting_line,_,_ = passage.get_cutting_line(row.axial_location)
516
+ row.cutting_line,_,_ = passage.get_cutting_line(row.location)
516
517
  row.x,row.r = row.cutting_line.get_point(np.linspace(0,1,num_streamlines))
517
518
  streamline_percent_length = np.sqrt((row.r-row.r[0])**2+(row.x-row.x[0])**2)/row.cutting_line.length
518
519
 
@@ -609,21 +610,24 @@ def interpolate_quantities(q:npt.NDArray,r:npt.NDArray,r2:npt.NDArray):
609
610
  else:
610
611
  return interp1d(r,q,kind='linear')(r2)
611
612
 
612
- def compute_gas_constants(row:BladeRow):
613
- """Calculates all the gas constants for a row.
614
- This should be done if T or P change
613
+ def compute_gas_constants(row:BladeRow,fluid:Solution=None) -> None:
614
+ """Updates the Cp, Gamma, and density for a blade row. If fluid is not specified then only density and viscosity is updated.
615
+
616
+ Args:
617
+ row (BladeRow): _description_
618
+ fluid (Solution, optional): _description_. Defaults to None.
619
+
620
+ Returns:
621
+ (BladeRow): updated row
615
622
  """
616
- Tm = row.T.mean()
617
- Pm = row.P.mean()
618
- row.fluid.TP = Tm,Pm
619
- row.Cp = row.fluid.cp
620
- row.Cv = row.fluid.cv
621
- row.R = row.Cp-row.Cv
622
- row.gamma = row.Cp/row.Cv
623
- row.mu = sutherland(Tm) # type: ignore
624
- row.rho[:] = row.fluid.density
625
- # i = 0
626
- # for T,P in zip(row.T,row.P):
627
- # row.rho[i] = P/(T*row.R)
628
- # i+=1
629
- return row
623
+ if fluid:
624
+ Tm = row.T.mean()
625
+ Pm = row.P.mean()
626
+ fluid.TP = Tm,Pm
627
+ row.Cp = fluid.cp
628
+ row.Cv = fluid.cv
629
+ row.R = row.Cp-row.Cv
630
+ row.gamma = row.Cp/row.Cv
631
+ # Use Ideal Gas
632
+ row.rho = row.P/(row.T*row.R)
633
+ 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,57 +16,85 @@ class Inlet(BladeRow):
16
16
  (BladeRow): Defines the properties of the blade row
17
17
  """
18
18
  fun: interp1d
19
- def __init__(self,M:float,T0:Union[float,List[float]],P0:Union[float,List[float]],percent_radii:Union[float,List[float]],fluid:Solution,axial_location:float=0,beta:Union[float,List[float]]=[0]):
19
+
20
+ def __init__(self,M:float,T0:Union[float,List[float]],
21
+ P0:Union[float,List[float]],
22
+ 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
- axial_location (float): Axial Location as a percentage of hub length
33
+ location (float): 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
- super().__init__(row_type=RowType.Inlet,axial_location=axial_location,stage_id=-1)
34
- self.loss_function = None
37
+ super().__init__(row_type=RowType.Inlet,location=location,stage_id=-1)
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(beta))
42
- self.alpha1 = np.radians(convert_to_ndarray(beta))
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
- self.T = self.T0 * 1/(1 + (self.gamma-1) * self.M**2)
47
- self.P = self.P0 * 1/(1 + (self.gamma-1) * self.M**2)**(self.gamma/(self.gamma-1))
48
- fluid.TP = self.T.mean(),self.P.mean()
49
- self.rho = convert_to_ndarray([fluid.density])
50
- self.fluid = fluid
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
66
94
  t,x,radius = passage.get_streamline(self.percent_hub_shroud)
67
95
  radius = radius[0]
68
96
 
69
- cutline,_,_ = passage.get_cutting_line(self.axial_location)
97
+ cutline,_,_ = passage.get_cutting_line(self.location)
70
98
  self.x,self.r = cutline.get_point(np.linspace(0,1,num_streamlines))
71
99
  for _ in range(10):
72
100
  T0_T = (1+(self.gamma-1)/2 * self.M**2)
@@ -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
- self = compute_gas_constants(self)
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/outlet.py CHANGED
@@ -12,7 +12,7 @@ from scipy.interpolate import interp1d
12
12
  class Outlet(BladeRow):
13
13
  P_fun:interp1d
14
14
 
15
- def __init__(self,P:Union[float,List[float]],percent_radii:List[float],num_streamlines:int=3):
15
+ def __init__(self,P:Union[float,List[float]],percent_radii:List[float],num_streamlines:int=3,location:float=1):
16
16
  """Initialize the outlet
17
17
 
18
18
  Args:
@@ -26,6 +26,7 @@ class Outlet(BladeRow):
26
26
  self.P_fun = interp1d(self.percent_hub_shroud,self.P)
27
27
  self.row_type = RowType.Outlet
28
28
  self.loss_function = None
29
+ self.location = location
29
30
 
30
31
 
31
32
  def transfer_quantities(self,upstream:BladeRow):
turbodesign/passage.py CHANGED
@@ -1,7 +1,7 @@
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 PchipInterpolator
4
+ from scipy.interpolate import PchipInterpolator, interp1d
5
5
  from pyturbo.helper import line2D
6
6
  from .enums import PassageType
7
7
  from scipy.optimize import minimize_scalar
@@ -142,7 +142,31 @@ class Passage:
142
142
 
143
143
  return phi, rm, r
144
144
 
145
- def get_cutting_line(self, t_hub:float) -> line2D:
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
168
+
169
+ def get_cutting_line(self, t_hub:float) -> Tuple[line2D,float,float]:
146
170
  """Gets the cutting line perpendicular to hub and shroud
147
171
 
148
172
  Args:
@@ -188,17 +212,18 @@ class Passage:
188
212
  rshroud = self.rshroud(t_shroud)
189
213
  return line2D([xhub,rhub],[xshroud,rshroud]), t_hub, t_shroud
190
214
 
191
- def get_xr_slice(self,t_span:float,axial_location:Tuple[float,float]):
215
+ def get_xr_slice(self,t_span:float,percent_hub:Tuple[float,float],resolution:int=100):
192
216
  """Returns the xr coordinates of a streamline, a line that is parallel to both hub and shroud
193
217
 
194
218
  Args:
195
219
  t_span (float): _description_
196
- axial_location (float): _description_
220
+ meridional_location (float): _description_
221
+ resolution (int): number of points to resolve
197
222
 
198
223
  Returns:
199
224
  np.NDArray: _description_
200
225
  """
201
- t_hub = np.linspace(axial_location[0],axial_location[1],100)
226
+ t_hub = np.linspace(percent_hub[0],percent_hub[1],resolution)
202
227
  t_hub = convert_to_ndarray(t_hub)*self.hub_length
203
228
 
204
229
  shroud_pts_cyl = np.vstack([self.xshroud(t_hub),self.rshroud(t_hub)]).transpose()
@@ -209,8 +234,39 @@ class Passage:
209
234
  for j in range(n):
210
235
  l = line2D(hub_pts_cyl[j,:],shroud_pts_cyl[j,:])
211
236
  xr[j,0],xr[j,1] = l.get_point(t_span)
237
+
212
238
  return xr
213
-
239
+
240
+ def get_m(self,t_span:float,resolution:int=100) -> npt.NDArray:
241
+ """Meridional cooridnates
242
+
243
+ Args:
244
+ t_span (float): _description_
245
+ resolution (int, optional): _description_. Defaults to 100.
246
+
247
+ Returns:
248
+ npt.NDArray: _description_
249
+ """
250
+ xr = self.get_xr_slice(t_span,(0,1),resolution)
251
+ dx = np.diff(xr[:,0])
252
+ dr = np.diff(xr[:,1])
253
+ m = np.concat([[0],np.cumsum(np.sqrt(dx**2 + dr**2))])
254
+ return m
255
+
256
+ def get_dm(self,t_span:float,location:float,resolution:int=1000) -> float:
257
+ """return the derivative in the meridional direction at a particular point
258
+
259
+ Args:
260
+ t_span (float): percent span
261
+ location (float): hub location of the blade
262
+ resolution (int, optional): number of points to represent the hub curve. Defaults to 1000.
263
+
264
+ Returns:
265
+ (float) : returns the derivative
266
+ """
267
+ m = self.get_m(t_span,resolution)
268
+ return PchipInterpolator(np.linspace(0,1,resolution),np.diff(m))(location)
269
+
214
270
  @property
215
271
  def hub_length(self):
216
272
  """returns the computed length of the hub
turbodesign/radeq.py CHANGED
@@ -1,11 +1,12 @@
1
- from scipy.interpolate import interp1d
1
+ from scipy.interpolate import interp1d,PchipInterpolator
2
2
  from scipy.integrate import odeint
3
- import numpy as np
3
+ import numpy as np
4
+ import numdifftools as nd
4
5
  from .bladerow import BladeRow
5
6
  from .enums import RowType
6
7
 
7
8
 
8
- def radeq(row:BladeRow,upstream:BladeRow) -> BladeRow:
9
+ def radeq(row:BladeRow,upstream:BladeRow,downstream:BladeRow=None) -> BladeRow:
9
10
  """Solves the radial equilibrium equation for axial machines and returns the convergence.
10
11
 
11
12
  Note:
@@ -14,7 +15,8 @@ def radeq(row:BladeRow,upstream:BladeRow) -> BladeRow:
14
15
  Args:
15
16
  row (BladeRow): Current row
16
17
  upstream (BladeRow): Previous row
17
-
18
+ downstream (BladeRow): Next row
19
+
18
20
  Returns:
19
21
  BladeRow: current row with T0, P0, and Vm calculated
20
22
  """
@@ -57,8 +59,30 @@ def radeq(row:BladeRow,upstream:BladeRow) -> BladeRow:
57
59
  # Estimations
58
60
  dVm_dr = float(interp1d(row_radius, np.gradient(row.Vm, row_radius))(r))
59
61
  dVt_dr = dVm_dr*np.tan(alpha)
60
- dVr_dr = dVm_dr*np.sin(phi)
61
-
62
+ # dVr_dr = dVm_dr*np.sin(phi)
63
+
64
+ up_Vm = interp1d(row_radius, upstream.Vm)(r)
65
+ if downstream:
66
+ if downstream.row_type == RowType.Outlet:
67
+ down_Vm = Vm
68
+ else:
69
+ down_Vm = interp1d(row_radius, downstream.Vm)(r)
70
+ else:
71
+ down_Vm = Vm
72
+ up_m = interp1d(row_radius, upstream.m)(r)
73
+
74
+ # Get a rough guess of dVm/dm
75
+ if downstream!=None:
76
+ down_m = interp1d(row_radius, downstream.m)(r)
77
+ row_m = interp1d(row_radius, row.m)(r)
78
+ if down_m != row_m:
79
+ func_Vm_m = PchipInterpolator([up_m, row_m, down_m],[up_Vm, Vm, down_Vm])
80
+ else:
81
+ func_Vm_m = PchipInterpolator([up_m, row_m],[up_Vm, Vm])
82
+ else:
83
+ func_Vm_m = PchipInterpolator([up_m, row_m],[up_Vm, Vm])
84
+ dVm_dm = func_Vm_m.derivative()(row_m)
85
+
62
86
  # Upstream
63
87
  dT0up_dr = float(interp1d(upstream.percent_hub_shroud, np.gradient(upstream.T0,up_radius))((r-row_radius[0])/(row_radius[-1]-row_radius[0]))) # use percentage to get the T0 upstream value
64
88
  dP0up_dr = float(interp1d(upstream.percent_hub_shroud, np.gradient(upstream.P0,up_radius))((r-row_radius[0])/(row_radius[-1]-row_radius[0]))) # use percentage to get the T0 upstream value
@@ -79,7 +103,12 @@ def radeq(row:BladeRow,upstream:BladeRow) -> BladeRow:
79
103
  raise Exception("Invalid value of C {C}, change reduce alpha or Vm")
80
104
  B = (1-C)**(gamma/(gamma-1))
81
105
  A = P0 * gamma/(gamma-1) * (1-C)**(1/(gamma-1))
82
- 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
106
+
107
+ epsilon = 1e-10 # or another small threshold
108
+ if abs(rm) > epsilon:
109
+ dVm_dr = Cp*T0/(Vm*A*(1+np.tan(alpha)**2)) * (rho*(Vt**2/r + Vm**2/rm * np.cos(phi) - Vr*dVm_dm) - B*dP0_dr) + Vm/(2*T0) *dT0_dr # Eqn 6
110
+ else:
111
+ dVm_dr = Cp*T0/(Vm*A*(1+np.tan(alpha)**2)) * (rho*(Vt**2/r - Vr*dVm_dm) - B*dP0_dr) + Vm/(2*T0) *dT0_dr # Eqn 6
83
112
 
84
113
  ydot = np.array([dP0_dr,dT0_dr,dVm_dr])
85
114
 
@@ -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 _,row in enumerate(blade_rows):
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
@@ -26,13 +27,13 @@ def adjust_streamlines(blade_rows:List[BladeRow],passage:Passage):
26
27
  new_percent_streamline = interp1d(row.massflow,row.percent_hub_shroud)(ideal_massflow_fraction[1:-1])
27
28
  row.percent_hub_shroud[1:-1] = new_percent_streamline
28
29
 
29
- cut_line, thub,_ = passage.get_cutting_line(row.axial_location)
30
+ cut_line, thub,_ = passage.get_cutting_line(row.percent_hub)
30
31
  row.x,row.r = cut_line.get_point(row.percent_hub_shroud)
31
32
  # Radii may have shifted, recompute Ay and rm
32
33
  for i,tr in enumerate(row.percent_hub_shroud):
33
34
  t_streamline, x_streamline, r_streamline = passage.get_streamline(tr)
34
35
  phi, rm, r = passage.streamline_curvature(x_streamline,r_streamline)
35
- row.phi[i] = float(interp1d(t_streamline,phi)(row.axial_location))
36
- row.rm[i] = float(interp1d(t_streamline,rm)(row.axial_location))
37
- row.r[i] = float(interp1d(t_streamline,r)(row.axial_location))
38
- row.x[i] = float(interp1d(t_streamline,x_streamline)(row.axial_location))
36
+ row.phi[i] = float(interp1d(t_streamline,phi)(row.percent_hub))
37
+ row.rm[i] = float(interp1d(t_streamline,rm)(row.percent_hub))
38
+ row.r[i] = float(interp1d(t_streamline,r)(row.percent_hub))
39
+ row.x[i] = float(interp1d(t_streamline,x_streamline)(row.percent_hub))
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
@@ -34,7 +34,7 @@ class Spool:
34
34
  def __init__(self,passage:Passage,
35
35
  massflow:float,rows=List[BladeRow],
36
36
  num_streamlines:int=3,
37
- fluid:Solution=Solution('air.yaml'),
37
+ fluid:Solution=None,
38
38
  rpm:float=-1,
39
39
  massflow_constraint:MassflowConstraint=MassflowConstraint.MatchMassFlow):
40
40
  """Initializes a Spool
@@ -50,7 +50,7 @@ class Spool:
50
50
  massflow (float): massflow at spool inlet
51
51
  rows (List[BladeRow], optional): List of blade rows. Defaults to List[BladeRow].
52
52
  num_streamlines (int, optional): number of streamlines. Defaults to 3.
53
- gas (ct.Solution, optional): cantera gas solution. Defaults to ct.Solution('air.yaml').
53
+ fluid (ct.Solution, optional): cantera gas solution. Defaults to None, fluid is set by bladerow cp
54
54
  rpm (float, optional): RPM for the entire spool Optional, you can also set rpm of the blade rows individually. Defaults to -1.
55
55
  massflow_constraint (MassflowConstraint, optional): MatchMassflow - Matches the massflow defined in the spool. BalanceMassflow - Balances the massflow between BladeRows, matches the lowest massflow.
56
56
  """
@@ -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
- self.blade_rows[i].axial_chord = self.blade_rows[i].axial_location * self.passage.hub_length
74
+ self.blade_rows[i].axial_chord = self.blade_rows[i].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
@@ -159,13 +158,15 @@ class Spool:
159
158
  row.phi = np.zeros((self.num_streamlines,))
160
159
  row.rm = np.zeros((self.num_streamlines,))
161
160
  row.r = np.zeros((self.num_streamlines,))
161
+ row.m = np.zeros((self.num_streamlines,))
162
162
 
163
163
  t_radial = np.linspace(0,1,self.num_streamlines)
164
164
  self.calculate_streamline_curvature(row,t_radial)
165
-
165
+
166
166
  # Set the loss function if it's not set
167
- if (row.loss_function == None):
168
- row.loss_function = TD2()
167
+ if (type(row)!= Inlet and type(row) != Outlet):
168
+ if row.loss_function == None:
169
+ row.loss_function = TD2()
169
170
 
170
171
  def calculate_streamline_curvature(self,row:BladeRow,t_radial:Union[List[float],npt.NDArray]):
171
172
  """Called to calculate new streamline curvature
@@ -177,9 +178,10 @@ class Spool:
177
178
  for i,tr in enumerate(t_radial):
178
179
  t_streamline, x_streamline, r_streamline = self.passage.get_streamline(tr)
179
180
  phi, rm, r = self.passage.streamline_curvature(x_streamline,r_streamline)
180
- row.phi[i] = float(interp1d(t_streamline,phi)(row.axial_location))
181
- row.rm[i] = float(interp1d(t_streamline,rm)(row.axial_location))
182
- row.r[i] = float(interp1d(t_streamline,r)(row.axial_location))
181
+ row.phi[i] = float(interp1d(t_streamline,phi)(row.location))
182
+ row.rm[i] = float(interp1d(t_streamline,rm)(row.location))
183
+ row.r[i] = float(interp1d(t_streamline,r)(row.location))
184
+ row.m[i] = float(interp1d(t_streamline,self.passage.get_m(tr,resolution=len(t_streamline)))(row.location))
183
185
 
184
186
  def solve(self):
185
187
  raise NotImplementedError('Solve is not implemented')
@@ -214,10 +216,10 @@ class Spool:
214
216
  else: # i>0
215
217
  upstream = self.blade_rows[i-1]
216
218
  if upstream.row_type== RowType.Inlet:
217
- cut_line1,_,_ = self.passage.get_cutting_line((row.axial_location*hub_length +(0.5*row.blade_to_blade_gap*row.axial_chord) - row.axial_chord)/hub_length)
219
+ cut_line1,_,_ = self.passage.get_cutting_line((row.location*hub_length +(0.5*row.blade_to_blade_gap*row.axial_chord) - row.axial_chord)/hub_length)
218
220
  else:
219
- cut_line1,_,_ = self.passage.get_cutting_line((upstream.axial_location*hub_length)/hub_length)
220
- cut_line2,_,_ = self.passage.get_cutting_line((row.axial_location*hub_length-(0.5*row.blade_to_blade_gap*row.axial_chord))/hub_length)
221
+ cut_line1,_,_ = self.passage.get_cutting_line((upstream.location*hub_length)/hub_length)
222
+ cut_line2,_,_ = self.passage.get_cutting_line((row.location*hub_length-(0.5*row.blade_to_blade_gap*row.axial_chord))/hub_length)
221
223
 
222
224
  if self.blade_rows[i].row_type == RowType.Stator:
223
225
  x1,r1 = cut_line1.get_point(np.linspace(0,1,10))
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
- row.coolant.fluid.TP = row.coolant.T0, row.coolant.P0
21
+
21
22
  massflow = row.massflow
22
23
  total_massflow_no_coolant = row.total_massflow_no_coolant
23
24
  Cp = row.Cp
24
- Cpc = row.coolant.fluid.cp
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:]*row.fluid.cp + massflow_coolant*Cpc)
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-12: # Axial Machines
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):
@@ -89,7 +93,7 @@ def compute_reynolds(rows:List[BladeRow],passage:Passage):
89
93
 
90
94
  for i in range(1,len(rows)):
91
95
  row = rows[i]
92
- xr = passage.get_xr_slice(0.5,[rows[i-1].axial_location,row.axial_location])
96
+ xr = passage.get_xr_slice(0.5,[rows[i-1].location,row.percent_hub])
93
97
  dx = np.diff(xr[:,0])
94
98
  dr = np.diff(xr[:,1])
95
99
  c = np.sum(np.sqrt(dx**2+dr**2))
@@ -107,8 +111,6 @@ def compute_reynolds(rows:List[BladeRow],passage:Passage):
107
111
  row.axial_chord = max(c,1E-12) # Axial chord
108
112
  # row.num_blades = int(2*np.pi*row.r.mean() / row.pitch_to_chord * row.axial_chord)
109
113
 
110
-
111
-
112
114
  def compute_power(row:BladeRow,upstream:BladeRow) -> None:
113
115
  """Calculates the power
114
116
 
@@ -125,11 +127,14 @@ def compute_power(row:BladeRow,upstream:BladeRow) -> None:
125
127
  row.T_is = 0
126
128
  row.T0_is = 0
127
129
  else:
128
- row.T_is = row.T0R*(row.P/upstream.P0R)**((row.gamma-1)/row.gamma)
129
- row.T0_is = row.T_is*(1+(row.gamma-1)/2*row.M**2)
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
+
130
135
  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.T0_is.mean()))
132
- row.eta_total = row.power / (row.massflow[-1]*row.Cp * (upstream.T0.mean()-row.T0_is.mean()))
136
+ row.eta_static = row.power/ (row.massflow[-1]*row.Cp*(upstream.T0.mean()-row.T_is.mean()))
137
+ row.eta_total = (upstream.T0.mean() - row.T0.mean()) / (upstream.T0.mean() - row.T0_is.mean())
133
138
  row.stage_loading = row.Cp*(upstream.T0.mean() - row.T0.mean())/row.U.mean()**2
134
139
  row.euler_power = row.massflow[-1]* (upstream.U*upstream.Vt - row.U*row.Vt).mean()
135
140
 
@@ -150,7 +155,7 @@ def compute_quantities(row:BladeRow,upstream:BladeRow):
150
155
  if row.row_type == RowType.Rotor:
151
156
  Cp_avg = (row.Cp+upstream.Cp)/2
152
157
  # 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)
158
+ row.T0R = upstream.T0R - T0_coolant_weighted_average(row) # - (upstream.U**2-row.U**2)/(2*Cp_avg)
154
159
  row.P = upstream.P0_stator_inlet/row.P0_P
155
160
 
156
161
  if row.loss_function.loss_type == LossType.Pressure:
@@ -225,20 +230,21 @@ def stator_calc(row:BladeRow,upstream:BladeRow,downstream:BladeRow=None,calculat
225
230
 
226
231
  # Static Pressure is assumed
227
232
  row.P0 = upstream.P0 - row.Yp*(upstream.P0-row.P)
228
- row.P0_P = row.P0/downstream.P
233
+
229
234
  if downstream is not None:
235
+ row.P0_P = row.P0/downstream.P
230
236
  row.rp = (row.P-downstream.P)/(upstream.P0-downstream.P)
231
237
 
232
238
  if calculate_vm:
233
239
  row.M = ((row.P0/row.P)**((row.gamma-1)/row.gamma) - 1) * 2/(row.gamma-1)
234
240
  row.M = np.sqrt(row.M)
235
- T0_T = (1+(row.gamma-1)/2 * row.M.mean()**2)
241
+ T0_T = (1+(row.gamma-1)/2 * row.M**2)
236
242
  row.T0 = upstream.T0 - T0_coolant_weighted_average(row)
237
243
  row.T = row.T0/T0_T
238
244
  row.V = row.M*np.sqrt(row.gamma*row.R*row.T)
245
+ row.Vm = row.V*np.cos(row.alpha2)
239
246
  row.Vx = row.Vm*np.cos(row.phi)
240
- row.Vr = row.V*np.sin(row.phi)
241
- row.Vm = np.sqrt(row.Vx**2+row.Vr**2)
247
+ row.Vr = row.Vm*np.sin(row.phi)
242
248
  row.Vt = row.Vm*np.tan(row.alpha2)
243
249
  else: # We know Vm, P0, T0, P
244
250
  row.Vx = row.Vm*np.cos(row.phi)
@@ -254,6 +260,7 @@ def stator_calc(row:BladeRow,upstream:BladeRow,downstream:BladeRow=None,calculat
254
260
  row.beta1 = upstream.beta2
255
261
  row.rho = row.P/(row.R*row.T)
256
262
  row.U = row.omega*row.r
263
+ row.Wt = row.Vt-row.U
257
264
  row.P0_stator_inlet = upstream.P0
258
265
 
259
266
  def rotor_calc(row:BladeRow,upstream:BladeRow,calculate_vm:bool=True):
@@ -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
- print(f'nan detected: check flow path. Turbine inlet cut should be horizontal')
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
- print(f"High inlet mach can lead to errors iter:{iter} Mach:{avg_mach}")
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
- print(f"Unusually slow flow:{iter} Mach:{avg_mach}")
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)
@@ -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, minimize, fmin_slsqp
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
- massflow_constraint:MassflowConstraint=MassflowConstraint.MatchMassFlow):
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.blade_rows[0].row_type == RowType.Inlet:
49
- self.blade_rows[0].massflow = np.linspace(0,1,self.num_streamlines)*W0
50
- self.blade_rows[0].total_massflow = W0
51
- self.blade_rows[0].total_massflow_no_coolant = W0
52
-
53
- interpolate_streamline_radii(self.blade_rows[0],self.passage,self.num_streamlines)
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
59
+
60
+ inlet.initialize_velocity(self.passage,self.num_streamlines)
61
+ interpolate_streamline_radii(inlet,self.passage,self.num_streamlines)
54
62
 
55
- # Set the gas to total values for now
56
- self.blade_rows[0].fluid.TP = self.blade_rows[0].T0.mean(), self.blade_rows[0].P0.mean()
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.fluid.T
87
- P0c = self.blade_rows[i].coolant.fluid.P
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.fluid.cp
91
+ Cpc = self.blade_rows[i].coolant.Cp
90
92
  else:
91
93
  T0c = 100
92
94
  P0c = 0
@@ -120,10 +122,12 @@ class TurbineSpool(Spool):
120
122
 
121
123
  if row.row_type == RowType.Stator:
122
124
  stator_calc(row,upstream,downstream)
125
+ compute_massflow(row)
123
126
  elif row.row_type == RowType.Rotor:
124
127
  rotor_calc(row,upstream)
125
128
  compute_massflow(row)
126
129
  compute_power(row,upstream)
130
+
127
131
 
128
132
  def solve(self):
129
133
  """
@@ -133,9 +137,9 @@ class TurbineSpool(Spool):
133
137
  self.initialize_quantities()
134
138
 
135
139
  if self.massflow_constraint ==MassflowConstraint.MatchMassFlow:
136
- self.__match_massflow()
140
+ self.__match_massflow() # Matches massflow by changing turning angle
137
141
  elif self.massflow_constraint == MassflowConstraint.BalanceMassFlow:
138
- self.__balance_massflow()
142
+ self.__balance_massflow() # Balances massflow by changing row exit static pressure
139
143
 
140
144
 
141
145
  def __match_massflow(self):
@@ -161,7 +165,7 @@ class TurbineSpool(Spool):
161
165
  bounds = [-80,0]
162
166
  if row.row_type != RowType.Inlet:
163
167
  for j in range(1,self.num_streamlines):
164
- res = minimize_scalar(massflow_loss_function, bounds=bounds,args=(j,row,upstream,downstream),tol=1E-2)
168
+ res = minimize_scalar(massflow_loss_function, bounds=bounds,args=(j,row,upstream,downstream),tol=1E-3)
165
169
  if row.row_type == RowType.Rotor:
166
170
  row.beta2[j] = np.radians(res.x)
167
171
  # Initialize the value at the hub to not upset the mean
@@ -169,14 +173,41 @@ class TurbineSpool(Spool):
169
173
  elif row.row_type == RowType.Stator:
170
174
  row.alpha2[j] = np.radians(res.x)
171
175
  row.alpha2[0] = 1/(len(row.alpha2)-1)*row.alpha2[1:].sum()
172
- upstream = compute_gas_constants(upstream)
173
- row = compute_gas_constants(row)
176
+ compute_gas_constants(upstream,self.fluid)
177
+ compute_gas_constants(row,self.fluid)
174
178
 
175
179
 
176
180
  # Step 3: Adjust streamlines to evenly divide massflow
177
181
  adjust_streamlines(self.blade_rows,self.passage)
178
182
  compute_reynolds(self.blade_rows,self.passage)
179
-
183
+
184
+ @staticmethod # Private static method
185
+ def __massflow_std__(blade_rows:List[BladeRow]):
186
+ """Returns the standard deviation of the massflow
187
+
188
+ Args:
189
+ blade_rows (List[BladeRow]): List of blade rows
190
+
191
+ Returns:
192
+ _type_: _description_
193
+ """
194
+ total_massflow = list(); s = 0; massflow_stage = list()
195
+ stage_ids = list(set([row.stage_id for row in blade_rows if row.stage_id>=0]))
196
+ for row in blade_rows[1:-1]: # Ignore inlet and outlet
197
+ total_massflow.append(row.total_massflow_no_coolant)
198
+ sign = 1
199
+ for s in stage_ids:
200
+ for row in blade_rows:
201
+ if row.stage_id == s and row.row_type == RowType.Rotor:
202
+ massflow_stage.append(sign*row.total_massflow_no_coolant)
203
+ sign*=-1
204
+ if len(stage_ids) % 2 == 1:
205
+ massflow_stage.append(massflow_stage[-1]*sign)
206
+ deviation = np.std(total_massflow)*2
207
+ if deviation>1.0:
208
+ print("high massflow deviation detected")
209
+ return np.std(total_massflow)*2 # + abs(sum(massflow_stage)) # Equation 28
210
+
180
211
  def __balance_massflow(self):
181
212
  """ Balances the massflow between rows. Use radial equilibrium.
182
213
 
@@ -193,24 +224,7 @@ class TurbineSpool(Spool):
193
224
  3. Adjust the streamlines for each blade row to balance the massflow
194
225
  """
195
226
 
196
- def calculate_error(blade_rows):
197
- total_massflow = list(); s = 0; massflow_stage = list()
198
- stage_ids = list(set([row.stage_id for row in self.blade_rows if row.stage_id>=0]))
199
- for row in blade_rows[1:]:
200
- total_massflow.append(row.total_massflow_no_coolant)
201
-
202
- sign = 1
203
- for s in stage_ids:
204
- for row in blade_rows:
205
- if row.stage_id == s and row.row_type == RowType.Rotor:
206
- massflow_stage.append(sign*row.total_massflow_no_coolant)
207
- sign*=-1
208
- if len(stage_ids) % 2 == 1:
209
- massflow_stage.append(massflow_stage[-1]*sign)
210
- deviation = np.std(total_massflow)*2
211
- if deviation>1.0:
212
- print("high massflow deviation detected")
213
- return np.std(total_massflow)*2 # + abs(sum(massflow_stage)) # Equation 28
227
+
214
228
 
215
229
  # Balance the massflow between Stages
216
230
  def balance_massflows(x0:List[float],blade_rows:List[List[BladeRow]],P0:npt.NDArray,P:npt.NDArray,balance_mean_pressure:bool=True):
@@ -232,27 +246,29 @@ class TurbineSpool(Spool):
232
246
  Returns:
233
247
  _type_: _description_
234
248
  """
249
+ blade_rows_backup = copy.deepcopy(blade_rows)
235
250
  # try:
236
251
  if balance_mean_pressure:
237
- for j in range(self.num_streamlines):
252
+ for j in range(self.num_streamlines):
238
253
  Ps_range = outlet_pressure(x0,P0[j],P[j])
239
- for i in range(1,len(blade_rows)-1):
254
+ for i in range(1,len(blade_rows)-2):
240
255
  blade_rows[i].P[j] = Ps_range[i-1]
241
- blade_rows[-1].P = P
256
+ blade_rows[-2].P = P
242
257
  else:
243
258
  for i in range(1,len(blade_rows)-1):
244
259
  for j in range(self.num_streamlines):
245
260
  blade_rows[i].P[j] = P[j]*x0[(i-1)*self.num_streamlines+j] # x0 size = num_streamlines -1
246
-
247
- calculate_massflows(blade_rows,True)
261
+ # try:
262
+ calculate_massflows(blade_rows,True,self.fluid)
248
263
  print(x0)
249
- return calculate_error(blade_rows)
250
- # except:
251
- # for i in range(1,len(blade_rows)-1):
252
- # for j in range(self.num_streamlines):
253
- # blade_rows[i].P[j] = P[j]
254
- # calculate_massflows(blade_rows,True)
255
- # return 10
264
+ return self.__massflow_std__(blade_rows)
265
+ # except Exception as e:
266
+ # print(e)
267
+ # finally:
268
+ # blade_rows = blade_rows_backup
269
+ # return np.inf # Return a high error
270
+
271
+
256
272
  # Break apart the rows to stages
257
273
  outlet_P=list(); outlet_P_guess = list() # Outlet P is the bounds, outlet_p_guess is the guessed values
258
274
 
@@ -260,60 +276,38 @@ class TurbineSpool(Spool):
260
276
  outlet_P.append(self.blade_rows[i].inlet_to_outlet_pratio)
261
277
  outlet_P_guess.append(np.mean(self.blade_rows[i].inlet_to_outlet_pratio))
262
278
 
263
- print('Find average P in between stages')
264
- if len(outlet_P) == 1:
265
- res = minimize_scalar(fun=balance_massflows,args=(self.blade_rows[:-1],self.blade_rows[0].P0,self.blade_rows[-1].P),
266
- bounds=outlet_P[0],tol=0.0001,options={'disp': True})
267
- x = res.x
268
- else:
269
- x = fmin_slsqp(func=balance_massflows,args=(self.blade_rows[:-1],self.blade_rows[0].P0,self.blade_rows[-1].P),
270
- bounds=outlet_P, x0=outlet_P_guess,epsilon=0.001,iter=100) # ,tol=0.001,options={'disp': True})
271
- outlet_P_guess = x
279
+ print(f"Looping to converge massflow")
280
+ past_err = -100; loop_iter = 0; err = 0.001
281
+ while np.abs((err-past_err)/err)>0.05:
282
+ if len(outlet_P) == 1:
283
+ # x = balance_massflows(0.658,self.blade_rows[:-1],self.blade_rows[0].P0,self.blade_rows[-1].P)
284
+ res = minimize_scalar(fun=balance_massflows,args=(self.blade_rows,self.blade_rows[0].P0,self.blade_rows[-1].P),bounds=outlet_P[0],tol=0.001,options={'disp': True},method='bounded')
285
+ x = res.x
286
+ print(x)
287
+ else:
288
+ x = fmin_slsqp(func=balance_massflows,args=(self.blade_rows,self.blade_rows[0].P0,self.blade_rows[-1].P),
289
+ bounds=outlet_P, x0=outlet_P_guess,epsilon=0.001,iter=100) # ,tol=0.001,options={'disp': True})
290
+ outlet_P_guess = x
272
291
 
273
- # Adjust the inlet: Set the massflow
274
- self.blade_rows[0].massflow = np.linspace(0,1,self.num_streamlines)*self.blade_rows[1].total_massflow_no_coolant
275
- inlet_calc(self.blade_rows[0]) # adjust the inlet to match massflow
292
+ # Adjust the inlet: Set the massflow
293
+ self.blade_rows[0].massflow = np.linspace(0,1,self.num_streamlines)*self.blade_rows[1].total_massflow_no_coolant
294
+ self.blade_rows[0].total_massflow_no_coolant = self.blade_rows[1].total_massflow_no_coolant
295
+ self.blade_rows[0].total_massflow = np.linspace(0,1,self.num_streamlines)*self.blade_rows[1].total_massflow_no_coolant
296
+ self.blade_rows[0].calculated_massflow = self.blade_rows[0].total_massflow_no_coolant
297
+ inlet_calc(self.blade_rows[0]) # adjust the inlet to match massflow
276
298
 
277
- if self.adjust_streamlines:
278
- for _ in range(2):
299
+ if self.adjust_streamlines:
279
300
  adjust_streamlines(self.blade_rows[:-1],self.passage)
280
- self.blade_rows[-1].transfer_quantities(self.blade_rows[-2])
281
- self.blade_rows[-1].P = self.blade_rows[-1].get_static_pressure(self.blade_rows[-1].percent_hub_shroud)
282
- balance_massflows(x,self.blade_rows[:-1],self.blade_rows[0].P0,self.blade_rows[-1].P)
283
- else:
301
+
284
302
  self.blade_rows[-1].transfer_quantities(self.blade_rows[-2])
285
303
  self.blade_rows[-1].P = self.blade_rows[-1].get_static_pressure(self.blade_rows[-1].percent_hub_shroud)
286
- err = calculate_error(self.blade_rows[:-1])
287
- print(f"Massflow convergenced error:{err}")
304
+
305
+ err = self.__massflow_std__(self.blade_rows)
306
+ print(f"Loop {loop_iter} massflow convergenced error:{err}")
288
307
 
289
308
  # calculate Reynolds number
290
309
  compute_reynolds(self.blade_rows,self.passage)
291
310
 
292
- # finetune = True
293
- # if finetune:
294
- # print('Finetune static pressure between stages')
295
- # self.blade_rows[-1].transfer_quantities(self.blade_rows[-2])
296
- # self.blade_rows[-1].P = self.blade_rows[-1].get_static_pressure(self.blade_rows[-1].percent_hub_shroud)
297
- # P = [row.P for row in self.blade_rows] # Average static pressures
298
- # bounds = []; guess = []
299
- # for i in range(1,len(self.blade_rows)-1): # set the bounds
300
- # for j in range(self.num_streamlines):
301
- # bounds.append([0.8,1.2]) # vary by +- 20%
302
- # guess.append(1)
303
-
304
- # x = fmin_slsqp(func=balance_massflows,args=(self.blade_rows[:-1],self.blade_rows[0].P0,P,False),
305
- # bounds=bounds, x0=guess,epsilon=0.001,iter=200)
306
- # P = [row.P for row in self.blade_rows] # Average static pressures
307
-
308
- # for _ in range(2):
309
- # adjust_streamlines(self.blade_rows[:-1],self.passage)
310
- # self.blade_rows[-1].transfer_quantities(self.blade_rows[-2])
311
- # self.blade_rows[-1].P = self.blade_rows[-1].get_static_pressure(self.blade_rows[-1].percent_hub_shroud)
312
- # balance_massflows(x,self.blade_rows[:-1],self.blade_rows[0].P0,P,False)
313
-
314
- # err = calculate_error(self.blade_rows[:-1])
315
- # print(f"Massflow convergenced error after finetuning:{err}")
316
-
317
311
 
318
312
  def export_properties(self,filename:str="turbine_spool.json"):
319
313
  """Export the spool object to json
@@ -327,7 +321,7 @@ class TurbineSpool(Spool):
327
321
  total_static_efficiency = list()
328
322
  stage_loading = list()
329
323
  euler_power = list()
330
-
324
+ enthalpy_power = list()
331
325
  x_streamline = np.zeros((self.num_streamlines,len(self.blade_rows)))
332
326
  r_streamline = np.zeros((self.num_streamlines,len(self.blade_rows)))
333
327
  massflow = list()
@@ -342,14 +336,14 @@ class TurbineSpool(Spool):
342
336
 
343
337
  stage_loading.append(row.stage_loading)
344
338
  euler_power.append(row.euler_power)
345
-
339
+ enthalpy_power.append(row.power)
346
340
  if row.row_type!=RowType.Inlet and row.row_type!=RowType.Outlet:
347
341
  massflow.append(row.massflow[-1])
348
342
 
349
343
  for j,p in enumerate(row.percent_hub_shroud):
350
344
  t,x,r = self.passage.get_streamline(p)
351
- x_streamline[j,indx] = float(interp1d(t,x)(row.axial_location))
352
- r_streamline[j,indx] = float(interp1d(t,r)(row.axial_location))
345
+ x_streamline[j,indx] = float(interp1d(t,x)(row.percent_hub))
346
+ r_streamline[j,indx] = float(interp1d(t,r)(row.percent_hub))
353
347
 
354
348
  Pratio_Total_Total = np.mean(self.blade_rows[0].P0 / self.blade_rows[-2].P0)
355
349
  Pratio_Total_Static = np.mean(self.blade_rows[0].P0 / self.blade_rows[-2].P)
@@ -368,6 +362,8 @@ class TurbineSpool(Spool):
368
362
  "xhub":self.passage.xhub_pts.tolist(),
369
363
  "xshroud":self.passage.xshroud_pts.tolist(),
370
364
  "num_streamlines":self.num_streamlines,
365
+ "euler_power": euler_power,
366
+ "enthalpy_power":enthalpy_power,
371
367
  "total-total_efficiency":total_total_efficiency,
372
368
  "total-static_efficiency":total_static_efficiency,
373
369
  "stage_loading":stage_loading,
@@ -389,7 +385,7 @@ class TurbineSpool(Spool):
389
385
  json.dump(data, f, indent=4,cls=NumpyEncoder)
390
386
 
391
387
 
392
- def calculate_massflows(blade_rows:List[BladeRow],calculate_vm:bool=False):
388
+ def calculate_massflows(blade_rows:List[BladeRow],calculate_vm:bool=False,fluid:Solution=None):
393
389
  """Calculates the massflow
394
390
 
395
391
  Args:
@@ -398,7 +394,7 @@ def calculate_massflows(blade_rows:List[BladeRow],calculate_vm:bool=False):
398
394
  calculate_vm (bool, optional): _description_. Defaults to False.
399
395
  """
400
396
  for p in range(3):
401
- for i in range(1,len(blade_rows)):
397
+ for i in range(1,len(blade_rows)-1):
402
398
  row = blade_rows[i]
403
399
  # Upstream Row
404
400
  if i == 0:
@@ -407,8 +403,6 @@ def calculate_massflows(blade_rows:List[BladeRow],calculate_vm:bool=False):
407
403
  upstream = blade_rows[i-1]
408
404
  if i<len(blade_rows)-1:
409
405
  downstream = blade_rows[i+1]
410
- else:
411
- downstream = None
412
406
 
413
407
  # Pressure loss = shift in entropy which affects the total pressure of the row
414
408
  if row.row_type == RowType.Inlet:
@@ -420,16 +414,16 @@ def calculate_massflows(blade_rows:List[BladeRow],calculate_vm:bool=False):
420
414
  if row.row_type == RowType.Rotor:
421
415
  rotor_calc(row,upstream,calculate_vm=True)
422
416
  # Finds Equilibrium between Vm, P0, T0
423
- row = radeq(row,upstream)
424
- row = compute_gas_constants(row)
417
+ row = radeq(row,upstream,downstream)
418
+ compute_gas_constants(row,fluid)
425
419
  rotor_calc(row,upstream,calculate_vm=False)
426
420
  elif row.row_type == RowType.Stator:
427
421
  stator_calc(row,upstream,downstream,calculate_vm=True)
428
422
  # Finds Equilibrium between Vm, P0, T0
429
- row = radeq(row,upstream)
430
- row = compute_gas_constants(row)
423
+ row = radeq(row,upstream,downstream)
424
+ compute_gas_constants(row,fluid)
431
425
  stator_calc(row,upstream,downstream,calculate_vm=False)
432
- row = compute_gas_constants(row)
426
+ compute_gas_constants(row,fluid)
433
427
  compute_massflow(row)
434
428
  compute_power(row,upstream)
435
429
 
@@ -442,7 +436,7 @@ def calculate_massflows(blade_rows:List[BladeRow],calculate_vm:bool=False):
442
436
  row.Yp = Yp
443
437
  rotor_calc(row,upstream,calculate_vm=True)
444
438
  row = radeq(row,upstream)
445
- row = compute_gas_constants(row)
439
+ compute_gas_constants(row,fluid)
446
440
  rotor_calc(row,upstream,calculate_vm=False)
447
441
  return abs(row.eta_total - eta_total)
448
442
 
@@ -452,13 +446,13 @@ def calculate_massflows(blade_rows:List[BladeRow],calculate_vm:bool=False):
452
446
  row.Yp = 0
453
447
  stator_calc(row,upstream,downstream,calculate_vm=True)
454
448
  row = radeq(row,upstream)
455
- row = compute_gas_constants(row)
449
+ row = compute_gas_constants(row,fluid)
456
450
  stator_calc(row,upstream,downstream,calculate_vm=False)
457
- row = compute_gas_constants(row)
451
+ row = compute_gas_constants(row,fluid)
458
452
  compute_massflow(row)
459
453
  compute_power(row,upstream)
460
454
 
461
- def massflow_loss_function(exit_angle:float,index:int,row:BladeRow,upstream:BladeRow,downstream:BladeRow=None):
455
+ def massflow_loss_function(exit_angle:float,index:int,row:BladeRow,upstream:BladeRow,downstream:BladeRow=None,fluid:Solution=None):
462
456
  """Finds the blade exit angles that balance the massflow throughout the stage
463
457
 
464
458
  Args:
@@ -483,8 +477,8 @@ def massflow_loss_function(exit_angle:float,index:int,row:BladeRow,upstream:Blad
483
477
  elif row.row_type == RowType.Stator:
484
478
  row.alpha2[index] = np.radians(exit_angle)
485
479
  stator_calc(row,upstream,downstream)
486
- upstream = compute_gas_constants(upstream)
487
- row = compute_gas_constants(row)
480
+ upstream = compute_gas_constants(upstream,fluid)
481
+ row = compute_gas_constants(row,fluid)
488
482
  elif row.loss_function.loss_type == LossType.Enthalpy:
489
483
  # Search for pressure loss that results in the correct total temperature drop
490
484
  if row.row_type == RowType.Rotor:
@@ -496,8 +490,8 @@ def massflow_loss_function(exit_angle:float,index:int,row:BladeRow,upstream:Blad
496
490
  def find_yp(Yp):
497
491
  row.Yp = Yp
498
492
  rotor_calc(row,upstream)
499
- upstream = compute_gas_constants(upstream)
500
- row = compute_gas_constants(row)
493
+ upstream = compute_gas_constants(upstream,fluid)
494
+ row = compute_gas_constants(row,fluid)
501
495
  return abs(row.T0.mean() - T0_target)
502
496
  res = minimize_scalar(find_yp,bounds=[0,0.6])
503
497
  row.Yp = res.x
@@ -505,8 +499,8 @@ def massflow_loss_function(exit_angle:float,index:int,row:BladeRow,upstream:Blad
505
499
  row.Yp = 0
506
500
  row.alpha2[index] = np.radians(exit_angle)
507
501
  stator_calc(row,upstream,downstream)
508
- upstream = compute_gas_constants(upstream)
509
- row = compute_gas_constants(row)
502
+ upstream = compute_gas_constants(upstream,fluid)
503
+ row = compute_gas_constants(row,fluid)
510
504
 
511
505
 
512
506
  # if use_radeq:
@@ -516,12 +510,12 @@ def massflow_loss_function(exit_angle:float,index:int,row:BladeRow,upstream:Blad
516
510
  compute_power(row,upstream)
517
511
 
518
512
  if row.row_type!=RowType.Inlet:
519
- if row.row_type == RowType.Rotor:
520
- T3_is = upstream.T0 * (1/row.P0_P)**((row.gamma-1)/row.gamma)
521
- else:
522
- T3_is = upstream.T0 * (row.P0/row.P)**((row.gamma-1)/row.gamma)
513
+ # if row.row_type == RowType.Rotor:
514
+ T3_is = upstream.T0 * (1/row.P0_P)**((row.gamma-1)/row.gamma)
515
+ # else:
516
+ # T3_is = upstream.T0 * (row.P0/row.P)**((row.gamma-1)/row.gamma)
523
517
  a = np.sqrt(row.gamma*row.R*T3_is)
524
- T03_is = T3_is * (1+(row.gamma-1)/2*(row.Vm/a)**2)
518
+ T03_is = T3_is * (1+(row.gamma-1)/2*(row.V/a)**2)
525
519
  row.eta_total = (upstream.T0.mean() - row.T0.mean())/(upstream.T0.mean()-T03_is.mean())
526
520
 
527
521
  return np.abs(row.total_massflow*index/(len(row.massflow)-1) - row.massflow[index])