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 (struct Diffusion p)
{
If dt is zero we don’t do anything.
if (p.dt == 0.) {
mgstats s = {0};
return s;
}
We define f and r for convenience.
scalar f = p.f, r = automatic (p.r);
We define a (possibly constant) field equal to \theta/dt.
const scalar idt[] = - 1./p.dt;
(const) scalar theta_idt = p.theta.i ? p.theta : idt;
if (p.theta.i) {
scalar theta_idt = p.theta;
foreach()
[] *= idt[];
theta_idt}
We use r
to store the r.h.s. of the Poisson–Helmholtz
solver.
if (p.r.i)
foreach()
[] = theta_idt[]*f[] - r[];
relse // r was not passed by the user
foreach()
[] = theta_idt[]*f[];
r#if EMBED
foreach()
[] *= cs[];
r#endif // EMBED
boundary ({r});
If \beta is provided, we use it to store the diagonal term \lambda.
scalar lambda[];
foreach()
[] = theta_idt[];
lambdaif (p.beta.i) {
scalar beta = p.beta;
foreach()
[] += beta[];
lambda}
#if EMBED
foreach()
[] *= cs[];
lambda#endif // EMBED
boundary ({lambda});
Finally we solve the system.
return poisson (f, r, p.D, lambda);
}