src/solve.h
Helper macro to invert (linear) spatial operators
The macro below can be used to easily invert linear systems described by stencils i.e. \mathcal{L}(a) = b For example, let us consider the Poisson equation \nabla^2 a = b where a is unknown and b is given. This can be discretised as
(a[1] + a[-1] + a[0,1] + a[0,-1] - 4.*a[])/sq(Delta) = b[];
This can be solved using the macro below and a multigrid solver with
(a, (a[1] + a[-1] + a[0,1] + a[0,-1] - 4.*a[])/sq(Delta), b); solve
The macro can take the same optional arguments as mg_solve() to tune the multigrid solver.
The macro returns multigrid statistics.
#include "poisson.h"
Implementation
Note that the macro below is a slightly simplified version of the mg_solve() and mg_cycle() functions where more documentation can be found.
macro
mgstats solve (scalar a, double func, double rhs,
int nrelax = 4,
int minlevel = 0,
double tolerance = TOLERANCE)
{{
mgstats _s = (mgstats){0};
scalar _res[], _da[];
(_da, a);
scalar_clone for (int b = 0; b < nboundary; b++)
.boundary[b] = _da.boundary_homogeneous[b];
_da.nrelax = nrelax;
_sdouble _resb;
{
double maxres = 0.;
foreach (reduction(max:maxres)) {
[] = rhs - func;
_resif (fabs (_res[]) > maxres)
= fabs (_res[]);
maxres }
= _s.resb = _s.resa = maxres;
_resb }
for (_s.i = 0; _s.i < NITERMAX && (_s.i < NITERMIN || _s.resa > tolerance); _s.i++) {
{
({_res});
restriction int _maxlevel = grid->maxdepth;
int _minlevel = min (minlevel, _maxlevel);
for (int l = _minlevel; l <= _maxlevel; l++) {
if (l == _minlevel)
foreach_level_or_leaf (l)
foreach_blockf (_da)
[] = 0.;
_da
else(l)
foreach_level foreach_blockf (_da)
[] = bilinear (point, _da);
_da({_da}, l);
boundary_level for (int i = 0; i < _s.nrelax; i++) {
scalar a = _da;
foreach_level_or_leaf (l) {
[] = 0.;
adouble _n = _res[] - func, _d;
diagonalize(a)
= func;
_d [] = _n/_d;
a}
({_da}, l);
boundary_level }
}
foreach()
foreach_blockf (a)
[] += _da[];
a}
{
double maxres = 0.;
foreach (reduction(max:maxres)) {
[] = rhs - func;
_resif (fabs (_res[]) > maxres)
= fabs (_res[]);
maxres }
.resa = maxres;
_s}
if (_s.resa > tolerance) {
if (_resb/_s.resa < 1.2 && _s.nrelax < 100)
.nrelax++;
_selse if (_resb/_s.resa > 10 && _s.nrelax > 2)
.nrelax--;
_s}
= _s.resa;
_resb }
.minlevel = minlevel;
_sif (_s.resa > tolerance)
fprintf (stderr,
"src/solve.h:%d: warning: convergence for %s not reached after %d iterations\n"
" res: %g nrelax: %d\n", LINENO, a.name,
.i, _s.resa, _s.nrelax),
_sfflush (ferr);
return _s;
}}