Skip to content

Commit 7fecfd0

Browse files
authored
Add airfoil transonic dataset (#46)
1 parent 7199dbd commit 7fecfd0

9 files changed

+204
-0
lines changed

smithers/dataset/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
from .datasets.graetz import GraetzDataset
66
from .datasets.unsteady_heat import UnsteadyHeatDataset
77
from .datasets.lid_cavity import LidCavity
8+
from .datasets.airfoil_transonic import AirfoilTransonicDataset
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
from ..abstract_dataset import AbstractDataset
2+
import os
3+
import numpy as np
4+
import matplotlib
5+
import matplotlib.pyplot as plt
6+
import matplotlib.tri as tri
7+
from mpl_toolkits.axes_grid1 import make_axes_locatable
8+
from scipy.interpolate import CubicSpline
9+
10+
11+
class AirfoilTransonicDataset(AbstractDataset):
12+
13+
parametric = True
14+
time_dependent = False
15+
description = "Transonic flow past a NACA 0012 airfoil"
16+
data_directory = os.path.join(os.path.dirname(__file__),
17+
'airfoil_transonic')
18+
19+
def __init__(self):
20+
'''
21+
Initialize the dataset and structure it in dictionaries.
22+
'''
23+
self.params = np.load(os.path.join(self.data_directory, 'params.npy'))
24+
v_internal = np.load(os.path.join(self.data_directory,
25+
'snapshots_v_internal.npy'))
26+
p_internal = np.load(os.path.join(self.data_directory,
27+
'snapshots_p_internal.npy'))
28+
p_airfoil = np.load(os.path.join(self.data_directory,
29+
'snapshots_p_airfoil.npy'))
30+
wn_airfoil = np.load(os.path.join(self.data_directory,
31+
'snapshots_wn_airfoil.npy'))
32+
33+
self.snapshots = {
34+
'internal': {'mag(v)': v_internal, 'p': p_internal},
35+
'airfoil': {'p': p_airfoil, 'wallshear_normal': wn_airfoil}
36+
}
37+
coords_internal = np.load(os.path.join(self.data_directory,
38+
'coords_internal.npy'))
39+
coords_airfoil = np.load(os.path.join(self.data_directory,
40+
'coords_airfoil.npy'))
41+
self.pts_coordinates = {
42+
'internal': coords_internal, 'airfoil': coords_airfoil
43+
}
44+
self.auxiliary_triang = tri.Triangulation(coords_internal[0, :],
45+
coords_internal[1, :])
46+
self.auxiliary_triang.set_mask(self._mask_airfoil())
47+
48+
def _coords_airfoil(self, which='pos'):
49+
'''
50+
Get the positive (if which='pos') or negative (if which='neg')
51+
coordinates of the airfoil.
52+
'''
53+
x_airfoil = self.pts_coordinates['airfoil'][0, :]
54+
y_airfoil = self.pts_coordinates['airfoil'][1, :]
55+
if which=='pos':
56+
indices = y_airfoil >= 0
57+
elif which=='neg':
58+
indices = y_airfoil <= 0
59+
60+
x_airfoil_which = sorted(x_airfoil[indices])
61+
y_airfoil_which = y_airfoil[indices][
62+
np.argsort(x_airfoil[indices])]
63+
return x_airfoil_which, y_airfoil_which
64+
65+
def _f_airfoil_neg(self, tol=1e-4):
66+
'''
67+
Return a function that represents the negative part of the airfoil.
68+
'''
69+
x_airfoil_neg, y_airfoil_neg = self._coords_airfoil(which='neg')
70+
f_neg = CubicSpline(x_airfoil_neg, y_airfoil_neg)
71+
array = []
72+
for x in self.pts_coordinates['internal'][0, :]:
73+
if x >= 0 and x <= 1:
74+
array.append(f_neg(x) - tol)
75+
else:
76+
array.append(np.nan)
77+
return np.array(array)
78+
79+
def _f_airfoil_pos(self, tol=1e-4):
80+
'''
81+
Return a function that represents the positive part of the airfoil.
82+
'''
83+
x_airfoil_pos, y_airfoil_pos = self._coords_airfoil(which='pos')
84+
f_pos = CubicSpline(x_airfoil_pos, y_airfoil_pos)
85+
array = []
86+
for x in self.pts_coordinates['internal'][0, :]:
87+
if x >= 0 and x <= 1:
88+
array.append(f_pos(x) + tol)
89+
else:
90+
array.append(np.nan)
91+
return np.array(array)
92+
93+
def _mask_airfoil(self):
94+
'''
95+
Mask the triangles that are inside the airfoil (useful for plots).
96+
'''
97+
coords = self.pts_coordinates['internal']
98+
x_airfoil = self.pts_coordinates['airfoil'][0, :]
99+
y_airfoil = self.pts_coordinates['airfoil'][1, :]
100+
isbad = (np.greater(coords[0, :], x_airfoil.min()) &
101+
np.less(coords[0, :], x_airfoil.max()) &
102+
np.less(coords[1, :], self._f_airfoil_pos()) &
103+
np.greater(coords[1, :], self._f_airfoil_neg()))
104+
triangles = self.auxiliary_triang.triangles
105+
mask = np.all(np.where(isbad[triangles], True, False), axis=1)
106+
return mask
107+
108+
def plot_internal(self, snaps_array, idx=0, title='Snapshot', namefig=None,
109+
lim_x=(-0.5, 2), lim_y=(-0.5, 1), figsize=(8, 4), logscale=False):
110+
'''
111+
Plot a snapshot of the internal flow.
112+
113+
Parameters
114+
----------
115+
snaps_array : numpy.ndarray
116+
Snapshots of the internal flow (also external, not only
117+
self.snapshots['internal']).
118+
The shape should be (nparams, npoints).
119+
idx : int, optional
120+
Index of the snapshot to plot. The default is 0.
121+
title : str, optional
122+
Title of the plot. The default is 'Snapshot'.
123+
namefig : str, optional
124+
Name of the file where the plot is saved. The default is None.
125+
lim_x : tuple, optional
126+
Limits of the x-axis. The default is (-0.5, 2).
127+
lim_y : tuple, optional
128+
Limits of the y-axis. The default is (-0.5, 1).
129+
figsize: tuple, optional
130+
Size of the output figure. The default is (8, 4).
131+
'''
132+
fig, ax = plt.subplots(1, 1, figsize=figsize)
133+
snapshot = snaps_array[idx, :]
134+
if logscale:
135+
lognorm = matplotlib.colors.LogNorm(vmin=snapshot.min()+1e-12,
136+
vmax=snapshot.max())
137+
c = ax.tripcolor(self.auxiliary_triang, snapshot, cmap='rainbow',
138+
shading='gouraud', norm=lognorm)
139+
else:
140+
c = ax.tripcolor(self.auxiliary_triang, snapshot, cmap='rainbow',
141+
shading='gouraud')
142+
ax.plot(self._coords_airfoil()[0], self._coords_airfoil()[1],
143+
color='black', lw=0.5)
144+
ax.plot(self._coords_airfoil(which='neg')[0],
145+
self._coords_airfoil(which='neg')[1],
146+
color='black', lw=0.5)
147+
ax.set_aspect('equal')
148+
if lim_x is not None:
149+
ax.set_xlim(lim_x)
150+
if lim_y is not None:
151+
ax.set_ylim(lim_y)
152+
if title is not None:
153+
ax.set_title(title)
154+
divider = make_axes_locatable(ax)
155+
cax = divider.append_axes("right", size= "5%", pad=0.1)
156+
plt.colorbar(c, cax=cax)
157+
if namefig is not None:
158+
fig.savefig(namefig, dpi=300)
159+
plt.show()
160+
161+
def plot_airfoil(self, snaps_array, idx=0, title='Snapshot', namefig=None,
162+
lim_x=(-0.1, 1.1), lim_y=(-0.2, 0.2), figsize=(8, 4)):
163+
'''
164+
Plot a snapshot on the airfoil.
165+
166+
Parameters
167+
----------
168+
snaps_array : numpy.ndarray
169+
Snapshot on the airfoil (also external, not only
170+
self.snapshots['airfoil']).
171+
The shape should be (nparams, npoints).
172+
idx : int, optional
173+
Index of the snapshot to plot. The default is 0.
174+
title : str, optional
175+
Title of the plot. The default is 'Snapshot'.
176+
namefig : str, optional
177+
Name of the file where the plot is saved. The default is None.
178+
lim_x : tuple, optional
179+
Limits of the x-axis. The default is (-0.1, 1.1).
180+
lim_y : tuple, optional
181+
Limits of the y-axis. The default is (-0.2, 0.2).
182+
figsize: tuple, optional
183+
Size of the output figure. The default is (8, 4).
184+
'''
185+
fig, ax = plt.subplots(1, 1, figsize=figsize)
186+
snapshot = snaps_array[idx, :]
187+
coords = self.pts_coordinates['airfoil']
188+
ax.grid()
189+
c = ax.scatter(coords[0, :], coords[1, :], c=snapshot, s=10)
190+
ax.set_aspect('equal')
191+
if lim_x is not None:
192+
ax.set_xlim(lim_x)
193+
if lim_y is not None:
194+
ax.set_ylim(lim_y)
195+
if title is not None:
196+
ax.set_title(title)
197+
divider = make_axes_locatable(ax)
198+
cax = divider.append_axes("right", size= "5%", pad=0.1)
199+
plt.colorbar(c, cax=cax)
200+
if namefig is not None:
201+
fig.savefig(namefig, dpi=300)
202+
plt.show()
203+
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)