2D cell indices

In this notebook, we show the differences that exist between coordinates and indices on a grid.

Moreover, we show the difference between the Wolf array conventions (which are born out of the Fortran language) and the numpy array conventions.

Our code base uses the two simultaneously and being comfortable with them will help you a lot.

Note that a WolfArray is built on top of a numpy array but with a major difference: a WolfArray numbers its indices as (x, y) whereas in numpy, the indices are (y,x). That difference comes from the long history of Wolf arrays which begins in the Fortran world.

[1]:
import _add_path # can be removed/commented if not in debug mode

import matplotlib.pyplot as plt
import numpy
from wolfhece.assets.mesh import Mesh2D, header_wolf

Creation of a 2D grid

  • number of cells along X = 3

  • number of cells along Y = 3

[2]:
h = header_wolf()
h.set_origin(0., 0.)     # origx, origy
h.set_resolution(1., 1.) # dx, dy
h.shape = (3,3)          # nbx, nby
[ ]:
grid = Mesh2D(h)

Viewing the Grid as Coordinates/Georeferenced item

In this perspective, the X-Y coordinate system follows a right-handed (dextrorsum) orientation:

  • The X-axis extends horizontally from left to right and is measured in meters.

  • The Y-axis extends vertically from bottom to top and is measured in meters.

[ ]:
fig, ax = grid.plot_cells() # plot cells
fig.suptitle('Mesh2D cells')
Text(0.5, 0.98, 'Mesh2D cells')
../_images/tutorials_2dmesh_6_1.png

Cell/Mesh Numbering

The indices of the meshes follow this convention:

  • Rows evolve along the X-axis.

  • Columns evolve along the Y-axis.

Thus, the index \([i, j]\) corresponds to the position:

\([origx + (i - 0.5) dx, \, origy + (j - 0.5) dy]\)

where:

  • \(origx\) is the x-coordinate of the origin (in local or global coordinates, adjusted by \(translx\) if applicable).

  • \(origy\) is the y-coordinate of the origin (in local or global coordinates, adjusted by \(transly\) if applicable).

  • \(dx\) is the resolution along the X-axis.

  • \(dy\) is the resolution along the Y-axis.

[5]:
fig, ax = grid.plot_cells()
grid.set_ticks_as_dxdy(ax)
grid.plot_circle_at_centers(ax, radius = .05, alpha = 0.1) # plot circle at centers
grid.plot_indices_at_centers(ax=ax, color='green', fontsize = 10) # plot indices at centers
[5]:
(<Figure size 640x480 with 1 Axes>, <Axes: xlabel='X (m)', ylabel='Y (m)'>)
../_images/tutorials_2dmesh_8_1.png

Edge Numbering

Edges are also indexed.

We distinguish:

  • the bordersX, i.e., those whose normal flux is aligned with X (the edge itself is aligned with Y)

  • the bordersY, i.e., those whose normal flux is aligned with Y (the edge itself is aligned with X)

[6]:
fig, ax = grid.plot_cells() # plot nodes
grid.set_ticks_as_dxdy(ax)
grid.plot_circle_at_centers(ax, radius = .05, alpha = 0.1) # plot circle at nodes
grid.plot_indices_at_bordersX(ax=ax, color='blue', fontsize = 10) # plot indices at bordersX
fig.suptitle('BordersX')
[6]:
Text(0.5, 0.98, 'BordersX')
../_images/tutorials_2dmesh_10_1.png
[7]:
fig, ax = grid.plot_cells() # plot nodes
grid.set_ticks_as_dxdy(ax)
grid.plot_circle_at_centers(ax, radius = .05, alpha = 0.1) # plot circle at nodes
grid.plot_indices_at_bordersY(ax=ax, color='red', fontsize = 10) # plot indices at bordersX
fig.suptitle('BordersY')
[7]:
Text(0.5, 0.98, 'BordersY')
../_images/tutorials_2dmesh_11_1.png

Shape

  • a matrice storing cells values has a shape (nbx, nby)

  • a matrice storing bordersX values has a shape (nbx+1, nby)

  • a matrice storing bordersY values has a shape (nbx, nby+1)

[8]:
print('Cells matrice - shape : ',grid.zeros().shape)
print('BordersX matrice - shape : ',grid.zeros_bordersX().shape)
print('BordersY matrice - shape : ',grid.zeros_bordersY().shape)
Cells matrice - shape :  (3, 3)
BordersX matrice - shape :  (4, 3)
BordersY matrice - shape :  (3, 4)

Fortran/Python Numbering

  • Fortran is 1-based.

  • Python is 0-based.

In routines, you have a parameter named ‘aswolf’. If it is True, the Fortran convention is applied. Generally, “True” is the default value but read the routine’s docstring if necessary.

Boundary condition indices must be provided using the Fortran-type (1-based).

[14]:
fig, ax = plt.subplots(1,2, figsize=(10,5)) # plot nodes

grid.plot_cells(ax=ax[0]) # plot cells
grid.set_ticks_as_dxdy(ax[0])
grid.plot_circle_at_centers(ax[0], radius = .05, alpha = 0.1) # plot circle at nodes
grid.plot_indices_at_centers(ax=ax[0], Fortran_type=True, color='blue', fontsize = 10) # plot indices at bordersX
ax[0].set_title('Fortran type')

grid.plot_cells(ax=ax[1]) # plot cells
grid.set_ticks_as_dxdy(ax[1])
grid.plot_circle_at_centers(ax[1], radius = .05, alpha = 0.1) # plot circle at nodes
grid.plot_indices_at_centers(ax=ax[1], Fortran_type=False, color='green', fontsize = 10) # plot indices at bordersX
ax[1].set_title('Python type')
[14]:
Text(0.5, 1.0, 'Python type')
../_images/tutorials_2dmesh_15_1.png
[13]:
fig, ax = plt.subplots(2,2, figsize=(10,5)) # plot nodes

grid.plot_cells(ax=ax[0,0]) # plot cells
grid.set_ticks_as_dxdy(ax[0,0])
grid.plot_circle_at_centers(ax[0,0], radius = .05, alpha = 0.1) # plot circle at nodes
grid.plot_indices_at_bordersX(ax=ax[0,0], Fortran_type=True, color='blue', fontsize = 10) # plot indices at bordersX
ax[0,0].set_title('Fortran type')

grid.plot_cells(ax=ax[0,1]) # plot cells
grid.set_ticks_as_dxdy(ax[0,1])
grid.plot_circle_at_centers(ax[0,1], radius = .05, alpha = 0.1) # plot circle at nodes
grid.plot_indices_at_bordersX(ax=ax[0,1], Fortran_type=False, color='green', fontsize = 10) # plot indices at bordersX
ax[0,1].set_title('Python type')

grid.plot_cells(ax=ax[1,0]) # plot cells
grid.set_ticks_as_dxdy(ax[1,0])
grid.plot_circle_at_centers(ax[1,0], radius = .05, alpha = 0.1) # plot circle at nodes
grid.plot_indices_at_bordersY(ax=ax[1,0], Fortran_type=True, color='blue', fontsize = 10) # plot indices at bordersX

grid.plot_cells(ax=ax[1,1]) # plot cells
grid.set_ticks_as_dxdy(ax[1,1])
grid.plot_circle_at_centers(ax[1,1], radius = .05, alpha = 0.1) # plot circle at nodes
grid.plot_indices_at_bordersY(ax=ax[1,1], Fortran_type=False, color='green', fontsize = 10) # plot indices at bordersX

[13]:
(<Figure size 1000x500 with 4 Axes>, <Axes: xlabel='X (m)', ylabel='Y (m)'>)
../_images/tutorials_2dmesh_16_1.png

Exploring a More Complex Grid Configuration

In this section, we apply the previously discussed concepts to a grid where the number of cells along the X and Y axes differ. This demonstrates how the grid structure adapts to varying resolutions and dimensions.

[9]:
h2 = header_wolf()
h2.set_origin(10., -5.)     # origx, origy
h2.set_resolution(0.5, 0.5) # dx, dy
h2.shape = (10,5)          # nbx, nby
[10]:
grid2 = Mesh2D(h2)
fig, ax = grid2.plot_cells() # plot cells
../_images/tutorials_2dmesh_19_0.png
[11]:
fig, ax = grid2.plot_cells() # plot nodes
grid2.set_ticks_as_dxdy(ax)
grid2.plot_circle_at_centers(ax, radius = .05, alpha = 0.1) # plot circle at nodes
grid2.plot_indices_at_centers(ax=ax, color='blue', fontsize = 10) # plot indices at bordersX
[11]:
(<Figure size 640x480 with 1 Axes>, <Axes: xlabel='X (m)', ylabel='Y (m)'>)
../_images/tutorials_2dmesh_20_1.png
[12]:
fig, ax = grid2.plot_outside_domain() # plot outside domain
grid2.plot_cells(ax) # plot nodes
grid2.set_ticks_as_dxdy(ax)
grid2.scale_axes(ax, .1) # scale axes by 2.0
[12]:
(<Figure size 640x480 with 1 Axes>, <Axes: xlabel='X (m)', ylabel='Y (m)'>)
../_images/tutorials_2dmesh_21_1.png