Skip to content

Commit f95e39c

Browse files
authored
Update all tutorials with new API and new plotting (#57)
* Update all tutorials with new API and new plotting * Remove xvfb * Add back xvfb to make it possible to do screenshots
1 parent f7093ad commit f95e39c

26 files changed

+983
-617
lines changed

.github/workflows/build-publish.yml

+2-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
build:
2121
# The type of runner that the job will run on
2222
runs-on: ubuntu-latest
23-
container: dokken92/dolfinx_custom:26122021
23+
container: dokken92/dolfinx_custom:07012022
2424

2525
env:
2626
HDF5_MPI: "ON"
@@ -35,12 +35,11 @@ jobs:
3535
- uses: actions/checkout@v2
3636

3737
- name: Install dependencies
38-
run: pip3 install notebook nbconvert "jupyter-book<6" --upgrade
38+
run: pip3 install notebook nbconvert jupyter-book --upgrade
3939
- name: Test notebooks in parallel
4040
run: |
4141
cd chapter1
4242
jupyter-nbconvert --to python fundamentals_code.ipynb
43-
python3 -c "from pyvista import start_xvfb; start_xvfb(0.1)"
4443
mpirun -n 2 python3 fundamentals_code.py
4544
jupyter-nbconvert --to python membrane_code.ipynb
4645
mpirun -n 2 python3 membrane_code.py

.github/workflows/docker-image.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,4 @@ jobs:
3737
run: echo ${{ secrets.DOCKERHUB_TOKEN }} | docker login -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin
3838
- name: Push to the DockerHub registry
3939
run: |
40-
docker push dokken92/dolfinx_custom:26122021
40+
docker push dokken92/dolfinx_custom:07012022

.github/workflows/main-test.yml

+5-5
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,22 @@ jobs:
3636

3737
- name: Install dependencies
3838
run: |
39-
wget -qO - https://deb.nodesource.com/setup_17.x | bash
39+
CC=mpicc HDF_MPI="ON" HDF5_DIR="/usr/lib/x86_64-linux-gnu/hdf5/mpich/" pip3 install --no-cache-dir --no-binary=h5py h5py meshio
4040
apt-get -qq update
4141
apt-get install -y libgl1-mesa-dev xvfb nodejs
4242
apt-get clean
4343
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
44-
CC=mpicc HDF_MPI="ON" HDF5_DIR="/usr/lib/x86_64-linux-gnu/hdf5/mpich/" pip3 install --no-cache-dir --no-binary=h5py h5py meshio
4544
pip3 install --no-cache-dir tqdm pandas seaborn
4645
pip3 install notebook nbconvert jupyter-book myst_parser pyvista jupyterlab
47-
pip3 install --no-cache-dir matplotlib itkwidgets ipywidgets setuptools --upgrade
48-
jupyter labextension install jupyter-matplotlib jupyterlab-datawidgets && \
46+
pip3 install ipygany pythreejs
47+
pip3 install --no-cache-dir matplotlib setuptools --upgrade
48+
jupyter nbextension enable --py --sys-prefix ipygany
4949
rm -rf /usr/local/share/.cache/*
5050
- name: Test notebooks in parallel
5151
run: |
5252
cd chapter1
53-
jupyter-nbconvert --to python fundamentals_code.ipynb
5453
python3 -c "from pyvista import start_xvfb; start_xvfb(0.1)"
54+
jupyter-nbconvert --to python fundamentals_code.ipynb
5555
mpirun -n 2 python3 fundamentals_code.py
5656
jupyter-nbconvert --to python nitsche.ipynb
5757
mpirun -n 2 python3 nitsche.py

Changelog.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Changelog
22

33
## Dev
4+
- API updates wrt. DOLFINx. `Form`->`form`, `DirichletBC`->`dirichletbc`.
5+
- Switch plotting backend to `ipygany` and `pythreejs`
46
- Updates on error computations in [Error control: Computing convergence rates](chapter4/convergence).
57
- Added tutorial on interpolation of `ufl.Expression` in [Deflection of a membrane](chapter1/membrane_code).
68
- Added tutorial on how to apply constant-valued Dirichet conditions in [Deflection of a membrane](chapter1/membrane_code).

Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM dokken92/dolfinx_custom:26122021
1+
FROM dokken92/dolfinx_custom:07012022
22

33
# create user with a home directory
44
ARG NB_USER

chapter1/fundamentals_code.ipynb

+45-39
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
},
6565
{
6666
"cell_type": "code",
67-
"execution_count": 2,
67+
"execution_count": 1,
6868
"metadata": {},
6969
"outputs": [],
7070
"source": [
@@ -95,7 +95,7 @@
9595
},
9696
{
9797
"cell_type": "code",
98-
"execution_count": 3,
98+
"execution_count": 2,
9999
"metadata": {},
100100
"outputs": [],
101101
"source": [
@@ -126,7 +126,7 @@
126126
},
127127
{
128128
"cell_type": "code",
129-
"execution_count": 4,
129+
"execution_count": 3,
130130
"metadata": {},
131131
"outputs": [],
132132
"source": [
@@ -147,7 +147,7 @@
147147
},
148148
{
149149
"cell_type": "code",
150-
"execution_count": 5,
150+
"execution_count": 4,
151151
"metadata": {},
152152
"outputs": [],
153153
"source": [
@@ -176,13 +176,13 @@
176176
},
177177
{
178178
"cell_type": "code",
179-
"execution_count": 6,
179+
"execution_count": 5,
180180
"metadata": {},
181181
"outputs": [],
182182
"source": [
183-
"from dolfinx.fem import locate_dofs_topological, DirichletBC\n",
183+
"from dolfinx.fem import locate_dofs_topological, dirichletbc\n",
184184
"boundary_dofs = locate_dofs_topological(V, fdim, boundary_facets)\n",
185-
"bc = DirichletBC(uD, boundary_dofs)"
185+
"bc = dirichletbc(uD, boundary_dofs)"
186186
]
187187
},
188188
{
@@ -199,7 +199,7 @@
199199
},
200200
{
201201
"cell_type": "code",
202-
"execution_count": 7,
202+
"execution_count": 6,
203203
"metadata": {},
204204
"outputs": [],
205205
"source": [
@@ -218,7 +218,7 @@
218218
},
219219
{
220220
"cell_type": "code",
221-
"execution_count": 8,
221+
"execution_count": 7,
222222
"metadata": {},
223223
"outputs": [],
224224
"source": [
@@ -241,7 +241,7 @@
241241
},
242242
{
243243
"cell_type": "code",
244-
"execution_count": 9,
244+
"execution_count": 8,
245245
"metadata": {},
246246
"outputs": [],
247247
"source": [
@@ -277,7 +277,7 @@
277277
},
278278
{
279279
"cell_type": "code",
280-
"execution_count": 10,
280+
"execution_count": 9,
281281
"metadata": {},
282282
"outputs": [],
283283
"source": [
@@ -297,7 +297,7 @@
297297
},
298298
{
299299
"cell_type": "code",
300-
"execution_count": 11,
300+
"execution_count": 10,
301301
"metadata": {},
302302
"outputs": [],
303303
"source": [
@@ -316,12 +316,12 @@
316316
},
317317
{
318318
"cell_type": "code",
319-
"execution_count": 12,
319+
"execution_count": 11,
320320
"metadata": {},
321321
"outputs": [],
322322
"source": [
323-
"from dolfinx.fem import assemble_scalar\n",
324-
"L2_error = ufl.inner(uh - uex, uh - uex) * ufl.dx\n",
323+
"from dolfinx.fem import assemble_scalar, form\n",
324+
"L2_error = form(ufl.inner(uh - uex, uh - uex) * ufl.dx)\n",
325325
"error_local = assemble_scalar(L2_error)\n",
326326
"error_L2 = numpy.sqrt(mesh.comm.allreduce(error_local, op=MPI.SUM))"
327327
]
@@ -340,7 +340,7 @@
340340
},
341341
{
342342
"cell_type": "code",
343-
"execution_count": 13,
343+
"execution_count": 12,
344344
"metadata": {},
345345
"outputs": [
346346
{
@@ -374,37 +374,46 @@
374374
},
375375
{
376376
"cell_type": "code",
377-
"execution_count": 14,
377+
"execution_count": 13,
378378
"metadata": {},
379379
"outputs": [],
380380
"source": [
381381
"from dolfinx.plot import create_vtk_topology\n",
382382
"topology, cell_types = create_vtk_topology(mesh, mesh.topology.dim)"
383383
]
384384
},
385+
{
386+
"cell_type": "markdown",
387+
"metadata": {},
388+
"source": [
389+
"There are several backends that can be used with pyvista, and they have different benefits and drawbacks. See the [pyvista documentation](https://docs.pyvista.org/user-guide/jupyter/index.html) for more information and installation details. In this example and the rest of the tutorial we will use [ipygany](https://github.com/QuantStack/ipygany) and [pythreejs](https://github.com/jupyter-widgets/pythreejs)."
390+
]
391+
},
385392
{
386393
"cell_type": "code",
387-
"execution_count": 15,
394+
"execution_count": 14,
388395
"metadata": {},
389396
"outputs": [],
390397
"source": [
391398
"import pyvista\n",
392-
"grid = pyvista.UnstructuredGrid(topology, cell_types, mesh.geometry.x)"
399+
"pyvista.set_jupyter_backend(\"pythreejs\")"
393400
]
394401
},
395402
{
396403
"cell_type": "markdown",
397404
"metadata": {},
398405
"source": [
406+
"We start by creating a pyvista grid the `vtk_topology` and the `mesh.geometry`.\n",
399407
"Next, we attach data from our solution `uh` by computing the values of the function at each vertex."
400408
]
401409
},
402410
{
403411
"cell_type": "code",
404-
"execution_count": 16,
412+
"execution_count": 15,
405413
"metadata": {},
406414
"outputs": [],
407415
"source": [
416+
"grid = pyvista.UnstructuredGrid(topology, cell_types, mesh.geometry.x)\n",
408417
"grid.point_data[\"u\"] = uh.compute_point_values().real\n",
409418
"grid.set_active_scalars(\"u\")"
410419
]
@@ -414,65 +423,62 @@
414423
"metadata": {},
415424
"source": [
416425
"We can now use the `pyvista.Plotter` to visualize the solution. We visualize it by showing it in 2D and warped in 3D.\n",
417-
"In the jupyter notebook environment, we use the default setting of `pyvista.OFF_SCREEN=False`, which will render plots directly in the notebook. . PYVITo render in the online notebooks or in docker containers without X-forwarding, we need to start a virtual framebuffer.\n",
418-
"```{admonition} Rendering with pyvista using Docker-containers\n",
419-
"To make the plots render, we have to call `pyvista.start_xvfb` to start a virtual framebuffer if using docker-containers or jupyter notebooks on Linux.\n",
420-
"```"
426+
"In the jupyter notebook environment, we use the default setting of `pyvista.OFF_SCREEN=False`, which will render plots directly in the notebook."
421427
]
422428
},
423429
{
424430
"cell_type": "code",
425-
"execution_count": 17,
431+
"execution_count": 16,
426432
"metadata": {},
427433
"outputs": [
428434
{
429435
"data": {
430436
"application/vnd.jupyter.widget-view+json": {
431-
"model_id": "52f926f800b84003bd2eda5e14ba1871",
437+
"model_id": "026dd4bdc8354af88ecd23be302ee96c",
432438
"version_major": 2,
433439
"version_minor": 0
434440
},
435441
"text/plain": [
436-
"ViewInteractiveWidget(height=768, layout=Layout(height='auto', width='100%'), width=1024)"
442+
"Renderer(camera=PerspectiveCamera(aspect=1.3333333333333333, children=(DirectionalLight(color='#fefefe', inten…"
437443
]
438444
},
439445
"metadata": {},
440446
"output_type": "display_data"
441447
}
442448
],
443449
"source": [
444-
"pyvista.start_xvfb(wait=0.05)\n",
445450
"plotter = pyvista.Plotter()\n",
446-
"plotter.add_mesh(grid, show_edges=True, show_scalar_bar=True)\n",
451+
"plotter.add_mesh(grid, show_edges=True)\n",
447452
"plotter.view_xy()\n",
448453
"if not pyvista.OFF_SCREEN:\n",
449454
" plotter.show()\n",
450455
"else:\n",
456+
" pyvista.start_xvfb()\n",
451457
" figure = plotter.screenshot(\"fundamentals.png\")"
452458
]
453459
},
454460
{
455461
"cell_type": "markdown",
456462
"metadata": {},
457463
"source": [
458-
"## Alternative plotting\n",
459-
"To create a more interactive plot using pyvista in a Jupyter notebook we us `pyvista.ITKPlotter` which uses `itkwidgets`. To modify the visualization, click on the three bars in the top left corner."
464+
"## ipygany\n",
465+
"We change plotting from `pythreejs` to `ipygany` by initializing another `Plotter` with `jupyter_backend=\"ipygany\"`. We also warp the mesh by scalar to make use of the 3D plotting."
460466
]
461467
},
462468
{
463469
"cell_type": "code",
464-
"execution_count": 19,
470+
"execution_count": 17,
465471
"metadata": {},
466472
"outputs": [
467473
{
468474
"data": {
469475
"application/vnd.jupyter.widget-view+json": {
470-
"model_id": "6b86e726693d42f3b675cea1633f9136",
476+
"model_id": "2b14ac59f2cf4d129b2843ce038c4b90",
471477
"version_major": 2,
472478
"version_minor": 0
473479
},
474480
"text/plain": [
475-
"Viewer(geometries=[{'vtkClass': 'vtkPolyData', 'points': {'vtkClass': 'vtkPoints', 'name': '_points', 'numberO"
481+
"AppLayout(children=(VBox(children=(HTML(value='<h3>u</h3>'), Dropdown(description='Colormap:', options={'BrBG'"
476482
]
477483
},
478484
"metadata": {},
@@ -481,10 +487,10 @@
481487
],
482488
"source": [
483489
"if not pyvista.OFF_SCREEN:\n",
484-
" plotter_itk = pyvista.PlotterITK()\n",
485-
" warped = grid.warp_by_scalar(\"u\", factor=0.5)\n",
486-
" plotter_itk.add_mesh(warped)\n",
487-
" plotter_itk.show(True)"
490+
" warped = grid.warp_by_scalar()\n",
491+
" plotter2 = pyvista.Plotter()\n",
492+
" plotter2.add_mesh(warped, show_edges=True, show_scalar_bar=True)\n",
493+
" plotter2.show(jupyter_backend=\"ipygany\")"
488494
]
489495
},
490496
{
@@ -497,7 +503,7 @@
497503
},
498504
{
499505
"cell_type": "code",
500-
"execution_count": 20,
506+
"execution_count": 18,
501507
"metadata": {},
502508
"outputs": [],
503509
"source": [

0 commit comments

Comments
 (0)