Grid Functions

In Bempp, data on a given grid is represented as a grid function object. A grid function consists of a set of basis function coefficients and a corresponding function space.

Initialising with a Python callable

Grid functions can be created from Python callables.

@bempp.api.complex_callable
def fun(x, normal, domain_index, result):
    result[0] = np.exp(1j * x[0])

The first argument x is the coordinates of an evaluation point. The second argument normal is the normal direction at the evaluation point. The third one is the domain_index: this corresponds to the physical id in Gmsh and can be used to assign different boundary data to different parts of the grid. The last argument result is the variable that stores the value of the callable. It is a Numpy array with as many components as the basis functions of the underlying space have.

A Python callable that you want to use to build a grid function should always have these four inputs. An optional fifth input may be used to pass parameters into the function.

In order for Bempp to assemble a grid function with coefficients of the correct data type, these callables must be decorated with either @bempp.api.real_callable or @bempp.api.real_callable.

The projection of this callable into a Bempp space can be created with:

grid_fun = bempp.api.GridFunction(space, fun=fun)

Disabling just-in-time compilation

By default, Bempp with use Numba just-in-time compilation when creating grid functions from callables. In some cases, this compilation is not possible and should be disabled. This can be done by passing jit=False into the decorator:

@bempp.api.complex_callable(jit=False)
def fun(x, normal, domain_index, result):
    result[0] = np.exp(1j * x[0])

grid_fun = bempp.api.GridFunction(space, fun=fun)

The construction of this grid function will be slower as it is not sped up by Numba.

Initialising with coefficients or projections

Instead of a callable, we can initialise a grid function from a vector of coefficients or a vector of projections. This can be done as follows.

c = np.array([...])  # These are the coefficients
grid_fun = GridFunction(space, coefficients=c)

p = np.array([...])  # These are the projections
grid_fun = GridFunction(space, projections=p, dual_space=dual)

The argument dual_space gives the space with which the projection coefficients were computed. The parameter is optional and if it is not given then space == dual_space is assumed.

Coefficients and projections

The functions in a discrete function space are represented as a linear combination of some basis functions. The coefficients of a grid function are the scalars which each basis function is multiplied by in this combination. The coefficients of a grid function can be obtained using:

grid_fun.coefficients

The projections of a grid function are calculated by applying a discrete mass matrix to the coefficients. The mass matrix will be between the grid function’s space and a dual space provided to the projections call. These can be obtained using:

grid_fun.projections(dual_space)

In some situations, for example when the space and the dual are RWG and SNC spaces, the mass matrix for projections may be numerically singular. In these cases, the coefficients of a grid function that has been initialised using projections cannot be accurately calculated. Bempp, however, can still use these grid functions by only querying the projections.

Plotting and exporting grid functions

To export a grid function, we can use the export command:

bempp.api.export('grid_function.msh', grid_function=grid_fun)

This commands export the object grid_fun as Gmsh file with the name grid_function.msh.

In order to plot a grid function, we can simply use the command:

grid_fun.plot()

By default, this will plot using Gmsh (or plotly if you are inside a Jupyter notebook). The following command can be used to change the plotting backend.

bempp.api.PLOT_BACKEND = "gmsh"
bempp.api.PLOT_BACKEND = "paraview"

This requires Gmsh or Paraview to be available in the system path.