File: demo_interpolation-io.py

package info (click to toggle)
fenics-dolfinx 1%3A0.10.0.post4-1exp1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 6,028 kB
  • sloc: cpp: 36,535; python: 25,391; makefile: 226; sh: 171; xml: 55
file content (133 lines) | stat: -rw-r--r-- 4,245 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.13.6
# ---

# # Interpolation and IO
#
# Copyright (C) 2022 Garth N. Wells
#
#
# ```{admonition} Download sources
# :class: download
# * {download}`Python script <./demo_interpolation-io.py>`
# * {download}`Jupyter notebook <./demo_interpolation-io.ipynb>`
# ```
# This demo shows how to:
# - Interpolate functions into vector-element $H(\mathrm{curl})$
#   finite element spaces
# - Interpolate these special finite elements into discontinuous Lagrange
#   spaces for artifact-free visualisation.
# $H(\mathrm{curl})$ finite element spaces, and the interpolation of
# these special finite elements in discontinuous Lagrange spaces for
# artifact-free visualisation.


# +
from pathlib import Path

from mpi4py import MPI

import numpy as np
from sys import byteorder

from dolfinx import default_scalar_type, has_adios2, plot
from dolfinx.fem import Function, functionspace
from dolfinx.mesh import CellType, create_rectangle, locate_entities

# -

# Create a mesh. For later in the demo we need to ensure that a boundary
# between cells is located at $x_0=0.5$.

msh = create_rectangle(MPI.COMM_WORLD, ((0.0, 0.0), (1.0, 1.0)), (16, 16), CellType.triangle)

# Create a Nédélec function space and finite element Function

V = functionspace(msh, ("Nedelec 1st kind H(curl)", 1))
u = Function(V, dtype=default_scalar_type)

# Find cells with *all* vertices (0) $x_0 <= 0.5$ or (1) $x_0 >= 0.5$:

tdim = msh.topology.dim
cells0 = locate_entities(msh, tdim, lambda x: x[0] <= 0.5)
cells1 = locate_entities(msh, tdim, lambda x: x[0] >= 0.5)

# Interpolate in the Nédélec/H(curl) space a vector-valued expression
# `f`, where $f \cdot n$ is discontinuous at $x_0 = 0.5$ and  $f \cdot
# e$ is continuous.

u.interpolate(lambda x: np.vstack((x[0], x[1])), cells0)
u.interpolate(lambda x: np.vstack((x[0] + 1, x[1])), cells1)

# Create a vector-valued discontinuous Lagrange space and function, and
# interpolate the $H({\rm curl})$ function `u`

gdim = msh.geometry.dim
V0 = functionspace(msh, ("Discontinuous Lagrange", 1, (gdim,)))
u0 = Function(V0, dtype=default_scalar_type)
u0.interpolate(u)

# We save the interpolated function `u0` in VTX format. When visualising
# the field, at $x_0 = 0.5$ the $x_0$-component should appear
# discontinuous and the $x_1$-component should appear continuous.
# We use the {py:class}`dolfinx.io.VTXWriter` to store the data.

out_folder = Path("output_nedelec")
out_folder.mkdir(parents=True, exist_ok=True)
if has_adios2:
    from dolfinx.io import VTXWriter

    with VTXWriter(msh.comm, out_folder / "output_nedelec.bp", u0) as f:
        f.write(0.0)
else:
    print("ADIOS2 required for VTX output")


# Plot the functions

try:
    import pyvista

    cells, types, x = plot.vtk_mesh(V0)
    grid = pyvista.UnstructuredGrid(cells, types, x)
    values = np.zeros((x.shape[0], 3), dtype=np.float64)
    values[:, : msh.topology.dim] = u0.x.array.reshape(x.shape[0], msh.topology.dim).real
    grid.point_data["u"] = values

    pl = pyvista.Plotter(shape=(2, 2))

    pl.subplot(0, 0)
    pl.add_text("magnitude", font_size=12, color="black", position="upper_edge")
    pl.add_mesh(grid.copy(), show_edges=True)

    pl.subplot(0, 1)
    glyphs = grid.glyph(orient="u", factor=0.08)
    pl.add_text("vector glyphs", font_size=12, color="black", position="upper_edge")
    pl.add_mesh(glyphs, show_scalar_bar=False)
    pl.add_mesh(grid.copy(), style="wireframe", line_width=2, color="black")

    pl.subplot(1, 0)
    pl.add_text("x-component", font_size=12, color="black", position="upper_edge")
    pl.add_mesh(grid.copy(), component=0, show_edges=True)

    pl.subplot(1, 1)
    pl.add_text("y-component", font_size=12, color="black", position="upper_edge")
    pl.add_mesh(grid.copy(), component=1, show_edges=True)

    pl.view_xy()
    pl.link_views()

    # If pyvista environment variable is set to off-screen (static)
    # plotting save png
    if pyvista.OFF_SCREEN:
        pl.screenshot(out_folder / "uh.png")
    else:
        pl.show()
except ModuleNotFoundError:
    print("pyvista is required to visualise the solution")