|
| 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 | + |
0 commit comments