turbo-design 1.0.8__tar.gz → 1.0.10__tar.gz

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.

Files changed (32) hide show
  1. {turbo_design-1.0.8 → turbo_design-1.0.10}/PKG-INFO +1 -1
  2. {turbo_design-1.0.8 → turbo_design-1.0.10}/pyproject.toml +1 -1
  3. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/passage.py +1 -1
  4. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/solve_radeq.py +2 -1
  5. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/spool.py +19 -1
  6. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/td_math.py +5 -3
  7. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/turbinespool.py +116 -38
  8. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/__init__.py +0 -0
  9. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/arrayfuncs.py +0 -0
  10. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/bladerow.py +0 -0
  11. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/cantera_gas/co2.yaml +0 -0
  12. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/compressorspool.py +0 -0
  13. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/coolant.py +0 -0
  14. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/enums.py +0 -0
  15. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/inlet.py +0 -0
  16. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/isentropic.py +0 -0
  17. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/loss/__init__.py +0 -0
  18. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/loss/compressor/__init__.py +0 -0
  19. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/loss/losstype.py +0 -0
  20. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/loss/turbine/TD2.py +0 -0
  21. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/loss/turbine/__init__.py +0 -0
  22. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/loss/turbine/ainleymathieson.py +0 -0
  23. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/loss/turbine/craigcox.py +0 -0
  24. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/loss/turbine/fixedefficiency.py +0 -0
  25. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/loss/turbine/fixedpressureloss.py +0 -0
  26. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/loss/turbine/kackerokapuu.py +0 -0
  27. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/loss/turbine/traupel.py +0 -0
  28. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/lossinterp.py +0 -0
  29. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/outlet.py +0 -0
  30. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/radeq.py +0 -0
  31. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/rotor.py +0 -0
  32. {turbo_design-1.0.8 → turbo_design-1.0.10}/turbodesign/stage.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: turbo-design
3
- Version: 1.0.8
3
+ Version: 1.0.10
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
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "turbo-design"
3
- version = "1.0.8"
3
+ version = "1.0.10"
4
4
  description = "TurboDesign is a library used to design turbines and compressors using radial equilibrium."
5
5
  authors = ["Paht Juangphanich <paht.juangphanich@nasa.gov>"]
6
6
  packages = [
@@ -59,7 +59,7 @@ class Passage:
59
59
  """Gets the streamline at a certain percent radius
60
60
 
61
61
  Args:
62
- t_radial (float): _description_
62
+ t_radial (float): percent between hub and shroud
63
63
 
64
64
  Returns:
65
65
  Tuple containing:
@@ -34,4 +34,5 @@ def adjust_streamlines(blade_rows:List[BladeRow],passage:Passage):
34
34
  phi, rm, r = passage.streamline_curvature(x_streamline,r_streamline)
35
35
  row.phi[i] = float(interp1d(t_streamline,phi)(row.axial_location))
36
36
  row.rm[i] = float(interp1d(t_streamline,rm)(row.axial_location))
37
- row.r[i] = float(interp1d(t_streamline,r)(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))
@@ -28,6 +28,7 @@ class Spool:
28
28
  _fluid: Solution = Solution("air.yaml")
29
29
 
30
30
  massflow_constraint: MassflowConstraint
31
+ _adjust_streamlines:bool = True
31
32
 
32
33
  # Inlet Conditions
33
34
  def __init__(self,passage:Passage,
@@ -87,6 +88,23 @@ class Spool:
87
88
  """
88
89
  self._fluid = newFluid
89
90
 
91
+ @property
92
+ def adjust_streamlines(self) -> bool:
93
+ """Variable that determines whether or not to try and adjust the streamlines to balance massflow
94
+ This can be a source of failure. Setting it to false may help with debugging.
95
+
96
+ Returns:
97
+ bool: True = streamlines are adjusted after calculation; False = No changes in streamlines
98
+ """
99
+ return self._adjust_streamlines
100
+
101
+ @adjust_streamlines.setter
102
+ def adjust_streamlines(self,val:bool):
103
+ """Variable that determines whether or not to try and adjust the streamlines to balance massflow
104
+ This can be a source of failure. Setting it to false may help with debugging.
105
+ """
106
+ self._adjust_streamlines = val
107
+
90
108
 
91
109
  def set_blade_row_rpm(self,index:int,rpm:float):
92
110
  """sets the rpm of a particular blade row"""
@@ -229,7 +247,7 @@ class Spool:
229
247
  x_start = 0
230
248
  y_max = 0; y_min = 0
231
249
  plt.figure(num=1,clear=True)
232
- for i in range(1,len(self.blade_rows)):
250
+ for i in range(1,len(self.blade_rows)-1): # Don't plot inlet or outlet
233
251
  row = self.blade_rows[i]
234
252
  x_end = x_start + row.Vx.mean()
235
253
  dx = x_end - x_start
@@ -57,8 +57,8 @@ def compute_massflow(row:BladeRow) -> None:
57
57
  massflow = row.percent_hub_shroud*0
58
58
  total_area = 0
59
59
  for j in range(1,len(row.percent_hub_shroud)):
60
- Vm = row.Vm[j]
61
- rho = row.rho[j]
60
+ Vm = (row.Vm[j]+row.Vm[j-1])/2
61
+ rho = (row.rho[j]+row.rho[j-1])/2
62
62
  if np.abs((row.x[j]-row.x[j-1]))<1E-12: # Axial Machines
63
63
  total_area += np.pi*(row.r[j]**2-row.r[j-1]**2)
64
64
  massflow[j] = Vm * rho * np.pi* (row.r[j]**2-row.r[j-1]**2) + massflow[j-1]
@@ -360,8 +360,10 @@ def inlet_calc(row:BladeRow):
360
360
  row (BladeRow): _description_
361
361
  """
362
362
  area = row.Vm.copy()*0
363
+ # Estimate the density
363
364
  row.T = row.T0
364
365
  row.P = row.P0
366
+ row.rho = row.P/(row.T*row.R)
365
367
  total_area = 0
366
368
  for _ in range(5): # Lets converge the Mach and Total and Static pressures
367
369
  for j in range(1,len(row.percent_hub_shroud)):
@@ -381,7 +383,7 @@ def inlet_calc(row:BladeRow):
381
383
  row.Vr = row.Vm*np.sin(row.phi)
382
384
  row.Vt = row.Vm*np.cos(row.phi)*np.tan(row.alpha2)
383
385
  row.V = np.sqrt(row.Vt**2+row.Vm**2)
384
-
386
+ # Fine tune the Temperature and Pressure and density
385
387
  row.M = row.V/np.sqrt(row.gamma*row.R*row.T)
386
388
  row.T = row.T0 * 1/(1+(row.gamma-1)/2*row.M**2)
387
389
  row.P = row.P0 * (row.T/row.T0)**(row.gamma/(row.gamma-1))
@@ -3,7 +3,7 @@ from cantera.composite import Solution
3
3
  from .bladerow import BladeRow, interpolate_streamline_radii
4
4
  from .enums import RowType, MassflowConstraint, LossType, PassageType
5
5
  from .spool import Spool
6
- import json
6
+ import json, copy
7
7
  from .passage import Passage
8
8
  from scipy.interpolate import interp1d
9
9
  import numpy as np
@@ -11,7 +11,8 @@ import numpy.typing as npt
11
11
  from .td_math import inlet_calc,rotor_calc, stator_calc, compute_massflow, compute_power, compute_gas_constants
12
12
  from .solve_radeq import adjust_streamlines, radeq
13
13
  from scipy.optimize import minimize_scalar, minimize, fmin_slsqp
14
-
14
+ from .inlet import Inlet
15
+ from .outlet import Outlet
15
16
 
16
17
  class TurbineSpool(Spool):
17
18
  def __init__(self,passage:Passage,
@@ -49,7 +50,7 @@ class TurbineSpool(Spool):
49
50
  self.blade_rows[0].total_massflow = W0
50
51
  self.blade_rows[0].total_massflow_no_coolant = W0
51
52
 
52
- interpolate_streamline_radii(self.blade_rows[0],self.passage)
53
+ interpolate_streamline_radii(self.blade_rows[0],self.passage,self.num_streamlines)
53
54
 
54
55
  # Set the gas to total values for now
55
56
  self.blade_rows[0].fluid.TP = self.blade_rows[0].T0.mean(), self.blade_rows[0].P0.mean()
@@ -61,7 +62,7 @@ class TurbineSpool(Spool):
61
62
  inlet_calc(self.blade_rows[0])
62
63
 
63
64
  for row in self.blade_rows:
64
- interpolate_streamline_radii(row,self.passage)
65
+ interpolate_streamline_radii(row,self.passage,self.num_streamlines)
65
66
 
66
67
  outlet = self.blade_rows[-1]
67
68
  for j in range(self.num_streamlines):
@@ -191,56 +192,122 @@ class TurbineSpool(Spool):
191
192
  3. Adjust the streamlines for each blade row to balance the massflow
192
193
  """
193
194
 
194
- # Balance the massflow between Stages
195
- def balance_massflows(x0:List[float],blade_rows:List[List[BladeRow]],P0:npt.NDArray,P:npt.NDArray):
196
- total_massflow = list(); massflow_stage = list()
197
- stage_ids = list(set([row.stage_id for row in self.blade_rows if row.stage_id>=0])); s = 0
198
- sign = 1
199
- for j in range(self.num_streamlines):
200
- Ps_range = outlet_pressure(x0,P0[j],P[j])
201
- for i in range(1,len(blade_rows)-1):
202
- blade_rows[i].P[j] = Ps_range[i-1]
203
- blade_rows[-1].P = P
204
- calculate_massflows(blade_rows,True)
195
+ def calculate_error(blade_rows):
196
+ total_massflow = list(); s = 0; massflow_stage = list()
197
+ stage_ids = list(set([row.stage_id for row in self.blade_rows if row.stage_id>=0]))
205
198
  for row in blade_rows[1:]:
206
199
  total_massflow.append(row.total_massflow_no_coolant)
207
- for s in stage_ids:
208
- for row in blade_rows:
209
- if row.stage_id == s and row.row_type == RowType.Rotor:
210
- massflow_stage.append(sign*row.total_massflow_no_coolant)
211
- sign*=-1
212
- if len(stage_ids) % 2 == 1:
213
- massflow_stage.append(massflow_stage[-1]*sign)
214
- print(x0)
200
+
201
+ sign = 1
202
+ for s in stage_ids:
203
+ for row in blade_rows:
204
+ if row.stage_id == s and row.row_type == RowType.Rotor:
205
+ massflow_stage.append(sign*row.total_massflow_no_coolant)
206
+ sign*=-1
207
+ if len(stage_ids) % 2 == 1:
208
+ massflow_stage.append(massflow_stage[-1]*sign)
209
+
215
210
  return np.std(total_massflow)*2 # + abs(sum(massflow_stage)) # Equation 28
216
-
211
+
212
+ # Balance the massflow between Stages
213
+ def balance_massflows(x0:List[float],blade_rows:List[List[BladeRow]],P0:npt.NDArray,P:npt.NDArray,balance_mean_pressure:bool=True):
214
+ """Balance Massflows.
215
+
216
+ Steps:
217
+ 1. Balance the mean static pressure in between the blade rows. X0 = [0.2,0.5,...] size = num_rows
218
+ P = outlet static pressure
219
+
220
+ 2. Keep the mean
221
+
222
+ Args:
223
+ x0 (List[float]): _description_
224
+ blade_rows (List[List[BladeRow]]): _description_
225
+ P0 (npt.NDArray): _description_
226
+ P (npt.NDArray): (1) Outlet Static Pressure. (2)
227
+ balance_mean_pressure (bool, optional): _description_. Defaults to True.
228
+
229
+ Returns:
230
+ _type_: _description_
231
+ """
232
+ try:
233
+ if balance_mean_pressure:
234
+ for j in range(self.num_streamlines):
235
+ Ps_range = outlet_pressure(x0,P0[j],P[j])
236
+ for i in range(1,len(blade_rows)-1):
237
+ blade_rows[i].P[j] = Ps_range[i-1]
238
+ blade_rows[-1].P = P
239
+ else:
240
+ for i in range(1,len(blade_rows)-1):
241
+ for j in range(self.num_streamlines):
242
+ blade_rows[i].P[j] = P[j]*x0[(i-1)*self.num_streamlines+j] # x0 size = num_streamlines -1
243
+
244
+ calculate_massflows(blade_rows,True)
245
+ print(x0)
246
+ return calculate_error(blade_rows)
247
+ except:
248
+ for i in range(1,len(blade_rows)-1):
249
+ for j in range(self.num_streamlines):
250
+ blade_rows[i].P[j] = P[j]
251
+ calculate_massflows(blade_rows,True)
252
+ return 10
217
253
  # Break apart the rows to stages
218
- outlet_P=list(); outlet_P_guess = list()
254
+ outlet_P=list(); outlet_P_guess = list() # Outlet P is the bounds, outlet_p_guess is the guessed values
219
255
 
220
256
  for i in range(1,len(self.blade_rows)-2):
221
257
  outlet_P.append(self.blade_rows[i].inlet_to_outlet_pratio)
222
258
  outlet_P_guess.append(np.mean(self.blade_rows[i].inlet_to_outlet_pratio))
223
259
 
260
+ print('Find average P in between stages')
224
261
  if len(outlet_P) == 1:
225
- res1 = minimize_scalar(fun=balance_massflows,args=(self.blade_rows[:-1],self.blade_rows[0].P0,self.blade_rows[-1].P),
226
- bounds=outlet_P[0],tol=0.001,options={'disp': True})
227
- x = res1.x
262
+ res = minimize_scalar(fun=balance_massflows,args=(self.blade_rows[:-1],self.blade_rows[0].P0,self.blade_rows[-1].P),
263
+ bounds=outlet_P[0],tol=0.0001,options={'disp': True})
264
+ x = res.x
228
265
  else:
229
266
  x = fmin_slsqp(func=balance_massflows,args=(self.blade_rows[:-1],self.blade_rows[0].P0,self.blade_rows[-1].P),
230
267
  bounds=outlet_P, x0=outlet_P_guess,epsilon=0.001,iter=100) # ,tol=0.001,options={'disp': True})
268
+ outlet_P_guess = x
231
269
 
232
270
  # Adjust the inlet: Set the massflow
233
271
  self.blade_rows[0].massflow = np.linspace(0,1,self.num_streamlines)*self.blade_rows[1].total_massflow_no_coolant
234
272
  inlet_calc(self.blade_rows[0]) # adjust the inlet to match massflow
235
- for _ in range(3):
236
- adjust_streamlines(self.blade_rows[:-1],self.passage)
273
+
274
+ if self.adjust_streamlines:
275
+ for _ in range(2):
276
+ adjust_streamlines(self.blade_rows[:-1],self.passage)
277
+ self.blade_rows[-1].transfer_quantities(self.blade_rows[-2])
278
+ self.blade_rows[-1].P = self.blade_rows[-1].get_static_pressure(self.blade_rows[-1].percent_hub_shroud)
279
+ balance_massflows(x,self.blade_rows[:-1],self.blade_rows[0].P0,self.blade_rows[-1].P)
280
+ else:
237
281
  self.blade_rows[-1].transfer_quantities(self.blade_rows[-2])
238
282
  self.blade_rows[-1].P = self.blade_rows[-1].get_static_pressure(self.blade_rows[-1].percent_hub_shroud)
239
- err = balance_massflows(x,self.blade_rows[:-1],self.blade_rows[0].P0,self.blade_rows[-1].P)
240
- if err>5E-2:
241
- print(f"Massflow is not convergenced error:{err}")
242
- else:
243
- print(f"Massflow converged to less than 0.05kg/s error:{err}")
283
+ err = calculate_error(self.blade_rows[:-1])
284
+ print(f"Massflow convergenced error:{err}")
285
+
286
+ # finetune = True
287
+ # if finetune:
288
+ # print('Finetune static pressure between stages')
289
+ # self.blade_rows[-1].transfer_quantities(self.blade_rows[-2])
290
+ # self.blade_rows[-1].P = self.blade_rows[-1].get_static_pressure(self.blade_rows[-1].percent_hub_shroud)
291
+ # P = [row.P for row in self.blade_rows] # Average static pressures
292
+ # bounds = []; guess = []
293
+ # for i in range(1,len(self.blade_rows)-1): # set the bounds
294
+ # for j in range(self.num_streamlines):
295
+ # bounds.append([0.8,1.2]) # vary by +- 20%
296
+ # guess.append(1)
297
+
298
+ # x = fmin_slsqp(func=balance_massflows,args=(self.blade_rows[:-1],self.blade_rows[0].P0,P,False),
299
+ # bounds=bounds, x0=guess,epsilon=0.001,iter=200)
300
+ # P = [row.P for row in self.blade_rows] # Average static pressures
301
+
302
+ # for _ in range(2):
303
+ # adjust_streamlines(self.blade_rows[:-1],self.passage)
304
+ # self.blade_rows[-1].transfer_quantities(self.blade_rows[-2])
305
+ # self.blade_rows[-1].P = self.blade_rows[-1].get_static_pressure(self.blade_rows[-1].percent_hub_shroud)
306
+ # balance_massflows(x,self.blade_rows[:-1],self.blade_rows[0].P0,P,False)
307
+
308
+ # err = calculate_error(self.blade_rows[:-1])
309
+ # print(f"Massflow convergenced error after finetuning:{err}")
310
+
244
311
 
245
312
  def export_properties(self,filename:str="turbine_spool.json"):
246
313
  """Export the spool object to json
@@ -277,7 +344,13 @@ class TurbineSpool(Spool):
277
344
  t,x,r = self.passage.get_streamline(p)
278
345
  x_streamline[j,indx] = float(interp1d(t,x)(row.axial_location))
279
346
  r_streamline[j,indx] = float(interp1d(t,r)(row.axial_location))
280
-
347
+
348
+ Pratio_Total_Total = np.mean(self.blade_rows[0].P0 / self.blade_rows[-2].P0)
349
+ Pratio_Total_Static = np.mean(self.blade_rows[0].P0 / self.blade_rows[-2].P)
350
+ FlowFunction = np.mean(massflow)*np.sqrt(self.blade_rows[0].T0)*self.blade_rows[0].P0/1000 # kg sqrt(K)/(sec kPa)
351
+ CorrectedSpeed = self.rpm * np.pi/30 / np.sqrt(self.blade_rows[0].T0.mean()) # rad/s * 1/sqrt(K)
352
+ EnergyFunction = (self.blade_rows[0].T0 - self.blade_rows[-2].T0) * 0.5* (self.blade_rows[0].Cp + self.blade_rows[-2].Cp) / self.blade_rows[0].T0 # J/(KgK)
353
+ EnergyFunction = np.mean(EnergyFunction)
281
354
  data = {
282
355
  "blade_rows": blade_rows,
283
356
  "massflow":np.mean(massflow),
@@ -292,7 +365,12 @@ class TurbineSpool(Spool):
292
365
  "total-total_efficiency":total_total_efficiency,
293
366
  "total-static_efficiency":total_static_efficiency,
294
367
  "stage_loading":stage_loading,
295
- "degree_of_reaction":degree_of_reaction
368
+ "degree_of_reaction":degree_of_reaction,
369
+ "Pratio_Total_Total":Pratio_Total_Total,
370
+ "Pratio_Total_Static":Pratio_Total_Static,
371
+ "FlowFunction":FlowFunction,
372
+ "CorrectedSpeed":CorrectedSpeed,
373
+ "EnergyFunction":EnergyFunction
296
374
  }
297
375
  # Dump all the Python objects into a single JSON file.
298
376
  class NumpyEncoder(json.JSONEncoder):
@@ -326,7 +404,7 @@ def calculate_massflows(blade_rows:List[BladeRow],calculate_vm:bool=False):
326
404
  else:
327
405
  downstream = None
328
406
 
329
- # Pressure loss = shift in entropy which affects the total pressure of the row
407
+ # Pressure loss = shift in entropy which affects the total pressure of the row
330
408
  if row.row_type == RowType.Inlet:
331
409
  row.Yp = 0
332
410
  else: