In the previous section we have seen that the `Range`

class can be used to define rectangular regions of arbitrary dimension. The `Boundary`

class makes use of these regions to define regions of ghost cells and boundary cells.

Ghost cells are parts of the grid that are not part of the inner simulation domain. They are needed for many grid based calculations when the value of a grid cell is updated from the values of the neighbouring cells. On the global simulation boundaries the ghost cells (or boundary cells) have to be filled with values determined by the boundary conditions. On the other hand, in a parallel simulation the ghost cells a one process have to be filled with values from the neighbouring process.

The `Boundary`

class makes it easy to obtain the rectangular domains that correspond to the ghost cells on each side of the simulation domain. The image shows the geometry of the simulation domain and the ghost domains.

The `Boundary`

class takes two template parameters, the `rank`

represents the dimensionality of the grid and `CheckingPolicy`

supplies the checking policy.

The class defines three constructors.

Boundary(); Boundary(const LimitType &lo, const LimitType &hi, int delta_); Boundary(DomainType &size_, int delta_);

The first of these constructors creates an empty boundary. A `Boundary`

created this way needs to be filled with values before it can be used. The second constructor takes the coordinates of the lower and upper corners of the simulation domain, given by `lo`

and `high`

, and the thickness of the ghost domain given by `delta`

. The type `Boundary::LimitType`

is simply defined as an `Array`

.

typedef Array<int, rank, CheckingPolicy> LimitType;

The third constructor takes a the size of the simulation domain given by `size`

and the thickness of the ghost domain given by `delta`

. Here the type `Boundary::DomainType`

is simply defined as a `Range`

.

typedef Range<int, rank, CheckingPolicy> DomainType;

Two inspector methods simply return the simulation domain and the thickness of the ghost domain.

const DomainType& getDomain(); int getDelta();

The following three methods are related to creating the ghost domain and the source region on the neighbouring process form which the ghost domain is filled. Figure 1 shows how these regions are arranged. The ghost domain lies outside the inner domain and surrounds it with a thickness given by `delta`

. For parallel simulations the ghost domain must be filled with values from the neighbouring process. The rectangular region that is the source for the ghost domain on the neighbouring process is called ghost source domain.

typedef enum {Min, Max} bound; DomainType getGhostDomain(int dim, bound b); DomainType getGhostSourceDomain(int dim, bound b); DomainType getInnerDomain();

The method `getGhostDomain()`

will return the rectangular range representing the ghost domain on one side of the simulation domain. The arguments `dim`

specifies the direction of the boundary and `bound`

specifies whether the upper or lower ghost domain should be returned.

The method `getGhostSourceDomain()`

will return the rectangular range representing the ghost source domain on one side of the simulation domain. As above, the arguments `dim`

specifies the direction of the boundary and `bound`

specifies whether the upper or lower ghost source domain should be returned. **Note** that the lower ghost source domain of one process should be used to fill the upper ghost domain of the neighbouring process.

The following piece of code illustrates the behaviour.

Array<int, 3> lo(0,0,0), hi(10, 10, 10); Boundary<3> boundary(lo, hi, 2); Range<int, 3> ghost = boundary.getGhostDomain(1,Boundary<3>::Max); Range<int, 3> source = boundary.getGhostSourceDomain(1,Boundary<3>::Max); Range<int, 3> inner = boundary.getInnerDomain();

A boundary object is initialised with a range from (0,0,0) to (10, 10, 10) and a ghost layer thickness of 2. Then the ghost domain and the ghost source domain of the upper boundary in the y-direction is calculated. After this code has finished the three ranges will have the following values.

ghost = (0, 9, 0) - (10, 10, 10) source = (0, 7, 0) - (10, 8, 10) inner = (2, 2, 2) - (8, 8, 8)

A method that behaves similar to `getGhostDomain`

is `getBoundaryDomain`

. However, `getBoundaryDomain`

takes grid staggering into account when calculating the boundary domain. This is useful for outer simulation boundaries in which the staggering affects the number of cells in the boundary region.

DomainType getBoundaryDomain(int dim, bound b, bool stagger);

The arguments have `dim`

and `bound`

have the same meaning as before. The boolean `stagger`

indicated if the grid is staggered by half a grid cell in the direction specified by `dim`

.

Instead of calculating just the ghost domain, you can directly create a sub-grid representing the ghost cells.

template SubGrid<GridType, CheckingPolicy> getGhostBoundary(int dim, bound b, GridType &grid);

This method takes, in addition to `dim`

and `bound`

, a grid and returns a `SubGrid`

that provides a view on the original grid, restricted to the corresponding boundary domain.

The code for this tutorial can be found here.