sandbox/msaini/Marangoni/functionsHF.h
Check if this is exact copy of curvature.h in Basilisk scr
#if TREE
static void curvature_restriction (Point point, scalar kappa)
{
double k = 0., s = 0.;
foreach_child()
if (kappa[] != nodata)
k += kappa[], s++;
kappa[] = s ? k/s : nodata;
}
static void curvature_prolongation (Point point, scalar kappa)
{
foreach_child() {
double sk = 0., s = 0.;
for (int i = 0; i <= 1; i++)
#if dimension > 1
for (int j = 0; j <= 1; j++)
#endif
#if dimension > 2
for (int k = 0; k <= 1; k++)
#endif
if (coarse(kappa,child.x*i,child.y*j,child.z*k) != nodata)
sk += coarse(kappa,child.x*i,child.y*j,child.z*k), s++;
kappa[] = s ? sk/s : nodata;
}
}
#endif // TREE
#include "heights.h"
foreach_dimension()
static double kappa_y (Point point, vector h)
{
int ori = orientation(h.y[]);
for (int i = -1; i <= 1; i++)
if (h.y[i] == nodata || orientation(h.y[i]) != ori)
return nodata;
double hx = (h.y[1] - h.y[-1])/2.;
double hxx = (h.y[1] + h.y[-1] - 2.*h.y[])/Delta;
return hxx/pow(1. + sq(hx), 3/2.);
}
foreach_dimension()
static coord normal_y (Point point, vector h)
{
coord n = {nodata, nodata, nodata};
if (h.y[] == nodata)
return n;
int ori = orientation(h.y[]);
if (h.y[-1] != nodata && orientation(h.y[-1]) == ori) {
if (h.y[1] != nodata && orientation(h.y[1]) == ori)
n.x = (h.y[-1] - h.y[1])/2.;
else
n.x = h.y[-1] - h.y[];
}
else if (h.y[1] != nodata && orientation(h.y[1]) == ori)
n.x = h.y[] - h.y[1];
else
return n;
double nn = (ori ? -1. : 1.)*sqrt(1. + sq(n.x));
n.x /= nn;
n.y = 1./nn;
return n;
}
static double height_curvature (Point point, scalar c, vector h)
{
typedef struct {
double n;
double (* kappa) (Point, vector);
} NormKappa;
struct { NormKappa x, y, z; } n;
foreach_dimension()
n.x.n = c[1] - c[-1], n.x.kappa = kappa_x;
double (* kappaf) (Point, vector) = NULL; NOT_UNUSED (kappaf);
if (fabs(n.x.n) < fabs(n.y.n))
swap (NormKappa, n.x, n.y);
#if dimension == 3
if (fabs(n.x.n) < fabs(n.z.n))
swap (NormKappa, n.x, n.z);
if (fabs(n.y.n) < fabs(n.z.n))
swap (NormKappa, n.y, n.z);
#endif
double kappa = nodata;
foreach_dimension()
if (kappa == nodata) {
kappa = n.x.kappa (point, h);
if (kappa != nodata) {
kappaf = n.x.kappa;
if (n.x.n < 0.)
kappa = - kappa;
}
}
if (kappa != nodata) {
if (fabs(kappa) > 1./Delta)
kappa = sign(kappa)/Delta;
}
return kappa;
}
coord height_normal (Point point, scalar c, vector h)
{
typedef struct {
double n;
coord (* normal) (Point, vector);
} NormNormal;
struct { NormNormal x, y, z; } n;
foreach_dimension()
n.x.n = c[1] - c[-1], n.x.normal = normal_x;
if (fabs(n.x.n) < fabs(n.y.n))
swap (NormNormal, n.x, n.y);
#if dimension == 3
if (fabs(n.x.n) < fabs(n.z.n))
swap (NormNormal, n.x, n.z);
if (fabs(n.y.n) < fabs(n.z.n))
swap (NormNormal, n.y, n.z);
#endif
coord normal = {nodata, nodata, nodata};
foreach_dimension()
if (normal.x == nodata)
normal = n.x.normal (point, h);
return normal;
}
#include "parabola.h"
static int independents (coord * p, int n)
{
if (n < 2)
return n;
int ni = 1;
for (int j = 1; j < n; j++) {
bool depends = false;
for (int i = 0; i < j && !depends; i++) {
double d2 = 0.;
foreach_dimension()
d2 += sq(p[i].x - p[j].x);
depends = (d2 < sq(0.5));
}
ni += !depends;
}
return ni;
}
static double height_curvature_fit (Point point, scalar c, vector h)
{
coord ip[dimension == 2 ? 6 : 27];
int n = 0;
foreach_dimension() {
int n1 = 0, n2 = 0;
for (int i = -1; i <= 1; i++)
if (h.y[i] != nodata) {
if (orientation(h.y[i])) n1++; else n2++;
}
int ori = (n1 > n2);
for (int i = -1; i <= 1; i++)
if (h.y[i] != nodata && orientation(h.y[i]) == ori)
ip[n].x = i, ip[n++].y = height(h.y[i]);
}
if (independents (ip, n) < (dimension == 2 ? 3 : 9))
return nodata;
coord m = mycs (point, c), fc;
double alpha = plane_alpha (c[], m);
double area = plane_area_center (m, alpha, &fc);
ParabolaFit fit;
parabola_fit_init (&fit, fc, m);
NOT_UNUSED(area);
parabola_fit_add (&fit, fc, PARABOLA_FIT_CENTER_WEIGHT);
for (int i = 0; i < n; i++)
parabola_fit_add (&fit, ip[i], 1.);
parabola_fit_solve (&fit);
double kappa = parabola_fit_curvature (&fit, 2., NULL)/Delta;
return kappa;
}
static double centroids_curvature_fit (Point point, scalar c)
{
coord m = mycs (point, c), fc;
double alpha = plane_alpha (c[], m);
plane_area_center (m, alpha, &fc);
ParabolaFit fit;
parabola_fit_init (&fit, fc, m);
coord r = {x,y,z};
foreach_neighbor(1)
if (c[] > 0. && c[] < 1.) {
coord m = mycs (point, c), fc;
double alpha = plane_alpha (c[], m);
double area = plane_area_center (m, alpha, &fc);
coord rn = {x,y,z};
foreach_dimension()
fc.x += (rn.x - r.x)/Delta;
parabola_fit_add (&fit, fc, area);
}
parabola_fit_solve (&fit);
double kappa = parabola_fit_curvature (&fit, 2., NULL)/Delta;
return kappa;
}
static inline bool interfacial (Point point, scalar c)
{
if (c[] >= 1.) {
for (int i = -1; i <= 1; i += 2)
foreach_dimension()
if (c[i] <= 0.)
return true;
}
else if (c[] <= 0.) {
for (int i = -1; i <= 1; i += 2)
foreach_dimension()
if (c[i] >= 1.)
return true;
}
else // c[] > 0. && c[] < 1.
return true;
return false;
}
typedef struct {
int h; // number of standard HF curvatures
int f; // number of parabolic fit HF curvatures
int a; // number of averaged curvatures
int c; // number of centroids fit curvatures
} cstats;
trace
cstats curvature (scalar c, scalar kappa,
double sigma = 1.[0], bool add = false)
{
int sh = 0, sf = 0, sa = 0, sc = 0;
vector ch = c.height, h = automatic (ch);
if (!ch.x.i)
heights (c, h);
On trees we set the prolongation and restriction functions for the curvature.
#if TREE
kappa.refine = kappa.prolongation = curvature_prolongation;
kappa.restriction = curvature_restriction;
#endif
We first compute a temporary curvature k: a “clone” of \kappa.
scalar k[];
scalar_clone (k, kappa);
foreach(reduction(+:sh) reduction(+:sf)) {
if ((k[] = height_curvature (point, c, h)) != nodata)
sh++;
else if ((k[] = height_curvature_fit (point, c, h)) != nodata)
sf++;
}
foreach (reduction(+:sa) reduction(+:sc)) {
We then construct the final curvature field using either the computed temporary curvature…
double kf;
if (k[] < nodata)
kf = k[];
else if (interfacial (point, c)) {
…or the average of the curvatures in the 3^{d} neighborhood of interfacial cells.
double sk = 0., a = 0.;
foreach_neighbor(1)
if (k[] < nodata)
sk += k[], a++;
if (a > 0.)
kf = sk/a, sa++;
else
Empty neighborhood: we try centroids as a last resort.
kf = centroids_curvature_fit (point, c), sc++;
}
else
kf = nodata;
We add or set kappa.
if (kf == nodata)
kappa[] = nodata;
else if (add)
kappa[] += sigma*kf;
else
kappa[] = sigma*kf;
}
return (cstats){sh, sf, sa, sc};
}
Position of an interface
This is similar to curvature but this time for the position of the interface, defined as \displaystyle pos = \mathbf{G}\cdot(\mathbf{x} - \mathbf{Z}) with \mathbf{G} and \mathbf{Z} two vectors and \mathbf{x} the coordinates of the interface.
This is defined only in interfacial cells. In all the other cells it takes the value nodata.
We first need a function to compute the position \mathbf{x} of an interface. For accuracy, we first try to use height functions.
foreach_dimension()
static double pos_x (Point point, vector h, coord * G, coord * Z)
{
if (fabs(height(h.x[])) > 1.)
return nodata;
coord o = {x, y, z};
o.x += height(h.x[])*Delta;
double pos = 0.;
foreach_dimension()
pos += (o.x - Z->x)*G->x;
return pos;
}
We now need to choose one of the x, y or z height functions to compute the position. This is done by the function below which returns the HF position given a volume fraction field f, a height function field h and vectors G and Z.
static double height_position (Point point, scalar f, vector h,
coord * G, coord * Z)
{
We first define pairs of normal coordinates n (computed by simple differencing of f) and corresponding HF position function pos (defined above).
typedef struct {
double n;
double (* pos) (Point, vector, coord *, coord *);
} NormPos;
struct { NormPos x, y, z; } n;
foreach_dimension()
n.x.n = f[1] - f[-1], n.x.pos = pos_x;
We sort these pairs in decreasing order of |n|.
if (fabs(n.x.n) < fabs(n.y.n))
swap (NormPos, n.x, n.y);
#if dimension == 3
if (fabs(n.x.n) < fabs(n.z.n))
swap (NormPos, n.x, n.z);
if (fabs(n.y.n) < fabs(n.z.n))
swap (NormPos, n.y, n.z);
#endif
We try each position function in turn.
double pos = nodata;
foreach_dimension()
if (pos == nodata)
pos = n.x.pos (point, h, G, Z);
return pos;
}
The position() function fills field pos with \displaystyle \mathbf{G}\cdot(\mathbf{x} - \mathbf{Z}) with \mathbf{x} the position of the interface defined by f.
If add is true, the position is added to pos.
void position (scalar f, scalar pos,
coord G = {0}, coord Z = {0}, bool add = false)
{
On trees we set the prolongation and restriction functions for the position.
#if TREE
pos.refine = pos.prolongation = curvature_prolongation;
pos.restriction = curvature_restriction;
#endif
vector fh = f.height, h = automatic (fh);
if (!fh.x.i)
heights (f, h);
foreach() {
if (interfacial (point, f)) {
double hp = height_position (point, f, h, &G, &Z);
if (hp == nodata) {
If the height function is not defined, we use the centroid of the reconstructed VOF interface.
coord n = mycs (point, f), o = {x,y,z}, c;
double alpha = plane_alpha (f[], n);
plane_area_center (n, alpha, &c);
hp = 0.;
foreach_dimension()
hp += (o.x + Delta*c.x - Z.x)*G.x;
}
if (add)
pos[] += hp;
else
pos[] = hp;
}
else
pos[] = nodata;
}
}