Blog : Tracer l’allée de tourbillons de von Karman

Imaginons que nous ayons besoin de cartes de contours de vitesse au format vectoriel (SVG, PDF).

En général, on utilise Matplotlib à cette fin. La bibliothèque inclut la fonction tricontourf, capable de trianguler directement les données. Cependant, nous avons ici un “trou” au milieu du domaine (le cylindre) qui ne doit surtout pas être triangulé. Nous exploitons donc le fichier VTK issu de l’objet fonction cuttingPlane.

Le tracé se divise en deux étapes : la préparation des données et le tracé proprement dit.

Pour la préparation, nous utilisons le module Python de VTK afin de lire les données et de les trianguler proprement pour Matplotlib. Nous en extrayons ensuite les sommets, les valeurs de vitesse et les triangles, qui sont directement transmis à la fonction tricontourf.

Voici le code Python correspondant.

D’abord, nous importons les modules nécessaires :

#!/usr/bin/env python3

import vtk
from vtk.util import numpy_support

import numpy as np

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable

Le premier est VTK, servant à lire et manipuler la sortie de l’objet fonction. Nous importons ensuite NumPy pour la manipulation rapide de tableaux, et enfin Matplotlib pour le tracé. make_axes_locatable est nécessaire pour ajuster la barre de couleurs (colorbar).

reader = vtk.vtkXMLPolyDataReader()

reader.SetFileName('postProcessing/surfacesf/200/centerPlane.vtp')
reader.Update()

data = reader.GetOutput()

triangle_filter = vtk.vtkTriangleFilter()
triangle_filter.SetInputData(data)
triangle_filter.Update()
data = triangle_filter.GetOutput()

Puis, nous lisons et triangulons les données de vitesse.

vtk_points = data.GetPoints().GetData()
points = numpy_support.vtk_to_numpy(vtk_points)
x = points[:, 0]
y = points[:, 1]

vtk_vectors = data.GetPointData().GetArray("U")

vtk_cells = data.GetPolys().GetData()
cells_raw = numpy_support.vtk_to_numpy(vtk_cells)
triangles = cells_raw.reshape(-1, 4)[:, 1:]

U = numpy_support.vtk_to_numpy(vtk_vectors)
magU = np.linalg.norm(U, axis=1)

Nous extrayons ensuite les sommets du fichier VTK, les valeurs de vitesse aux cellules, la topologie des triangles, puis nous calculons la norme de la vitesse.

fig, ax = plt.subplots(figsize=(8, 6))

contour_filled = ax.tricontourf(x, y, triangles, magU, levels=16, cmap="turbo")

ax.tricontour(
    x, y, triangles, magU, levels=16, colors="white", linewidths=0.5, alpha=0.5
)

plt.xticks(fontsize=18)
plt.yticks(fontsize=18)

divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.1)

cbar = fig.colorbar(contour_filled, cax=cax)
ax.set_aspect("equal")

Enfin, nous traçons les données. Quelques ajustements sur la barre de couleurs ont été nécessaires pour l’aligner parfaitement sur la hauteur de la figure.

for f in ["svg", "pdf", "eps", "png"]:
    plt.savefig("velocity.{}".format(f), dpi=300, bbox_inches="tight", pad_inches=0.5)

Pour terminer, nous sauvegardons la figure dans les formats souhaités. Un nombre élevé de niveaux de contours génère des fichiers vectoriels plus lourds qu’un PNG, mais ils peuvent être agrandis sans aucune perte de qualité.

Filled contours of velocity magnitude at 200 s

SVG file (5.5M)

Python source for the plotting