-
Notifications
You must be signed in to change notification settings - Fork 3
/
two-phaseAxiVP.h
executable file
·200 lines (166 loc) · 6.77 KB
/
two-phaseAxiVP.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/**
# Two-phase interfacial flows
This is a modified version of [two-phase.h](http://basilisk.fr/src/two-phase.h). It contains the implementation of
Viscoplastic Fluid (Bingham Fluid).<br/>
This file helps setup simulations for flows of two fluids separated by
an interface (i.e. immiscible fluids). It is typically used in
combination with a [Navier--Stokes solver](navier-stokes/centered.h).
The interface between the fluids is tracked with a Volume-Of-Fluid
method. The volume fraction in fluid 1 is $f=1$ and $f=0$ in fluid
2. The densities and dynamic viscosities for fluid 1 and 2 are *rho1*,
*mu1*, *rho2*, *mu2*, respectively. */
#include "vof.h"
scalar f[], * interfaces = {f};
scalar D2[];
face vector D2f[];
double rho1 = 1., mu1 = 0., rho2 = 1., mu2 = 0.;
double mumax = 0., tauy = 0.;
/**
Auxilliary fields are necessary to define the (variable) specific
volume $\alpha=1/\rho$ as well as the cell-centered density. */
face vector alphav[];
scalar rhov[];
event defaults (i = 0) {
alpha = alphav;
rho = rhov;
/**
If the viscosity is non-zero, we need to allocate the face-centered
viscosity field. */
mu = new face vector;
}
/**
The density and viscosity are defined using arithmetic averages by
default. The user can overload these definitions to use other types of
averages (i.e. harmonic). */
#ifndef rho
# define rho(f) (clamp(f,0.,1.)*(rho1 - rho2) + rho2)
#endif
#ifndef mu
// # define mu(muTemp, mu2, f) (clamp(f,0.,1.)*(muTemp - mu2) + mu2)
// New harmonic mean definition:
# define mu(muTemp, mu2, f) (1.0 / ((clamp(f,0.,1.) / muTemp) + ((1.0 - clamp(f,0.,1.)) / mu2)))
#endif
/**
We have the option of using some "smearing" of the density/viscosity
jump. */
#ifdef FILTERED
scalar sf[];
#else
# define sf f
#endif
event tracer_advection (i++) {
/**
When using smearing of the density jump, we initialise *sf* with the
vertex-average of *f*. */
#ifndef sf
#if dimension <= 2
foreach()
sf[] = (4.*f[] +
2.*(f[0,1] + f[0,-1] + f[1,0] + f[-1,0]) +
f[-1,-1] + f[1,-1] + f[1,1] + f[-1,1])/16.;
#else // dimension == 3
foreach()
sf[] = (8.*f[] +
4.*(f[-1] + f[1] + f[0,1] + f[0,-1] + f[0,0,1] + f[0,0,-1]) +
2.*(f[-1,1] + f[-1,0,1] + f[-1,0,-1] + f[-1,-1] +
f[0,1,1] + f[0,1,-1] + f[0,-1,1] + f[0,-1,-1] +
f[1,1] + f[1,0,1] + f[1,-1] + f[1,0,-1]) +
f[1,-1,1] + f[-1,1,1] + f[-1,1,-1] + f[1,1,1] +
f[1,1,-1] + f[-1,-1,-1] + f[1,-1,-1] + f[-1,-1,1])/64.;
#endif
#endif
#if TREE
sf.prolongation = refine_bilinear;
sf.dirty = true; // boundary conditions need to be updated
#endif
}
event properties (i++) {
/**
This is part where we have made changes.
$$\mathcal{D}_{11} = \frac{\partial u_r}{\partial r}$$
$$\mathcal{D}_{22} = \frac{u_r}{r}$$
$$\mathcal{D}_{13} = \frac{1}{2}\left( \frac{\partial u_r}{\partial z}+ \frac{\partial u_z}{\partial r}\right)$$
$$\mathcal{D}_{31} = \frac{1}{2}\left( \frac{\partial u_z}{\partial r}+ \frac{\partial u_r}{\partial z}\right)$$
$$\mathcal{D}_{33} = \frac{\partial u_z}{\partial z}$$
$$\mathcal{D}_{12} = \mathcal{D}_{23} = 0.$$
The second invariant is $\mathcal{D}_2=\sqrt{\mathcal{D}_{ij}\mathcal{D}_{ij}}$ (this is the Frobenius norm)
$$\mathcal{D}_2^2= \mathcal{D}_{ij}\mathcal{D}_{ij}= \mathcal{D}_{11}\mathcal{D}_{11} + \mathcal{D}_{22}\mathcal{D}_{22} + \mathcal{D}_{13}\mathcal{D}_{31} + \mathcal{D}_{31}\mathcal{D}_{13} + \mathcal{D}_{33}\mathcal{D}_{33}$$
**Note:** $\|\mathcal{D}\| = D_2/\sqrt{2}$.<br/>
We use the formulation as given in [Balmforth et al. (2013)](https://www.annualreviews.org/doi/pdf/10.1146/annurev-fluid-010313-141424), they use $\dot \gamma$
which is by their definition $\sqrt{\frac{1}{2}\dot \gamma_{ij} \dot \gamma_{ij}}$
and as $\dot \gamma_{ij}=2 D_{ij}$
Therefore, $\dot \gamma$ = $\sqrt{2} \mathcal{D}_2$, that is why we have a $\sqrt{2}$ in the equations.
Factorising with $2 \mathcal{D}_{ij}$ to obtain a equivalent viscosity
$$\tau_{ij} = 2( \mu_0 + \frac{\tau_y}{2 \|\mathcal{D}\| } ) D_{ij}=2( \mu_0 + \frac{\tau_y}{\sqrt{2} \mathcal{D}_2 } ) \mathcal{D}_{ij} $$
As defined by [Balmforth et al. (2013)](https://www.annualreviews.org/doi/pdf/10.1146/annurev-fluid-010313-141424)
$$\tau_{ij} = 2 \mu_{eq} \mathcal{D}_{ij} $$
with
$$\mu_{eq}= \mu_0 + \frac{\tau_y}{\sqrt{2} \mathcal{D}_2 }$$
Finally, mu is the min of of $\mu_{eq}$ and a large $\mu_{max}$.
The fluid flows always, it is not a solid, but a very viscous fluid.
$$ \mu = \text{min}\left(\mu_{eq}, \mu_{max}\right) $$
Reproduced from: [P.-Y. Lagrée's Sandbox](http://basilisk.fr/sandbox/M1EMN/Exemples/bingham_simple.c). Here, we use a face implementation of the regularisation method, described [here](http://basilisk.fr/sandbox/vatsal/GenaralizedNewtonian/Couette_NonNewtonian.c).
*/
foreach_face(x) {
double ff = (sf[] + sf[-1])/2.;
alphav.x[] = fm.x[]/rho(ff);
double muTemp = mu1;
face vector muv = mu;
double D11 = 0.5*( (u.y[0,1] - u.y[0,-1] + u.y[-1,1] - u.y[-1,-1])/(2.*Delta) );
double D22 = (u.y[] + u.y[-1, 0])/(2*max(y, 1e-20));
double D33 = (u.x[] - u.x[-1,0])/Delta;
double D13 = 0.5*( (u.y[] - u.y[-1, 0])/Delta + 0.5*( (u.x[0,1] - u.x[0,-1] + u.x[-1,1] - u.x[-1,-1])/(2.*Delta) ) );
double D2temp = sqrt( sq(D11) + sq(D22) + sq(D33) + 2*sq(D13) );
if (D2temp > 0. && tauy > 0.){
double temp = tauy/(sqrt(2.)*D2temp) + mu1;
muTemp = min(temp, mumax);
} else {
if (tauy > 0.){
muTemp = mumax;
} else {
muTemp = mu1;
}
}
muv.x[] = fm.x[]*mu(muTemp, mu2, ff);
D2f.x[] = D2temp;
}
foreach_face(y) {
double ff = (sf[0,0] + sf[0,-1])/2.;
alphav.y[] = fm.y[]/rho(ff);
double muTemp = mu1;
face vector muv = mu;
double D11 = (u.y[0,0] - u.y[0,-1])/Delta;
double D22 = (u.y[0,0] + u.y[0,-1])/(2*max(y, 1e-20));
double D33 = 0.5*( (u.x[1,0] - u.x[-1,0] + u.x[1,-1] - u.x[-1,-1])/(2.*Delta) );
double D13 = 0.5*( (u.x[0,0] - u.x[0,-1])/Delta + 0.5*( (u.y[1,0] - u.y[-1,0] + u.y[1,-1] - u.y[-1,-1])/(2.*Delta) ) );
double D2temp = sqrt( sq(D11) + sq(D22) + sq(D33) + 2*sq(D13) );
if (D2temp > 0. && tauy > 0.){
double temp = tauy/(sqrt(2.)*D2temp) + mu1;
muTemp = min(temp, mumax);
} else {
if (tauy > 0.){
muTemp = mumax;
} else {
muTemp = mu1;
}
}
muv.y[] = fm.y[]*mu(muTemp, mu2, ff);
D2f.y[] = D2temp;
}
/**
I also calculate a cell-centered scalar D2, where I store $\|\mathbf{\mathcal{D}}\|$. This can also be used for refimnement to accurately refine the fake-yield surfaces.
*/
foreach(){
rhov[] = cm[]*rho(sf[]);
D2[] = (D2f.x[]+D2f.y[]+D2f.x[1,0]+D2f.y[0,1])/4.;
if (D2[] > 0.){
D2[] = log(D2[])/log(10);
} else {
D2[] = -10;
}
}
#if TREE
sf.prolongation = fraction_refine;
sf.dirty = true; // boundary conditions need to be updated
#endif
}