diff --git a/book/_toc.yml b/book/_toc.yml index 0ae07d8..01f7d46 100644 --- a/book/_toc.yml +++ b/book/_toc.yml @@ -32,6 +32,13 @@ parts: - file: content/temperatures/temperatures_basic - file: content/temperatures/temperatures_advanced + - caption: Post-processing + chapters: + - file: content/post_process/derived + - file: content/post_process/exports + - file: content/post_process/paraview + - file: content/post_process/pyvista + - caption: Applications chapters: - file: content/applications/task02 diff --git a/book/content/post_process/derived.md b/book/content/post_process/derived.md new file mode 100644 index 0000000..2159204 --- /dev/null +++ b/book/content/post_process/derived.md @@ -0,0 +1,120 @@ +--- +jupytext: + formats: ipynb,md:myst + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.18.1 +kernelspec: + display_name: festim-workshop + language: python + name: python3 +--- + +# Exporting derived quantities # + +This tutorial goes over FESTIM's built-in functions to help users export derived results. + +Objectives: +* Exporting surface quantities and fluxes +* Exporting volume quantities +* Exporting multiple derived quantities in a FESTIM simulation + ++++ + +## Exporting surface quantities ## + +Users can export surface values in FESTIM by passing in the desired `field`, `SurfaceSubdomain`, and an optional `filename` (ending in `.txt` or `.csv`). + +To get total, average, minimum, and maximum surface values, we can use the `TotalSurface`, `AverageSurface`, `MinimumSurface`, and `MaximumSurface` classes: + +```{code-cell} ipython3 +import festim as F + +left = F.SurfaceSubdomain(1) +H = F.Species("H") + +my_total = F.TotalSurface(field=H, surface=left,filename="total.csv") +my_average = F.AverageSurface(field=H, surface=left,filename="avg.csv") +my_minimum = F.MinimumSurface(field=H, surface=left,filename="min.csv") +my_maximum = F.MaximumSurface(field=H, surface=left,filename="max.csv") +``` + +These exports will result in a text file with a list of data points and corresponding time steps. General surface quantities can be exported using `SurfaceQuantity`. + +We can also calculate the surface flux using the `SurfaceFlux` class: + +```{code-cell} ipython3 +my_flux = F.SurfaceFlux(field=H, surface=left,filename="flux.csv") +``` + +## Exporting volume quantities ## + +Volume quanities can similary be exported in FESTIM, except now we must pass in a `VolumeSubdomain`. + +To get total, average, minimum, and maximum volume values, we can use the `TotalVolume`, `AverageVolume`, `MinimumVolume`, and `MaximumVolume` classes: + +```{code-cell} ipython3 +import festim as F + +mat = F.Material(D_0=1, E_D=0) +vol = F.VolumeSubdomain(1,material=mat) +H = F.Species("H") + +my_total = F.TotalVolume(field=H, volume=vol,filename="total.csv") +my_average = F.AverageVolume(field=H, volume=vol,filename="avg.csv") +my_minimum = F.MinimumVolume(field=H, volume=vol,filename="min.csv") +my_maximum = F.MaximumVolume(field=H, volume=vol,filename="max.csv") +``` + +General volume quantities can be exported using `VolumeQuantity`. + ++++ + +## Exporting multiple derived quanitites in a FESTIM simulation ## + +To export your results from a FESTIM simulation, you can pass a list of derived quantity objects into the `export` attribute for your problem. Here we export an average volume and surface flux: + +```{code-cell} ipython3 +import numpy as np +import festim as F +from dolfinx.mesh import create_unit_square +from mpi4py import MPI + +mesh = create_unit_square(MPI.COMM_WORLD, 10, 10) +my_model = F.HydrogenTransportProblem() +my_model.mesh = F.Mesh(mesh) +mat = F.Material(D_0=1e-3, E_D=0) +right_surface = F.SurfaceSubdomain(id=1, locator = lambda x: np.isclose(x[0], 1.0)) +left_surface = F.SurfaceSubdomain(id=2, locator = lambda x: np.isclose(x[0], 0.0)) +vol = F.VolumeSubdomain(id=1, material=mat) +H = F.Species("H") + +avg_vol = F.AverageVolume(field=H, volume=vol) +right_flux = F.SurfaceFlux(field=H, surface=right_surface) + +my_model.subdomains = [right_surface, left_surface, vol] +my_model.species = [H] +my_model.boundary_conditions = [ + F.FixedConcentrationBC(subdomain=right_surface, value=0, species=H), + F.FixedConcentrationBC(subdomain=left_surface, value=1, species=H) +] +my_model.temperature = 400 +my_model.settings = F.Settings(atol=1e-10,rtol=1e-10,transient=False) + +my_model.exports = [ + avg_vol, + right_flux +] + +my_model.initialise() +my_model.run() +``` + +To view the export values, we can use the `data` attribute for each export: + +```{code-cell} ipython3 +print(f"Average volume concentration: {avg_vol.data}") +print(f"Right surface flux: {right_flux.data}") +``` diff --git a/book/content/post_process/exports.md b/book/content/post_process/exports.md new file mode 100644 index 0000000..8a74baf --- /dev/null +++ b/book/content/post_process/exports.md @@ -0,0 +1,167 @@ +--- +jupytext: + formats: ipynb,md:myst + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.18.1 +kernelspec: + display_name: festim-workshop + language: python + name: python3 +--- + +# Exporting fields # + +FESTIM has convenience classes that allow users to create XDMF and VTX exports, which can then be viewed in Paraview. + +Objectives: +* Learn how to write XDMF files for field exports +* Writing VTX files for species and temperature fields +* Exporting fields in a discontinuous FESTIM simulation + ++++ + +## Learn how to write XDMF files for field exports ## + +Users can export functions to XDMF files using the `XDMFExport` class, which requires a `filename` and `field`: + +```{code-cell} ipython3 +import festim as F + +H = F.Species("H") +my_export = F.XDMFExport(filename="my_export.xdmf", field=H) +``` + +To export this in a FESTIM simulation, add the export to your problem's `export` attribute: + +```{code-cell} ipython3 +from dolfinx.mesh import create_unit_square +from mpi4py import MPI + +mesh = create_unit_square(MPI.COMM_WORLD, 10, 10) +my_model = F.HydrogenTransportProblem() +my_model.mesh = F.Mesh(mesh) +mat = F.Material(D_0=1, E_D=0) +vol = F.VolumeSubdomain(id=1, material=mat) + +my_model.subdomains = [vol] +my_model.species = [H] + +my_model.temperature = 400 +my_model.settings = F.Settings(atol=1e-10,rtol=1e-10,transient=False) + +my_model.exports = [ + my_export +] + +my_model.initialise() +my_model.run() +``` + +This will produce the corresponding export files (`my_export.xdmf` and `my_export.h5`). + ++++ + +## Writing VTX files for species and temperature fields ## + +Users can also export temperature and concentration fields to VTX files using `VTXTemperatureExport` and `VTKSpeciesExport`, respectively. For both classes, we need to provide the `filename` for the output and an optional list of `times` (exports all times otherwise, defaults to `None`). + +To export a temperature field using `VTXTemperatureExport`: + +```{code-cell} ipython3 +import festim as F + +my_model = F.HydrogenTransportProblem() +my_model.exports = [ + F.VTXTemperatureExport(filename="out.bp",times=[0, 5, 10]) +] +``` + +Exporting the concentration also requires us to define the `field` to export, which `subdomain` to export on (defaults to all if none is provided), and the option to turn on `checkpoints` (exports to a checkpoint file using __[adios4dolfinx](https://github.com/jorgensd/adios4dolfinx)__, defaults to `False`): + +```{code-cell} ipython3 +H = F.Species("H") +subdomain = F.SurfaceSubdomain(id=1) +my_model.species = [H] +my_model.exports = [ + F.VTXSpeciesExport(filename="out.bp",field=H,subdomain=subdomain,checkpoint=False) +] +``` + +These `.bp` exports can then be viewed in Paraview. + ++++ + +## Exporting fields in a discontinuous problem ## + +Fields must be exported to VTX files for discontinuous problems, since results are exported on each subdomain. + +Consider the same __[multi-material problem](https://festim-workshop.readthedocs.io/en/festim2/content/material/material_basics.html#multi-material-example)__ in the Materials chapter, where we use `HydrogenTransportProblemDiscontinuous` to solve a multi-material problem: + +```{code-cell} ipython3 +import festim as F +import numpy as np +from dolfinx.mesh import create_unit_square +from mpi4py import MPI + +fenics_mesh = create_unit_square(MPI.COMM_WORLD, 10, 10) +festim_mesh = F.Mesh(fenics_mesh) + +my_model = F.HydrogenTransportProblemDiscontinuous() + +material_top = F.Material(D_0=1, E_D=0, K_S_0=2, E_K_S=0) +material_bottom = F.Material(D_0=2, E_D=0, K_S_0=3, E_K_S=0) + +top_volume = F.VolumeSubdomain(id=3, material=material_top, locator=lambda x: x[1] >= 0.5) +bottom_volume = F.VolumeSubdomain(id=4, material=material_bottom, locator=lambda x: x[1] <= 0.5) + +top_surface = F.SurfaceSubdomain(id=1, locator=lambda x: np.isclose(x[1], 1.0)) +bottom_surface = F.SurfaceSubdomain(id=2, locator=lambda x: np.isclose(x[1], 0.0)) + +my_model.mesh = festim_mesh +my_model.subdomains = [top_surface, bottom_surface, top_volume, bottom_volume] + +my_model.interfaces = [F.Interface(5, (bottom_volume, top_volume), penalty_term=1000)] +my_model.surface_to_volume = { + top_surface: top_volume, + bottom_surface: bottom_volume, +} + +H = F.Species("H") +my_model.species = [H] +H.subdomains = [top_volume, bottom_volume] + +my_model.temperature = 400 + +my_model.boundary_conditions = [ + F.FixedConcentrationBC(subdomain=top_surface, value=1.0, species=H), + F.FixedConcentrationBC(subdomain=bottom_surface, value=0.0, species=H), +] + +my_model.settings = F.Settings(atol=1e-10, rtol=1e-10, transient=False) +``` + +Instead of viewing the results using PyVista, we can export the fields for each subdomain in Paraview using `VTXSpeciesExport`: + +```{code-cell} ipython3 +top_export = F.VTXSpeciesExport(filename="top.bp", field=H, subdomain=top_volume) +bottom_export = F.VTXSpeciesExport(filename="bottom.bp", field=H, subdomain=bottom_volume) +my_model.exports = [ + top_export, + bottom_export, +] +my_model.initialise() +my_model.run() +``` + +```{image} multi_material_paraview.png +:alt: multi +:class: bg-primary mb-1 +:align: center +``` + +```{note} +For multi-material discontinuous problems, exports need to be written to VTX files, not XDMF. +``` diff --git a/book/content/post_process/multi_material_paraview.png b/book/content/post_process/multi_material_paraview.png new file mode 100644 index 0000000..880a781 Binary files /dev/null and b/book/content/post_process/multi_material_paraview.png differ diff --git a/book/content/post_process/paraview.md b/book/content/post_process/paraview.md new file mode 100644 index 0000000..1a0909f --- /dev/null +++ b/book/content/post_process/paraview.md @@ -0,0 +1,108 @@ +--- +jupytext: + formats: ipynb,md:myst + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.18.1 +kernelspec: + display_name: festim-workshop + language: python + name: python3 +--- + +# Viewing exports in Paraview # + +Paraview is a strong visualization tool that users can use to view their FESTIM exports. This tutorial goes over a simple introduction to viewing results in Paraview. Look at __[Paraview's download page](https://www.paraview.org/download/)__ for more information on installing Paraview. + +Objectives +* Creating a VTX species export +* Opening file in Paraview + ++++ + +## Creating a VTX species export ## + +First, let us run a simple 2D diffusion problem and export a VTK file: + +```{code-cell} ipython3 +import festim as F +import numpy as np +from dolfinx.mesh import create_unit_square +from mpi4py import MPI + +fenics_mesh = create_unit_square(MPI.COMM_WORLD, 10, 10) +festim_mesh = F.Mesh(fenics_mesh) + +my_model = F.HydrogenTransportProblem() + +mat = F.Material(D_0=1, E_D=0) + +vol = F.VolumeSubdomain(id=1, material=mat) +top_surface = F.SurfaceSubdomain(id=1, locator=lambda x: np.isclose(x[1], 1.0)) +bottom_surface = F.SurfaceSubdomain(id=2, locator=lambda x: np.isclose(x[1], 0.0)) + +my_model.mesh = festim_mesh +my_model.subdomains = [top_surface, bottom_surface, vol] + +H = F.Species("H") +my_model.species = [H] +my_model.temperature = 400 + +my_model.boundary_conditions = [ + F.FixedConcentrationBC(subdomain=top_surface, value=1.0, species=H), + F.FixedConcentrationBC(subdomain=bottom_surface, value=0.0, species=H), +] + +my_model.exports = [ + F.VTXSpeciesExport(filename="paraview/out.bp",field=H,subdomain=vol,checkpoint=False) +] + +my_model.settings = F.Settings(atol=1e-10, rtol=1e-10, transient=False) + +my_model.initialise() +my_model.run() +``` + +## Opening file in Paraview ## + +Now, we can open Paraview and open our exported file. + +First, we need to select the correct file by navigating to the file browser located in the top left: + +```{image} paraview/paraview_opening.png +:class: bg-primary mb-1 +:align: center +``` + +Then, we select our `out.bp` file and press OK on the bottom: + +```{image} paraview/paraview_selecting_file.png +:class: bg-primary mb-1 +:align: center +``` + +Now we must press apply to visualize our domain: + +```{image} paraview/paraview_select_apply.png +:class: bg-primary mb-1 +:align: center +``` + +To view our concentration, we need to select the dropdown box that says "Solid Color" and change it to our field variable (named "f" in our example): + +```{image} paraview/paraview_changing_variables.png +:class: bg-primary mb-1 +:align: center +``` + +```{note} +Users can also choose to view other exported fields (such as temperature) using this dropdown section. +``` + +Finally, we see our diffusion field! +```{image} paraview/paraview_result.png +:class: bg-primary mb-1 +:align: center +``` diff --git a/book/content/post_process/paraview/out.bp/data.0 b/book/content/post_process/paraview/out.bp/data.0 new file mode 100644 index 0000000..e1c41e2 Binary files /dev/null and b/book/content/post_process/paraview/out.bp/data.0 differ diff --git a/book/content/post_process/paraview/out.bp/md.0 b/book/content/post_process/paraview/out.bp/md.0 new file mode 100644 index 0000000..b2878b1 Binary files /dev/null and b/book/content/post_process/paraview/out.bp/md.0 differ diff --git a/book/content/post_process/paraview/out.bp/md.idx b/book/content/post_process/paraview/out.bp/md.idx new file mode 100644 index 0000000..d4a1600 Binary files /dev/null and b/book/content/post_process/paraview/out.bp/md.idx differ diff --git a/book/content/post_process/paraview/out.bp/mmd.0 b/book/content/post_process/paraview/out.bp/mmd.0 new file mode 100644 index 0000000..5294083 Binary files /dev/null and b/book/content/post_process/paraview/out.bp/mmd.0 differ diff --git a/book/content/post_process/paraview/out.bp/profiling.json b/book/content/post_process/paraview/out.bp/profiling.json new file mode 100644 index 0000000..8792810 --- /dev/null +++ b/book/content/post_process/paraview/out.bp/profiling.json @@ -0,0 +1,3 @@ +[ +{ "rank":0, "start":"Wed_Jan_07_10:35:32_2026","PP_mus": 0, "PP":{"mus":0, "nCalls":1},"ES_close_mus": 64, "ES_close":{"mus":64, "nCalls":1},"ES_AWD_mus": 76, "ES_AWD":{"mus":76, "nCalls":1},"ES_mus": 187, "ES":{"mus":187, "nCalls":1},"ES_meta2_mus": 45, "ES_meta2":{"mus":45, "nCalls":1},"ES_meta1_mus": 1, "ES_meta1":{"mus":1, "nCalls":1}, "databytes":0, "metadatabytes":0, "metametadatabytes":0, "transport_0":{"type":"File_POSIX", "wbytes":11368, "close":{"mus":115, "nCalls":1}, "write":{"mus":25, "nCalls":1}, "open":{"mus":412, "nCalls":1}}, "transport_1":{"type":"File_POSIX", "wbytes":1960, "close":{"mus":26, "nCalls":1}, "write":{"mus":10, "nCalls":5}, "open":{"mus":1051, "nCalls":1}} } +] diff --git a/book/content/post_process/paraview/paraview_changing_variables.png b/book/content/post_process/paraview/paraview_changing_variables.png new file mode 100644 index 0000000..696941c Binary files /dev/null and b/book/content/post_process/paraview/paraview_changing_variables.png differ diff --git a/book/content/post_process/paraview/paraview_opening.png b/book/content/post_process/paraview/paraview_opening.png new file mode 100644 index 0000000..5db0478 Binary files /dev/null and b/book/content/post_process/paraview/paraview_opening.png differ diff --git a/book/content/post_process/paraview/paraview_result.png b/book/content/post_process/paraview/paraview_result.png new file mode 100644 index 0000000..395bb7e Binary files /dev/null and b/book/content/post_process/paraview/paraview_result.png differ diff --git a/book/content/post_process/paraview/paraview_select_apply.png b/book/content/post_process/paraview/paraview_select_apply.png new file mode 100644 index 0000000..46cbef9 Binary files /dev/null and b/book/content/post_process/paraview/paraview_select_apply.png differ diff --git a/book/content/post_process/paraview/paraview_selecting_file.png b/book/content/post_process/paraview/paraview_selecting_file.png new file mode 100644 index 0000000..3693f4a Binary files /dev/null and b/book/content/post_process/paraview/paraview_selecting_file.png differ diff --git a/book/content/post_process/pyvista.md b/book/content/post_process/pyvista.md new file mode 100644 index 0000000..3a15fea --- /dev/null +++ b/book/content/post_process/pyvista.md @@ -0,0 +1,206 @@ +--- +jupytext: + formats: ipynb,md:myst + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.18.1 +kernelspec: + display_name: festim-workshop + language: python + name: python3 +--- + +# Using PyVista for interactive visualization # + +PyVista has many helpful capabilities for 3D visualization based on VTK code, and is used frequently throughout the FESTIM workshop. Users can use PyVista in Jupyter Notebook to visualize fields and meshes interactively. + +Objectives: +* Viewing meshes in 3D interactive scenes +* Plotting the solution for continuous problems +* Plotting the solution for discontinuous problems + ++++ + +## Viewing meshes in 3D interactive scenes ## + +PyVista is very helpful when plotting 1D/2D/3D meshes, such as this unit square: + +```{code-cell} ipython3 +from dolfinx.mesh import create_unit_square +from mpi4py import MPI +from dolfinx import plot +import pyvista + +nx, ny = 10, 10 +mesh = create_unit_square(MPI.COMM_WORLD, nx, ny) + +pyvista.start_xvfb() +pyvista.set_jupyter_backend("html") + +tdim = mesh.topology.dim + +mesh.topology.create_connectivity(tdim, tdim) +topology, cell_types, geometry = plot.vtk_mesh(mesh, tdim) +grid = pyvista.UnstructuredGrid(topology, cell_types, geometry) + +plotter = pyvista.Plotter() +plotter.add_mesh(grid, show_edges=True) +plotter.view_xy() +if not pyvista.OFF_SCREEN: + plotter.show() +else: + figure = plotter.screenshot("mesh.png") +``` + +## Plotting the solution for a continuous problem ## + +FESTIM has some convenience attributes to plot the solution fields in continuous problems. + +For example, let's solve a simple 2D diffusion problem on a unit square: + +```{code-cell} ipython3 +import festim as F +import numpy as np +from dolfinx.mesh import create_unit_square +from mpi4py import MPI + +fenics_mesh = create_unit_square(MPI.COMM_WORLD, 10, 10) +festim_mesh = F.Mesh(fenics_mesh) + +my_model = F.HydrogenTransportProblem() + +mat = F.Material(D_0=1, E_D=0) + +vol = F.VolumeSubdomain(id=1, material=mat) +top_surface = F.SurfaceSubdomain(id=1, locator=lambda x: np.isclose(x[1], 1.0)) +bottom_surface = F.SurfaceSubdomain(id=2, locator=lambda x: np.isclose(x[1], 0.0)) + +my_model.mesh = festim_mesh +my_model.subdomains = [top_surface, bottom_surface, vol] + +H = F.Species("H") +my_model.species = [H] +my_model.temperature = 400 + +my_model.boundary_conditions = [ + F.FixedConcentrationBC(subdomain=top_surface, value=1.0, species=H), + F.FixedConcentrationBC(subdomain=bottom_surface, value=0.0, species=H), +] + +my_model.settings = F.Settings(atol=1e-10, rtol=1e-10, transient=False) + +my_model.initialise() +my_model.run() +``` + +We can plot the solution as an unstructured grid using the species' `post_processing_solution` attribute: + +```{code-cell} ipython3 +pyvista.start_xvfb() +pyvista.set_jupyter_backend("html") + +def make_ugrid(solution): + topology, cell_types, geometry = plot.vtk_mesh(solution.function_space) + u_grid = pyvista.UnstructuredGrid(topology, cell_types, geometry) + u_grid.point_data["c"] = solution.x.array.real + u_grid.set_active_scalars("c") + return u_grid + +u_plotter = pyvista.Plotter() +u_grid = make_ugrid(H.post_processing_solution) +u_plotter.add_mesh(u_grid, cmap="viridis", show_edges=False) +u_plotter.view_xy() +u_plotter.add_text("Hydrogen concentration", font_size=12) + +if not pyvista.OFF_SCREEN: + u_plotter.show() +else: + figure = u_plotter.screenshot("concentration.png") +``` + +## Plotting the solution for continuous problems ## + +Users can also use PyVista to visualize the fields in discontinuous problems. + +Let us consider the same __[multi-material problem](https://festim-workshop.readthedocs.io/en/festim2/content/material/material_basics.html#multi-material-example)__ in the Materials chapter, where we use `HydrogenTransportProblemDiscontinuous` to solve a multi-material problem: + +```{code-cell} ipython3 +import festim as F +import numpy as np +from dolfinx.mesh import create_unit_square +from mpi4py import MPI +import pyvista +from dolfinx import plot + +fenics_mesh = create_unit_square(MPI.COMM_WORLD, 10, 10) +festim_mesh = F.Mesh(fenics_mesh) + +my_model = F.HydrogenTransportProblemDiscontinuous() + +material_top = F.Material(D_0=1, E_D=0, K_S_0=2, E_K_S=0) +material_bottom = F.Material(D_0=2, E_D=0, K_S_0=3, E_K_S=0) + +top_volume = F.VolumeSubdomain(id=3, material=material_top, locator=lambda x: x[1] >= 0.5) +bottom_volume = F.VolumeSubdomain(id=4, material=material_bottom, locator=lambda x: x[1] <= 0.5) + +top_surface = F.SurfaceSubdomain(id=1, locator=lambda x: np.isclose(x[1], 1.0)) +bottom_surface = F.SurfaceSubdomain(id=2, locator=lambda x: np.isclose(x[1], 0.0)) + +my_model.mesh = festim_mesh +my_model.subdomains = [top_surface, bottom_surface, top_volume, bottom_volume] + +my_model.interfaces = [F.Interface(5, (bottom_volume, top_volume), penalty_term=1000)] +my_model.surface_to_volume = { + top_surface: top_volume, + bottom_surface: bottom_volume, +} + +H = F.Species("H") +my_model.species = [H] + +for species in my_model.species: + species.subdomains = [bottom_volume, top_volume] + +my_model.temperature = 400 + +my_model.boundary_conditions = [ + F.FixedConcentrationBC(subdomain=top_surface, value=1.0, species=H), + F.FixedConcentrationBC(subdomain=bottom_surface, value=0.0, species=H), +] + +my_model.settings = F.Settings(atol=1e-10, rtol=1e-10, transient=False) + +my_model.initialise() +my_model.run() +``` + +We must create an unstructured grid for each volume subdomain in our problem using `subdomain_to_post_processing_solution`, which requires a subdomain to be specified: + +```{code-cell} ipython3 +def make_ugrid(solution): + topology, cell_types, geometry = plot.vtk_mesh(solution.function_space) + u_grid = pyvista.UnstructuredGrid(topology, cell_types, geometry) + u_grid.point_data["c"] = solution.x.array.real + u_grid.set_active_scalars("c") + return u_grid + +pyvista.start_xvfb() +pyvista.set_jupyter_backend("html") + +u_plotter = pyvista.Plotter() +u_grid_top = make_ugrid(H.subdomain_to_post_processing_solution[top_volume]) +u_grid_bottom = make_ugrid(H.subdomain_to_post_processing_solution[bottom_volume]) +u_plotter.add_mesh(u_grid_top, cmap="magma", show_edges=False) +u_plotter.add_mesh(u_grid_bottom, cmap="magma", show_edges=False) +u_plotter.view_xy() +u_plotter.add_text("Hydrogen concentration in multi-material problem", font_size=12) + +if not pyvista.OFF_SCREEN: + u_plotter.show() +else: + figure = u_plotter.screenshot("concentration.png") +``` + +We see each subdomain plotted in the PyVista scene, with a discontinuity at the interface between each subdomain. diff --git a/environment.yml b/environment.yml index 155b7b8..f88797b 100644 --- a/environment.yml +++ b/environment.yml @@ -3,7 +3,7 @@ channels: - conda-forge - defaults dependencies: - - jupyter-book + - jupyter-book<2 - jupytext # necessary to open MyST files using BinderHub https://jupyterbook.org/en/stable/interactive/launchbuttons.html#launchbuttons-binder - sphinx-tags - matplotlib