Generic nonlinear elliptic solver interface

Erik Schnetter <schnetter@uni-tuebingen.de >

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 different solvers at run time.

1 Elliptic equations

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

F(u) = 0 (1)

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(n) is an approximation to a solution u, then

r(n) := F(u(n)) (2)

is called the corresponding residual. An approximation u(n) 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 defined by the combination of

  1. the elliptic operator F
  2. a set of initial data u(0)
  3. 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 (Δu = 0) and the Poisson (Δu = ρ) equations.

In Cactus, u(n) and r(n) are represented by grid functions, while F and the boundary conditions to u are functions or subroutines written in C or Fortran.

2 Solver Interface

TATelliptic_CallSolver

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);


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


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. Different solvers will take different 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 final 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 file.

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 file.

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 file TATelliptic.h into your source files, your thorn has to use the header file 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);


calcres

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);


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

applybnds

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);


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

TATelliptic_RegisterSolver

Register an elliptic solver

Synopsis

C

#include "cctk.h"  
#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:

typedef int (* solvefunc) (cGH * cctkGH,  
                           const int * var,  
                           const int * res,  
                           int nvars,  
                           int options_table,  
                           calcfunc calcres,  
                           calcfunc applybnds,  
                           void * userdata);


solvername The name of the solver

Discussion

Each solver has to register its solving function with TATelliptic at startup time.

See Also

TATelliptic_CallSolver Call an elliptic solver

3 Pseudo solver

This thorn provides also a pseudo solver, called TATmonitor. This is not a real solver, although it poses as one and uses the TATelliptic_CallSolver interface. It does nothing but evaluate the residual and then return successfully.

You will find this a useful intermediate step when debugging your residual evaluation routines.

4 Parameters

5 Interfaces

General

Implements:

tatelliptic

Adds header:

TATelliptic.h

6 Schedule

This section lists all the variables which are assigned storage by thorn CactusElliptic/TATelliptic. Storage can either last for the duration of the run (Always means that if this thorn is activated storage will be assigned, Conditional means that if this thorn is activated storage will be assigned for the duration of the run if some condition is met), or can be turned on for the duration of a schedule function.

Storage

NONE

Scheduled Functions

CCTK_STARTUP

  tatelliptic_register_monitor

  register the pseudo solver

 

 Language:c
 Type: function