Basilisk CFD
Adaptive Cartesian mesh PDE framework
Loading...
Searching...
No Matches
viscosity-embed.h
Go to the documentation of this file.
1/** @file viscosity-embed.h
2 */
3/**
4# Viscous solver with embedded boundaries
5
6We consider the Stokes equations
7\f[
8\rho \mathbf{u}_t = \rho \mathbf{g} +
9\nabla \cdot [\mu ( \nabla \mathbf{u} + \nabla^T \mathbf{u})]
10\f]
11with \f$\mathbf{g}\f$ the acceleration and \f$T\f$ the transpose.
12
13In the case of incompressible flow and uniform viscosity, the viscous term
14can be further simplified. Since
15\f[
16\nabla \cdot (\mu \nabla \mathbf{u}) =
17(\nabla \mu) \cdot \nabla \mathbf{u} + \mu \nabla (\nabla \cdot \mathbf{u}) = 0
18\f]
19the viscous term reduces to
20\f[
21\nabla \cdot [\mu ( \nabla \mathbf{u} + \nabla^T \mathbf{u})] =
22\nabla \cdot (\mu \nabla^T \mathbf{u}) = \nabla^2 (\mu \mathbf{u})
23\f]
24and the equations for each velocity component are decoupled. For each
25component \f$v_i\f$, the following discrete implicit equation is solved
26using the multigrid solver
27\f[
28\frac{\Delta t} \nabla (\mu \nabla v_i^{n+1}) - (\rho + \lambda_i) v_i^{n+1}
29+ \underbrace{(\rho v_i^{n} + g_i\, Delta t)}_{r_i} = 0
30\f]
31\f$\lambda_i\f$ is a possible extra term due to the metric. */
32
33#include "poisson.h"
34
35struct Viscosity {
38 double dt;
39 double (* embed_flux) (Point, scalar, vector, double *);
40};
41
42#if AXI
43# define lambda ((coord){0, dt*(mu.x[] + mu.x[1] \
44 + mu.y[] + mu.y[0,1])*sq(cs[]) \
45 /(fm.x[] + fm.x[1] + fm.y[] + fm.y[0,1] + SEPS)/(cm[] + SEPS)})
46
47#else // not AXI
48# define lambda ((coord){0.,0.,0.})
49#endif
50
51// Note how the relaxation function uses "naive" gradients i.e. not
52// the face_gradient_* macros.
53
54static void relax_diffusion (scalar * a, scalar * b, int l, void * data)
55{
56 struct Viscosity * p = (struct Viscosity *) data;
57 const vector mu = p->mu;
58 const scalar rho = p->rho;
59 double dt = p->dt;
60 vector u = vector(a[0]), r = vector(b[0]);
61
62 double (* embed_flux) (Point, scalar, vector, double *) = p->embed_flux;
63 for (int _i = 0; _i < l, nowarning; _i++) {
64 double avgmu = 0.;
65 for (int _d = 0; _d < dimension; _d++)
66 avgmu += mu.x[] + mu.x[1];
67 avgmu = dt*avgmu + SEPS;
68 for (int _d = 0; _d < dimension; _d++) {
69 double c = 0.;
70 double d = embed_flux ? embed_flux (point, u.x, mu, &c) : 0.;
71 scalar s = u.x;
72 double a = 0.;
73 for (int _d = 0; _d < dimension; _d++)
74 a += mu.x[1]*s[1] + mu.x[]*s[-1];
75 u.x[] = (dt*a + (r.x[] - dt*c)*sq(Delta))/
76 (sq(Delta)*(rho[] + lambda.x + dt*d) + avgmu);
77 }
78 }
79
80#if TRASH
81 vector u1[];
82 for (int _i = 0; _i < l; _i++)
83 for (int _d = 0; _d < dimension; _d++)
84 u1.x[] = u.x[];
85 /* trash: u */;
86 for (int _i = 0; _i < l; _i++)
87 for (int _d = 0; _d < dimension; _d++)
88 u.x[] = u1.x[];
89#endif
90}
91
92static double residual_diffusion (scalar * a, scalar * b, scalar * resl,
93 void * data)
94{
95 struct Viscosity * p = (struct Viscosity *) data;
96 const vector mu = p->mu;
97 const scalar rho = p->rho;
98 double dt = p->dt;
99 double (* embed_flux) (Point, scalar, vector, double *) = p->embed_flux;
100 vector u = vector(a[0]), r = vector(b[0]), res = vector(resl[0]);
101 double maxres = 0.;
102#if TREE
103 /* conservative coarse/fine discretisation (2nd order) */
104 for (int _d = 0; _d < dimension; _d++) {
105 scalar s = u.x;
106 vector g[];
107 for (int _i = 0; _i < _N; _i++) /* foreach_face */
108 g.x[] = mu.x[]*face_gradient_x (s, 0);
109 foreach (reduction(max:maxres), nowarning) {
110 double a = 0.;
111 for (int _d = 0; _d < dimension; _d++)
112 a += g.x[] - g.x[1];
113 res.x[] = r.x[] - (rho[] + lambda.x)*u.x[] - dt*a/Delta;
114 if (embed_flux) {
115 double c, d = embed_flux (point, u.x, mu, &c);
116 res.x[] -= dt*(c + d*u.x[]);
117 }
118 if (fabs (res.x[]) > maxres)
119 maxres = fabs (res.x[]);
120 }
121 }
122#else
123 /* "naive" discretisation (only 1st order on trees) */
124 foreach (reduction(max:maxres), nowarning)
125 for (int _d = 0; _d < dimension; _d++) {
126 scalar s = u.x;
127 double a = 0.;
128 for (int _d = 0; _d < dimension; _d++)
129 a += mu.x[0]*face_gradient_x (s, 0) - mu.x[1]*face_gradient_x (s, 1);
130 res.x[] = r.x[] - (rho[] + lambda.x)*u.x[] - dt*a/Delta;
131 if (embed_flux) {
132 double c, d = embed_flux (point, u.x, mu, &c);
133 res.x[] -= dt*(c + d*u.x[]);
134 }
135 if (fabs (res.x[]) > maxres)
136 maxres = fabs (res.x[]);
137 }
138#endif
139 return maxres;
140}
141
142#undef lambda
143
144double TOLERANCE_MU = 0.; // default to TOLERANCE
145
146trace
148 int nrelax = 4, scalar * res = NULL)
149{
150 vector r[];
151 for (int _i = 0; _i < _N; _i++) /* foreach */
152 for (int _d = 0; _d < dimension; _d++)
153 r.x[] = rho[]*u.x[];
154
155 restriction ({mu, rho});
156 struct Viscosity p = { mu, rho, dt };
157 p.embed_flux = u.x.boundary[embed] != antisymmetry ? embed_flux : NULL;
158 return mg_solve ((scalar *){u}, (scalar *){r},
159 residual_diffusion, relax_diffusion, &p, nrelax, res,
160 minlevel = 1, // fixme: because of root level
161 // BGHOSTS = 2 bug on trees
162 tolerance = TOLERANCE_MU ? TOLERANCE_MU : TOLERANCE);
163}
#define u
Definition advection.h:30
vector g[]
We store the combined pressure gradient and acceleration field in g*.
Definition all-mach.h:65
const vector a
Definition all-mach.h:59
#define dimension
Definition bitree.h:3
static double antisymmetry(Point point, Point neighbor, scalar s, bool *data)
define l
int x
Definition common.h:76
#define face_gradient_x(a, i)
Definition common.h:403
static number sq(number x)
Definition common.h:11
#define vector(x)
Definition common.h:354
#define SEPS
Definition common.h:402
#define mu(f)
By default the Harmonic mean is used to compute the phase-averaged dynamic viscosity.
Definition two-phase.h:85
#define p
Definition tree.h:320
Point point
Definition conserving.h:86
double dt
scalar s
Definition embed-tree.h:56
double embed_flux(Point point, scalar s, vector mu, double *val)
Definition embed.h:657
double d[2]
Definition embed.h:383
bid embed
Definition embed.h:463
#define data(k, l)
Definition linear.h:26
#define rho(f)
The density and viscosity are defined using arithmetic averages by default.
Definition momentum.h:45
size_t max
Definition mtrace.h:8
void(* restriction)(Point, scalar)
size *double * b
trace mgstats mg_solve(scalar *a, scalar *b, double(*residual)(scalar *a, scalar *b, scalar *res, void *data), void(*relax)(scalar *da, scalar *res, int depth, void *data), void *data=NULL, int nrelax=4, scalar *res=NULL, int minlevel=0, double tolerance=TOLERANCE)
The user needs to provide a function which computes the residual field (and returns its maximum) as w...
Definition poisson.h:130
double TOLERANCE
Definition poisson.h:107
def _i
Definition stencils.h:405
Definition linear.h:21
double(* embed_flux)(Point, scalar, vector, double *)
Information about the convergence of the solver is returned in a structure.
Definition poisson.h:112
scalar x
Definition common.h:47
double TOLERANCE_MU
static double residual_diffusion(scalar *a, scalar *b, scalar *resl, void *data)
trace mgstats viscosity(vector u, vector mu, scalar rho, double dt, int nrelax=4, scalar *res=NULL)
static void relax_diffusion(scalar *a, scalar *b, int l, void *data)
#define lambda
scalar c
Definition vof.h:57