Using LegoExcision

Denis Pollney



LegoExcision implements excision on a Cactus grid. It uses a mask function to determine which grid points are to be excised, then applies a simple boundary condition to points on the edge of the mask.

1 Background

The LegoExcision thorn was originally written spring 2001 by Miguel Alcubierre, Eric Schnetter and Deirdre Shoemaker. It extends the functionality of Miguel’s SimpleExcision thorn (described in [1]) by allowing arbitrary shapes and number of holes to be excised.

2 Implementing excision in a thorn

LegoExcision is not scheduled. It simply provides three functions (excision_findboundary(), excision_findnormals() and excision_extrapolate()) which are used to apply the excision boundary condition to a grid function. This functions must be called at the appropriate time (eg. whenever boundary conditions are applied) within the source code of any thorn that wishes to use excision. The functions are written in Fortran90, and no C wrappers exist as of yet.

The first function, excision_findboundary(), can be used to mark the boundaries of an excision region in the mask function. It is passed the mask in the form of a Cactus gridfunction which has interior points marked appropriately (see Section 3, below). It then passes over the mask and marks any point which is on the boundary of an excision region. Boundary points are any point which has at least one neighbour that is not excised.

excision_findboundary (ierr, mask, ni, nj, nk)

ierr (integer) Holds the return value, 0 for success.
mask (CCTK_REAL(ni,nj,nk)) A Cactus gridfunction (array of CCTK_REAL whose dimensions are given by the cctk_lsh variables) which contians the excision mask.
ni , nj , nk (integer) Dimensions of the grid, corresponding to cctk_lsh(1...3).

Next, the function excision_findnormals() can be used to determine normal directions from each point on the excision boundary. The normals are stored in three grid functions (dirx, diry and dirz) which contain the (x,y,z) components of the normal vector for points on the boundary. The normal is determined as a sum of the relative components of each active (non-excised) neighbour,

ni = x{neighboursofx}xi xi, (1)

which is then normalised. For points which are not on the excision boundary, the normal is set to 0.

excision_findnormals (ierr, mask, dirx, diry, dirz, ni, nj, nk)

(integer) Holds the return value, 0 for success.
(CCTK_REAL(ni,nj,nk)) A Cactus gridfunction which contians the excision mask.
dirx, diry, dirz
(CCTK_REAL(ni,nj,nk)) Grid functions describing the normal directions to the excision boundary. These are determined by excision_findnormals().
ni, nj, nk
(integer) Dimensions of the grid, corresponding to cctk_lsh(1...3).

Finally, the excision_extrapolate() routine applies the a boundary condition to a grid function at each point that the mask has identified as an excision boundary. At present, only one boundary condition is implemented, which corresponds to the ‘time derivative copy’ which was successfully used in [1]. Namely, the time derivative dvdt of the variable is determined at one point away from the excision boundary, and copied to the excision boundary where it is used as a source. This determines a new value on the boundary at the next timeslice.

excision_extrapolate (ierr, var, oldvar, mask, dirx, diry, dirz, ni, nj, nk, var0)

(integer) Holds the return value, 0 for success.
(CCTK_REAL(ni,nj,nk)) A Cactus gridfunction (array of CCTK_REAL whose dimensions are given by the cctk_lsh variables) corresponding the the variable to which excision is to be applied.
(CCTK_REAL(ni,nj,nk)) A Cactus gridfunction holding the values of the variable to be excised on the previous slice (ie. previous time).
(CCTK_REAL(ni,nj,nk)) A Cactus gridfunction which contians the excision mask.
dirx, diry, dirz
(CCTK_REAL(ni,nj,nk)] Grid functions describing the normal directions to the excision boundary. These are determined by excision_findnormals().
ni, nj, nk
(integer) Dimensions of the grid, corresponding to cctk_lsh(1...3).
(CCTK_REAL) A constant value which will be written to all points of the grid function within the excision mask.

For example, given an excision mask ex_mask, excision can be applied to the grid functions fn0, fn1 and fn2 using the following code:

       call excision_findboundary (ierr, ex_mask, nx, ny, nz)  
       call excision_findnormals (ierr, ex_mask, normx, normy, normz, nx,  
     +   ny, nz)  
       call excision_extrapolate (ierr, fn0, fn0_p, ex_mask, normx,  
     +   normy, normz, nx, ny, nz, 0.d0)  
       call excision_extrapolate (ierr, fn1, fn1_p, ex_mask, normx,  
     +   normy, normz, nx, ny, nz, 0.d0)  
       call excision_extrapolate (ierr, fn2, fn2_p, ex_mask, normx,  
     +   normy, normz, nx, ny, nz, 1.d0)

Since the excision mask is the same for each grid function, the boundary and normals only needed to be determined once. In this example, normx, normy and normz are cactus grid functions which should have been declared as, for instance,

  real ex_norm type=GF  
  } "Excision boundary normals"

in the param.ccl of the thorn implementing this code, or one from which it inherits. The same is true of the excision mask. The fn0_p grid function should hold the value of fn0 on the previous timestep.

The final argument which is passed is a value which is used to overwrite grid function values within the excision region. Thus, though boundary points have a value applied by excision_extrapolate(), points of fn0 within the boundary are overwritten by the value 0, while for fn2 the value 1 is used instead.

Finally, note that any thorn which uses code as in the example above will depend on the LegoExcision thorn, and thus should declare

  inherits: legoexcision

in its interface.ccl, otherwise it will not compile unless LegoExcision is also included. This can be avoided through use of an #ifdef clause around any section of code which refers directly to LegoExcision:


This is, however, considered to be dubious form.

3 The mask function

The mask should be declared as a real-valued grid function, thus something like

  real legoexcision_mask type=GF  
  } "Excision mask"

in the calling thorn, or one which it inherits. Each point of the mask should take one of the following values, defined in maskvalues.h:

points which are within the excision region;
points on the excision boundary;
normal (non-excised) grid points.

The LegoExcision thorn does not specify any criteria for how these points should be set (ie. which points should be marked as excision points), but rather assumes that they have already been set by the calling thorn, or at some other point in the schedule. Thus, for instance for black hole evolutions, a horizon finder could be used to set an excision mask which would then be passed to an evolution thorn to ensure that points within horizon are not evolved. Note also that the mask function does not need to have boundary points identified, as the excision_findboundary() function can be used to locate them.

The CactusEinstein/Einstein thorn defines a generic mask function einstein::emask whose values are not defined, and can be used for this purpose. Storage for this grid function is turned on based on the value of the einstein::use_mask parameter.

Note that as of the time of writing, the Einstein heirarchy is undergoing a revision and the details of this description are likely to be modified. In particular, the use of the Einstein mask function is being formalised, so that at least the above definitions will change in the near future.

4 Boundary conditions

As mentioned above, the LegoExcision thorn applies a copying condition to points on the excision boundary. Namely, the time derivative is determined at one point away from the boundary in the direction determined by the normal. This time derivative is then applied to evolve the variable on the excision boundary.

For black hole spacetimes, it is possible that this condition is sufficient, since it is usually assumed that excision is only applied within an event horizon so that errors are causally propogated into the excision region. This particular condition has the advantage that if the spacetime is stationary, or evolves to a stationary state, outside of the excision region then the boundary respects this.

5 Using excision

The LegoExcision thorn has no parameters. To activate excision, include LegoExcision in the ActiveThorns any parameter file:

  ActiveThorns = "... LegoExcision ..."

This will ensure that the functions described above are available to any thorn which has implemented them.

6 Thorns which use LegoExcision

A number of the existing physic thorns can be used in conjunction with LegoExcision. In particular, the horizon finder can be used to set the mask to excise regions within the horizon so that they are not evolved by the BSSN evolution system.

The apparent horizon finder, CactusEinstein/AHFinder, includes a number of parameters which can be used to set a mask:

By setting this to either “strong” or “weak”, the mask will be set to excise points within any detected horizon. The difference between the two is that if “weak” is specified then the mask will be set even if only a probable marginally trapped surface is found, while “strong” will only set the mask if a horizon is definitely found. Usually it is fine to set ahfinder::ahf_mask="weak".
This parameter sets the shape of the mask which is set. If set to “cube”, then a region the shape of a cube will be used. The largest cube which fits entirely within the horizon will be used. This option was used for comparison with earlier results using SimpleExcision.
ahf_mask_0, ahf_mask_1, ahf_mask_2
These parameters determine whether the mask should be set for the respective horizons.
This fixes the minimum number of points which must exist between the apparent horizon and the excision region. Thus, the masked region will sit within a “buffer” region of the specified width from the horizon.
The region which is masked will be smaller than the actual horizon by a factor which is specified by this parameter. As with the ahf_maskbuffer parameter, this can be used to control the size of the buffer region between the horizon and the region to be excised.

If the apparent horizon finder is called with ahf_mask set to either “weak” or “strong”, then the grid function einstein::emask will be initialised according to the horizon locations, and can then be passed to the LegoExcision functions.

The AEIThorns/ADM_BSSN thorn can make use of a LegoExcision mask for evolutions. In order to turn on excision for an evolution, the parameters

  adm_bssn::excise = "yes"  
  adm_bssn::excisiontype = "lego"

should be set. The same holds for the BSSN_MoL thorn.

The Einstein/ADMConstraints thorn also respects the einstein::emask, so that the constraints will not be calculated within the excision region. To enable this feature, set

  admconstraints::excise = "yes"

In summary, to use LegoExcision in a BSSN evolution using the horizon finder to set the mask, modifications along the following lines need to be made to a parameter file: