# Mesh and Fields¶

## Mesh¶

The mesh consists of NX cells in X (hence azimuth in cylindrical and
spherical geometries), NY+2*NGHY cells in Y (radius in cylindrical and
spherical geometries) and NZ+2*NGHZ cells in Z (colatitude in
spherical geometry). Here NGHY and NGHZ stand for the number of ghost
or buffer zones next to the active mesh. If a direction is not
included in the setup (for instance Z in the 2D polar `fargo`

setup), the corresponding value of NGHY/Z is set to 0.

The variables NX, NY, and NZ are defined in the parameter file (they
default to 1, so there is no need to define, for instance, NZ in a 2D
setup such as `fargo`

, or NX in the 2D setup `otvortex`

, which
corresponds to the Orszag-Tang vortex problem in Y and Z).

In practice, this mesh is split among processors, and locally (within the scope of a given process) the submesh considered has size Nx, Ny+2*NGHY and Nz+2*NGHZ.

The information about cells coordinates is stored in 1D arrays

- [xyz]min(index)
- [xyz]med(index)

where *min* refers to the inner edge of a zone (in x, y or z) whereas
*med* refers to the center of a zone (in x, y or z). This notation
should look familiar to former FARGO users.

Warning

[xyz][min/max](index) are not vectors, they are macrocommands. They must be invoked with (), not with [].

NGHY and NGHZ are preprocessor variables, defined in the file `src/define.h`

.

Because we have a multi-geometry code, another set of secondary geometrical variables is defined (surfaces, volumes). See the end of this section for details.

## Fields¶

Fields are structures, and they can be seen as cubes of cells, of size
equal to the mesh size. The location at which a given variable is defined is [xyz]med if
the field is [xyz]-centered, or [xyz]min if the field is
[xyz]-staggered. You can find a comprehensive list of the fields in
`src/global.h`

. The place where the fields are created is in
`CreateFields()`

, inside `src/LowTasks.c`

.

Internally, all fields are cubes written as 1D-arrays. So we need
indices to work with the 3D-data. We have a set of helpers defined in
`src/define.h`

. They are:

`l`

: The index of the current zone.`lxp`

,`lxm`

: lxplus/lxminnus, the right/left x-neighbor`lyp`

,`lym`

: lyplus/lyminnus, the right/left y-neighbor`lzp`

,`lzm`

: lzplus/lzminnus, the right/left z-neighbor

These helpers must be used with the proper loop indices:

```
int i,j,k;
for (k=z_lower_bound; k<z_upper_bound; k++) {
for (j=y_lower_bound; j<y_upper_bound; j++) {
for (i=x_lower_bound; i<x_upper_bound; i++) {
field[l] = 3.0;
field2[l] = (field1[lxp]-field1[l])/(xmed(ixp)-xmed(i)); //obviously some gradient calculation...
}
}
}
```

where [kji] always means [zyx]-direction.

Warning

Do not change the order of the indices! The definition of `l`

,
`lxp`

, `lxm`

, etc. assumes the following correspondence:

i->x, j->y, k->z

These helpers are extremely useful. No explicit algebra has to be
performed on the indices within a loop (but never use or define a
variable called `l`

or `lxp`

!…). Besides, the definition of
`l`

is also correct within GPU kernels (for which the indices
algebra is slightly different owing to memory alignment
considerations), and this is totally transparent to the user who
should never have to worry about this.

In practice, a loop is similar to (isothermal equation of state):

```
int i,j,k;
for (k=0; k<Nz+2*NGHZ; k++) {
for (j=0; j<Ny+2*NGHY; j++) {
for (i=0; i<Nx; i++ ) {
pres[l] = dens[l]*cs[l]*cs[l];
}
}
}
```

Note

Note that the lines of code above do not evaluate, nor define
`l`

, which is used straight out of the box, since it is a
preprocessor macrocommand.

## Working with fields¶

A field structure is defined as follows (in `src/structs.h`

):

```
struct field {
char *name;
real *field_cpu;
real *field_gpu;
};
```

where we have stripped the definition of all extra lines not relevant
at this stage. The `name`

is a string that is used to determine the
name of output files. `field_cpu`

is a pointer to a double or float
1D array which has been duly allocated on the RAM prior to any
invocation.

Similarly `field_gpu`

is a pointer to a double or float 1D array
which has been duly allocated on the Video RAM prior to any
invocation. The user should never have to invoke directly this
field. Rather, C files will always make use of the `field_cpu`

,
which will be automatically translated to `field_gpu`

as needed
during the C to CUDA conversion.

Acceding a field value is generally done as follows:

```
struct Field *Density; // Definition at the beginning of a function
real *density; // real is either double or float.
density = Density->field_cpu;
...
later on in a loop:
...
density[l] = ....;
```

Note

Note that we define an “array of reals” straight away and subsequently only refer to it to manipulate cell values. In order to avoid confusion, it is a good idea to have an upper case for the initial of Fields*, and lower case for the corresponding real arrays.

## Fields on the GPU¶

Similar techniques are used on the GPU, but we have made it totally transparent to the user, so unless you want to program your CUDA kernels directly, you should never to worry about this.

## Useful variables¶

For the handling of the mesh, a set of useful variables and macrocommands has been defined. An extensive list with a description is given below:

**Indices**:

`l`

: The index of the current cell. It is a function of (`i`

,``j``,``k``,`pitch`

&`stride`

).`lxp`

: The index of the “right” neighbor in x of the current cell. It is a function of`l`

.`lxm`

: The index of the “left” neighbor in x of the current cell. It is a function of`l`

.`lyp`

: The index of the “right” neighbor in y of the current cell. It is a function of`l`

.`lym`

: The index of the “left” neighbor in y of the current cell. It is a function of`l`

.`lzp`

: The index of the “right” neighbor in z of the current cell. It is a function of`l`

.`lzm`

: The index of the “left” neighbor in z of the current cell. It is a function of`l`

.`l2D`

: The current index in a 2D field (eg: vmean). It is a function of (`j`

,``k``).`l2D_int`

: The current index in a 2D integer field (eg: a field of shifts). It is a function if (`j`

,``k``).`ixm`

:`i`

-index of the “left” neighbor in x of the current cell, taking periodicity into account.`ixp`

:`i`

-index of the “right” neighbor in x of the current cell, taking periodicity into account.

**Coordinates**:

`XC`

: center of the current cell in X. It is a function of the indices; must to be used*inside a loop*.`YC`

: center of the current cell in Y. It is a function of the indices; must to be used*inside a loop*.`ZC`

: center of the current cell in Z. It is a function of the indices; must to be used*inside a loop*.`xmin(i)`

: The lower x-bound of a cell.`xmed(i)`

: The x-center of a cell, same as XC but can be used outside a loop.`ymin(j)`

: The lower y-bound of a cell.`ymed(j)`

: The y-center of a cell, same as YC but can be used outside a loop.`zmin(k)`

: The lower z-bound of a cell.`zmed(k)`

: The z-center of a cell, same as ZC but can be used outside a loop.

**Length**:

`zone_size_x(j,k)`

: Face to face distance in the x direction.`zone_size_y(j,k)`

: Face to face distance in the y direction.`zone_size_z(j,k)`

: Face to face distance in the z direction.`edge_size_x(j,k)`

: The same as zone_size_x, but measured on the lower x-border.`edge_size_y(j,k)`

: The same as zone_size_y, but measured on the lower y-border.`edge_size_z(j,k)`

: The same as zone_size_z, but measured on the lower z-border.`edge_size_x_middlez_lowy(j,k)`

: The same as edge_size_x but measured half a cell above in z.`edge_size_x_middley_lowz(j,k)`

: The same as edge_size_x but measured half a cell above in y.

**Surfaces**:

`SurfX(j,k)`

: The lower surface of a cell at x=cte.`SurfY(j,k)`

: The lower surface of a cell at y=cte.`SurfZ(j,k)`

: The lower surface of a cell at z=cte.

**Volumes**:

`Vol(j,k)`

: The volume of the current cell.`InvVol(j,k)`

: The inverse of the current cell’s volume.

You can see examples on how to use these variables in `src/`

. They
are widely used in many routines.