turbo-design 1.3.1__py3-none-any.whl → 1.3.3__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.3.1
3
+ Version: 1.3.3
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,6 +1,6 @@
1
1
  turbodesign/__init__.py,sha256=N8Nu0I1vrlEHYJZZ7yhhg-FtbNbLyrgjy7hoicygUqg,325
2
2
  turbodesign/arrayfuncs.py,sha256=GHIlTyLfeNsNCQQoh5m1aXK3iyvU6RjdYQipkqpU_ps,519
3
- turbodesign/bladerow.py,sha256=v4tX27aOL7iuN0ILWYbtSbANWZ_7_LIxksu4ux1aQ2o,24959
3
+ turbodesign/bladerow.py,sha256=FOs3I1dPHG0sPvfGH0PtZK9tyoTV9C8062_xGNZ4CrA,24974
4
4
  turbodesign/cantera_gas/co2.yaml,sha256=M2o_RzxV9B9rDkgkXJC-l3voKraFZguTZuKKt4F7S_c,887
5
5
  turbodesign/compressorspool.py,sha256=z8ZVczJ-EdZvIqqZArC6UdwC5MbU2SZh_MT2CGq5avY,2600
6
6
  turbodesign/coolant.py,sha256=evDtUFOYhfZKTVAsDWzxRzUX20gTvfjj0uybaWg4CsI,427
@@ -21,13 +21,13 @@ turbodesign/loss/turbine/traupel.py,sha256=aZxFE9JDcCfi1gy-fqS1SxjjlhuDG-H-g3LPu
21
21
  turbodesign/lossinterp.py,sha256=B2KEobp-nD9jwD6UINgBmTlH9kKyWg3UNvXxqfUsr-k,6198
22
22
  turbodesign/outlet.py,sha256=-0XpeEmTQpFjUQNYQxOp5WuHkF7cXfx59hxy7BmaxgY,2119
23
23
  turbodesign/passage.py,sha256=Ur6zZCzI9Y7HW0o5LrDq9yeatRain1mBLZBcTOzgjEU,11996
24
- turbodesign/radeq.py,sha256=hmHNmP5Fj0qgwq0o_j_bSyC4ktL3XFuC3QaebH5Ju_M,11361
24
+ turbodesign/radeq.py,sha256=NC4cRJG1Kz4n4zaLS5GFoIKBRSvTPuuj1dR1dgTa1mU,6475
25
25
  turbodesign/rotor.py,sha256=tHl9o5H4aQ6Etd4gqa8Ime1UK7k0de4GLt5Yb1sJdGs,1376
26
- turbodesign/solve_radeq.py,sha256=mGVBHmc20pAXEDKGzyiU3BVUsmY9gJl7zhbtHZqxARg,1956
27
- turbodesign/spool.py,sha256=XKvYABvfigLulGLHH23X7k6aL6wvfuqgfLkKCMK9X8c,14338
26
+ turbodesign/solve_radeq.py,sha256=nLYlRtXElPgHaoUP9jwMulRmYKTJs_uQ1eCulk2V59I,1938
27
+ turbodesign/spool.py,sha256=63Gc6U3-6zcHEJx8RDLN4kM12poo5E-M-nlbKvHm43I,14376
28
28
  turbodesign/stage.py,sha256=UP45sDKDLsAkO_WfDWJ6kqXU7cYKh_4QO01QZnSN1oQ,166
29
- turbodesign/td_math.py,sha256=NMKgHkc36LCrr4bZxjxx7TcA4ztaRps1cIsm1tucMrk,16069
30
- turbodesign/turbinespool.py,sha256=VmoyLH-TqaX9uXF5xWhwNriLPKZ5trjLiRg8NdV9MiE,25268
31
- turbo_design-1.3.1.dist-info/METADATA,sha256=3b9pATZ2DBpozyTFfEHxS5YxjY-pCCfwgYEQ5NGnjkA,683
32
- turbo_design-1.3.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
33
- turbo_design-1.3.1.dist-info/RECORD,,
29
+ turbodesign/td_math.py,sha256=czq-u1otamELybdBW5tP_05rzeTHo7lnrckzQkR4rG4,16183
30
+ turbodesign/turbinespool.py,sha256=8ttt2DuExuQFt9SXraRWhaYHQDkgyh_B6AoJqdNgRlg,25046
31
+ turbo_design-1.3.3.dist-info/METADATA,sha256=eJGhBnk9pjFtVMPNk6RiXg9DS5y1By2thmrniE1zxfo,734
32
+ turbo_design-1.3.3.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
33
+ turbo_design-1.3.3.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
@@ -14,6 +14,7 @@ from .passage import Passage
14
14
 
15
15
 
16
16
  class BladeRow:
17
+ id:int = 0
17
18
  stage_id:int = 0
18
19
  row_type: RowType = RowType.Stator
19
20
  loss_function:LossBaseClass
turbodesign/radeq.py CHANGED
@@ -1,10 +1,10 @@
1
1
  from scipy.interpolate import interp1d,PchipInterpolator
2
- from scipy.integrate import odeint
2
+ from scipy.integrate import solve_ivp
3
3
  import numpy as np
4
4
  import numdifftools as nd
5
5
  from .bladerow import BladeRow
6
6
  from .enums import RowType
7
-
7
+ import math
8
8
 
9
9
  def radeq(row:BladeRow,upstream:BladeRow,downstream:BladeRow=None) -> BladeRow:
10
10
  """Solves the radial equilibrium equation for axial machines and returns the convergence.
@@ -22,7 +22,7 @@ def radeq(row:BladeRow,upstream:BladeRow,downstream:BladeRow=None) -> BladeRow:
22
22
  """
23
23
  row_radius = row.r # Use these for gradient
24
24
  up_radius = upstream.r
25
-
25
+
26
26
  def ode_radeq_streamtube(r:np.ndarray,y:np.ndarray):
27
27
  """Solves the radial equilibrium equation for a streamtube
28
28
 
@@ -34,6 +34,7 @@ def radeq(row:BladeRow,upstream:BladeRow,downstream:BladeRow=None) -> BladeRow:
34
34
  P0 = y[0]
35
35
  T0 = y[1]
36
36
  Vm = y[2]
37
+ r = row.r.mean()+r
37
38
  if r>row_radius[-1]:
38
39
  return [0,0,0]
39
40
  elif r<row_radius[0]:
@@ -42,6 +43,8 @@ def radeq(row:BladeRow,upstream:BladeRow,downstream:BladeRow=None) -> BladeRow:
42
43
  Cp = row.Cp
43
44
  phi = interp1d(row_radius, row.phi)(r)
44
45
  alpha = interp1d(row_radius, row.alpha2)(r)
46
+ T = interp1d(row_radius, row.T)(r)
47
+ P = interp1d(row_radius, row.P)(r)
45
48
  rm = interp1d(row_radius, row.rm)(r)
46
49
  rho = row.rho.mean()
47
50
 
@@ -57,11 +60,9 @@ def radeq(row:BladeRow,upstream:BladeRow,downstream:BladeRow=None) -> BladeRow:
57
60
  Vt = Vm*np.tan(alpha)
58
61
  Vr = Vm*np.sin(phi)
59
62
  # Estimations
60
- dVm_dr = float(interp1d(row_radius, np.gradient(row.Vm, row_radius))(r))
61
- dVt_dr = dVm_dr*np.tan(alpha)
62
- # dVr_dr = dVm_dr*np.sin(phi)
63
-
63
+ dVm_dr = float(interp1d(row_radius, np.gradient(row.Vm, row_radius))(r))
64
64
  up_Vm = interp1d(row_radius, upstream.Vm)(r)
65
+
65
66
  if downstream:
66
67
  if downstream.row_type == RowType.Outlet:
67
68
  down_Vm = Vm
@@ -84,32 +85,28 @@ def radeq(row:BladeRow,upstream:BladeRow,downstream:BladeRow=None) -> BladeRow:
84
85
  dVm_dm = func_Vm_m.derivative()(row_m)
85
86
 
86
87
  # Upstream
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
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
89
-
90
- dP0_dr = float(interp1d(row.percent_hub_shroud, np.gradient(row.P0,row_radius))((r-row_radius[0])/(row_radius[-1]-row_radius[0]))) # use percentage to get
91
-
92
- U_up = float(interp1d(upstream.percent_hub_shroud,up_radius*omega)((r-row_radius[0])/(row_radius[-1]-row_radius[0]))) # use percentage to get the T0 upstream value
93
- dVtup_dr = float(interp1d(upstream.percent_hub_shroud,np.gradient(upstream.Vt,up_radius))((r-row_radius[0])/(row_radius[-1]-row_radius[0])))
94
- Vtup = float(interp1d(upstream.percent_hub_shroud,upstream.Vt)((r-row_radius[0])/(row_radius[-1]-row_radius[0])))
95
-
96
-
97
- dT0_dr = dT0up_dr - 1/row.Cp*(U_up*dVtup_dr + Vtup*omega - (U*dVt_dr+Vt*omega)) # Eqn 8
98
- # if row.loss_function.LossType == LossType.Pressure: # type: ignore
99
- # dP0_dr = dP0up_dr-row.Yp*(dP0up_dr - dP_dr) # Eqn 9
100
-
101
- C = Vm**2*(1+np.tan(alpha)**2)/(2*Cp*T0)
102
- if (C>1) & ((gamma/(gamma-1))<2):
103
- raise Exception("Invalid value of C {C}, change reduce alpha or Vm")
104
- B = (1-C)**(gamma/(gamma-1))
105
- A = P0 * gamma/(gamma-1) * (1-C)**(1/(gamma-1)) * (1+np.tan(alpha)**2)/(2*Cp)
88
+ dT_dr = float(interp1d(row_radius, np.gradient(row.T,row_radius))(r))
89
+ dP_dr = float(interp1d(row_radius, np.gradient(row.P,row_radius))(r))
90
+ P = float(interp1d(row_radius, np.gradient(row.P,row_radius))(r))
91
+ dT0_dr = dT_dr + Vm/Cp * (1 + np.tan(alpha)**2)*dVm_dr
92
+ dP0_dr = dP_dr * (T0/T)**(gamma/(gamma-1)) + P*gamma/(gamma-1) * (T0/T)**(1/(gamma-1)) * (T*dT0_dr-T0*dT_dr)/T**2
93
+ # dT0_dr = float(interp1d(row.percent_hub_shroud, np.gradient(row.T0,row_radius))((r-row_radius[0])/(row_radius[-1]-row_radius[0])))
94
+ # dP0_dr = float(interp1d(row.percent_hub_shroud, np.gradient(row.P0,row_radius))((r-row_radius[0])/(row_radius[-1]-row_radius[0])))
95
+
96
+ C = (1 + np.tan(alpha)**2) * Vm**2/(2*Cp*T0)
97
+ if (C>1):
98
+ raise Exception(f"Invalid value of C {C:0.2f} which causes Vm to be nan.\nChange reduce alpha/beta for {row.row_type} {row.id}")
99
+ B = (1-C)**(gamma/(gamma-1))
100
+ A = -P0 * gamma/(gamma-1) * (1-C)**(1/(gamma-1)) * (1 + np.tan(alpha)**2)/(2*Cp)
101
+
102
+ eqn15_rhs = Vt**2/r - Vm**2/rm*np.cos(phi) - Vr*dVm_dm # right hand side of equation 15
103
+ eqn15_rhs_simple = Vt**2/r # right hand side of equation 15 simplified for axial machines
106
104
 
107
105
  epsilon = 1e-10 # or another small threshold
108
106
  if abs(rm) > epsilon:
109
- dVm_dr = Vm/(2*T0**2) * dT0_dr - rho/(2*A*Vm) * (Vt**2/r + Vm/rm*np.cos(phi)-Vr*dVm_dm) + B/(2*A*Vm) * dP0_dr # Eqn 21
107
+ dVm_dr = T0/(2*Vm*A) * (rho*eqn15_rhs - B*dP0_dr) + Vm/(2*T0) * dT0_dr # Eqn 21
110
108
  else:
111
- dVm_dr = Vm/(2*T0**2) * dT0_dr - rho/(2*A*Vm) * (Vt**2/r) + B/(2*A*Vm) * dP0_dr # Eqn 21, modified
112
-
109
+ dVm_dr = T0/(2*Vm*A) * (rho*eqn15_rhs_simple - B*dP0_dr) + Vm/(2*T0) * dT0_dr # Eqn 21, simple
113
110
  ydot = np.array([dP0_dr,dT0_dr,dVm_dr])
114
111
 
115
112
  return ydot
@@ -121,166 +118,46 @@ def radeq(row:BladeRow,upstream:BladeRow,downstream:BladeRow=None) -> BladeRow:
121
118
 
122
119
  # Estimate the Vt based on a given turning angle
123
120
  mean_radius = row_radius.mean()
124
- tip_radius = row_radius[-1]
125
- hub_radius = row_radius[0]
121
+ tip_radius = row_radius.max()
122
+ hub_radius = row_radius.min()
126
123
 
127
124
  T0m = interp1d(row.percent_hub_shroud,T0)(0.5);
128
125
  P0m = interp1d(row.percent_hub_shroud,P0)(0.5); Vmm = interp1d(row.percent_hub_shroud,Vm)(0.5)
129
126
  # We are solving for the values of these quantities at row exit
130
127
  ics = np.array([P0m,T0m,Vmm])
131
128
 
132
- rm_to_tip = np.linspace(mean_radius,tip_radius)
133
- res1 = odeint(ode_radeq_streamtube, ics, rm_to_tip, tfirst=True)
129
+ # hub_to_tip = np.linspace(hub_radius,tip_radius)
130
+ # res = odeint(ode_radeq_streamtube, ics, hub_to_tip, tfirst=True)
134
131
 
135
- rm_to_hub = np.flip(np.linspace(hub_radius,mean_radius))
136
- res2 = odeint(ode_radeq_streamtube, ics, rm_to_hub, tfirst=True)
132
+ # P0_new = interp1d(hub_to_tip,res[:,0])(row_radius)
133
+ # T0_new = interp1d(hub_to_tip,res[:,1])(row_radius)
134
+ # Vm_new = interp1d(hub_to_tip,res[:,2])(row_radius)
135
+ r_eval = row.r - mean_radius
136
+ # mean_radius_to_tip = np.linspace(0,tip_radius-mean_radius,len(row_radius)*5)
137
+ res1 = solve_ivp(ode_radeq_streamtube, t_span =[0, tip_radius-mean_radius], y0 = ics,
138
+ t_eval=np.linspace(0,tip_radius-mean_radius,len(row_radius)*2))
137
139
 
138
- res2 = np.flipud(res2)
139
- res = np.concatenate([res2[:-1,:],res1])
140
- r = np.concatenate([np.flip(rm_to_hub)[:-1], rm_to_tip])
140
+ # mean_radius_to_hub = np.linspace(0,hub_radius-mean_radius,len(row_radius)*5)
141
+ res2 = solve_ivp(ode_radeq_streamtube, t_span = [0,hub_radius-mean_radius], y0 = ics,
142
+ t_eval=np.linspace(0,hub_radius-mean_radius,len(row_radius)*2))
141
143
 
142
- P0_new = interp1d(r,res[:,0])(row_radius)
143
- T0_new = interp1d(r,res[:,1])(row_radius)
144
- Vm_new = interp1d(r,res[:,2])(row_radius)
144
+ mid_to_tip_vals = res1.y.transpose()
145
+ mid_to_tip_r = res1.t + mean_radius
146
+ mid_to_hub_vals = res2.y.transpose()
147
+ mid_to_hub_r = res2.t + mean_radius
148
+ mid_to_hub_vals = np.flipud(mid_to_hub_vals)
149
+ mid_to_hub_r = np.flipud(mid_to_hub_r)
145
150
 
146
- row.P0 = P0_new
147
- row.T0 = T0_new
148
- row.Vm = Vm_new
149
- if row.row_type == RowType.Rotor:
150
- # U(VT1-VT2) = Power/massflow; VT2 = VT1 - Power/massflow
151
- row.Vt = upstream.Vt-row.power/(row.total_massflow*row.U)
152
- row.alpha2 = np.arctan2(row.Vt,row.Vx)
153
- elif row.row_type == RowType.Stator:
154
- row.Vt = row.Vm*np.cos(row.phi)*np.tan(row.alpha2)
155
- row.Vr = row.Vm*np.sin(row.phi)
156
- row.Vx = row.Vm*np.cos(row.phi)
151
+ hub_to_tip_vals = np.concatenate([mid_to_hub_vals[:-1,:],mid_to_tip_vals])
157
152
 
158
- return row
159
-
160
-
161
- def radeq_normalized(row:BladeRow,upstream:BladeRow) -> BladeRow:
162
- """Solves the radial equilibrium equation for axial or radial machines and returns the convergence.
163
-
164
- Args:
165
- row (BladeRow): Current row
166
- upstream (BladeRow): Previous row
167
-
168
- Returns:
169
- BladeRow: current row with Vt, T0, P0, and Vm calculated
170
- """
171
- _,row_radius = row.streamline.get_point(row.percent_hub_shroud) # Use these for gradient
172
- _,up_radius = upstream.streamline.get_point(upstream.percent_hub_shroud)
173
-
174
- def ode_radeq_streamtube(t:np.ndarray,y:np.ndarray):
175
- """Solves the radial equilibrium equation for a streamtube
176
-
177
- Args:
178
- t (np.ndarray): percent from hub to shroud
179
- y (np.ndarray): Array containing [P0,Vt,VtU,T0]
180
-
181
- """
182
- P0 = y[0]
183
- T0 = y[1]
184
- Vm = y[2]
185
- if t>1:
186
- return [0,0,0]
187
- elif t<0:
188
- return [0,0,0]
189
-
190
- _,r = row.streamline.get_point()
191
- Cp = row.Cp
192
- # Interpolate angle of inclination (phi), exit flow angle (alpha), radius of curvature (rm) at a particular percentage from hub to shroud
193
- phi = interp1d(row.percent_hub_shroud, row.phi)(t)
194
- alpha = interp1d(row.percent_hub_shroud, row.alpha2)(t)
195
- rm = interp1d(row.percent_hub_shroud,row.rm)(t)
196
- rho = interp1d(row.percent_hub_shroud,row.rho)(t)
197
-
198
-
199
- if (row.row_type == RowType.Rotor):
200
- omega = row.rpm*np.pi/30
201
- U = omega*r
202
- else:
203
- omega = 0
204
- U = 0
205
- gamma = row.gamma
206
-
207
- # Solve the Radial Equlibrium
208
- Vt = Vm*np.cos(phi)*np.tan(alpha)
209
- Vr = float(interp1d(row.percent_hub_shroud, row.Vr)(t))
210
- # Estimations: need the radius of the streamline to compute gradients
211
- dVm_dr = interp1d(row_radius,np.gradient(row.Vm, row_radius))(r)
212
- dVt_dr = dVm_dr*np.cos(phi)*np.tan(alpha)
213
-
214
- dVm_dm = interp1d(row_radius, np.gradient(Vm, r)) + interp1d(x, np.gradient(Vm, r))
215
-
216
- # Upstream: We interpolate the gradient based on the percentage from hub to shroud
217
- dT0up_dr = interp1d(upstream.percent_hub_shroud,
218
- np.gradient(upstream.T0,up_radius))(t)
219
- dP0up_dr = interp1d(upstream.percent_hub_shroud,
220
- np.gradient(upstream.P0,up_radius))(t)
221
- dP0_dr = interp1d(upstream.percent_hub_shroud,
222
- np.gradient(upstream.P0,up_radius))(t)
223
-
224
- U_up = interp1d(upstream.percent_hub_shroud,up_radius*omega)(t) # use percentage to get the T0 upstream value
225
- dVtup_dr = interp1d(upstream.percent_hub_shroud,np.gradient(upstream.Vt,up_radius))(t)
226
- Vtup = interp1d(upstream.percent_hub_shroud,upstream.Vt)(t)
227
-
228
- dP_dr = interp1d(row.percent_hub_shroud,np.gradient(row.P,row_radius))(t)
229
- dT0_dr = dT0up_dr - 1/row.Cp*(U_up*dVtup_dr + Vtup*omega - (U*dVt_dr+Vt*omega)) # Eqn 8
230
- # if row.loss_function.LossType == LossType.Pressure: # type: ignore
231
- # dP0_dr = dP0up_dr-row.Yp*(dP0up_dr - dP_dr) # Eqn 9
232
-
233
- C = Vm**2*(1+np.cos(phi)**2 * np.tan(alpha)**2)/(2*Cp*T0)
234
- B = (1-C)**(gamma/(gamma-1))
235
- A = P0 * gamma/(gamma-1) * (1-C)**(1/(gamma-1))
236
- dVm_dr = 1/(2*Vm*A) * (rho*(Vt/r - Vm**2/rm * np.cos(phi)-Vr*dVm_dm) - dP0_dr*B) + 1/(2*T0) *dT0_dr # Eqn 6
237
-
238
- ydot = np.array([dP0_dr,dT0_dr,dVm_dr])
239
-
240
- return ydot
241
-
242
- T0 = row.T0
243
- P0 = row.P0
244
- Vm = row.Vm
245
-
246
- # Estimate the Vt based on a given turning angle
247
- _, mean_radius = row.streamline.get_point(0.5)
248
- _, tip_radius = row.streamline.get_point(1)
249
- _, hub_radius = row.streamline.get_point(0)
250
-
251
- T0m = interp1d(row.percent_hub_shroud,T0)(0.5);
252
- P0m = interp1d(row.percent_hub_shroud,P0)(0.5);
253
- Vmm = interp1d(row.percent_hub_shroud,Vm)(0.5)
254
- # We are solving for the values of these quantities at row exit
255
- ics = np.array([P0m,T0m,Vmm])
256
-
257
- mid_to_tip = np.linspace(0,1)
258
- res1 = odeint(ode_radeq_streamtube, ics, mid_to_tip, tfirst=True) # Results
153
+ r = np.concatenate([mid_to_hub_r[:-1], mid_to_tip_r])
259
154
 
260
- mid_to_hub = np.flip(np.linspace(hub_radius,mean_radius))
261
- res2 = odeint(ode_radeq_streamtube, ics, mid_to_hub, tfirst=True) # Results
262
-
263
- res2 = np.flipud(res2)
264
- res = np.concatenate([res2[:-1,:],res1]) # Combine the results
265
- t = np.concatenate([np.flip(mid_to_hub)[:-1], mid_to_tip])
266
-
267
- P0_new = interp1d(t,res[:,0])(row.percent_hub_shroud)
268
- T0_new = interp1d(t,res[:,1])(row.percent_hub_shroud)
269
- Vm_new = interp1d(t,res[:,2])(row.percent_hub_shroud)
155
+ P0_new = interp1d(r,hub_to_tip_vals[:,0])(row_radius)
156
+ T0_new = interp1d(r,hub_to_tip_vals[:,1])(row_radius)
157
+ Vm_new = interp1d(r,hub_to_tip_vals[:,2])(row_radius)
270
158
 
271
159
  row.P0 = P0_new
272
160
  row.T0 = T0_new
273
161
  row.Vm = Vm_new
274
- if row.row_type == RowType.Rotor:
275
- # U(VT1-VT2) = Power/massflow; VT2 = VT1 - Power/massflow
276
- row.Vt = upstream.Vt-row.power/(row.total_massflow*row.U)
277
- row.alpha2 = np.arctan2(row.Vt,row.Vx)
278
- elif row.row_type == RowType.Stator:
279
- row.Vt = row.Vm*np.cos(row.phi)*np.tan(row.alpha2)
280
- row.Vr = row.Vm*np.sin(row.phi)
281
- row.Vx = row.Vm*np.cos(row.phi)
282
-
283
162
  return row
284
-
285
163
 
286
-
@@ -1,5 +1,5 @@
1
1
  from typing import List, Tuple
2
- from .radeq import radeq, radeq_normalized
2
+ from .radeq import radeq
3
3
  from .enums import LossType, RowType, PowerType, MassflowConstraint
4
4
  from .bladerow import BladeRow
5
5
  from .td_math import compute_gas_constants
turbodesign/spool.py CHANGED
@@ -69,6 +69,7 @@ class Spool:
69
69
  1. Conventional: Stator-Rotor-Stator-Rotor-etc. Set the RPM equally across all
70
70
  2. Counter Rotation: We either use the RPM already persecribed for each blade row.
71
71
  '''
72
+ self.blade_rows[i].id = i
72
73
  if (type(self.blade_rows[i]) != Inlet) and (type(self.blade_rows[i]) != Outlet):
73
74
  self.blade_rows[i].rpm = rpm
74
75
  self.blade_rows[i].axial_chord = self.blade_rows[i].location * self.passage.hub_length
turbodesign/td_math.py CHANGED
@@ -132,7 +132,8 @@ def compute_power(row:BladeRow,upstream:BladeRow) -> None:
132
132
  a = np.sqrt(row.gamma*row.R*row.T_is)
133
133
  row.T0_is = row.T_is * (1+(row.gamma-1)/2*(row.V/a)**2)
134
134
 
135
- row.power = row.massflow[-1] * row.Cp * (upstream.T0.mean() - row.T0.mean())
135
+ row.power = row.massflow[-1] * (row.Cp * (upstream.T0 - row.T0)).mean()
136
+ # row.power = sum(v * w for v, w in zip(row.power[1:], np.diff(row.massflow))) # Massflow weighted average
136
137
  row.eta_static = row.power/ (row.massflow[-1]*row.Cp*(upstream.T0.mean()-row.T_is.mean()))
137
138
  row.eta_total = (upstream.T0.mean() - row.T0.mean()) / (upstream.T0.mean() - row.T0_is.mean())
138
139
  row.stage_loading = row.Cp*(upstream.T0.mean() - row.T0.mean())/row.U.mean()**2
@@ -296,7 +297,7 @@ def rotor_calc(row:BladeRow,upstream:BladeRow,calculate_vm:bool=True):
296
297
  row.P0R = upstream.P0R - row.Yp*(upstream.P0R-row.P)
297
298
 
298
299
  # Total Relative Temperature stays constant through the rotor. Adjust for change in radius from rotor inlet to exit
299
- row.T0R = (upstream_rothalpy + 0.5*row.U**2)/row.Cp - T0_coolant_weighted_average(row)
300
+ row.T0R = upstream.T0R # (upstream_rothalpy + 0.5*row.U**2)/row.Cp # - T0_coolant_weighted_average(row)
300
301
  P0R_P = row.P0R / row.P
301
302
  T0R_T = P0R_P**((row.gamma-1)/row.gamma)
302
303
  row.T = (row.T0R/T0R_T) # Exit static temperature
@@ -326,7 +327,7 @@ def rotor_calc(row:BladeRow,upstream:BladeRow,calculate_vm:bool=True):
326
327
  row.Vt = row.Wt+row.U
327
328
 
328
329
  row.alpha2 = np.arctan2(row.Vt,row.Vm)
329
- row.V = np.sqrt(row.Vx**2 + row.Vr**2 + row.Vt**2)
330
+ row.V = np.sqrt(row.Vm**2*(1+np.tan(row.alpha2)**2))
330
331
 
331
332
  row.M = row.V/np.sqrt(row.gamma*row.R*row.T)
332
333
  T0_T = (1+(row.gamma-1)/2 * row.M**2)
@@ -369,7 +370,7 @@ def inlet_calc(row:BladeRow):
369
370
  raise ValueError(f"Unusually slow flow:{iter} Mach:{avg_mach}")
370
371
  row.Vm[0] = 1/(len(row.Vm)-1)*row.Vm[1:].sum() # Initialize the value at the hub to not upset the mean
371
372
  row.Vr = row.Vm*np.sin(row.phi)
372
- row.Vt = row.Vm*np.cos(row.phi)*np.tan(row.alpha2)
373
+ row.Vt = row.Vm*np.tan(row.alpha2)
373
374
  row.V = np.sqrt(row.Vt**2+row.Vm**2)
374
375
  # Fine tune the Temperature and Pressure and density
375
376
  row.M = row.V/np.sqrt(row.gamma*row.R*row.T)
@@ -13,6 +13,7 @@ from .solve_radeq import adjust_streamlines, radeq
13
13
  from scipy.optimize import minimize_scalar, differential_evolution, fmin_slsqp
14
14
  from .inlet import Inlet
15
15
  from .outlet import Outlet
16
+ from pyturbo.helper import convert_to_ndarray
16
17
 
17
18
  class TurbineSpool(Spool):
18
19
 
@@ -193,7 +194,7 @@ class TurbineSpool(Spool):
193
194
  """
194
195
  total_massflow = list(); s = 0; massflow_stage = list()
195
196
  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
+ for row in blade_rows: # Ignore inlet and outlet
197
198
  total_massflow.append(row.total_massflow_no_coolant)
198
199
  sign = 1
199
200
  for s in stage_ids:
@@ -237,7 +238,7 @@ class TurbineSpool(Spool):
237
238
  2. Keep the mean
238
239
 
239
240
  Args:
240
- x0 (List[float]): _description_
241
+ x0 (List[float]): Percentage of P0 exiting each row
241
242
  blade_rows (List[List[BladeRow]]): _description_
242
243
  P0 (npt.NDArray): _description_
243
244
  P (npt.NDArray): (1) Outlet Static Pressure. (2)
@@ -250,9 +251,9 @@ class TurbineSpool(Spool):
250
251
  # try:
251
252
  if balance_mean_pressure:
252
253
  for j in range(self.num_streamlines):
253
- Ps_range = outlet_pressure(x0,P0[j],P[j])
254
+ Ps = outlet_pressure(x0,P0[j],P[j])
254
255
  for i in range(1,len(blade_rows)-2):
255
- blade_rows[i].P[j] = Ps_range[i-1]
256
+ blade_rows[i].P[j] = float(Ps[i-1])
256
257
  blade_rows[-2].P = P
257
258
  else:
258
259
  for i in range(1,len(blade_rows)-1):
@@ -261,7 +262,7 @@ class TurbineSpool(Spool):
261
262
  # try:
262
263
  calculate_massflows(blade_rows,True,self.fluid)
263
264
  print(x0)
264
- return self.__massflow_std__(blade_rows)
265
+ return self.__massflow_std__(blade_rows[1:-1]) # do not consider inlet and outlet
265
266
  # except Exception as e:
266
267
  # print(e)
267
268
  # finally:
@@ -280,7 +281,7 @@ class TurbineSpool(Spool):
280
281
  past_err = -100; loop_iter = 0; err = 0.001
281
282
  while (np.abs((err-past_err)/err)>0.05) and loop_iter<10:
282
283
  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
+ # x = balance_massflows(0.22896832148169688,self.blade_rows,self.blade_rows[0].P0,self.blade_rows[-1].P)
284
285
  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
286
  x = res.x
286
287
  print(x)
@@ -395,64 +396,63 @@ def calculate_massflows(blade_rows:List[BladeRow],calculate_vm:bool=False,fluid:
395
396
  passage (Passage): _description_
396
397
  calculate_vm (bool, optional): _description_. Defaults to False.
397
398
  """
398
- for p in range(3):
399
- for i in range(1,len(blade_rows)-1):
400
- row = blade_rows[i]
401
- # Upstream Row
402
- if i == 0:
403
- upstream = blade_rows[i]
404
- else:
405
- upstream = blade_rows[i-1]
406
- if i<len(blade_rows)-1:
407
- downstream = blade_rows[i+1]
408
-
409
- # Pressure loss = shift in entropy which affects the total pressure of the row
410
- if row.row_type == RowType.Inlet:
411
- row.Yp = 0
412
- else:
413
- if row.loss_function.loss_type == LossType.Pressure:
414
- row.Yp = row.loss_function(row,upstream)
415
- for _ in range(2):
416
- if row.row_type == RowType.Rotor:
417
- rotor_calc(row,upstream,calculate_vm=True)
418
- # Finds Equilibrium between Vm, P0, T0
419
- row = radeq(row,upstream,downstream)
420
- compute_gas_constants(row,fluid)
421
- rotor_calc(row,upstream,calculate_vm=False)
422
- elif row.row_type == RowType.Stator:
423
- stator_calc(row,upstream,downstream,calculate_vm=True)
424
- # Finds Equilibrium between Vm, P0, T0
425
- row = radeq(row,upstream,downstream)
426
- compute_gas_constants(row,fluid)
427
- stator_calc(row,upstream,downstream,calculate_vm=False)
428
- compute_gas_constants(row,fluid)
429
- compute_massflow(row)
430
- compute_power(row,upstream)
431
-
432
- elif row.loss_function.loss_type == LossType.Enthalpy:
399
+ for i in range(1,len(blade_rows)-1):
400
+ row = blade_rows[i]
401
+ # Upstream Row
402
+ if i == 0:
403
+ upstream = blade_rows[i]
404
+ else:
405
+ upstream = blade_rows[i-1]
406
+ if i<len(blade_rows)-1:
407
+ downstream = blade_rows[i+1]
408
+
409
+ # Pressure loss = shift in entropy which affects the total pressure of the row
410
+ if row.row_type == RowType.Inlet:
411
+ row.Yp = 0
412
+ else:
413
+ if row.loss_function.loss_type == LossType.Pressure:
414
+ row.Yp = row.loss_function(row,upstream)
415
+ for _ in range(2):
433
416
  if row.row_type == RowType.Rotor:
434
- row.Yp = 0
435
- rotor_calc(row,upstream,calculate_vm=calculate_vm)
436
- eta_total = float(row.loss_function(row,upstream))
437
- def find_yp(Yp,row,upstream):
438
- row.Yp = Yp
439
- rotor_calc(row,upstream,calculate_vm=True)
440
- row = radeq(row,upstream)
441
- compute_gas_constants(row,fluid)
442
- rotor_calc(row,upstream,calculate_vm=False)
443
- return abs(row.eta_total - eta_total)
444
-
445
- res = minimize_scalar(find_yp,bounds=[0,0.6],args=(row,upstream))
446
- row.Yp = res.x
417
+ rotor_calc(row,upstream,calculate_vm=True)
418
+ # Finds Equilibrium between Vm, P0, T0
419
+ row = radeq(row,upstream,downstream)
420
+ compute_gas_constants(row,fluid)
421
+ rotor_calc(row,upstream,calculate_vm=False)
447
422
  elif row.row_type == RowType.Stator:
448
- row.Yp = 0
449
423
  stator_calc(row,upstream,downstream,calculate_vm=True)
450
- row = radeq(row,upstream)
451
- row = compute_gas_constants(row,fluid)
424
+ # Finds Equilibrium between Vm, P0, T0
425
+ row = radeq(row,upstream,downstream)
426
+ compute_gas_constants(row,fluid)
452
427
  stator_calc(row,upstream,downstream,calculate_vm=False)
453
- row = compute_gas_constants(row,fluid)
428
+ compute_gas_constants(row,fluid)
454
429
  compute_massflow(row)
455
430
  compute_power(row,upstream)
431
+
432
+ elif row.loss_function.loss_type == LossType.Enthalpy:
433
+ if row.row_type == RowType.Rotor:
434
+ row.Yp = 0
435
+ rotor_calc(row,upstream,calculate_vm=calculate_vm)
436
+ eta_total = float(row.loss_function(row,upstream))
437
+ def find_yp(Yp,row,upstream):
438
+ row.Yp = Yp
439
+ rotor_calc(row,upstream,calculate_vm=True)
440
+ row = radeq(row,upstream)
441
+ compute_gas_constants(row,fluid)
442
+ rotor_calc(row,upstream,calculate_vm=False)
443
+ return abs(row.eta_total - eta_total)
444
+
445
+ res = minimize_scalar(find_yp,bounds=[0,0.6],args=(row,upstream))
446
+ row.Yp = res.x
447
+ elif row.row_type == RowType.Stator:
448
+ row.Yp = 0
449
+ stator_calc(row,upstream,downstream,calculate_vm=True)
450
+ row = radeq(row,upstream)
451
+ row = compute_gas_constants(row,fluid)
452
+ stator_calc(row,upstream,downstream,calculate_vm=False)
453
+ row = compute_gas_constants(row,fluid)
454
+ compute_massflow(row)
455
+ compute_power(row,upstream)
456
456
 
457
457
  def massflow_loss_function(exit_angle:float,index:int,row:BladeRow,upstream:BladeRow,downstream:BladeRow=None,fluid:Solution=None):
458
458
  """Finds the blade exit angles that balance the massflow throughout the stage
@@ -533,14 +533,10 @@ def outlet_pressure(percents:List[float],inletP0:float,outletP:float) -> npt.NDA
533
533
  Returns:
534
534
  npt.NDArray: Array of static pressures
535
535
  """
536
- maxP = inletP0
537
- minP = outletP
538
- if isinstance(percents, float):
539
- Ps = [percents*(maxP-minP)+minP]
540
- else:
541
- Ps = np.zeros(shape=(len(percents),1)); i = 0
542
- for p in percents:
543
- Ps[i] = p*(maxP - minP) + minP
544
- maxP = Ps[i]
545
- i+=1
546
- return Ps
536
+ percents = convert_to_ndarray(percents)
537
+ Ps = np.zeros((len(percents),))
538
+ for i in range(len(percents)):
539
+ Ps[i] = float(interp1d((0,1),(inletP0,outletP))(percents[i]))
540
+ inletP0 = Ps[i]
541
+ return Ps
542
+