sandbox/Miguel/contact_angle/heights_angle.h
Height-Functions
The contact angle boundary condition is imposed by calculating the heights function in the ghost cells
#define HSHIFT 20.
static inline double height (double H) {
return H > HSHIFT/2. ? H - HSHIFT : H < -HSHIFT/2. ? H + HSHIFT : H;
}
static inline int orientation (double H) {
return fabs(H) > HSHIFT/2.;
}
#define BGHOSTS 2
static void half_column (Point point, scalar c, vector h, vector cs, int j)
{
const int complete = -1;
foreach_dimension() {
double S = c[], H = S, ci, a;
typedef struct { int s; double h; } HState;
HState state = {0, 0};
if (j == 1) {
if (h.x[] == 300.)
state.s = complete, state.h = nodata;
else {
int s = (h.x[] + HSHIFT/2.)/100.;
state.h = h.x[] - 100.*s;
state.s = s - 1;
}
if (state.s != complete)
S = state.s, H = state.h;
}
for (int i = 1; i <= 4; i++) {
ci = i <= 2 ? c[i*j] : cs.x[(i - 2)*j];
H += ci;
if (S > 0. && S < 1.) {
S = ci;
if (ci <= 0. || ci >= 1.) {
H -= i*ci;
break;
}
}
else if (S >= 1. && ci <= 0.) {
H = (H - 0.5)*j + (j == -1)*HSHIFT;
S = complete;
break;
}
else if (S <= 0. && ci >= 1.) {
H = (i + 0.5 - H)*j + (j == 1)*HSHIFT;
S = complete;
break;
}
else if (S == ci && modf(H, &a))
break;
}
if (j == -1) {
if (S != complete && ((c[] <= 0. || c[] >= 1.) ||
(S > 0. && S < 1.)))
h.x[] = 300.; // inconsistent
else if (S == complete)
h.x[] = H;
else
h.x[] = H + 100.*(1. + (S >= 1.));
}
else { // j = 1
if (state.s != complete ||
(S == complete && fabs(height(H)) < fabs(height(state.h))))
state.s = S, state.h = H;
if (state.s != complete)
h.x[] = nodata;
else
h.x[] = (state.h > 1e10 ? nodata : state.h);
}
}
}
static void column_propagation (vector h)
{
foreach()
for (int i = -2; i <= 2; i++)
foreach_dimension()
if (fabs(height(h.x[i])) <= 3.5 &&
fabs(height(h.x[i]) + i) < fabs(height(h.x[])))
h.x[] = h.x[i] + i;
boundary ((scalar *){h});
foreach_boundary(left)
{
h.y[-1,0] = height(h.y []) + (1/tan(theta_0));
}
}
#if !TREE
trace
void heights (scalar c, vector h)
{
vector cs[];
foreach_dimension()
for (int i = 0; i < nboundary; i++)
cs.x.boundary[i] = c.boundary[i];
for (int j = -1; j <= 1; j += 2) {
foreach()
foreach_dimension()
cs.x[] = c[2*j];
boundary ((scalar *){cs});
foreach()
half_column (point, c, h, cs, j);
}
boundary ((scalar *){h});
column_propagation (h);
}
#else // TREE
foreach_dimension()
static void refine_h_x (Point point, scalar h)
{
bool complete = true;
foreach_child() {
for (int i = -2; i <= 2; i++)
if (allocated(i) &&
!is_prolongation(neighbor(i)) && !is_boundary(neighbor(i)) &&
fabs(height(h[i])) <= 3.5 &&
fabs(height(h[i]) + i) < fabs(height(h[])))
h[] = h[i] + i;
if (h[] == nodata)
complete = false;
}
if (complete)
return;
int ori = orientation(h[]);
#if dimension == 2
for (int i = -1; i <= 1; i++)
if (h[0,i] == nodata || orientation(h[0,i]) != ori)
return;
double h0 = (30.*height(h[]) + height(h[0,1]) + height(h[0,-1]))/16.
+ HSHIFT*ori;
double dh = (height(h[0,1]) - height(h[0,-1]))/4.;
foreach_child()
if (h[] == nodata)
h[] = h0 + dh*child.y - child.x/2.;
#else // dimension == 3
double H[3][3], H0 = height(h[]);
for (int i = -1; i <= 1; i++)
for (int j = -1; j <= 1; j++)
if (h[0,i,j] == nodata || orientation(h[0,i,j]) != ori)
return;
else
H[i+1][j+1] = height(h[0,i,j]) - H0;
double h0 =
2.*H0 + (H[2][2] + H[2][0] + H[0][0] + H[0][2] +
30.*(H[2][1] + H[0][1] + H[1][0] + H[1][2]))/512.
+ HSHIFT*ori;
double h1 = (H[2][2] + H[2][0] - H[0][0] - H[0][2] +
30.*(H[2][1] - H[0][1]))/128.;
double h2 = (H[2][2] - H[2][0] - H[0][0] + H[0][2] +
30.*(H[1][2] - H[1][0]))/128.;
double h3 = (H[0][0] + H[2][2] - H[0][2] - H[2][0])/32.;
foreach_child()
if (h[] == nodata)
h[] = h0 + h1*child.y + h2*child.z + h3*child.y*child.z - child.x/2.;
#endif // dimension == 3
}
trace
void heights (scalar c, vector h)
{
vector cs[];
foreach_dimension()
for (int i = 0; i < nboundary; i++)
cs.x.boundary[i] = c.boundary[i];
restriction ({c});
for (int j = -1; j <= 1; j += 2) {
foreach_level(0)
foreach_dimension()
h.x[] = nodata;
for (int l = 1; l <= depth(); l++) {
foreach_level (l)
foreach_dimension()
cs.x[] = c[2*j];
foreach_level (l - 1)
foreach_dimension() {
cs.x[] = c[j];
cs.x[j] = c[2*j];
}
foreach_halo (prolongation, l - 1)
foreach_dimension()
c.prolongation (point, cs.x);
boundary_iterate (level, (scalar *){cs}, l);
foreach_level (l)
half_column (point, c, h, cs, j);
}
}
foreach_dimension() {
h.x.prolongation = no_data;
h.x.restriction = no_restriction;
}
boundary ((scalar *){h});Contact angle boundary condition implementation
foreach_boundary(left)
{
h.y[-1,0] = height(h.y []) + (1/tan(theta_0));
} foreach_dimension()
h.x.prolongation = refine_h_x;
column_propagation (h);
}
#endif // TREE