sandbox/Antoonvh/my_first_MG_solver.c
Evaluate a line integral
We want to find a, such that,
\displaystyle \frac{\partial a}{\partial n} = -b
With suitable boundary conditions, this corresponds to,
\displaystyle a = \int b \mathrm{d}n
with n some coordinate line under an angle \theta (THETA_ANGLE
) with the x axis. For this purpose a multigrid solver is used,
#include "grid/multigrid.h"
#include "poisson.h"
A residual function for our problem,
double THETA_ANGLE = 0.0;
static double residual_int (scalar * al, scalar * bl, scalar * resl, void * data) {
double maxres = 0.;
double st = sin(THETA_ANGLE);
double ct = cos(THETA_ANGLE);
int ix = ct > 0 ? 0 : -1;
int iy = st > 0 ? 0 : -1;
scalar a = al[0], b = bl[0], res = resl[0];
foreach(reduction(max:maxres)) {
double ax = (a[1 + ix] - a[ix])/Delta;
double ay = (a[0, 1 + iy] - a[0, iy])/Delta;
res[] = -b[] - ct*ax - st*ay ;
if (fabs (res[]) > maxres)
maxres = fabs (res[]);
}
return maxres;
}
with a relevant relaxation-function formulation.
static void relax_int (scalar * al, scalar * bl, int l, void * data) {
scalar a = al[0];
scalar b = bl[0];
double st = sin(THETA_ANGLE);
double ct = cos(THETA_ANGLE);
int ix = ct > 0 ? 1 : -1;
int iy = st > 0 ? 1 : -1;
st = fabs(st);
ct = fabs(ct);
The scheme appears to benefit from a few relaxations
for (int j = 0; j < 2; j++){
foreach_level_or_leaf(l)
a[] = (-b[]*Delta + ct*a[ix] + st*a[0, iy])/(ct + st);
//a[] = (a[] + 2*(-b[]*Delta + ct*a[ix] + st*a[0, iy])/(ct + st))/3;
}
}
User interface
Let us hope this procedure converges.
struct Integrate_dn {
scalar a, b;
(const) face vector alpha;
(const) scalar lambda;
double tolerance;
int nrelax, minlevel;
scalar * res;
};
mgstats integrate_dn (struct Integrate_dn p) {
scalar a = p.a, b = p.b;
return mg_solve({a}, {b}, residual_int, relax_int,
&p, p.nrelax, p.res, minlevel = 1);
}
Give it a go.
#include "utils.h"
scalar a[], b[];
a[right] = dirichlet (0);
a[top] = dirichlet (0);
a[left] = dirichlet (0);
a[bottom] = dirichlet (0);
int main() {
X0 = Y0 = -L0/2.;
init_grid (1 << 9);
foreach()
b[] = exp(-(sq(x*10) + sq(y*10)));
output_ppm (b, file = "b.png", n = 256, min = 0, max = 1);
restriction({b});
boundary ({b});
for (double THETA = 0.; THETA < 3*pi; THETA += 0.1){
THETA_ANGLE = THETA;
printf("%d\n", integrate_dn (a, b).i);
output_ppm (a, file = "a.mp4", n = 256, min = 0, max = sqrt(pi)/10.);
}
}
Results
The source term (b) looks like this:
And the solution (a):
Well done multigrid solver! Much better than this \mathcal{O}(N^2) approach!