Notebook 2: Variables

We can add discrete variables (unknowns associated with the mesh points).

import underworld3 as uw
import numpy as np
import sympy
mesh = uw.meshing.uw.meshing.CubedSphere(
    radiusOuter=1.0,
    radiusInner=0.547,
    numElements=8,
    simplex=False,
    verbose=False,
)

x,y,z = mesh.CoordinateSystem.X
r,th,phi = mesh.CoordinateSystem.R
r_vec = mesh.CoordinateSystem.unit_e_0
th_vec =  mesh.CoordinateSystem.unit_e_1
phi_vec =  mesh.CoordinateSystem.unit_e_2

This example shows how we can add a scalar field with a single value associated with each mesh node, and a vector field which has quadratic interpolation (points at the nodes plus interpolating points along mesh edges).

# mesh variable example / test

scalar_var = uw.discretisation.MeshVariable(
    varname="Radius",
    mesh=mesh, 
    vtype = uw.VarType.SCALAR,
    varsymbol=r"r"
)

vector_var = uw.discretisation.MeshVariable(
    varname="Vertical_Vec",
    mesh=mesh, 
    degree=2,
    vtype = uw.VarType.VECTOR,
    varsymbol=r"\mathbf{v}",
)

To set values of the variable, we first have to unlock it using the access context manager, and then we can evaluate a function at the coordinates appropriate to fill up each variable:

with mesh.access(scalar_var, vector_var):
    scalar_var.data[:,0] = uw.function.evaluate(r, scalar_var.coords)
    vector_var.data[:,:] = uw.function.evaluate(r_vec, vector_var.coords)

Variables are like most underworld and PETSc objects - they can be examined using their view() method. The information that you will see is split into the underworld representation (listed under MeshVariable) and the PETSc representation (listed under FE Data which also includes the numerical values).

scalar_var.view()

Class: <class ‘underworld3.discretisation._MeshVariable’>

MeshVariable:

symbol: \({ \hspace{ 0.03pt } {r} }\)

shape: \((1, 1)\)

degree: \(1\)

continuous: True

type: SCALAR

FE Data:

PETSc field id: \(0\)

PETSc field name: Radius

array([[1.      ],
       [1.      ],
       [1.      ],
       ...,
       [0.830125],
       [0.88675 ],
       [0.943375]])
# Visualise it / them

import pyvista as pv
import underworld3.visualisation as vis

pvmesh = vis.mesh_to_pv_mesh(mesh)
pvmesh.point_data["z"] = vis.scalar_fn_to_pv_points(pvmesh, mesh.CoordinateSystem.X[2])
pvmesh.point_data["r"] = vis.scalar_fn_to_pv_points(pvmesh, scalar_var.sym[0])
pvmesh.point_data["V"] = vis.vector_fn_to_pv_points(pvmesh, (1-scalar_var.sym[0]) * vector_var.sym)

if mesh.dim==3:
    pvmesh_clipped = pvmesh.clip( normal='z', crinkle=True,origin=(0.0,0.0,0.01))

# pvmesh.plot(show_edges=True, show_scalar_bar=False)

pl = pv.Plotter(window_size=(750, 750))

pl.add_mesh(pvmesh_clipped, 
            show_edges=True,
            scalars="z", 
            opacity=0.6,
            show_scalar_bar=False)

pl.add_arrows(pvmesh.points, 
              pvmesh.point_data["V"],
              mag=0.25,
              opacity=0.6,
              color="Black",
              show_scalar_bar=False)

pl.export_html("html5/echidna_plot.html")
from IPython.display import IFrame
IFrame(src="html5/echidna_plot.html", width=600, height=400)

Interactive Image: Spherical shell mesh cut away to show radial arrows with length decreasing away from the centre.

More information

The meshVariable code is described in the API docs: https://underworldcode.github.io/underworld3/main_api/underworld3/meshing.html