$$Date$$

Abstract

This thorn is a generic interface to nonlinear elliptic solvers. It provides a uniform calling conventions to elliptic solvers. Elliptic solvers can register themselves with this thorn. Thorns requiring elliptic solvers can use this interface to call the solvers, and can choose between diﬀerent solvers at run time.

This thorn is a generic interface to nonlinear elliptic solvers. It provides a uniform calling conventions to elliptic solvers, but does not contain any actual solvers. Solvers are supposed to be implemented in other thorns, and then register with this thorn. A generic interface has the advantage that it decouples the thorns calling the solvers, and the solvers themselves. Thorns using elliptic solvers can choose among the available solvers at run time.

For the discussion below, I write elliptic equations as

$$\begin{array}{rcll}F\left(u\right)& =& 0& \text{(1)}\text{}\text{}\end{array}$$

where $u$ is the unknown, which is also known as variable, or in a sloppy terminology as solution. $F$ is the elliptic operator. All elliptic equations can be written in the above form.

If ${u}^{\left(n\right)}$ is an approximation to a solution $u$, then

$$\begin{array}{rcll}{r}^{\left(n\right)}& :=& F\left({u}^{\left(n\right)}\right)& \text{(2)}\text{}\text{}\end{array}$$

is called the corresponding residual. An approximation ${u}^{\left(n\right)}$ is a solution if the residual is zero.

The interface provided by this thorn allows for coupled sets of elliptic equations to be solved at the same time. The elliptic operator is allowed to be nonlinear.

A solution $u$ is deﬁned by the combination of

- the elliptic operator $F$
- a set of initial data ${u}^{\left(0\right)}$
- boundary conditions for the solution $u$.

Note that periodicity is usually not a boundary condition that leads to a well-posed problem. It fails already for the Laplace ($\Delta u=0$) and the Poisson ($\Delta u=\rho $) equations.

In Cactus, ${u}^{\left(n\right)}$ and ${r}^{\left(n\right)}$ are represented by grid functions, while $F$ and the boundary conditions to $u$ are functions or subroutines written in C or Fortran.

Call an elliptic solver

Synopsis

C

#include "cctk.h"

#include "TATelliptic.h"

int TATelliptic_CallSolver (cGH * cctkGH,

const int * var,

const int * res,

int nvars,

int options_table,

calcfunc calcres,

calcfunc applybnds,

void * userdata,

const char * solvername);

#include "TATelliptic.h"

int TATelliptic_CallSolver (cGH * cctkGH,

const int * var,

const int * res,

int nvars,

int options_table,

calcfunc calcres,

calcfunc applybnds,

void * userdata,

const char * solvername);

Fortran

#include "cctk.h"

interface

subroutine TATelliptic_CallSolver (ierr, cctkGH, var, res, nvars, &

options_table, &

calcres, applybnds, userdata, &

solvername)

integer ierr

CCTK_POINTER cctkGH

integer nvars

integer var(nvars)

integer res(nvars)

integer options_table

CCTK_FNPOINTER calcres

CCTK_FNPOINTER applybnds

CCTK_POINTER userdata

character solvername*(*)

end subroutine TATelliptic_CallSolver

end interface

interface

subroutine TATelliptic_CallSolver (ierr, cctkGH, var, res, nvars, &

options_table, &

calcres, applybnds, userdata, &

solvername)

integer ierr

CCTK_POINTER cctkGH

integer nvars

integer var(nvars)

integer res(nvars)

integer options_table

CCTK_FNPOINTER calcres

CCTK_FNPOINTER applybnds

CCTK_POINTER userdata

character solvername*(*)

end subroutine TATelliptic_CallSolver

end interface

Result

0 Success.

nonzero Failure. Error codes are $-1$
if there are illegal arguments to the solver interface, and
$-2$ if the
requested solver does not exist. Otherwise, the error code from the solver is returned.

Parameters

cctkGH The pointer to the CCTK grid hierarchy

var Array with nvars grid function indices for the variables. The variables are also called “unknowns”, or
“solution”.

res Array with nvars grid function indices for the residuals. These grid functions store the residuals
corresponding to the variables above.

nvars Number of variables. This is also the number of residuals.

options_table Further options to and return values from the solver. Diﬀerent solvers will take
diﬀerent additional arguments. The interface TATelliptic does not look at these options, but
passes this table on to the real solver. This must be a table handle created with the table utility
functions.

Below is a list of some commonly accepted options. See the individual solver documentations for details:

- CCTK_REAL minerror:
- The desired solver accuracy.
- CCTK_REAL factor:
- A factor with which all residuals are multiplied. This factor can be used to scale the residuals.
- CCTK_REAL factors[nvars]:
- An array of factors with which the residuals are multiplied. These factors can be used to handle inconvenient sign conventions for the residuals.
- CCTK_INT maxiters:
- Maximum number of iterations.
- CCTK_INT nboundaryzones[2*dim]:
- Number of boundary points for each face. If not given, this is the same as the number of ghost points.

The following values are often returned. Again, see the individual solver documentations for details:

- CCTK_INT iters:
- Number of iterations taken
- CCTK_REAL error:
- Norm of the ﬁnal residual

calcres Pointer to a C function that evaluates the residual. This function is passed in a solution, and has to evaluate the residual. See below.

applybnds Pointer to a C function that applies the boundary condition to the variables. This function is passed in a solution, and has to apply the boundary conditions to it.

userdata A pointer to arbitrary application data. This pointer is passed through the solver unchanged on to calcres and applybnds. The application can use this instead of global variables to pass arbitrary data. If in doubt, pass a null pointer.

solvername The name of a registered solver.

Discussion

The function TATelliptic_CallSolver is the the interface to solve an elliptic equation.

Input arguments are the arrays var and res, containing the grid function indices for the solution and the residual, as well as functions calcres and applybnds to evaluate the residual and apply boundary conditions. solvername selects the solver.

Hint: It is convenient to make the solver name a string parameter. This allows the solver to be selected at run time from the parameter ﬁle.

On entry, the grid functions listed in var have to contain an initial guess for the solution. This is necessary because the equations can be nonlinear. An initial guess of zero has to be set explicitly.

On exit, if the solver was successul, these grid functions contain an approximation to a solution. The grid functions listed in res contain the corresponding residual.

Additional solver options are passed in a table with the table index options_table. This table must have been created with one of the table utility functions. The set of accepted options depends on the particular solver that is called. Do not forget to free the table after you are done with it.

Hint: It is convenient to create the table from a string parameter with a call to Util_TableCreateFromString. This allows the solver parameters to be set in the parameter ﬁle.

In order to be able to call this function in the thorn TATelliptic, your thorn has to inherit from TATelliptic in your interface.ccl:

INHERITS: TATelliptic

In order to be able to include the ﬁle TATelliptic.h into your source ﬁles, your thorn has to use the header ﬁle TATelliptic.h in your interface.ccl:

USES INCLUDE: TATelliptic.h

Currently, only three-dimensional elliptic equations can be solved.

See Also

calcres Evaluate the residual

applybnds Apply the boundary conditions

Examples

C

DECLARE_CCTK_PARAMETERS;

/* options and solver are string parameters */

int varind; /* index of variable */

int resind; /* index of residual */

int options_table; /* table for additional solver options */

int i,j,k;

int ipos; /* position in 3D array */

int ierr;

static int calc_residual (cGH * cctkGH, int options_table, void * userdata);

static int apply_bounds (cGH * cctkGH, int options_table, void * userdata);

/* Initial data for the solver */

for (k=0; k<cctk_lsh[2]; ++k) {

for (j=0; j<cctk_lsh[1]; ++j) {

for (i=0; i<cctk_lsh[0]; ++i) {

ipos = CCTK_GFINDEX3D(cctkGH,i,j,k);

phi[ipos] = 0;

}

}

}

/* Options for the solver */

options_table = Util_TableCreateFromString (options);

assert (options_table>=0);

/* Grid variables for the solver */

varind = CCTK_VarIndex ("wavetoy::phi");

assert (varind>=0);

resind = CCTK_VarIndex ("IDSWTE::residual");

assert (varind>=0);

/* Call solver */

ierr = TATelliptic_CallSolver (cctkGH, &varind, &resind, 1,

options_table,

calc_residual, apply_bounds, 0,

solver);

if (ierr!=0) {

CCTK_WARN (1, "Failed to solve elliptic equation");

}

ierr = Util_TableDestroy (options_table);

assert (!ierr);

/* options and solver are string parameters */

int varind; /* index of variable */

int resind; /* index of residual */

int options_table; /* table for additional solver options */

int i,j,k;

int ipos; /* position in 3D array */

int ierr;

static int calc_residual (cGH * cctkGH, int options_table, void * userdata);

static int apply_bounds (cGH * cctkGH, int options_table, void * userdata);

/* Initial data for the solver */

for (k=0; k<cctk_lsh[2]; ++k) {

for (j=0; j<cctk_lsh[1]; ++j) {

for (i=0; i<cctk_lsh[0]; ++i) {

ipos = CCTK_GFINDEX3D(cctkGH,i,j,k);

phi[ipos] = 0;

}

}

}

/* Options for the solver */

options_table = Util_TableCreateFromString (options);

assert (options_table>=0);

/* Grid variables for the solver */

varind = CCTK_VarIndex ("wavetoy::phi");

assert (varind>=0);

resind = CCTK_VarIndex ("IDSWTE::residual");

assert (varind>=0);

/* Call solver */

ierr = TATelliptic_CallSolver (cctkGH, &varind, &resind, 1,

options_table,

calc_residual, apply_bounds, 0,

solver);

if (ierr!=0) {

CCTK_WARN (1, "Failed to solve elliptic equation");

}

ierr = Util_TableDestroy (options_table);

assert (!ierr);

Evaluate the residual. This function is written by the user. The name of this function does not matter (and should likely not be calcres). This function is passed as a pointer to TATelliptic_CallSolver.

Synopsis

C

#include "cctk.h"

#include "TATelliptic.h"

int calcres (cGH * cctkGH,

int options_table,

void * userdata);

#include "TATelliptic.h"

int calcres (cGH * cctkGH,

int options_table,

void * userdata);

Fortran

No Fortran equivalent. Result

0 Success; continue solving

nonzero Failure; abort solving

Parameters

cctkGH The pointer to the CCTK grid hierarchy

options_table A table passed from the solver, or an illegal table index. If this is a table, then it may contain
additional information about the solving process (such as the current multigrid level). This depends on the
particular solver that is used.

userdata A pointer to arbitrary application data. This is the same pointer that was passed to
TATelliptic_CallSolver. The application can use this instead of global variables to pass arbitrary data.

Discussion

This function has to be provided by the user. It has to calculate the residual corresponding to the current (approximation of the) solution.

Input to this function are the unknowns, output are the residuals.

The residuals need not be synchronised. The boundary values of the residuals are not used, and hence do not have to be set.

See Also

TATelliptic_CallSolver Call an elliptic solver

applybnds Apply the boundary conditions

Apply the boundary conditions to the solution. This function is written by the user. The name of this function does not matter (and should likely not be applybnds). This function is passed as a pointer to TATelliptic_CallSolver.

Synopsis

C

#include "cctk.h"

#include "TATelliptic.h"

int applybnds (cGH * cctkGH,

int options_table,

void * userdata);

#include "TATelliptic.h"

int applybnds (cGH * cctkGH,

int options_table,

void * userdata);

Fortran

No Fortran equivalent. Result

0 Success; continue solving

nonzero Failure; abort solving

Parameters

cctkGH The pointer to the CCTK grid hierarchy

options_table A table passed from the solver, or an illegal table index. If this is a table, then it may contain
additional information about the solving process (such as the current multigrid level). This depends on the
particular solver that is used.

userdata A pointer to arbitrary application data. This is the same pointer that was passed to
TATelliptic_CallSolver. The application can use this instead of global variables to pass arbitrary data.

Discussion

This function has to be provided by the user. It has to apply the boundary and symmetry conditions to the solution.

Input to this function is the interior of the solution, output are the boundary values of the solution.

This function also has to synchronise the solution.

See Also

TATelliptic_CallSolver Call an elliptic solver

calcres Evaluate the residual

Register an elliptic solver

Synopsis

C

#include "cctk.h"

#include "TATelliptic.h"

int TATelliptic_RegisterSolver (solvefunc solver,

const char * solvername);

#include "TATelliptic.h"

int TATelliptic_RegisterSolver (solvefunc solver,

const char * solvername);

Result

0 Success.

-1 Failure: illegal arguments. solver or solvername are null.

-2 Failure: a solver with this name has already been registered.

Parameters

solver A pointer to the solver’s solving function. This function has to have the following interface, which is the same as that of TATelliptic_CallSolver except that the argument solvername is missing: