While these tutorials are typically meant to be visualized in serial, viskex also runs in parallel. To exemplify this, we will show a parallel case using ipyparallel.
First of all, we start a ipyparallel MPI cluster with 2 processes.
import ipyparallel as ipp
cluster = ipp.Cluster(engines="MPI", profile="mpi", n=2)
cluster.start_and_connect_sync()
Starting 2 engines with <class 'ipyparallel.cluster.launcher.MPIEngineSetLauncher'>
<ipyparallel.client.client.Client at 0x7fc2a4288ce0>
The jupyter magic %%px will run the following cells on the ipyparallel cluster.
%%px
import dolfinx.mesh # noqa: E402
import mpi4py.MPI # noqa: E402
%%px
import viskex # noqa: E402
To confirm that we are running in parallel, we can print the rank of the current process and the total number of processes.
%%px
comm_world = mpi4py.MPI.COMM_WORLD
print(f"rank = {comm_world.rank}, size = {comm_world.size}")
[stdout:0] rank = 0, size = 2
[stdout:1] rank = 1, size = 2
Generate a mesh on MPI_COMM_WORLD of the unit square by dividing each edge of the square in 6 segments.
%%px
square_world = dolfinx.mesh.create_unit_square(comm_world, 6, 6)
Plot the mesh defined on MPI_COMM_WORLD. Each rank will plot its local cells, and their neighbors (called ghosts in dolfinx).
%%px
viskex.dolfinx.plot_mesh(square_world)
[stderr:0] 2026-03-23 05:07:42.078 ( 1.091s) [ 7F687680F140]vtkXOpenGLRenderWindow.:1460 WARN| bad X server connection. DISPLAY=
[stderr:1] 2026-03-23 05:07:42.078 ( 1.092s) [ 7F5BA472F140]vtkXOpenGLRenderWindow.:1460 WARN| bad X server connection. DISPLAY=
[output:1]
[output:0]
For comparison, we can generate a similar mesh on MPI_COMM_SELF. Each rank will have its own copy of the whole mesh.
%%px
comm_self = mpi4py.MPI.COMM_SELF
square_self = dolfinx.mesh.create_unit_square(comm_self, 6, 6)
Plot the mesh defined on MPI_COMM_SELF. Each rank will produce a plot which is visually the same, since each rank has its own copy of the same mesh.
%%px
viskex.dolfinx.plot_mesh(square_self)
[output:1]
[output:0]
We finally stop the ipyparallel cluster. Note that when running with Run -> Run all cells all interactive plots will be closed when the kernel executes this cell.
cluster.stop_cluster_sync()
Stopping controller
Controller stopped: {'exit_code': 0, 'pid': 2767, 'identifier': 'ipcontroller-1774242453-9rqr-2748'}
Stopping engine(s): 1774242454
Output for ipengine-1774242453-9rqr-1774242454-2748: 2026-03-23 05:07:35.272 [IPEngine] Loading connection info from $IPP_CONNECTION_INFO 2026-03-23 05:07:35.272 [IPEngine] WARNING | Not using CurveZMQ security 2026-03-23 05:07:35.299 [IPEngine] Loading connection info from $IPP_CONNECTION_INFO 2026-03-23 05:07:35.299 [IPEngine] WARNING | Not using CurveZMQ security 2026-03-23 05:07:35.315 [IPEngine.1] Registering with controller at tcp://127.0.0.1:59237 2026-03-23 05:07:35.315 [IPEngine.0] Registering with controller at tcp://127.0.0.1:59237 2026-03-23 05:07:35.315 [IPEngine.0] Requesting id: 0 2026-03-23 05:07:35.315 [IPEngine.1] Requesting id: 1 2026-03-23 05:07:35.317 [IPEngine.1.1] Shell_addrs: ['tcp://127.0.0.1:57717', 'tcp://127.0.0.1:33449', 'tcp://127.0.0.1:48887'] 2026-03-23 05:07:35.318 [IPEngine.1.1] Connecting shell to tcp://127.0.0.1:57717 2026-03-23 05:07:35.318 [IPEngine.1.1] Connecting shell to tcp://127.0.0.1:33449 2026-03-23 05:07:35.318 [IPEngine.1.1] Connecting shell to tcp://127.0.0.1:48887 2026-03-23 05:07:35.318 [IPEngine.1.1] Starting nanny 2026-03-23 05:07:35.319 [IPEngine.0.0] Shell_addrs: ['tcp://127.0.0.1:57717', 'tcp://127.0.0.1:33449', 'tcp://127.0.0.1:57271'] 2026-03-23 05:07:35.319 [IPEngine.0.0] Connecting shell to tcp://127.0.0.1:57717 2026-03-23 05:07:35.319 [IPEngine.0.0] Connecting shell to tcp://127.0.0.1:33449 2026-03-23 05:07:35.319 [IPEngine.0.0] Connecting shell to tcp://127.0.0.1:57271 2026-03-23 05:07:35.319 [IPEngine.0.0] Starting nanny 2026-03-23 05:07:35.748 [KernelNanny.1] Starting kernel nanny for engine 1, pid=2801, nanny pid=2812 2026-03-23 05:07:35.749 [KernelNanny.1] Nanny watching parent pid 2801. 2026-03-23 05:07:35.749 [KernelNanny.0] Starting kernel nanny for engine 0, pid=2800, nanny pid=2813 2026-03-23 05:07:35.749 [KernelNanny.0] Nanny watching parent pid 2800. 2026-03-23 05:07:35.820 [IPEngine.0.0] Loading IPython extension: storemagic 2026-03-23 05:07:35.820 [IPEngine.1.1] Loading IPython extension: storemagic 2026-03-23 05:07:35.820 [IPEngine.0.0] Running code in user namespace: from mpi4py import MPI mpi_rank = MPI.COMM_WORLD.Get_rank() mpi_size = MPI.COMM_WORLD.Get_size() 2026-03-23 05:07:35.821 [IPEngine.1.1] Running code in user namespace: from mpi4py import MPI mpi_rank = MPI.COMM_WORLD.Get_rank() mpi_size = MPI.COMM_WORLD.Get_size() 2026-03-23 05:07:35.822 [IPEngine.0.0] WARNING | debugpy_stream undefined, debugging will not be enabled 2026-03-23 05:07:35.822 [IPEngine.1.1] WARNING | debugpy_stream undefined, debugging will not be enabled 2026-03-23 05:07:35.828 [IPEngine.0.0] Starting to monitor the heartbeat signal from the hub every 3500 ms. 2026-03-23 05:07:35.829 [IPEngine.0.0] Completed registration with id 0 2026-03-23 05:07:35.829 [IPEngine.1.1] Starting to monitor the heartbeat signal from the hub every 3500 ms. 2026-03-23 05:07:35.829 [IPEngine.1.1] Completed registration with id 1 2026-03-23 05:07:40.574 [IPEngine.0.0] Handling execute_request: 2956c2c8-8accbde62488dc9435e7e4e7_2748_1 2026-03-23 05:07:40.574 [IPEngine.1.1] Handling execute_request: 2956c2c8-8accbde62488dc9435e7e4e7_2748_2 2026-03-23 05:07:40.969 [IPEngine.0.0] Handling execute_request: 2956c2c8-8accbde62488dc9435e7e4e7_2748_3 2026-03-23 05:07:40.969 [IPEngine.1.1] Handling execute_request: 2956c2c8-8accbde62488dc9435e7e4e7_2748_4 2026-03-23 05:07:42.042 [IPEngine.0.0] Handling execute_request: 2956c2c8-8accbde62488dc9435e7e4e7_2748_5 2026-03-23 05:07:42.043 [IPEngine.1.1] Handling execute_request: 2956c2c8-8accbde62488dc9435e7e4e7_2748_6 2026-03-23 05:07:42.055 [IPEngine.0.0] Handling execute_request: 2956c2c8-8accbde62488dc9435e7e4e7_2748_7 2026-03-23 05:07:42.055 [IPEngine.1.1] Handling execute_request: 2956c2c8-8accbde62488dc9435e7e4e7_2748_8 2026-03-23 05:07:42.071 [IPEngine.0.0] Handling execute_request: 2956c2c8-8accbde62488dc9435e7e4e7_2748_9 2026-03-23 05:07:42.072 [IPEngine.1.1] Handling execute_request: 2956c2c8-8accbde62488dc9435e7e4e7_2748_10 2026-03-23 05:07:42.078 ( 1.092s) [ 7F5BA472F140]vtkXOpenGLRenderWindow.:1460 WARN| bad X server connection. DISPLAY= 2026-03-23 05:07:42.078 ( 1.091s) [ 7F687680F140]vtkXOpenGLRenderWindow.:1460 WARN| bad X server connection. DISPLAY= 2026-03-23 05:07:42.381 [IPEngine.0.0] Handling execute_request: 2956c2c8-8accbde62488dc9435e7e4e7_2748_11 2026-03-23 05:07:42.382 [IPEngine.1.1] Handling execute_request: 2956c2c8-8accbde62488dc9435e7e4e7_2748_12 2026-03-23 05:07:42.392 [IPEngine.0.0] Handling execute_request: 2956c2c8-8accbde62488dc9435e7e4e7_2748_13 2026-03-23 05:07:42.392 [IPEngine.1.1] Handling execute_request: 2956c2c8-8accbde62488dc9435e7e4e7_2748_14 2026-03-23 05:07:43.164 [KernelNanny.0] Pipe closed, parent 2800 has status: zombie 2026-03-23 05:07:43.164 [KernelNanny.0] Notifying Hub that our parent has shut down 2026-03-23 05:07:43.165 [KernelNanny.0] Parent 2800 exited with status None. 2026-03-23 05:07:43.168 [KernelNanny.1] Pipe closed, parent 2801 has status: zombie 2026-03-23 05:07:43.168 [KernelNanny.1] Parent 2801 exited with status None. 2026-03-23 05:07:43.168 [KernelNanny.1] Notifying Hub that our parent has shut down
engine set stopped 1774242454: {'exit_code': 1, 'pid': 2795, 'identifier': 'ipengine-1774242453-9rqr-1774242454-2748'}