ParaView Headless Rendering

ParaView ist ein leistungsfähiges Werkzeug zur Visualisierung von Ergebnissen aus Simulationen, aber auch zur Darstellung von Triangulierungen und Meshes. ParaView läuft standardmäßig interaktiv über eine GUI und benötigt dabei Grafikkarten sowie physische Displays. Viele wissenschaftliche und technische Anwendungen führen Simulationen jedoch auf Headless-Servern durch, die keine grafische Oberfläche haben. Hier entsteht ein Problem: ParaView kann ohne eine Display-Verbindung, die normalerweise X11 bereitgestellt, keine Renderings erstellen. Für diese Fälle ist ParaView Headless Rendering die Lösung, da es die Automatisierung von Visualisierungsaufgaben erheblich vereinfacht und ParaView auf Servern ohne grafische Oberfläche nutzbar macht.

Ein konkretes Beispiel für dieses Problem trat bei der Arbeit an einem OpenFOAM-Projekt auf, in dem das Meshing mit snappyHexMesh unter Jenkins automatisiert werden sollte. Um die Ergebnisse zu kontrollieren, sollte ein Screenshot des Meshings direkt im Jenkins-Workflow erscheinen. Das folgende Skript führte die erforderlichen Schritte unter Jenkins aus:

# Lade die OpenFOAM-Umgebung
source GoOpenFoam-v2306-jenkins
. $WM_PROJECT_DIR/bin/tools/RunFunctions

# Weitere Einstellungen und Kopieren des Testfalls ins Arbeitsverzeichnis 
...

# Starte die Bereinigung
./Allclean

# Starte die parallele Log-Ausgabe mit --retry im Hintergrund
tail --retry --follow=name log.snappyHexMesh &

./RunMeshing
...

Das Skript synchronisierte den Testfall in den Jenkins-Workspace, setzte die Umgebungsvariablen und führte die Meshing-Prozesse über das RunMeshing-Skript aus. Um die Ergebnisse anschließend im Jenkins-Workflow visualisieren zu können, wurde eine Lösung für ParaView Headless Rendering erforderlich. Am Ende des Skripts sollte ein ParaView-Aufruf wie pvpython my_script.py (siehe hier) ausgeführt werden, der lokal mit einem X-Server gut funktioniert. Auf dem Server ohne grafische Oberfläche führte dieser jedoch zu einer Fehlermeldung, und der Jenkins-Job brach ab.

Hier kommt Xvfb (X Virtual Frame Buffer) ins Spiel. Xvfb simuliert eine Display-Umgebung, die ParaView für Offscreen-Renderings ohne physisches Display oder GUI nutzen kann. Das ist besonders hilfreich auf Servern und ermöglicht die Einbindung von ParaView in automatisierte Workflows und Integrationsumgebungen wie Jenkins.

Voraussetzungen für ParaView Headless Rendering mit Xvfb

Um ParaView auf einem Server ohne Display auszuführen, sind folgende Voraussetzungen nötig:

  1. Eine funktionierende ParaView-Installation.
  2. Zugriff auf den Paketmanager (zum Beispiel dnf oder apt), um Xvfb zu installieren.

Die Installation von Xvfb erfolgt unter Fedora und CentOS-basierten Systemen (mit dnf) durch den folgenden Befehl:

sudo dnf install -y xorg-x11-server-Xvfb

ParaView ohne GUI: Einzeilige Lösung für Headless Rendering

Das Tool xvfb-run startet ParaView für das Offscreen-Rendering mit Xvfb. Es vereinfacht die Verwaltung des virtuellen X-Servers und wählt automatisch einen freien Server-Port aus:

xvfb-run --auto-servernum --server-args="-screen 0 1920x1080x24" pvpython paraview_script.py

xvfb-run führt das ParaView-Skript paraview_script.py headless aus und wählt mit der Option --auto-servernum automatisch einen freien Display-Server. Mit --server-args="-screen 0 1920x1080x24" legen wir die Bildschirmauflösung und Farbtiefe fest, die in vielen Anwendungsfällen für Renderings ausreichend ist.

Beispiel: OpenFOAM-Daten visualisieren

Hier ist ein Beispiel-Skript, das einen OpenFOAM-Fall lädt und als Surface With Edges darstellt. Dieses Skript speichert anschließend einen Screenshot der Ansicht:

from paraview.simple import *

# Lade den OpenFOAM-Fall
foam_case = OpenDataFile("./defrost.foam")

# Setze die Darstellung auf "Surface With Edges"
display = Show(foam_case)
display.Representation = 'Surface With Edges'

# Erstelle eine Render-Ansicht
render_view = GetActiveViewOrCreate('RenderView')

# Kameraeinstellungen für einen besseren Überblick
render_view.CameraPosition = [1, -1, 1]
render_view.CameraFocalPoint = [0, 0, 0]
render_view.CameraViewUp = [0, 0, 1]
render_view.CameraParallelScale = 1

# Screenshot speichern
render_view.ResetCamera()
SaveScreenshot("defrost_screenshot.png", render_view, ImageResolution=[1920, 1080])

# Ressourcen freigeben
Delete(render_view)

Ermittlung der Kamera- und Clipping-Einstellungen in der Python-Konsole

Um die Kamera-Position für das Headless-Rendering sinnvoll zu setzen, lässt sich die Python-Konsole von ParaView in einer interaktiven Sitzung verwenden. Die Python-Konsole ist in ParaView über View > Python Shell zugänglich. Zunächst wird das gewünschte Modell (z. B. case.foam) geladen, und der gewünschte Ausschnitt gewählt. Anschließend lässt sich die aktuelle Kamera-Position in der Konsole mit den folgenden Befehlen abrufen:

# Hole die aktive Ansicht (Render View)
render_view = GetActiveView()

# Kamera-Position abrufen
print("Camera Position:", render_view.CameraPosition)

# Kamera-Fokalpunkt abrufen
print("Camera Focal Point:", render_view.CameraFocalPoint)

# Kamera-Blickrichtung abrufen
print("Camera View Up:", render_view.CameraViewUp)

# Kamera-Skalierung (bei Verwendung der Parallelprojektion)
print("Camera Parallel Scale:", render_view.CameraParallelScale)

Genauso lassen sich auch die aktuellen Clipping-Einstellungen in der Python-Konsole abrufen:

# Hole den aktiven Clip-Filter
clip = GetActiveSource()

# Normalenrichtung der Schnittebene abrufen
print("Clip Normal:", clip.ClipType.Normal)

# Ursprung (Position) der Schnittebene abrufen
print("Clip Origin:", clip.ClipType.Origin)
Python-Konsole in ParaView
Ausgabe der Kamera- und Clipping-Daten in der Python-Konsole von ParaView.

Die ausgegebenen Werte für die Kamera-Position, den Fokalpunkt und die Blickrichtung lassen sich anschließend ins Skript einfügen, um dieselbe Ansicht im Headless-Modus wiederzugeben.

Integration in Jenkins

Um ParaView-Renderings als Teil eines automatisierten Workflows in Jenkins auszuführen, kann das Skript zusammen mit xvfb-run als Build-Step in einem Jenkins-Job verwendet werden. Dies ermöglicht regelmäßige Visualisierungen oder Tests in einem kontrollierten Umfeld und ohne grafische Benutzeroberfläche. Der Aufruf könnte im Jenkins-Build-Step folgendermaßen aussehen:


...
# Starte die Bereinigung
./Allclean

# Führe das Meshing-Skript aus
./RunMeshing

# Starte ParaView headless mit Xvfb für das Rendering
xvfb-run --auto-servernum --server-args="-screen 0 1920x1080x24" pvpython paraview_script.py

Screenshot der OpenFOAM-Visualisierung mit ParaView Headless Rendering
Screenshot eines OpenFOAM-Dummy-Cases, erstellt mit ParaView Headless Rendering und Xvfb im Jenkins-Workflow.

Fazit

Der Einsatz von Xvfb ermöglicht die Ausführung von ParaView auf Servern ohne physische Display-Verbindung und eröffnet so die Möglichkeit zur Automatisierung von Visualisierungen und zur Integration in komplexe Workflows. Das spart Ressourcen und erlaubt es, die Leistung von ParaView in verschiedensten Umgebungen zu nutzen.