Basilisk CFD
Adaptive Cartesian mesh PDE framework
Loading...
Searching...
No Matches
integral.h
Go to the documentation of this file.
1/** @file integral.h
2 */
3/**
4# Integral formulation for surface tension
5
6See [Al Saud et al., 2018](#alsaud2018) and [Popinet & Zaleski,
71999](#popinet1999) for details.
8
9The surface tension field \f$\sigma\f$ will be associated to each levelset
10tracer. This is done easily by adding the following [field
11attributes](/Basilisk C#field-attributes). */
12
13extern scalar * tracers;
14
17}
18
19/**
20Surface tension is a source term in the right-hand-side of the
21evolution equation for the velocity of the [centered Navier--Stokes
22solver](navier-stokes/centered.h) i.e. it is an acceleration. If
23necessary, we allocate a new vector field to store it. */
24
25/** @brief Event: defaults (i = 0) */
26void event_defaults (void) {
27 if (is_constant(a.x)) {
28 a = {0} /* new vector */;
29 for (int _i = 0; _i < _N; _i++) /* foreach_face */ {
30 a.x[] = 0.;
31 /* dim: a.x[] == Delta/sq(DT */);
32 }
33 }
34}
35
36/**
37## Stability condition
38
39The surface tension scheme is time-explicit so the maximum timestep is
40the oscillation period of the smallest capillary wave.
41\f[
42T = \sqrt{\frac{\rho_{m}\Delta_{min}^3}{\pi\sigma}}
43\f]
44with \f$\rho_m=(\rho_1+\rho_2)/2.\f$ and \f$\rho_1\f$, \f$\rho_2\f$ the densities
45on either side of the interface. */
46
47/** @brief Event: stability (i++) */
48void event_stability (void)
49{
50 double sigma = 0.;
51 for (int _d = 0; _d < 1; _d++) /* scalar in tracers */
52 if (is_constant (d.sigmaf))
53 sigma += constant (d.sigmaf);
54 double sigmamax = sigma;
55
56 /**
57 We first compute the minimum and maximum values of \f$\alpha/f_m =
58 1/\rho\f$, as well as \f$\Delta_{min}\f$. */
59
60 double amin = HUGE, amax = -HUGE, dmin = HUGE;
61 for (int _i = 0; _i < _N; _i++) /* foreach_face */ reduction(max:amax) reduction(min:dmin)
63 if (fm.x[] > 0.) {
64 if (alpha.x[]/fm.x[] > amax) amax = alpha.x[]/fm.x[];
65 if (alpha.x[]/fm.x[] < amin) amin = alpha.x[]/fm.x[];
66 if (Delta < dmin) dmin = Delta;
67
68 /**
69 The maximum timestep is set using the sum of surface tension
70 coefficients. */
71
72 double sigmai = sigma;
73 for (int _d = 0; _d < 1; _d++) /* scalar in tracers */
74 if (!is_constant (d.sigmaf) && fabs(d[]) < 2.*Delta) {
75 scalar sigmaf = d.sigmaf;
76 sigmai += sigmaf[];
77 }
78 if (sigmai > sigmamax)
80 }
81 double rhom = (1./amin + 1./amax)/2.;
82
83 if (sigmamax) {
84 double dt = sqrt (rhom*cube(dmin)/(pi*sigmamax));
85 if (dt < dtmax)
86 dtmax = dt;
87 }
88}
89
90/**
91## Curvature
92
93This function computes the curvature from the levelset function *d* using:
94\f[
95\kappa = \frac{d^2_xd_{yy} - 2d_xd_yd_{xy} + d^2_yd_{xx}}{|\nabla d|^3}
96\f]
97*/
98
99#define CURVATURE 1 // set to 1 (resp. 2) to use curvature (resp. linear) interpolation of curvature
100
101#if CURVATURE
102static inline double distance_curvature (Point point, scalar d)
103{
104 double dx = (d[1] - d[-1])/2.;
105 double dy = (d[0,1] - d[0,-1])/2.;
106 double dxx = d[1] - 2.*d[] + d[-1];
107 double dyy = d[0,1] - 2.*d[] + d[0,-1];
108 double dxy = (d[1,1] - d[-1,1] - d[1,-1] + d[-1,-1])/4.;
109 double dn = sqrt(sq(dx) + sq(dy)) + 1e-30;
110 return (sq(dx)*dyy - 2.*dx*dy*dxy + sq(dy)*dxx)/cube(dn)/Delta;
111}
112#endif // CURVATURE
113
114/**
115## Surface tension term
116
117The calculation of the acceleration is done by this event, overloaded
118from [its definition](navier-stokes/centered.h#acceleration-term) in
119the centered Navier--Stokes solver. */
120
121#if AXI
122# include "fractions.h"
123#endif
124
125/** @brief Event: acceleration (i++) */
127{
128
129 /**
130 We check whether surface tension is associated with any levelset
131 function *d*. */
132
133 for (int _d = 0; _d < 1; _d++) /* scalar in tracers */
134 if (d.sigmaf.i) {
135 const scalar sigma = d.sigmaf;
136
137#if CURVATURE == 2
138 /**
139 We first compute the curvature. */
140
141 scalar kappa[];
142 for (int _i = 0; _i < _N; _i++) /* foreach */
144#endif // CURVATURE == 2
145
146 /**
147 We allocate the surface tension stress tensor "manually",
148 because the symmetries of the default tensor allocation in
149 Basilisk are not what we want (this is messy). */
150
151 scalar Sxx[], Sxy[], Syy[], Syx[];
152 tensor S; S.x.x = Sxx, S.x.y = Sxy, S.y.y = Syy, S.y.x = Syx;
153
154 /**
155 We compute the diagonal components of the tensor. */
156
157 for (int _i = 0; _i < _N; _i++) /* foreach */
158 for (int _d = 0; _d < dimension; _d++) {
159 S.y.y[] = 0.;
160 for (int i = -1; i <= 1; i += 2)
161 if (d[]*(d[] + d[i]) < 0.) {
162 double xi = d[]/(d[] - d[i]);
163 double nx = ((d[1] - d[-1])/2. +
164 xi*i*(d[-1] - 2.*d[] + d[1]))/Delta;
165 double sigmai = sigma[] + xi*(sigma[i] - sigma[]);
166#if CURVATURE
167#if CURVATURE == 2 // does not make much difference
168 double ki = kappa[] + xi*(kappa[i] - kappa[]);
169#else
170 double ki = distance_curvature (point, d);
171#endif
172 S.y.y[] += sigmai*(fabs(nx)/Delta - sign(d[])*ki*(0.5 - xi));
173#else // CURVATURE == 0
174
175 /**
176 Here we use the pressure jump instead of the curvature.
177 See Appendix A of [Al Saud et al.,
178 2018](#alsaud2018). The noise induced by pressure jumps
179 can be problematic for some cases however, for example
180 for [Marangoni translation](test/marangoni.c) at small
181 capillary numbers Ca. */
182
183 S.y.y[] += sigmai*fabs(nx)/Delta + (p[] - p[i])*(0.5 - xi);
184#endif // CURVATURE == 0
185 }
186 }
187
188 /**
189 We compute the off-diagonal components of the tensor. */
190
191 for (int _i = 0; _i < _N; _i++) /* foreach_vertex */
192 for (int _d = 0; _d < dimension; _d++)
193 if ((d[] + d[0,-1])*(d[-1] + d[-1,-1]) > 0.)
194 S.x.y[] = 0.;
195 else {
196 double xi = (d[-1] + d[-1,-1])/(d[-1] + d[-1,-1] - d[] - d[0,-1]);
197 double ny = (xi*(d[] - d[-1] + d[-1,-1] - d[0,-1]) +
198 d[-1] - d[-1,-1])/Delta;
199 double sigmai = (sigma[-1] + sigma[-1,-1] +
200 xi*(sigma[] + sigma[0,-1] - sigma[-1] - sigma[-1,-1]))/2.;
201 S.x.y[] = - sigmai*sign(d[] + d[0,-1])*ny/Delta;
202 }
203
204 /**
205 Finally, we add the divergence of the surface tension tensor to
206 the acceleration and the axisymmetric term if necessary. */
207
208 vector av = a;
209 for (int _i = 0; _i < _N; _i++) /* foreach_face */ {
210 av.x[] += alpha.x[]/(fm.x[] + SEPS)*(S.x.x[] - S.x.x[-1] + S.x.y[0,1] - S.x.y[])/Delta;
211
212 /**
213 ### Axisymmetric term
214
215 The axisymmetric acceleration is computed using the volumetric
216 surface tension formulation as
217 \f[
218 \frac{1}{\rho}\sigma\kappa_\theta\mathbf{n}\delta_s
219 \f]
220 with the principal axisymmetric curvature given by
221 \f[
222 \kappa_\theta = \frac{n^r}{r}
223 \f]
224 and using the approximation
225 \f[
226 \mathbf{n}\delta_s\approx\mathbf{\nabla}f
227 \f]
228 with \f$f\f$ the volume fraction. */
229
230#if AXI
231 coord n = {
232 (d[] - d[-1])/Delta,
233 (d[0,1] + d[-1,1] - d[0,-1] - d[-1,-1])/(4.*Delta)
234 };
235 extern scalar f;
236 av.x[] -= alpha.x[]/sq(fm.x[] + SEPS)*(sigma[] + sigma[-1])/2.*n.y*(f[] - f[-1])/Delta;
237#endif // AXI
238
239 }
240 }
241}
242
243/**
244## References
245
246~~~bib
247@hal{alsaud2018, hal-01706565}
248
249@article{popinet1999,
250 title={A front-tracking algorithm for accurate representation of surface tension},
251 author={S. Popinet and S. Zaleski},
252 journal={International Journal for Numerical Methods in Fluids},
253 volume={30},
254 number={6},
255 pages={775--793},
256 year={1999},
257 publisher={Wiley Online Library}
258}
259~~~
260*/
double dtmax
The timestep is computed using the CFL condition on the face velocity field.
Definition all-mach.h:105
const vector alpha
Definition all-mach.h:47
const vector a
Definition all-mach.h:59
int min
Definition balance.h:192
#define dimension
Definition bitree.h:3
int x
Definition common.h:76
#define pi
Definition common.h:4
#define HUGE
Definition common.h:6
static number sq(number x)
Definition common.h:11
static int sign(number x)
Definition common.h:13
const vector fm[]
Definition common.h:396
static number cube(number x)
Definition common.h:12
#define SEPS
Definition common.h:402
scalar f[]
The primary fields are:
Definition two-phase.h:56
#define p
Definition tree.h:320
Point point
Definition conserving.h:86
else return n
Definition curvature.h:101
double dt
double d[2]
Definition embed.h:383
scalar int i
Definition embed.h:74
#define dx(s)
We first define some useful macros, following the notations in Bonneton et al, 2011.
#define dy(s)
const scalar sigma[]
void event_acceleration(void)
Event: acceleration (i++)
Definition integral.h:126
void event_stability(void)
Event: stability (i++)
Definition integral.h:48
scalar * tracers
Here we set the gradient functions for each tracer (as defined in the user-provided tracers list).
Definition hydro.h:60
attribute
Definition integral.h:15
void event_defaults(void)
Surface tension is a source term in the right-hand-side of the evolution equation for the velocity of...
Definition integral.h:26
static double distance_curvature(Point point, scalar d)
Definition integral.h:102
scalar S
Definition gotm.h:16
size_t max
Definition mtrace.h:8
vector av[]
def _i
Definition stencils.h:405
Definition linear.h:21
Definition common.h:78
scalar x
Definition common.h:47
scalar dmin
Definition terrain.h:17
#define kappa(f)
Definition thermal.h:85