-
Notifications
You must be signed in to change notification settings - Fork 1
/
three-phase-viscoelastic.h
163 lines (140 loc) · 4.38 KB
/
three-phase-viscoelastic.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
/**
# Three-phase interfacial flows: here, at least one of the phases (f1*(1-f2)) forms a precursor film
# Version 0.2
# Author: Vatsal Sanjay
# Physics of Fluids
# Last Updated: Jul 24, 2024
This file helps setup simulations for flows of three fluids separated by
corresponding interfaces (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 i is $f_i=1$ and $f_i=0$ everywhere else.
The densities and dynamic viscosities for fluid 1, 2 and 3 are *rho1*,
*mu1*, *rho2*, *mu2*, and *rho3*, *mu3* respectively. */
#include "vof.h"
scalar f1[], f2[], *interfaces = {f1, f2};
(const) scalar Gp = unity; // elastic modulus
(const) scalar lambda = unity; // relaxation time
double rho1 = 1., mu1 = 0., rho2 = 1., mu2 = 0., rho3 = 1., mu3 = 0.;
double G1 = 0., G2 = 0., G3 = 0.; // elastic moduli
double lambda1 = 0., lambda2 = 0., lambda3 = 0.; // relaxation times
double TOLelastic = 1e-1; // tolerance for elastic modulus
/**
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[];
scalar Gpd[];
scalar lambdapd[];
event defaults (i = 0) {
alpha = alphav;
rho = rhov;
Gp = Gpd;
lambda = lambdapd;
/**
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(f1, f2) (clamp(f1*(1-f2), 0., 1.) * rho1 + clamp(f1*f2, 0., 1.) * rho2 + clamp((1-f1), 0., 1.) * rho3)
#endif
#ifndef mu
#define mu(f1, f2) (clamp(f1*(1-f2), 0., 1.) * mu1 + clamp(f1*f2, 0., 1.) * mu2 + clamp((1-f1), 0., 1.) * mu3)
#endif
/**
We have the option of using some "smearing" of the density/viscosity
jump. */
#ifdef FILTERED
scalar sf1[], sf2[], *smearInterfaces = {sf1, sf2};
#else
#define sf1 f1
#define sf2 f2
scalar *smearInterfaces = {sf1, sf2};
#endif
event tracer_advection (i++)
{
if (i > 1){
foreach(){
if ((f2[] > 1e-2) && (f1[] < 1.-1e-2)){
f1[] = f2[];
}
}
}
/**
When using smearing of the density jump, we initialise *sfi* with the
vertex-average of *fi*. */
#ifdef FILTERED
int counter1 = 0;
for (scalar sf in smearInterfaces){
counter1++;
int counter2 = 0;
for (scalar f in interfaces){
counter2++;
if (counter1 == counter2){
// fprintf(ferr, "%s %s\n", sf.name, f.name);
#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
for (scalar sf in smearInterfaces){
sf.prolongation = refine_bilinear;
sf.dirty = true; // boundary conditions need to be updated
}
#endif
}
event properties (i++) {
foreach_face() {
double ff1 = (sf1[] + sf1[-1])/2.;
double ff2 = (sf2[] + sf2[-1])/2.;
alphav.x[] = fm.x[]/rho(ff1, ff2);
face vector muv = mu;
muv.x[] = fm.x[]*mu(ff1, ff2);
}
foreach(){
rhov[] = cm[]*rho(sf1[], sf2[]);
Gpd[] = 0.;
lambdapd[] = 0.;
if (clamp(sf1[]*(1-sf2[]), 0., 1.) > TOLelastic){
Gpd[] += G1*clamp(sf1[]*(1-sf2[]), 0., 1.);
lambdapd[] += lambda1*clamp(sf1[]*(1-sf2[]), 0., 1.);
}
if (clamp(sf1[]*sf2[], 0., 1.) > TOLelastic){
Gpd[] += G2*clamp(sf1[]*sf2[], 0., 1.);
lambdapd[] += lambda2*clamp(sf1[]*sf2[], 0., 1.);
}
if (clamp((1-sf1[]), 0., 1.) > TOLelastic){
Gpd[] += G3*clamp((1-sf1[]), 0., 1.);
lambdapd[] += lambda3*clamp((1-sf1[]), 0., 1.);
}
}
#if TREE
for (scalar sf in smearInterfaces){
sf.prolongation = fraction_refine;
sf.dirty = true;
}
#endif
}