Numerical method¶
Interface capturing¶
To begin with, I consider an indicator function \(H\), which works as a marker taking \(0\) or \(1\) when the infinitesimal control volume is occupied with the primary or the secondary liquids, respectively. By this definition, as an equation governing the evolution of \(H\), I have
Since I assume the liquids are incompressible, this advection equation is equal to
whose volume-integrated form leads to
where \(\phi\) is the rate of the primary phase volume inside the control volume, or known as volume-of-fluid. Note that I assume the coordinate systems do not change in time. To integrate this equation, I employ the THINC/QQ method (Xie and Xiao, J. Comput. Phys. (349), 2017), whose numerical treatment is extensively discussed in the other project.
Consistency¶
Note that the following idea is widely known in the phase-field community (e.g. Mirjalili and Mani, J. Comput. Phys. (426), 2021), which is slightly customised and applied here.
As discussed above, how the volume fraction is evolved is totally determined by the volume-of-fluid method. Since \(H\) and \(\rho\) are related by
the evolution of the density (i.e. mass per unit volume) is also governed by the VOF method. Since the momentum is tightly linked to the flux of the mass, it is natural to apply this information (mass flux) to update the momentum field. To this end, I focus on the evolution of \(\phi\) again:
As the flux of the indicator function \(H u_j\) is already known, the density flux \(\rho u_j\) is obtained by
31for(int j = 0; j <= jsize + 1; j++){
32 for(int i = 1; i <= isize + 1; i++){
33 FLUXX(i, j) = UX(i, j) + (denr - 1.) * FLUXX(i, j);
34 }
35}
38for(int k = 0; k <= ksize + 1; k++){
39 for(int j = 0; j <= jsize + 1; j++){
40 for(int i = 1; i <= isize + 1; i++){
41 FLUXX(i, j, k) = UX(i, j, k) + (denr - 1.) * FLUXX(i, j, k);
42 }
43 }
44}
64for(int j = 0; j <= jsize + 1; j++){
65 for(int i = 0; i <= isize + 1; i++){
66 FLUXY(i, j) = UY(i, j) + (denr - 1.) * FLUXY(i, j);
67 }
68}
71for(int k = 0; k <= ksize + 1; k++){
72 for(int j = 0; j <= jsize + 1; j++){
73 for(int i = 0; i <= isize + 1; i++){
74 FLUXY(i, j, k) = UY(i, j, k) + (denr - 1.) * FLUXY(i, j, k);
75 }
76 }
77}
95for(int k = 0; k <= ksize + 1; k++){
96 for(int j = 0; j <= jsize + 1; j++){
97 for(int i = 0; i <= isize + 1; i++){
98 FLUXZ(i, j, k) = UZ(i, j, k) + (denr - 1.) * FLUXZ(i, j, k);
99 }
100 }
101}
Surface tension force¶
For simplicity, the continuum surface force model (Brackbill et al., J. Comput. Phys. (100), 1992) is adopted to model the interfacial tension:
39for(int j = 1; j <= jsize; j++){
40 for(int i = 2; i <= isize; i++){
41 const double den_x0 = (
42 + 0.5 * DEN(i-1, j )
43 + 0.5 * DEN(i , j )
44 );
45 const double kappa = (
46 + 0.5 * CURV(i-1, j )
47 + 0.5 * CURV(i , j )
48 );
49 const double delta = 1. / HXXF(i ) * (
50 - VOF(i-1, j )
51 + VOF(i , j )
52 );
53 IFRCX(i, j) = den_x0 * refdeninv * tension * kappa * delta;
54 }
55}
58for(int k = 1; k <= ksize; k++){
59 for(int j = 1; j <= jsize; j++){
60 for(int i = 2; i <= isize; i++){
61 const double den_x0 = (
62 + 0.5 * DEN(i-1, j , k )
63 + 0.5 * DEN(i , j , k )
64 );
65 const double kappa = (
66 + 0.5 * CURV(i-1, j , k )
67 + 0.5 * CURV(i , j , k )
68 );
69 const double delta = 1. / HXXF(i ) * (
70 - VOF(i-1, j , k )
71 + VOF(i , j , k )
72 );
73 IFRCX(i, j, k) = den_x0 * refdeninv * tension * kappa * delta;
74 }
75 }
76}
100for(int j = 1; j <= jsize; j++){
101 for(int i = 1; i <= isize; i++){
102 const double den_y0 = (
103 + 0.5 * DEN(i , j-1)
104 + 0.5 * DEN(i , j )
105 );
106 const double kappa = (
107 + 0.5 * CURV(i , j-1)
108 + 0.5 * CURV(i , j )
109 );
110 const double delta = 1. / hy * (
111 - VOF(i , j-1)
112 + VOF(i , j )
113 );
114 IFRCY(i, j) = den_y0 * refdeninv * tension * kappa * delta;
115 }
116}
119for(int k = 1; k <= ksize; k++){
120 for(int j = 1; j <= jsize; j++){
121 for(int i = 1; i <= isize; i++){
122 const double den_y0 = (
123 + 0.5 * DEN(i , j-1, k )
124 + 0.5 * DEN(i , j , k )
125 );
126 const double kappa = (
127 + 0.5 * CURV(i , j-1, k )
128 + 0.5 * CURV(i , j , k )
129 );
130 const double delta = 1. / hy * (
131 - VOF(i , j-1, k )
132 + VOF(i , j , k )
133 );
134 IFRCY(i, j, k) = den_y0 * refdeninv * tension * kappa * delta;
135 }
136 }
137}
159for(int k = 1; k <= ksize; k++){
160 for(int j = 1; j <= jsize; j++){
161 for(int i = 1; i <= isize; i++){
162 const double den_z0 = (
163 + 0.5 * DEN(i , j , k-1)
164 + 0.5 * DEN(i , j , k )
165 );
166 const double kappa = (
167 + 0.5 * CURV(i , j , k-1)
168 + 0.5 * CURV(i , j , k )
169 );
170 const double delta = 1. / hz * (
171 - VOF(i , j , k-1)
172 + VOF(i , j , k )
173 );
174 IFRCZ(i, j, k) = den_z0 * refdeninv * tension * kappa * delta;
175 }
176 }
177}
The pre-factor is computed here:
14static double compute_refdeninv(
15 const double denr
16){
17 return 2. / (1. + denr);
18}