12.2. VTK Output for 3D (and 2D) Visualization#

Besides the convenient visualizations of the Netgen GUI and the NGSolve webgui, we can also use the VTK output for 3D visualization.

This is particularly useful for polished visualizations of 3D simulations where you want to apply several filters to the visualization, e.g. to show the solution on a slice of the domain, or to show the solution as a surface plot and possibly combine these things.

12.2.1. Setup dependencies#

In this unit we will use pyvista to visualize the VTK output and we will need vtk as well. You can install these packages via pip in your terminal (or a virtual env.):

pip3 install pyvista vtk ipywidgets trame trame-vtk trame-vuetify --break-system-packages --upgrade

or execute the following cell:

!PIP_BREAK_SYSTEM_PACKAGES=1 pip3 install pyvista vtk ipywidgets trame trame-vtk trame-vuetify --upgrade
WARNING: Ignoring invalid distribution ~etgen-mesher (/home/jschoebe/ngs24/lib/python3.11/site-packages)

WARNING: Ignoring invalid distribution ~etgen-mesher (/home/jschoebe/ngs24/lib/python3.11/site-packages)

Requirement already satisfied: pyvista in /home/jschoebe/ngs24/lib/python3.11/site-packages (0.43.10)
Requirement already satisfied: vtk in /home/jschoebe/ngs24/lib/python3.11/site-packages (9.3.0)
Requirement already satisfied: ipywidgets in /home/jschoebe/ngs24/lib/python3.11/site-packages (8.1.3)
Requirement already satisfied: trame in /home/jschoebe/ngs24/lib/python3.11/site-packages (3.6.3)
Requirement already satisfied: trame-vtk in /home/jschoebe/ngs24/lib/python3.11/site-packages (2.8.9)
Requirement already satisfied: trame-vuetify in /home/jschoebe/ngs24/lib/python3.11/site-packages (2.6.0)
Requirement already satisfied: matplotlib>=3.0.1 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from pyvista) (3.9.0)
Requirement already satisfied: numpy>=1.21.0 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from pyvista) (1.26.4)
Requirement already satisfied: pillow in /home/jschoebe/ngs24/lib/python3.11/site-packages (from pyvista) (10.3.0)
Requirement already satisfied: pooch in /home/jschoebe/ngs24/lib/python3.11/site-packages (from pyvista) (1.8.1)
Requirement already satisfied: scooby>=0.5.1 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from pyvista) (0.10.0)
Requirement already satisfied: comm>=0.1.3 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from ipywidgets) (0.2.2)
Requirement already satisfied: ipython>=6.1.0 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from ipywidgets) (8.24.0)
Requirement already satisfied: traitlets>=4.3.1 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from ipywidgets) (5.14.3)
Requirement already satisfied: widgetsnbextension~=4.0.11 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from ipywidgets) (4.0.11)
Requirement already satisfied: jupyterlab-widgets~=3.0.11 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from ipywidgets) (3.0.11)
Requirement already satisfied: trame-server<4,>=3 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from trame) (3.0.1)
Requirement already satisfied: trame-client<4,>=3 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from trame) (3.1.0)
Requirement already satisfied: decorator in /home/jschoebe/ngs24/lib/python3.11/site-packages (from ipython>=6.1.0->ipywidgets) (5.1.1)
Requirement already satisfied: jedi>=0.16 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from ipython>=6.1.0->ipywidgets) (0.19.1)
Requirement already satisfied: matplotlib-inline in /home/jschoebe/ngs24/lib/python3.11/site-packages (from ipython>=6.1.0->ipywidgets) (0.1.7)
Requirement already satisfied: prompt-toolkit<3.1.0,>=3.0.41 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from ipython>=6.1.0->ipywidgets) (3.0.43)
Requirement already satisfied: pygments>=2.4.0 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from ipython>=6.1.0->ipywidgets) (2.18.0)
Requirement already satisfied: stack-data in /home/jschoebe/ngs24/lib/python3.11/site-packages (from ipython>=6.1.0->ipywidgets) (0.6.3)
Requirement already satisfied: typing-extensions>=4.6 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from ipython>=6.1.0->ipywidgets) (4.11.0)
Requirement already satisfied: pexpect>4.3 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from ipython>=6.1.0->ipywidgets) (4.9.0)
Requirement already satisfied: contourpy>=1.0.1 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from matplotlib>=3.0.1->pyvista) (1.2.1)
Requirement already satisfied: cycler>=0.10 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from matplotlib>=3.0.1->pyvista) (0.12.1)
Requirement already satisfied: fonttools>=4.22.0 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from matplotlib>=3.0.1->pyvista) (4.51.0)
Requirement already satisfied: kiwisolver>=1.3.1 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from matplotlib>=3.0.1->pyvista) (1.4.5)
Requirement already satisfied: packaging>=20.0 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from matplotlib>=3.0.1->pyvista) (24.0)
Requirement already satisfied: pyparsing>=2.3.1 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from matplotlib>=3.0.1->pyvista) (3.1.2)
Requirement already satisfied: python-dateutil>=2.7 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from matplotlib>=3.0.1->pyvista) (2.9.0.post0)
Requirement already satisfied: wslink<3,>=2 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from trame-server<4,>=3->trame) (2.0.4)
Requirement already satisfied: more-itertools in /home/jschoebe/ngs24/lib/python3.11/site-packages (from trame-server<4,>=3->trame) (10.2.0)
Requirement already satisfied: platformdirs>=2.5.0 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from pooch->pyvista) (4.2.2)
Requirement already satisfied: requests>=2.19.0 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from pooch->pyvista) (2.31.0)
Requirement already satisfied: parso<0.9.0,>=0.8.3 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from jedi>=0.16->ipython>=6.1.0->ipywidgets) (0.8.4)
Requirement already satisfied: ptyprocess>=0.5 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from pexpect>4.3->ipython>=6.1.0->ipywidgets) (0.7.0)
Requirement already satisfied: wcwidth in /home/jschoebe/ngs24/lib/python3.11/site-packages (from prompt-toolkit<3.1.0,>=3.0.41->ipython>=6.1.0->ipywidgets) (0.2.13)
Requirement already satisfied: six>=1.5 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from python-dateutil>=2.7->matplotlib>=3.0.1->pyvista) (1.16.0)
Requirement already satisfied: charset-normalizer<4,>=2 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from requests>=2.19.0->pooch->pyvista) (3.3.2)
Requirement already satisfied: idna<4,>=2.5 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from requests>=2.19.0->pooch->pyvista) (3.7)
Requirement already satisfied: urllib3<3,>=1.21.1 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from requests>=2.19.0->pooch->pyvista) (2.2.1)
Requirement already satisfied: certifi>=2017.4.17 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from requests>=2.19.0->pooch->pyvista) (2024.2.2)
Requirement already satisfied: aiohttp<4 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from wslink<3,>=2->trame-server<4,>=3->trame) (3.9.5)
Requirement already satisfied: msgpack<2,>=1 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from wslink<3,>=2->trame-server<4,>=3->trame) (1.0.8)
Requirement already satisfied: executing>=1.2.0 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from stack-data->ipython>=6.1.0->ipywidgets) (2.0.1)
Requirement already satisfied: asttokens>=2.1.0 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from stack-data->ipython>=6.1.0->ipywidgets) (2.4.1)
Requirement already satisfied: pure-eval in /home/jschoebe/ngs24/lib/python3.11/site-packages (from stack-data->ipython>=6.1.0->ipywidgets) (0.2.2)
Requirement already satisfied: aiosignal>=1.1.2 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from aiohttp<4->wslink<3,>=2->trame-server<4,>=3->trame) (1.3.1)
Requirement already satisfied: attrs>=17.3.0 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from aiohttp<4->wslink<3,>=2->trame-server<4,>=3->trame) (23.2.0)
Requirement already satisfied: frozenlist>=1.1.1 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from aiohttp<4->wslink<3,>=2->trame-server<4,>=3->trame) (1.4.1)
Requirement already satisfied: multidict<7.0,>=4.5 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from aiohttp<4->wslink<3,>=2->trame-server<4,>=3->trame) (6.0.5)
Requirement already satisfied: yarl<2.0,>=1.0 in /home/jschoebe/ngs24/lib/python3.11/site-packages (from aiohttp<4->wslink<3,>=2->trame-server<4,>=3->trame) (1.9.4)
WARNING: Ignoring invalid distribution ~etgen-mesher (/home/jschoebe/ngs24/lib/python3.11/site-packages)

WARNING: Ignoring invalid distribution ~etgen-mesher (/home/jschoebe/ngs24/lib/python3.11/site-packages)

12.2.2. Functionality on dummy data#

If you want to, you can skip to the next section for the visualization of a flow field.

12.2.2.1. Generating the VTK output#

from ngsolve import *
from netgen.occ import unit_cube
#VTKOutput?
mesh = Mesh (unit_cube.GenerateMesh(maxh=0.4))
gfu = GridFunction (L2(mesh=mesh, order=3))
gfu.Set(sin(4*pi*x*y*z))
gfv = GridFunction (L2(mesh=mesh, order=3))
gfv.Set(cos(x**2+y**2-z**2))

#define VTK output for visualization:
vtk = VTKOutput(mesh,coefs=[gfu,gfv],names=["gfu","gfv"],filename="vtkout",subdivision=3, floatsize="single",legacy=False)
#execute the VTK output:
vtk.Do()
'vtkout'

12.2.2.2. Reading the VTK data to pyvista#

import pyvista
pyvista.set_jupyter_backend('html')
visobj = pyvista.read('vtkout.vtu')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[5], line 3
      1 import pyvista
      2 pyvista.set_jupyter_backend('html')
----> 3 visobj = pyvista.read('vtkout.vtu')

File ~/ngs24/lib/python3.11/site-packages/pyvista/core/utilities/fileio.py:201, in read(filename, force_ext, file_format, progress_bar)
    199 if progress_bar:
    200     reader.show_progress()
--> 201 mesh = reader.read()
    202 if observer.has_event_occurred():
    203     warnings.warn(
    204         f"The VTK reader `{reader.reader.GetClassName()}` in pyvista reader `{reader}` raised an error"
    205         "while reading the file.\n"
    206         f'\t"{observer.get_message()}"'
    207     )

File ~/ngs24/lib/python3.11/site-packages/pyvista/core/utilities/reader.py:387, in BaseReader.read(self)
    384 data._post_file_load_processing()
    386 # check for any pyvista metadata
--> 387 data._restore_metadata()
    388 return data

File ~/ngs24/lib/python3.11/site-packages/pyvista/core/dataobject.py:192, in DataObject._restore_metadata(self)
    190 for assoc_type in ('POINT', 'CELL'):
    191     key = f'_PYVISTA_{assoc_name}_{assoc_type}_'.upper()
--> 192     if key in fdata:
    193         assoc_data = getattr(self, f'_association_{assoc_name}_names')
    194         assoc_data[assoc_type] = set(fdata[key])

TypeError: argument of type 'vtkmodules.vtkCommonDataModel.vtkFieldData' is not iterable

12.2.2.3. Simple plotting#

Option 1: Call plot: (will give no result for jupyter book)

visobj.plot(scalars="gfu")

Option 1b: Call plot with several options: (will give no result for jupyter book)

visobj.plot(scalars="gfu", show_scalar_bar=True, show_edges=False, 
            edge_color='black', cmap='jet', lighting=True, 
            n_colors=16, clim=[-1,1], 
            scalar_bar_args={'title':'u', 'height':1.5, 'width':0.5, 
                             'position_x':0.1, 'position_y':0.1})

Option 2: Use a visualization object (pyvista.Plotter) and add the data (possibly step by step) to it:

plot = pyvista.Plotter()
plot.add_mesh(visobj, scalars="gfu", cmap="terrain")
plot.show()
plot.export_html("plot1.html")

For jupyter book take a look here

12.2.2.4. Some filters#

Slices: (will give no result for jupyter book)

orthoslices = visobj.slice_orthogonal()
orthoslices.plot(scalars="gfu")

Iso-surfaces: (will give no result for jupyter book)

contour = visobj.contour([0.25], scalars="gfu", rng=[-1,1])
print(contour)
contour.plot(color="lightblue", smooth_shading=False)

Combining stuff: (will give no result for jupyter book)

import numpy as np
def translation_matrix(x, y, z):
    return np.array([
        [1, 0, 0, x],
        [0, 1, 0, 0],
        [0, 0, 1, 0],
        [0, 0, 0, 1]])
box_moved_left = visobj.copy().transform(translation_matrix(-1,0,0))
orthoslices_moved_right = orthoslices.combine().transform(translation_matrix(1,0,0))

plot = pyvista.Plotter(shape=(1,2))
plot.subplot(0,0)
plot.add_text("subplot1", font_size=24)
plot.add_mesh(box_moved_left, scalars="gfu", cmap="jet")
plot.add_mesh(contour, color="lightblue", opacity=0.7)
plot.add_mesh(orthoslices_moved_right, scalars="gfu", cmap="jet")
plot.subplot(0,1)
plot.add_text("subplot2", font_size=24)
plot.add_mesh(visobj, scalars="gfv")

plot.show()
plot.export_html("plot2.html")

For jupyter book take a look here

12.2.3. Visualizing for the flow problem#

We assume that you ran the navierstokes_hdg_chorin.ipynb example successfully (in parallel) and have the VTK output files available.

import pyvista
pyvista.set_jupyter_backend('html')
visobj = pyvista.read('parstokes.pvd')
visobj = visobj.combine()

(next cell generates no output in jupyter book)

orthoslices = visobj.slice_orthogonal().combine()
orthoslices.plot(scalars="velocity",cmap="jet",clim=[0,2.25])
orthoslices.plot(scalars="pressure",cmap="coolwarm",clim=[-0.06,0])
plot = pyvista.Plotter()
arrows = orthoslices.glyph(scale="velocity", orient="velocity", tolerance=0.03)

seed = pyvista.Box(bounds=(-2,1,-1,1,-1,1), level=5)

strl = visobj.streamlines_from_source(
    seed,
    vectors="velocity",
    max_step_length=1,
    min_step_length=0.1,
    max_time=500,
    max_steps=5000,
    max_error=1e-6,
    integration_direction="forward",
)

plot.add_mesh(orthoslices, scalars="velocity", cmap="jet")
#plot.add_mesh(arrows, color="black")
plot.add_mesh(strl, color="black")
#plot.add_mesh(pyvista.Cylinder(center=(0.5,0.2,0.2), direction=(0,0,1), height=0.41, radius=0.05), color="white")
plot.show()
plot.export_html("plot5.html")

When considered in html export (jupyter book), take a look here