property DiffOperators.stencil_cell_gradient_x

Differencing operator along x-direction (cell centers to x-faces)

This property constructs a differencing operator along the x-axis that acts on cell centered quantities; i.e. the stencil for the x-component of the cell gradient. The operator computes the differences between the values at adjacent cell centers along the x-direction, and places the result on the x-faces. The operator is a sparse matrix \(\mathbf{G_x}\) that can be applied as a matrix-vector product to a cell centered quantity \(\boldsymbol{\phi}\), i.e.:

diff_phi_x = Gx @ phi

By default, the operator assumes zero-Neumann boundary conditions on the scalar quantity. Before calling stencil_cell_gradient_x however, the user can set a mix of zero Dirichlet and zero Neumann boundary conditions using set_cell_gradient_BC. When stencil_cell_gradient_x is called, the boundary conditions are enforced for the differencing operator.

(n_faces_x, n_cells) scipy.sparse.csr_matrix

The stencil for the x-component of the cell gradient


Below, we demonstrate how to set boundary conditions for the x-component cell gradient stencil, construct the operator and apply it to a discrete scalar quantity. The mapping of the operator and its sparsity is also illustrated. Our example is carried out on a 2D mesh but it can be done equivalently for a 3D mesh.

We start by importing the necessary packages and modules.

>>> from discretize import TensorMesh
>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> import matplotlib as mpl

We then construct a mesh and define a scalar function at cell centers. In this case, the scalar represents some block within a homogeneous medium.

Create a uniform grid

>>> h = np.ones(40)
>>> mesh = TensorMesh([h, h], "CC")

Create a discrete scalar at cell centers

>>> centers = mesh.cell_centers
>>> phi = np.zeros(mesh.nC)
>>> k = (np.abs(mesh.cell_centers[:, 0]) < 10.) & (np.abs(mesh.cell_centers[:, 1]) < 10.)
>>> phi[k] = 1.

Before constructing the stencil gradient operator, we must define the boundary conditions; zero Neumann for our example. Even though we are only computing the difference along x, we define boundary conditions for all boundary faces. Once the operator is created, it is applied as a matrix-vector product.

>>> mesh.set_cell_gradient_BC(['neumann', 'neumann'])
>>> Gx = mesh.stencil_cell_gradient_x
>>> diff_phi_x = Gx @ phi

Now we plot the original scalar, and the differencing taken along the x axes.

Expand to show scripting for plot
>>> fig = plt.figure(figsize=(13, 5))
>>> ax1 = fig.add_subplot(121)
>>> mesh.plot_image(phi, ax=ax1)
>>> ax1.set_title("Scalar at cell centers", fontsize=14)
>>> ax2 = fig.add_subplot(122)
>>> v = np.r_[diff_phi_x, np.zeros(mesh.nFy)]  # Define vector for plotting fun
>>> mesh.plot_image(v, ax=ax2, v_type="Fx")
>>> ax2.set_yticks([])
>>> ax2.set_ylabel("")
>>> ax2.set_title("Difference (x-axis)", fontsize=14)
>>> plt.show()

(Source code, png, pdf)


The x-component cell gradient stencil is a sparse differencing matrix that maps from cell centers to x-faces. To demonstrate this, we construct a small 2D mesh. We then show the ordering of the elements and a spy plot.

>>> mesh = TensorMesh([[(1, 3)], [(1, 4)]])
>>> mesh.set_cell_gradient_BC('neumann')
Expand to show scripting for plot
>>> fig = plt.figure(figsize=(12, 8))
>>> ax1 = fig.add_subplot(121)
>>> mesh.plot_grid(ax=ax1)
>>> ax1.set_title("Mapping of Stencil", fontsize=14, pad=15)
>>> ax1.plot(mesh.cell_centers[:, 0], mesh.cell_centers[:, 1], "ro", markersize=8)
>>> for ii, loc in zip(range(mesh.nC), mesh.cell_centers):
...     ax1.text(loc[0] + 0.05, loc[1] + 0.02, "{0:d}".format(ii), color="r")
>>> ax1.plot(mesh.faces_x[:, 0], mesh.faces_x[:, 1], "g>", markersize=8)
>>> for ii, loc in zip(range(mesh.nFx), mesh.faces_x):
...     ax1.text(loc[0] + 0.05, loc[1] + 0.02, "{0:d}".format(ii), color="g")
>>> ax1.set_xticks([])
>>> ax1.set_yticks([])
>>> ax1.spines['bottom'].set_color('white')
>>> ax1.spines['top'].set_color('white')
>>> ax1.spines['left'].set_color('white')
>>> ax1.spines['right'].set_color('white')
>>> ax1.set_xlabel('X', fontsize=16, labelpad=-5)
>>> ax1.set_ylabel('Y', fontsize=16, labelpad=-15)
>>> ax1.legend(
...     ['Mesh', '$\mathbf{\phi}$ (centers)', '$\mathbf{Gx^* \phi}$ (x-faces)'],
...     loc='upper right', fontsize=14
... )
>>> ax2 = fig.add_subplot(122)
>>> ax2.spy(mesh.stencil_cell_gradient_x)
>>> ax2.set_title("Spy Plot", fontsize=14, pad=5)
>>> ax2.set_ylabel("X-Face Index", fontsize=12)
>>> ax2.set_xlabel("Cell Index", fontsize=12)
>>> plt.show()

(png, pdf)