Skip to content

Commit 12f194b

Browse files
committed
Changed panel method from built-in, Numba-compiled to lsv-panel
1 parent 1351118 commit 12f194b

File tree

3 files changed

+12
-164
lines changed

3 files changed

+12
-164
lines changed
Lines changed: 6 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1+
import lsv_panel
12
import numpy as np
2-
from numba import jit
3-
from numpy import zeros, pi, arctan2, sin, cos, sqrt, log, dot
4-
from numpy.linalg import inv
53

64

7-
@jit(nopython=True, cache=True)
8-
def single_element_inviscid(coord: np.ndarray, alpha: float or np.float64):
5+
def single_element_inviscid(coord: np.ndarray, alpha: float):
96
r"""
107
A linear strength vortex panel method for the inviscid solution of a single airfoil, sped up using the
118
just-in-time compiler in *numba*. Directly adapted from "Program 7" of Appendix D in [1].
@@ -20,8 +17,8 @@ def single_element_inviscid(coord: np.ndarray, alpha: float or np.float64):
2017
An :math:`N \times 2` array of airfoil coordinates, where :math:`N` is the number of coordinates, and the columns
2118
represent :math:`x` and :math:`y`
2219
23-
alpha: float or np.float64
24-
Angle of attack of the airfoil
20+
alpha: float
21+
Angle of attack of the airfoil in degrees
2522
2623
Returns
2724
-------
@@ -31,140 +28,5 @@ def single_element_inviscid(coord: np.ndarray, alpha: float or np.float64):
3128
one-dimensional array with length :math:`(N-1)` representing the surface pressure coefficient at each collocation
3229
point. The final returned value is the lift coefficient.
3330
"""
34-
35-
N = len(coord) # Number of panel end points
36-
M = N - 1 # Number of control points
37-
38-
EP = zeros((N, 2)) # Clockwise-defined panel end points
39-
EPT = zeros((N, 2)) # End points from file
40-
PT1 = zeros((M, 2)) # Start point of panel
41-
PT2 = zeros((M, 2)) # End point of panel
42-
CO = zeros((M, 2)) # Collocation point
43-
A = zeros((N, N)) # Aerodynamic influence coefficient matrix
44-
B = zeros((N, N)) # Tangential induced velocities (with gammas)
45-
TH = zeros((M,)) # Panel angle
46-
DL = zeros((M,)) # Panel length
47-
RHS = zeros((N, 1)) # Freestream component normal to panel
48-
V = zeros((M,)) # Panel tangential velocity
49-
50-
ALPHA = alpha # AOA in deg
51-
AL = ALPHA * pi / 180
52-
53-
EPT[:, 0] = coord[:, 0] # Read in x/c position of panel end points
54-
EPT[:, 1] = coord[:, 1] # Read in y/c position of panel end points
55-
56-
# Order panel end points defined in clockwise direction
57-
for i in range(N):
58-
EP[i, 0] = EPT[N - i - 1, 0]
59-
EP[i, 1] = EPT[N - i - 1, 1]
60-
61-
# Define end points of each panel (PT1 is beginning point, PT2 is end point)
62-
for i in range(M):
63-
PT1[i, 0] = EP[i, 0]
64-
PT2[i, 0] = EP[i+1, 0]
65-
PT1[i, 1] = EP[i, 1]
66-
PT2[i, 1] = EP[i+1, 1]
67-
68-
# Determine local slope of each panel
69-
for i in range(M):
70-
DZ = PT2[i, 1] - PT1[i, 1]
71-
DX = PT2[i, 0] - PT1[i, 0]
72-
TH[i] = arctan2(DZ, DX)
73-
74-
# Identify collocation points for each panel (half-panel location)
75-
for i in range(M):
76-
CO[i, 0] = (PT2[i, 0] - PT1[i, 0]) / 2 + PT1[i, 0]
77-
CO[i, 1] = (PT2[i, 1] - PT1[i, 1]) / 2 + PT1[i, 1]
78-
79-
# Determine influence coefficients
80-
for i in range(M):
81-
for j in range(M):
82-
83-
# Determine location of collocation point i in terms of panel j
84-
# coordinates
85-
XT = CO[i, 0] - PT1[j, 0]
86-
ZT = CO[i, 1] - PT1[j, 1]
87-
X2T = PT2[j, 0] - PT1[j, 0]
88-
Z2T = PT2[j, 1] - PT1[j, 1]
89-
90-
X = XT*cos(TH[j]) + ZT*sin(TH[j])
91-
Z = -XT*sin(TH[j]) + ZT*cos(TH[j])
92-
X2 = X2T*cos(TH[j]) + Z2T*sin(TH[j])
93-
Z2 = 0
94-
95-
# Store length of each panel (only required for first loop in i)
96-
if i == 0:
97-
DL[j] = X2
98-
99-
# Determine radial distance and angle between corner points of jth
100-
# panel and ith control point
101-
R1 = sqrt(X**2 + Z**2)
102-
R2 = sqrt((X - X2)**2 + Z**2)
103-
TH1 = arctan2(Z, X)
104-
TH2 = arctan2(Z, X - X2)
105-
106-
# Determine influence coefficient of jth panel on ith control point
107-
# (include consideration for self-induced velocities)
108-
if i == j:
109-
U1L = -0.5*(X - X2) / X2
110-
U2L = 0.5*X / X2
111-
W1L = -0.15916
112-
W2L = 0.15916
113-
else:
114-
U1L = -(Z*log(R2/R1) + X*(TH2 - TH1) - X2*(TH2 - TH1)) / (6.28319*X2)
115-
U2L = (Z*log(R2/R1) + X*(TH2 - TH1)) / (6.28319*X2)
116-
W1L = -((X2 - Z*(TH2 - TH1)) - X*log(R1/R2) + X2*log(R1/R2)) / (6.28319*X2)
117-
W2L = ((X2 - Z*(TH2 - TH1)) - X*log(R1/R2)) / (6.28319*X2)
118-
119-
# Rotate coordinates back from jth panel reference frame to airfoil
120-
# chord frame
121-
U1 = U1L * np.cos(-TH[j]) + W1L * np.sin(-TH[j])
122-
U2 = U2L*cos(-TH[j]) + W2L*sin(-TH[j])
123-
W1 = -U1L*sin(-TH[j]) + W1L*cos(-TH[j])
124-
W2 = -U2L*sin(-TH[j]) + W2L*cos(-TH[j])
125-
126-
# Define AIC: A(i,j) is the component of velocity normal to control
127-
# point i due to panel j
128-
# B(i,j) is the tangential velocity along control point i due to
129-
# panel j, used after solving for gammas
130-
if j == 0:
131-
A[i, 0] = -U1*sin(TH[i]) + W1*cos(TH[i])
132-
HOLDA = -U2*sin(TH[i]) + W2*cos(TH[i])
133-
B[i, 0] = U1*cos(TH[i]) + W1*sin(TH[i])
134-
HOLDB = U2*cos(TH[i]) + W2*sin(TH[i])
135-
elif j == M - 1:
136-
A[i, M - 1] = -U1*sin(TH[i]) + W1*cos(TH[i]) + HOLDA
137-
A[i, N - 1] = -U2*sin(TH[i]) + W2*cos(TH[i])
138-
B[i, M - 1] = U1*cos(TH[i]) + W1*sin(TH[i]) + HOLDB
139-
B[i, N - 1] = U2*cos(TH[i]) + W2*sin(TH[i])
140-
else:
141-
A[i, j] = -U1*sin(TH[i]) + W1*cos(TH[i]) + HOLDA
142-
HOLDA = -U2*sin(TH[i]) + W2*cos(TH[i])
143-
B[i, j] = U1*cos(TH[i]) + W1*sin(TH[i]) + HOLDB
144-
HOLDB = U2*cos(TH[i]) + W2*sin(TH[i])
145-
146-
# Set up freestream component of boundary condition
147-
RHS[i, 0] = cos(AL)*sin(TH[i]) - sin(AL)*cos(TH[i])
148-
149-
# Enforce Kutta condition
150-
RHS[N - 1, 0] = 0
151-
152-
A[N - 1, 0] = 1
153-
A[N - 1, N - 1] = 1
154-
155-
# Invert A matrix to solve for gammas
156-
G = dot(inv(A), RHS)
157-
158-
# With known gammas, solve for CL, CPs
159-
CL = 0.0
160-
161-
for i in range(M):
162-
VEL = 0.0
163-
for j in range(N):
164-
VEL = VEL + (B[i, j] * G[j])[0]
165-
V[i] = VEL + cos(AL)*cos(TH[i]) + sin(AL)*sin(TH[i])
166-
CL = CL + ((G[i] + G[i + 1]) * DL[i])[0]
167-
168-
CP = 1 - V**2
169-
170-
return CO, CP, CL
31+
co, cp, cl = lsv_panel.solve(coord, alpha)
32+
return np.array(co), np.array(cp), cl

pymead/gui/gui.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1204,7 +1204,9 @@ def single_airfoil_inviscid_analysis(self, plot_cp: bool,
12041204

12051205
self.dialog = PanelDialog(self, theme=self.themes[self.current_theme], settings_override=self.panel_settings)
12061206

1207-
if (dialog_test_action is not None and not dialog_test_action(self.dialog)) or self.dialog.exec():
1207+
if not plot_cp:
1208+
alpha_add = 0.0
1209+
elif (dialog_test_action is not None and not dialog_test_action(self.dialog)) or self.dialog.exec():
12081210
alpha_add = self.dialog.value()["alfa"]
12091211
self.panel_settings = self.dialog.value()
12101212
else:

pyproject.toml

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ classifiers = [
3535
"Programming Language :: Python :: 3",
3636
"Programming Language :: Python :: 3.10",
3737
"Programming Language :: Python :: 3.11",
38+
"Programming Language :: Python :: 3.12",
3839
"Programming Language :: Python :: 3.12"
3940
]
4041
dependencies = [
@@ -50,36 +51,19 @@ dependencies = [
5051
"python-benedict",
5152
"pandas",
5253
"pymoo==0.5.0",
53-
"numba",
5454
"networkx",
5555
"psutil",
5656
"triangle",
57-
"rust-nurbs>=0.24"
57+
"rust-nurbs>=0.24",
58+
"lsv-panel"
5859
]
5960
dynamic = ["version"]
6061

6162
[project.optional-dependencies]
6263
dev = [
63-
"scipy",
64-
"numpy",
65-
"shapely>=2.0",
66-
"matplotlib",
67-
"requests>=2.31",
68-
"PyQt6",
69-
"PyQt6-WebEngine",
70-
"PyQt6-Frameless-Window",
71-
"pyqtgraph",
72-
"python-benedict",
73-
"pandas",
74-
"pymoo==0.5.0",
75-
"numba",
76-
"networkx",
77-
"psutil",
7864
"pytest>=7",
7965
"pytest-qt",
8066
"pynput",
81-
"triangle",
82-
"rust-nurbs>=0.24"
8367
]
8468

8569
[project.urls]

0 commit comments

Comments
 (0)