sandbox/ghigo/src/mydiffusion.h
Time-implicit discretisation of reaction–diffusion equations
We want to discretise implicitly the reaction–diffusion equation \theta\partial_tf = \nabla\cdot(D\nabla f) + \beta f + r where \beta f + r is a reactive term, D is the diffusion coefficient and \theta can be a density term.
Using a time-implicit backward Euler discretisation, this can be written \theta\frac{f^{n+1} - f^{n}}{dt} = \nabla\cdot(D\nabla f^{n+1}) + \beta f^{n+1} + r Rearranging the terms we get \nabla\cdot(D\nabla f^{n+1}) + (\beta - \frac{\theta}{dt}) f^{n+1} = - \frac{\theta}{dt}f^{n} - r This is a Poisson–Helmholtz problem which can be solved with a multigrid solver.
#include "mypoisson.h"The parameters of the diffusion() function are a scalar
field f, scalar fields r and \beta defining the reactive term, the
timestep dt and a face vector field containing the
diffusion coefficient D. If D or \theta are omitted they are set to one. If
\beta is omitted it is set to zero.
Both D and \beta may be
constant fields.
Note that the r, \beta
and \theta fields will be modified by
the solver.
The function returns the statistics of the Poisson solver.
struct Diffusion {
// mandatory
scalar f;
double dt;
// optional
face vector D; // default 1
scalar r, beta; // default 0
scalar theta; // default 1
};
trace
mgstats diffusion (scalar f, double dt,
face vector D = {{-1}}, // default 1
scalar r = {-1}, // default 0
scalar beta = {-1}, // default 0
scalar theta = {-1}) // default 1
{
if (dt == 0.) {
mgstats s = {0};
return s;
}
scalar ar = automatic (r);
// theta_idt = -theta/dt (or -1/dt if theta not provided)
const scalar idt[] = -1./dt;
//(const) scalar theta_idt = theta.i >= 0 ? theta : idt;
scalar theta_idt[];
if (theta.i >= 0) {
foreach()
theta_idt[] = theta[] * idt[];
} else {
foreach()
theta_idt[] = idt[];
}
boundary ({theta_idt});
if (r.i >= 0)
foreach()
ar[] = theta_idt[]*f[] - ar[];
else
foreach()
ar[] = theta_idt[]*f[];
#if EMBED
foreach()
ar[] *= cs[];
#endif
boundary ({ar});
scalar lambda[];
foreach()
lambda[] = theta_idt[];
if (beta.i >= 0) {
foreach()
lambda[] += beta[];
}
#if EMBED
foreach()
lambda[] *= cs[];
#endif
boundary ({lambda});
return poisson (f, ar, D, lambda);
}