Tutorial¶
The Mesh objects in discretize provide a numerical grid on which to solve differential equations. Each mesh type has a similar API to make switching between different meshes relatively simple.
Overview of Meshes Available¶
Each mesh code follows the guiding principles that are present in this tutorial, but the details, advantages and disadvantages differ between the implementations.
(Source code, png, hires.png, pdf)
Variable Locations and Terminology¶
We will go over the basics of using a TensorMesh, but these skills are transferable to the other meshes available in discretize.
To create a TensorMesh we need to create mesh tensors, the widths of each cell of the mesh in each dimension. We will call these tensors h, and these will be define the constant widths of cells in each dimension of the TensorMesh.
import discretize
import numpy as np
import matplotlib.pyplot as plt
hx = np.r_[3,2,1,1,1,1,2,3]
hy = np.r_[3,1,1,3]
M = discretize.TensorMesh([hx, hy])
M.plotGrid(centers=True)
plt.show()
(Source code, png, hires.png, pdf)
In this simple mesh, the hx vector defines the widths of the cell in the x dimension, and starts counting from the origin (0,0). The resulting mesh is divided into cells, and the cellcenters are plotted above as red circles. Other terminology for this mesh are:
 cellcenters
 nodes
 faces
 edges
import discretize
import numpy as np
import matplotlib.pyplot as plt
hx = np.r_[3,2,1,1,1,1,2,3]
hy = np.r_[3,1,1,3]
M = discretize.TensorMesh([hx, hy])
M.plotGrid(faces=True, nodes=True)
plt.title('Cell faces in the x and ydirections.')
plt.legend(('Nodes', 'XFaces', 'YFaces'))
plt.show()
(Source code, png, hires.png, pdf)
Generally, the faces are used to discretize fluxes, quantities that leave or enter the cells. As such, these fluxes have a direction to them, which is normal to the cell (i.e. directly out of the cell face). The plot above shows that xfaces point in the xdirection, and yfaces point in the ydirection. The nodes are shown in blue, and lie at the intersection of the grid lines. In a twodimensional mesh, the edges actually live in the same location as the faces, however, they align (or are tangent to) the face. This is easier to see in 3D, when the edges do not live in the same location as the faces. In the 3D plot below, the edge variables are seen as black triangles, and live on the edges(!) of the cell.
from __future__ import print_function
import discretize
discretize.TensorMesh([1,1,1]).plotGrid(faces=True, edges=True, centers=True, showIt=True)
(Source code, png, hires.png, pdf)
How many of each?¶
When making variables that live in each of these locations, it is important to know how many of each variable type you are dealing with. discretize makes this pretty easy:
In [1]: print(M)
 2D TensorMesh 
x0: 0.00
y0: 0.00
nCx: 8
nCy: 4
hx: 3.00, 2.00, 4*1.00, 2.00, 3.00
hy: 3.00, 2*1.00, 3.00
In [2]: count = {'numCells': M.nC,
....: 'numCells_xDir': M.nCx,
....: 'numCells_yDir': M.nCy,
....: 'numCells_vector': M.vnC}
In [3]: print('This mesh has %(numCells)d cells, which is %(numCells_xDir)d*%(numCells_yDir)d!!' % count)
This mesh has 32 cells, which is 8*4!!
In [4]: print(count)
{
'numCells_vector': array([8, 4]),
'numCells_yDir': 4,
'numCells_xDir': 8,
'numCells': 32
}
discretize also counts the nodes, faces, and edges.
Nodes: M.nN, M.nNx, M.nNy, M.nNz, M.vnN
Faces: M.nF, M.nFx, M.nFy, M.nFz, M.vnF, M.vnFx, M.vnFy, M.vnFz
Edges: M.nE, M.nEx, M.nEy, M.nEz, M.vnE, M.vnEx, M.vnEy, M.vnEz
Face and edge variables have different counts depending on the dimension of the direction that you are interested in. In a 4x5 mesh, for example, there is a 5x5 grid of xfaces, and a 4x6 grid of yfaces. You can count them below! As such, the vnF(x,y,z) and vnE(x,y,z) properties give the vector grid size.
import discretize
discretize.TensorMesh([4,5]).plotGrid(faces=True, showIt=True)
(Source code, png, hires.png, pdf)
Making Tensors¶
For tensor meshes, there are some additional functions that can come in handy. For example, creating mesh tensors can be a bit time consuming, these can be created speedily by just giving numbers and sizes of padding. See the example below, that follows this notation:
h1 = (
(cellSize, numPad, [, increaseFactor]),
(cellSize, numCore),
(cellSize, numPad, [, increaseFactor])
)
import discretize
h1 = [(10, 5, 1.3), (5, 20), (10, 3, 1.3)]
M = discretize.TensorMesh([h1, h1], x0='CN')
M.plotGrid(showIt=True)
(Source code, png, hires.png, pdf)
Note
You can center your mesh by passing a ‘C’ for the x0[i] position. A ‘N’ will make the entire mesh negative, and a ‘0’ (or a 0) will make the mesh start at zero.
Hopefully, you now know how to create TensorMesh objects in discretize, and by extension you are also familiar with how to create and use other types of meshes in discretize.
The API¶

class
discretize.BaseMesh.
BaseMesh
(n, x0=None, **kwargs)[source]¶  BaseMesh does all the counting you don’t want to do. BaseMesh should be inherited by meshes with a regular structure.
Required Properties:
 axis_u (
Vector3
): Vector orientation of udirection. For more details see the docs for therotation_matrix
property., a 3D Vector of <class ‘float’> with shape (3), Default: X  axis_v (
Vector3
): Vector orientation of vdirection. For more details see the docs for therotation_matrix
property., a 3D Vector of <class ‘float’> with shape (3), Default: Y  axis_w (
Vector3
): Vector orientation of wdirection. For more details see the docs for therotation_matrix
property., a 3D Vector of <class ‘float’> with shape (3), Default: Z  reference_system (
String
): The type of coordinate reference frame. Can take on the values cartesian, cylindrical, or spherical. Abbreviations of these are allowed., a unicode string, Default: cartesian  x0 (
Array
): origin of the mesh (dim, ), a list or numpy array of <class ‘float’> with shape (*)

nC
¶ Total number of cells in the mesh.
Return type: int Returns: nC import discretize import numpy as np M = discretize.TensorMesh([np.ones(n) for n in [2,3]]) M.plotGrid(centers=True, showIt=True)
(Source code, png, hires.png, pdf)

nN
¶ Total number of nodes
Return type: int Returns: nN import discretize import numpy as np M = discretize.TensorMesh([np.ones(n) for n in [2,3]]) M.plotGrid(nodes=True, showIt=True)
(Source code, png, hires.png, pdf)

vnE
¶ Total number of edges in each direction
Return type: numpy.ndarray Returns: [nEx, nEy, nEz], (dim, ) import discretize import numpy as np M = discretize.TensorMesh([np.ones(n) for n in [2,3]]) M.plotGrid(edges=True, showIt=True)
(Source code, png, hires.png, pdf)

vnF
¶ Total number of faces in each direction
Return type: numpy.ndarray Returns: [nFx, nFy, nFz], (dim, ) import discretize import numpy as np M = discretize.TensorMesh([np.ones(n) for n in [2,3]]) M.plotGrid(faces=True, showIt=True)
(Source code, png, hires.png, pdf)

normals
¶ Face Normals
Return type: numpy.ndarray Returns: normals, (sum(nF), dim)

tangents
¶ Edge Tangents
Return type: numpy.ndarray Returns: normals, (sum(nE), dim)

projectFaceVector
(fV)[source]¶ Given a vector, fV, in cartesian coordinates, this will project it onto the mesh using the normals
Parameters: fV (numpy.ndarray) – face vector with shape (nF, dim) Return type: numpy.ndarray Returns: projected face vector, (nF, )

projectEdgeVector
(eV)[source]¶ Given a vector, eV, in cartesian coordinates, this will project it onto the mesh using the tangents
Parameters: eV (numpy.ndarray) – edge vector with shape (nE, dim) Return type: numpy.ndarray Returns: projected edge vector, (nE, )

save
(filename='mesh.json', verbose=False)[source]¶ Save the mesh to json :param str file: filename for saving the casing properties :param str directory: working directory for saving the file

axis_u
¶ axis_u (
Vector3
): Vector orientation of udirection. For more details see the docs for therotation_matrix
property., a 3D Vector of <class ‘float’> with shape (3), Default: X

axis_v
¶ axis_v (
Vector3
): Vector orientation of vdirection. For more details see the docs for therotation_matrix
property., a 3D Vector of <class ‘float’> with shape (3), Default: Y

axis_w
¶ axis_w (
Vector3
): Vector orientation of wdirection. For more details see the docs for therotation_matrix
property., a 3D Vector of <class ‘float’> with shape (3), Default: Z

reference_is_rotated
¶ True if the axes are rotated from the traditional <X,Y,Z> system with vectors of \((1,0,0)\), \((0,1,0)\), and \((0,0,1)\)

rotation_matrix
¶ Builds a rotation matrix to transform coordinates from their coordinate system into a conventional cartesian system. This is built off of the three axis_u, axis_v, and axis_w properties; these mapping coordinates use the letters U, V, and W (the three letters preceding X, Y, and Z in the alphabet) to define the projection of the X, Y, and Z durections. These UVW vectors describe the placement and transformation of the mesh’s coordinate sytem assuming at most 3 directions.
Why would you want to use these UVW mapping vectors the this rotation_matrix property? They allow us to define the realationship between local and global coordinate systems and provide a tool for switching between the two while still maintaing the connectivity of the mesh’s cells. For a visual example of this, please see the figure in the docs for the
vtkInterface
.
 axis_u (